Merge "Use AUDIO_IO_HANDLE_NONE instead of 0"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..010b2b4
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,18 @@
+// 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.
+
+subdirs = [
+    "native/android",
+    "native/graphics/jni",
+]
diff --git a/Android.mk b/Android.mk
index c5b3b6b..e352bc7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,7 @@
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
 	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
+	core/java/android/bluetooth/le/IAdvertiserCallback.aidl \
 	core/java/android/content/IClipboard.aidl \
 	core/java/android/content/IContentService.aidl \
 	core/java/android/content/IIntentReceiver.aidl \
@@ -199,6 +200,7 @@
 	core/java/android/net/ICaptivePortal.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/IConnectivityMetricsLogger.aidl \
+	core/java/android/net/IIpConnectivityMetrics.aidl \
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -220,6 +222,7 @@
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
+	core/java/android/os/IDeviceIdentifiersPolicyService.aidl \
 	core/java/android/os/IDeviceIdleController.aidl \
 	core/java/android/os/IHardwarePropertiesManager.aidl \
 	core/java/android/os/IMaintenanceActivityListener.aidl \
@@ -238,6 +241,7 @@
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
 	core/java/android/security/IKeystoreService.aidl \
+	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
@@ -328,6 +332,7 @@
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
 	core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
+	core/java/com/android/internal/os/IShellCallback.aidl \
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
 	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
 	core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
@@ -454,7 +459,7 @@
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl \
 	wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
@@ -490,8 +495,14 @@
 			$(framework_res_source_path)/android/Manifest.java \
 			$(framework_res_source_path)/com/android/internal/R.java
 
+# Make sure that R.java and Manifest.java are built before we build
+# the source for this library.
+framework_res_R_stamp := \
+	$(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp
+LOCAL_ADDITIONAL_DEPENDENCIES := $(framework_res_R_stamp)
+
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs conscrypt okhttp core-junit bouncycastle ext
+LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncycastle ext
 LOCAL_STATIC_JAVA_LIBRARIES := framework-protos
 
 LOCAL_MODULE := framework
@@ -505,15 +516,8 @@
 endif
 
 include $(BUILD_JAVA_LIBRARY)
+
 framework_module := $(LOCAL_INSTALLED_MODULE)
-
-# Make sure that R.java and Manifest.java are built before we build
-# the source for this library.
-framework_res_R_stamp := \
-	$(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp
-$(full_classes_compiled_jar): $(framework_res_R_stamp)
-$(built_dex_intermediate): $(framework_res_R_stamp)
-
 $(framework_module): | $(dir $(framework_module))framework-res.apk
 
 framework_built := $(call java-lib-deps,framework)
@@ -894,7 +898,7 @@
 
 ## SDK version identifiers used in the published docs
   # major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=6.0
+framework_docs_SDK_VERSION:=7.0
   # release version (ie "Release x")  (full releases only)
 framework_docs_SDK_REL_ID:=1
 
@@ -903,7 +907,7 @@
 		-hdf sdk.preview.version 5 \
 		-hdf sdk.version $(framework_docs_SDK_VERSION) \
 		-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-		-hdf sdk.preview 1
+		-hdf sdk.preview 0
 
 # ====  the api stubs and current.xml ===========================
 include $(CLEAR_VARS)
@@ -923,6 +927,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-api $(INTERNAL_PLATFORM_API_FILE) \
 		-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
 		-nodocs
@@ -956,6 +961,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-showAnnotation android.annotation.SystemApi \
 		-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
 		-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
@@ -990,6 +996,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
                $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+               -referenceonly \
                -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
                -showAnnotation android.annotation.TestApi \
                -api $(INTERNAL_PLATFORM_TEST_API_FILE) \
@@ -1023,6 +1030,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-parsecomments
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
@@ -1061,7 +1069,7 @@
 		-sdkvalues $(OUT_DOCS) \
 		-hdf android.whichdoc offline
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1103,10 +1111,17 @@
 include $(BUILD_DROIDDOC)
 
 static_doc_index_redirect := $(out_dir)/index.html
-$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-preview-index.html
+$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-documentation-redirect.html
 	$(copy-file-to-target)
 
+static_doc_properties := $(out_dir)/source.properties
+$(static_doc_properties): \
+	$(LOCAL_PATH)/docs/source.properties | $(ACP)
+	$(hide) mkdir -p $(dir $@)
+	$(hide) $(ACP) $< $@
+
 $(full_target): $(static_doc_index_redirect)
+$(full_target): $(static_doc_properties)
 $(full_target): $(framework_built)
 
 
@@ -1134,7 +1149,7 @@
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1158,6 +1173,7 @@
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-showAnnotation android.annotation.SystemApi \
 		-title "Android SDK - Including system APIs." \
 		-toroot / \
@@ -1194,17 +1210,67 @@
 
 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
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+
+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
+
+include $(BUILD_DROIDDOC)
+
+# ==== generates full navtree for resolving @links in ds postprocessing ====
+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_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+
+LOCAL_MODULE := ds-ref-navtree
+
+LOCAL_DROIDDOC_OPTIONS:= \
+		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-hdf android.whichdoc online \
+		-toroot / \
+		-atLinksNavtree \
+		-navtreeonly
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1229,11 +1295,10 @@
 		-toroot / \
 		-hdf android.whichdoc online \
 		$(sample_groups) \
-		-useUpdatedTemplates \
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
 
 include $(BUILD_DROIDDOC)
 
@@ -1252,6 +1317,7 @@
 LOCAL_MODULE := hidden
 LOCAL_DROIDDOC_OPTIONS:=\
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-referenceonly \
 		-title "Android SDK - Including hidden APIs."
 #		-hidden
 
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index 2fd6740..5fe2f02 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -6,9 +6,14 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test apct-perftests-utils
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    apct-perftests-utils
 
 LOCAL_PACKAGE_NAME := CorePerfTests
 
+# Use google-fonts/dancing-script for the performance metrics
+LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script
+
 include $(BUILD_PACKAGE)
 
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index ecb8d95..a709ee3 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.core.frameworks.perftests">
+    package="com.android.perftests.core">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -8,6 +8,6 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.core.frameworks.perftests"/>
+        android:targetPackage="com.android.perftests.core"/>
 
 </manifest>
diff --git a/apct-tests/perftests/graphics/res/drawable/vector_drawable01.xml b/apct-tests/perftests/core/res/drawable/vector_drawable01.xml
similarity index 100%
rename from apct-tests/perftests/graphics/res/drawable/vector_drawable01.xml
rename to apct-tests/perftests/core/res/drawable/vector_drawable01.xml
diff --git a/apct-tests/perftests/graphics/src/android/graphics/perftests/PaintHasGlyphPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
similarity index 100%
rename from apct-tests/perftests/graphics/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
rename to apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
diff --git a/apct-tests/perftests/graphics/src/android/graphics/perftests/PaintMeasureTextTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
similarity index 100%
rename from apct-tests/perftests/graphics/src/android/graphics/perftests/PaintMeasureTextTest.java
rename to apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
new file mode 100644
index 0000000..19047d3
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.graphics.perftests;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.view.RenderNode;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@LargeTest
+public class RenderNodePerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testMeasureRenderNodeJniOverhead() {
+        RenderNode node = RenderNode.create("benchmark", null);
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            node.setTranslationX(1.0f);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
new file mode 100644
index 0000000..11ee599
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.graphics.perftests;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Typeface;
+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 java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceCreatePerfTest {
+    // A font file name in asset directory.
+    private static final String TEST_FONT_NAME = "DancingScript-Regular.ttf";
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testCreate_fromFamily() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            Typeface face = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
+        }
+    }
+
+    @Test
+    public void testCreate_fromFamilyName() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            Typeface face = Typeface.create("monospace", Typeface.NORMAL);
+        }
+    }
+
+    @Test
+    public void testCreate_fromAsset() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getContext();
+        final AssetManager am = context.getAssets();
+
+        while (state.keepRunning()) {
+            Typeface face = Typeface.createFromAsset(am, TEST_FONT_NAME);
+        }
+    }
+
+    @Test
+    public void testCreate_fromFile() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getContext();
+        final AssetManager am = context.getAssets();
+
+        File outFile = null;
+        try {
+            outFile = File.createTempFile("example", "ttf", context.getCacheDir());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        try (InputStream in = am.open(TEST_FONT_NAME);
+                OutputStream out = new FileOutputStream(outFile)) {
+            byte[] buf = new byte[1024];
+            int n = 0;
+            while ((n = in.read(buf)) != -1) {
+                out.write(buf, 0, n);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        while (state.keepRunning()) {
+            Typeface face = Typeface.createFromFile(outFile);
+        }
+
+        outFile.delete();
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
new file mode 100644
index 0000000..5533782
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.graphics.perftests;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.VectorDrawable;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.BitmapUtils;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.perftests.core.R;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+import static junit.framework.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VectorDrawablePerfTest {
+
+    private static final boolean DUMP_BITMAP = false;
+
+    private int[] mTestWidths = {1024, 512};
+    private int[] mTestHeights = {512, 1024};
+
+    @Rule
+    public ActivityTestRule<StubActivity> mActivityRule =
+            new ActivityTestRule(StubActivity.class);
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testBitmapDrawPerf() {
+        int resId = R.drawable.vector_drawable01;
+        Activity activity = mActivityRule.getActivity();
+        VectorDrawable vd = (VectorDrawable) activity.getDrawable(resId);
+
+        int w = 1024, h = 1024;
+        Bitmap.Config conf = Bitmap.Config.ARGB_8888;
+        Bitmap bmp = Bitmap.createBitmap(w, h, conf);
+        Canvas canvas = new Canvas(bmp);
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        int i = 0;
+        while (state.keepRunning()) {
+            // Use different width / height each to force the vectorDrawable abandon the cache.
+            vd.setBounds(0, 0, mTestWidths[i % 2], mTestHeights[i % 2]);
+            i++;
+            vd.draw(canvas);
+        }
+
+        // Double check the bitmap pixels to make sure we draw correct content.
+        int backgroundColor = bmp.getPixel(w / 4, h / 2);
+        int objColor = bmp.getPixel(w / 8, h / 2 + 1);
+        int emptyColor = bmp.getPixel(w * 3 / 4, h * 3 / 4);
+        assertTrue("The background should be white", backgroundColor == Color.WHITE);
+        assertTrue("The object should be black", objColor == Color.BLACK);
+        assertTrue("The right bottom part should be empty", emptyColor == Color.TRANSPARENT);
+
+        if (DUMP_BITMAP) {
+            BitmapUtils.saveBitmapIntoPNG(activity, bmp, resId);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
new file mode 100644
index 0000000..e644a1f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.text;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.os.Bundle;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.StubActivity;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.style.ReplacementSpan;
+import android.util.ArraySet;
+
+import static android.text.Layout.Alignment.ALIGN_NORMAL;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Random;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class DynamicLayoutPerfTest {
+
+    @Parameters(name = "{0}")
+    public static Collection cases() {
+        return Arrays.asList(new Object[][] {
+            { "0%", 0.0f},
+            { "1%", 0.01f},
+            { "5%", 0.05f},
+            { "30%", 0.3f},
+            { "100%", 1.0f},
+        });
+    }
+
+    private final String mMetricKey;
+    private final float mProbability;
+    public DynamicLayoutPerfTest(String metricKey, float probability) {
+        mMetricKey = metricKey;
+        mProbability = probability;
+    }
+
+    private static class MockReplacementSpan extends ReplacementSpan {
+        @Override
+        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
+            return 10;
+        }
+
+        @Override
+        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+                int y, int bottom, Paint paint) {
+        }
+    }
+
+    @Rule
+    public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class);
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+
+    private final static String ALPHABETS = "abcdefghijklmnopqrstuvwxyz";
+
+    private SpannableStringBuilder getText() {
+        final long seed = 1234567890;
+        final Random r = new Random(seed);
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+
+        final int paragraphCount = 100;
+        for (int i = 0; i < paragraphCount; i++) {
+            final int wordCount = 5 + r.nextInt(20);
+            final boolean containsReplacementSpan = r.nextFloat() < mProbability;
+            final int replacedWordIndex = containsReplacementSpan ? r.nextInt(wordCount) : -1;
+            for (int j = 0; j < wordCount; j++) {
+                final int startIndex = builder.length();
+                final int wordLength = 1 + r.nextInt(10);
+                for (int k = 0; k < wordLength; k++) {
+                    char c = ALPHABETS.charAt(r.nextInt(ALPHABETS.length()));
+                    builder.append(c);
+                }
+                if (replacedWordIndex == j) {
+                    builder.setSpan(new MockReplacementSpan(), startIndex,
+                            builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                builder.append(' ');
+            }
+            builder.append('\n');
+        }
+        return builder;
+    }
+
+    @Test
+    public void testGetBlocksAlwaysNeedToBeRedrawn() {
+        final SpannableStringBuilder text = getText();
+        final DynamicLayout layout = new DynamicLayout(text, new TextPaint(), 1000,
+                ALIGN_NORMAL, 0, 0, false);
+
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final int steps = 10;
+        while (state.keepRunning()) {
+            for (int i = 0; i < steps; i++) {
+                int offset = (text.length() * i) / steps;
+                text.insert(offset, "\n");
+                text.delete(offset, offset + 1);
+                final ArraySet<Integer> set = layout.getBlocksAlwaysNeedToBeRedrawn();
+                if (set != null) {
+                    for (int j = 0; j < set.size(); j++) {
+                        layout.getBlockIndex(set.valueAt(j));
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java
new file mode 100644
index 0000000..07cd33f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.perftests;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.util.Log;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class LogPerfTest {
+
+    private final String[] strings = new String[] {
+            "This is a test log string 1",
+            "This is a test log string 2",
+            "This is a test log string 3",
+            "This is a test log string 4",
+            "This is a test log string 5",
+    };
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testLogPerf() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        int i = 0;
+        while (state.keepRunning()) {
+            Log.d("LogPerfTest", strings[(i++) % strings.length]);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
new file mode 100644
index 0000000..ce0c357
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.widget;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Random;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.RenderNodeAnimator;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class EditTextLongTextPerfTest {
+    @Parameters(name = "{0}")
+    public static Collection cases() {
+        return Arrays.asList(new Object[][] {
+            { "10x30K", 10, 30000 },
+            { "300x1K", 300, 1000 },
+        });
+    }
+
+    private final String mMetricKey;
+    private final int mChars;
+    private final int mLines;
+
+    public EditTextLongTextPerfTest(String metricKey, int chars, int lines) {
+        mMetricKey = metricKey;
+        mChars = chars;
+        mLines = lines;
+    }
+
+    @Rule
+    public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class);
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private EditText setupEditText() {
+        final EditText editText = new EditText(mActivityRule.getActivity());
+
+        String alphabet = "abcdefghijklmnopqrstuvwxyz";
+        final long seed = 1234567890;
+        Random r = new Random(seed);
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mLines; i++) {
+            for (int j = 0; j < mChars; j++) {
+                char c = alphabet.charAt(r.nextInt(alphabet.length()));
+                sb.append(c);
+            }
+            sb.append('\n');
+        }
+
+        final int height = 1000;
+        final int width = 1000;
+        editText.setHeight(height);
+        editText.setWidth(width);
+        editText.setLayoutParams(new ViewGroup.LayoutParams(width, height));
+
+        Activity activity = mActivityRule.getActivity();
+        activity.setContentView(editText);
+
+        editText.setText(sb.toString(), TextView.BufferType.EDITABLE);
+        editText.invalidate();
+        editText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+        editText.layout(0, 0, height, width);
+
+        return editText;
+    }
+
+    @Test
+    public void testEditText() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            final EditText editText = setupEditText();
+            final KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
+            final int steps = 100;
+            while (state.keepRunning()) {
+                for (int i = 0; i < steps; i++) {
+                    int offset = (editText.getText().length() * i) / steps;
+                    editText.setSelection(offset);
+                    editText.bringPointIntoView(offset);
+                    editText.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+                    editText.updateDisplayListIfDirty();
+                }
+            }
+        });
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
index d444c92..d570ef3 100644
--- a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
@@ -27,7 +27,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.android.core.frameworks.perftests.R;
+import com.android.perftests.core.R;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -78,29 +78,31 @@
 
     @Test
     @UiThreadTest
-    public void testLayoutPerf() {
-        assertTrue("We should be running on the main thread",
-                Looper.getMainLooper().getThread() == Thread.currentThread());
-        assertTrue("We should be running on the main thread",
-                Looper.myLooper() == Looper.getMainLooper());
+    public void testLayoutPerf() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue("We should be running on the main thread",
+                    Looper.getMainLooper().getThread() == Thread.currentThread());
+            assertTrue("We should be running on the main thread",
+                    Looper.myLooper() == Looper.getMainLooper());
 
-        Activity activity = mActivityRule.getActivity();
-        activity.setContentView(mLayoutId);
+            Activity activity = mActivityRule.getActivity();
+            activity.setContentView(mLayoutId);
 
-        ViewGroup viewGroup = (ViewGroup) activity.findViewById(mViewId);
+            ViewGroup viewGroup = (ViewGroup) activity.findViewById(mViewId);
 
-        List<View> allNodes = gatherViewTree(viewGroup);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            List<View> allNodes = gatherViewTree(viewGroup);
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
 
-        int length = mMeasureSpecs.length;
-        while (state.keepRunning()) {
-            for (int i = 0; i < length; i++) {
-                // The overhead of this call is ignorable, like within 1% difference.
-                requestLayoutForAllNodes(allNodes);
+            int length = mMeasureSpecs.length;
+            while (state.keepRunning()) {
+                for (int i = 0; i < length; i++) {
+                    // The overhead of this call is ignorable, like within 1% difference.
+                    requestLayoutForAllNodes(allNodes);
 
-                viewGroup.measure(mMeasureSpecs[i % length], mMeasureSpecs[i % length]);
-                viewGroup.layout(0, 0, viewGroup.getMeasuredWidth(), viewGroup.getMeasuredHeight());
+                    viewGroup.measure(mMeasureSpecs[i % length], mMeasureSpecs[i % length]);
+                    viewGroup.layout(0, 0, viewGroup.getMeasuredWidth(), viewGroup.getMeasuredHeight());
+                }
             }
-        }
+        });
     }
 }
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
new file mode 100644
index 0000000..6a49c03
--- /dev/null
+++ b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 java.lang.perftests;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SystemPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testNanoTimePerf() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            System.nanoTime();
+        }
+    }
+}
diff --git a/apct-tests/perftests/graphics/Android.mk b/apct-tests/perftests/graphics/Android.mk
deleted file mode 100644
index afdd743..0000000
--- a/apct-tests/perftests/graphics/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := apct-perftests-utils android-support-test
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GraphicsPerfTests
-
-include $(BUILD_PACKAGE)
-
diff --git a/apct-tests/perftests/graphics/AndroidManifest.xml b/apct-tests/perftests/graphics/AndroidManifest.xml
deleted file mode 100644
index 5416458..0000000
--- a/apct-tests/perftests/graphics/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.frameworks.perftests">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="android.perftests.utils.StubActivity" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.frameworks.perftests"/>
-
-</manifest>
diff --git a/apct-tests/perftests/graphics/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/graphics/src/android/graphics/perftests/VectorDrawablePerfTest.java
deleted file mode 100644
index 2af3b04..0000000
--- a/apct-tests/perftests/graphics/src/android/graphics/perftests/VectorDrawablePerfTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.graphics.perftests;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.drawable.VectorDrawable;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.BitmapUtils;
-import android.perftests.utils.PerfStatusReporter;
-import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.frameworks.perftests.R;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-
-import static junit.framework.Assert.assertTrue;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class VectorDrawablePerfTest {
-
-    private static final boolean DUMP_BITMAP = false;
-
-    private int[] mTestWidths = {1024, 512};
-    private int[] mTestHeights = {512, 1024};
-
-    @Rule
-    public ActivityTestRule<StubActivity> mActivityRule =
-            new ActivityTestRule(StubActivity.class);
-
-    @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
-    @Test
-    public void testBitmapDrawPerf() {
-        int resId = R.drawable.vector_drawable01;
-        Activity activity = mActivityRule.getActivity();
-        VectorDrawable vd = (VectorDrawable) activity.getDrawable(resId);
-
-        int w = 1024, h = 1024;
-        Bitmap.Config conf = Bitmap.Config.ARGB_8888;
-        Bitmap bmp = Bitmap.createBitmap(w, h, conf);
-        Canvas canvas = new Canvas(bmp);
-
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        int i = 0;
-        while (state.keepRunning()) {
-            // Use different width / height each to force the vectorDrawable abandon the cache.
-            vd.setBounds(0, 0, mTestWidths[i % 2], mTestHeights[i % 2]);
-            i++;
-            vd.draw(canvas);
-        }
-
-        // Double check the bitmap pixels to make sure we draw correct content.
-        int backgroundColor = bmp.getPixel(w / 4, h / 2);
-        int objColor = bmp.getPixel(w / 8, h / 2 + 1);
-        int emptyColor = bmp.getPixel(w * 3 / 4, h * 3 / 4);
-        assertTrue("The background should be white", backgroundColor == Color.WHITE);
-        assertTrue("The object should be black", objColor == Color.BLACK);
-        assertTrue("The right bottom part should be empty", emptyColor == Color.TRANSPARENT);
-
-        if (DUMP_BITMAP) {
-            BitmapUtils.saveBitmapIntoPNG(activity, bmp, resId);
-        }
-    }
-}
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..adb316f
--- /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.perftests.multiuser">
+
+    <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.perftests.multiuser"/>
+
+</manifest>
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..cdbca63
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.IStopUserCallback;
+import android.app.UserSwitchObserver;
+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;
+
+/**
+ * Perf tests for user life cycle events.
+ *
+ * Running the tests:
+ * make MultiUserPerfTests &&
+ * adb install -r \
+ *     ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
+ * adb shell am instrument -e class android.multiuser.UserLifecycleTest \
+ *     -w com.android.perftests.multiuser/android.support.test.runner.AndroidJUnitRunner
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class UserLifecycleTest {
+    private final int MIN_REPEAT_TIMES = 4;
+
+    private final int TIMEOUT_REMOVE_USER_MS = 4 * 1000; // 4 sec
+    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 final int TIMEOUT_USER_STOP_SEC = 1; // 1 sec
+
+    private final int TIMEOUT_MANAGED_PROFILE_UNLOCK_SEC = 2; // 2 sec
+
+    private final int TIMEOUT_LOCKED_BOOT_COMPLETE_MS = 5 * 1000; // 5 sec
+
+    private final int TIMEOUT_EPHERMAL_USER_STOP_SEC = 6; // 6 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) {
+            try {
+                mUm.removeUser(userId);
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+    }
+
+    @Test
+    public void createAndStartUserPerf() throws Exception {
+        while (mState.keepRunning()) {
+            final UserInfo userInfo = mUm.createUser("TestUser", 0);
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
+            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();
+        }
+    }
+
+    @Test
+    public void stopUserPerf() throws Exception {
+        while (mState.keepRunning()) {
+            mState.pauseTiming();
+            final UserInfo userInfo = mUm.createUser("TestUser", 0);
+            final CountDownLatch latch = new CountDownLatch(1);
+            registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
+            mIam.startUserInBackground(userInfo.id);
+            latch.await(TIMEOUT_USER_START_SEC, TimeUnit.SECONDS);
+            mState.resumeTiming();
+
+            stopUser(userInfo.id);
+
+            mState.pauseTiming();
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    @Test
+    public void lockedBootCompletedPerf() throws Exception {
+        while (mState.keepRunning()) {
+            mState.pauseTiming();
+            final int startUser = mAm.getCurrentUser();
+            final UserInfo userInfo = mUm.createUser("TestUser", 0);
+            final CountDownLatch latch = new CountDownLatch(1);
+            registerUserSwitchObserver(null, latch, userInfo.id);
+            mState.resumeTiming();
+
+            mAm.switchUser(userInfo.id);
+            latch.await(TIMEOUT_LOCKED_BOOT_COMPLETE_MS, TimeUnit.SECONDS);
+
+            mState.pauseTiming();
+            switchUser(startUser);
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    @Test
+    public void managedProfileUnlockPerf() throws Exception {
+        while (mState.keepRunning()) {
+            mState.pauseTiming();
+            final UserInfo userInfo = mUm.createProfileForUser("TestUser",
+                    UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
+            final CountDownLatch latch = new CountDownLatch(1);
+            registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
+            mState.resumeTiming();
+
+            mIam.startUserInBackground(userInfo.id);
+            latch.await(TIMEOUT_MANAGED_PROFILE_UNLOCK_SEC, TimeUnit.SECONDS);
+
+            mState.pauseTiming();
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    @Test
+    public void ephemeralUserStoppedPerf() throws Exception {
+        while (mState.keepRunning()) {
+            mState.pauseTiming();
+            final int startUser = mAm.getCurrentUser();
+            final UserInfo userInfo = mUm.createUser("TestUser",
+                    UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
+            switchUser(userInfo.id);
+            final CountDownLatch latch = new CountDownLatch(1);
+            InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
+                            Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userInfo.id) {
+                        latch.countDown();
+                    }
+                }
+            }, new IntentFilter(Intent.ACTION_USER_STOPPED));
+            final CountDownLatch switchLatch = new CountDownLatch(1);
+            registerUserSwitchObserver(switchLatch, null, startUser);
+            mState.resumeTiming();
+
+            mAm.switchUser(startUser);
+            latch.await(TIMEOUT_EPHERMAL_USER_STOP_SEC, TimeUnit.SECONDS);
+
+            mState.pauseTiming();
+            switchLatch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    private void switchUser(int userId) throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        registerUserSwitchObserver(latch, null, userId);
+        mAm.switchUser(userId);
+        latch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
+    }
+
+    private void stopUser(int userId) throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mIam.stopUser(userId, false /* force */, new IStopUserCallback.Stub() {
+            @Override
+            public void userStopped(int userId) throws RemoteException {
+                latch.countDown();
+            }
+
+            @Override
+            public void userStopAborted(int userId) throws RemoteException {
+            }
+        });
+        latch.await(TIMEOUT_USER_STOP_SEC, TimeUnit.SECONDS);
+    }
+
+    private void registerUserSwitchObserver(final CountDownLatch switchLatch,
+            final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
+        ActivityManagerNative.getDefault().registerUserSwitchObserver(
+                new UserSwitchObserver() {
+                    @Override
+                    public void onUserSwitchComplete(int newUserId) throws RemoteException {
+                        if (switchLatch != null && userId == newUserId) {
+                            switchLatch.countDown();
+                        }
+                    }
+
+                    @Override
+                    public void onLockedBootComplete(int newUserId) {
+                        if (bootCompleteLatch != null && userId == newUserId) {
+                            bootCompleteLatch.countDown();
+                        }
+                    }
+                }, "UserLifecycleTest");
+    }
+
+    private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
+            final int userId) {
+        InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (action.equals(intent.getAction()) && intent.getIntExtra(
+                        Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
+                    latch.countDown();
+                }
+            }
+        }, UserHandle.of(userId), new IntentFilter(action), null, null);
+    }
+
+    private void removeUser(int userId) {
+        try {
+            mUm.removeUser(userId);
+            final long startTime = System.currentTimeMillis();
+            while (mUm.getUserInfo(userId) != null &&
+                    System.currentTimeMillis() - startTime < TIMEOUT_REMOVE_USER_MS) {
+                Thread.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        } catch (Exception e) {
+            // Ignore
+        }
+        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..0a8965f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2921,11 +2921,11 @@
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
   }
 
-  public abstract interface AccountManagerCallback {
+  public abstract interface AccountManagerCallback<V> {
     method public abstract void run(android.accounts.AccountManagerFuture<V>);
   }
 
-  public abstract interface AccountManagerFuture {
+  public abstract interface AccountManagerFuture<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -3071,7 +3071,7 @@
     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
   }
 
-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract T convertBack(V);
     method public android.animation.BidirectionalTypeConverter<V, T> invert();
@@ -3163,26 +3163,26 @@
     method public java.lang.String getPropertyName();
     method public java.lang.Object getTarget();
     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
     method public void setAutoCancel(boolean);
     method public void setProperty(android.util.Property);
@@ -3206,17 +3206,17 @@
     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public void setConverter(android.animation.TypeConverter);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
@@ -3253,12 +3253,12 @@
     method public abstract float getInterpolation(float);
   }
 
-  public abstract class TypeConverter {
+  public abstract class TypeConverter<T, V> {
     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract V convert(T);
   }
 
-  public abstract interface TypeEvaluator {
+  public abstract interface TypeEvaluator<T> {
     method public abstract T evaluate(float, T, T);
   }
 
@@ -4042,6 +4042,7 @@
     field public static final java.lang.String OPSTR_MOCK_LOCATION = "android:mock_location";
     field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
     field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
+    field public static final java.lang.String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";
     field public static final java.lang.String OPSTR_READ_CALENDAR = "android:read_calendar";
     field public static final java.lang.String OPSTR_READ_CALL_LOG = "android:read_call_log";
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
@@ -4588,7 +4589,7 @@
     method public android.os.Parcelable saveAllState();
   }
 
-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
     method public void onAttachFragment(android.app.Fragment);
     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -4855,12 +4856,12 @@
     method public abstract void destroyLoader(int);
     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public static void enableDebugLogging(boolean);
-    method public abstract android.content.Loader<D> getLoader(int);
-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> getLoader(int);
+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
   }
 
-  public static abstract interface LoaderManager.LoaderCallbacks {
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
     method public abstract void onLoadFinished(android.content.Loader<D>, D);
     method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -4923,6 +4924,7 @@
     method public int describeContents();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5111,6 +5113,7 @@
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChannel(java.lang.String);
     method public android.app.Notification.Builder setChronometerCountDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
@@ -5259,6 +5262,7 @@
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
     method public java.util.List<android.app.Notification.Action> getActions();
     method public android.graphics.Bitmap getBackground();
+    method public java.lang.String getBridgeTag();
     method public int getContentAction();
     method public int getContentIcon();
     method public int getContentIconGravity();
@@ -5277,6 +5281,7 @@
     method public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
     method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
     method public android.app.Notification.WearableExtender setContentAction(int);
     method public android.app.Notification.WearableExtender setContentIcon(int);
     method public android.app.Notification.WearableExtender setContentIconGravity(int);
@@ -5304,17 +5309,40 @@
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
+  public final class NotificationChannel implements android.os.Parcelable {
+    ctor public NotificationChannel(java.lang.String, java.lang.CharSequence);
+    ctor protected NotificationChannel(android.os.Parcel);
+    method public boolean canBypassDnd();
+    method public int describeContents();
+    method public android.net.Uri getDefaultRingtone();
+    method public java.lang.String getId();
+    method public int getImportance();
+    method public java.lang.CharSequence getName();
+    method public void setDefaultRingtone(android.net.Uri);
+    method public void setLights(boolean);
+    method public void setVibration(boolean);
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
+    field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
   public class NotificationManager {
     method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
+    method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -5323,6 +5351,7 @@
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
+    method public void updateNotificationChannel(android.app.NotificationChannel);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5416,7 +5445,7 @@
     method public void onDisplayRemoved();
   }
 
-  public class ProgressDialog extends android.app.AlertDialog {
+  public deprecated class ProgressDialog extends android.app.AlertDialog {
     ctor public ProgressDialog(android.content.Context);
     ctor public ProgressDialog(android.content.Context, int);
     method public int getMax();
@@ -7649,7 +7678,7 @@
     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
   }
 
-  public abstract class AsyncTaskLoader extends android.content.Loader {
+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
     method public void cancelLoadInBackground();
     method public boolean isLoadInBackgroundCanceled();
@@ -7831,7 +7860,7 @@
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
@@ -7844,7 +7873,7 @@
     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public static abstract interface ContentProvider.PipeDataWriter {
+  public static abstract interface ContentProvider.PipeDataWriter<T> {
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
@@ -8115,7 +8144,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
-    method public final T getSystemService(java.lang.Class<T>);
+    method public final <T> T getSystemService(java.lang.Class<T>);
     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
@@ -8470,8 +8499,8 @@
     method public long getLongExtra(java.lang.String, long);
     method public java.lang.String getPackage();
     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
-    method public T getParcelableExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
     method public java.lang.String getScheme();
     method public android.content.Intent getSelector();
     method public java.io.Serializable getSerializableExtra(java.lang.String);
@@ -8946,7 +8975,7 @@
     ctor public IntentSender.SendIntentException(java.lang.Exception);
   }
 
-  public class Loader {
+  public class Loader<D> {
     ctor public Loader(android.content.Context);
     method public void abandon();
     method public boolean cancelLoad();
@@ -8983,11 +9012,11 @@
     ctor public Loader.ForceLoadContentObserver();
   }
 
-  public static abstract interface Loader.OnLoadCanceledListener {
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
     method public abstract void onLoadCanceled(android.content.Loader<D>);
   }
 
-  public static abstract interface Loader.OnLoadCompleteListener {
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
 
@@ -10859,7 +10888,7 @@
     method public boolean isNull(int);
   }
 
-  public abstract class Observable {
+  public abstract class Observable<T> {
     ctor public Observable();
     method public void registerObserver(T);
     method public void unregisterAll();
@@ -12664,6 +12693,7 @@
   public class SurfaceTexture {
     ctor public SurfaceTexture(int);
     ctor public SurfaceTexture(int, boolean);
+    ctor public SurfaceTexture(boolean);
     method public void attachToGLContext(int);
     method public void detachFromGLContext();
     method public long getTimestamp();
@@ -12750,7 +12780,7 @@
   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
     ctor public AnimatedStateListDrawable();
     method public void addState(int[], android.graphics.drawable.Drawable, int);
-    method public void addTransition(int, int, T, boolean);
+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
   }
 
   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
@@ -13843,6 +13873,7 @@
     method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
+    method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CameraDevice getDevice();
     method public abstract android.view.Surface getInputSurface();
     method public abstract boolean isReprocessable();
@@ -13874,7 +13905,7 @@
   }
 
   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
@@ -13959,7 +13990,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
   }
 
-  public static final class CameraCharacteristics.Key {
+  public static final class CameraCharacteristics.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14024,7 +14055,7 @@
     method public void onTorchModeUnavailable(java.lang.String);
   }
 
-  public abstract class CameraMetadata {
+  public abstract class CameraMetadata<TKey> {
     method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
@@ -14232,7 +14263,7 @@
 
   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
     method public int describeContents();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
     method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
@@ -14295,20 +14326,20 @@
   public static final class CaptureRequest.Builder {
     method public void addTarget(android.view.Surface);
     method public android.hardware.camera2.CaptureRequest build();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public void removeTarget(android.view.Surface);
-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
     method public void setTag(java.lang.Object);
   }
 
-  public static final class CaptureRequest.Key {
+  public static final class CaptureRequest.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
   }
 
   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
     method public long getFrameNumber();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
@@ -14389,7 +14420,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
-  public static final class CaptureResult.Key {
+  public static final class CaptureResult.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14481,9 +14512,11 @@
   public final class OutputConfiguration implements android.os.Parcelable {
     ctor public OutputConfiguration(android.view.Surface);
     ctor public OutputConfiguration(int, android.view.Surface);
+    ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
     method public int describeContents();
     method public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
+    method public void setDeferredSurface(android.view.Surface);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -14514,14 +14547,14 @@
     method public android.util.Size[] getInputSizes(int);
     method public final int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
     method public final int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
@@ -16222,7 +16255,7 @@
 
 package android.icu.text {
 
-  public final class AlphabeticIndex implements java.lang.Iterable {
+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
     ctor public AlphabeticIndex(android.icu.util.ULocale);
     ctor public AlphabeticIndex(java.util.Locale);
     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
@@ -16248,7 +16281,7 @@
     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
   }
 
-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
     method public java.lang.String getLabel();
     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
@@ -16264,14 +16297,14 @@
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
   }
 
-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
     method public int getBucketCount();
     method public int getBucketIndex(java.lang.CharSequence);
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
   }
 
-  public static class AlphabeticIndex.Record {
+  public static class AlphabeticIndex.Record<V> {
     method public V getData();
     method public java.lang.CharSequence getName();
   }
@@ -17784,8 +17817,8 @@
     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
-    method public android.icu.text.UnicodeSet addAll(T...);
-    method public T addAllTo(T);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17813,15 +17846,15 @@
     method public final boolean contains(java.lang.CharSequence);
     method public boolean containsAll(android.icu.text.UnicodeSet);
     method public boolean containsAll(java.lang.String);
-    method public boolean containsAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
     method public boolean containsNone(int, int);
     method public boolean containsNone(android.icu.text.UnicodeSet);
     method public boolean containsNone(java.lang.CharSequence);
-    method public boolean containsNone(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
     method public final boolean containsSome(int, int);
     method public final boolean containsSome(android.icu.text.UnicodeSet);
     method public final boolean containsSome(java.lang.CharSequence);
-    method public final boolean containsSome(java.lang.Iterable<T>);
+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet freeze();
     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
@@ -17839,14 +17872,14 @@
     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet set(int, int);
     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
     method public int size();
@@ -18256,7 +18289,7 @@
     method public long getToDate();
   }
 
-  public abstract interface Freezable implements java.lang.Cloneable {
+  public abstract interface Freezable<T> implements java.lang.Cloneable {
     method public abstract T cloneAsThawed();
     method public abstract T freeze();
     method public abstract boolean isFrozen();
@@ -18538,7 +18571,7 @@
     field public static final android.icu.util.TimeUnit YEAR;
   }
 
-  public class Output {
+  public class Output<T> {
     ctor public Output();
     ctor public Output(T);
     field public T value;
@@ -21429,6 +21462,7 @@
     field public static final int AMR_NB = 3; // 0x3
     field public static final int AMR_WB = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
+    field public static final int MPEG_2_TS = 8; // 0x8
     field public static final int MPEG_4 = 2; // 0x2
     field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
@@ -22584,8 +22618,8 @@
     method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
-    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
@@ -22634,7 +22668,7 @@
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
     method public void setRepeatMode(int);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -22663,7 +22697,7 @@
     method public void setRatingType(int);
     method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -22687,7 +22721,7 @@
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
     method public void onSetRepeatMode(int);
-    method public void onSetShuffleMode(boolean);
+    method public void onSetShuffleModeEnabled(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -22749,7 +22783,7 @@
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
     field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
-    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
@@ -23866,19 +23900,6 @@
     field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
   }
 
-  public abstract class PskKeyManager {
-    ctor public PskKeyManager();
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
-    method public java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
-    method public java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
-    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
-  }
-
   public final class RouteInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.IpPrefix getDestination();
@@ -28233,7 +28254,7 @@
 
 package android.os {
 
-  public abstract class AsyncTask {
+  public abstract class AsyncTask<Params, Progress, Result> {
     ctor public AsyncTask();
     method public final boolean cancel(boolean);
     method protected abstract Result doInBackground(Params...);
@@ -28367,6 +28388,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -28382,7 +28404,7 @@
     field public static final java.lang.String MODEL;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
@@ -28461,16 +28483,16 @@
     method public float getFloat(java.lang.String, float);
     method public float[] getFloatArray(java.lang.String);
     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
-    method public T getParcelable(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
     method public java.io.Serializable getSerializable(java.lang.String);
     method public short getShort(java.lang.String);
     method public short getShort(java.lang.String, short);
     method public short[] getShortArray(java.lang.String);
     method public android.util.Size getSize(java.lang.String);
     method public android.util.SizeF getSizeF(java.lang.String);
-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
     method public boolean hasFileDescriptors();
     method public void putAll(android.os.Bundle);
@@ -28975,8 +28997,8 @@
     method public final long[] createLongArray();
     method public final java.lang.String[] createStringArray();
     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
     method public final int dataAvail();
     method public final int dataCapacity();
     method public final int dataPosition();
@@ -29009,7 +29031,7 @@
     method public final long readLong();
     method public final void readLongArray(long[]);
     method public final void readMap(java.util.Map, java.lang.ClassLoader);
-    method public final T readParcelable(java.lang.ClassLoader);
+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
     method public final android.os.PersistableBundle readPersistableBundle();
     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
@@ -29022,9 +29044,9 @@
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
     method public final android.os.IBinder readStrongBinder();
-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
     method public final java.lang.Object readValue(java.lang.ClassLoader);
     method public final void recycle();
     method public final void setDataCapacity(int);
@@ -29055,7 +29077,7 @@
     method public final void writeMap(java.util.Map);
     method public final void writeNoException();
     method public final void writeParcelable(android.os.Parcelable, int);
-    method public final void writeParcelableArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
     method public final void writePersistableBundle(android.os.PersistableBundle);
     method public final void writeSerializable(java.io.Serializable);
     method public final void writeSize(android.util.Size);
@@ -29067,9 +29089,9 @@
     method public final void writeStringList(java.util.List<java.lang.String>);
     method public final void writeStrongBinder(android.os.IBinder);
     method public final void writeStrongInterface(android.os.IInterface);
-    method public final void writeTypedArray(T[], int);
-    method public final void writeTypedList(java.util.List<T>);
-    method public final void writeTypedObject(T, int);
+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
     method public final void writeValue(java.lang.Object);
     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
   }
@@ -29147,11 +29169,11 @@
     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
   }
 
-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
   }
 
-  public static abstract interface Parcelable.Creator {
+  public static abstract interface Parcelable.Creator<T> {
     method public abstract T createFromParcel(android.os.Parcel);
     method public abstract T[] newArray(int);
   }
@@ -29266,7 +29288,7 @@
     method public abstract void onProgress(int);
   }
 
-  public class RemoteCallbackList {
+  public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
     method public void finishBroadcast();
@@ -30285,6 +30307,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -30293,6 +30317,7 @@
     method public android.print.PageRange[] getPages();
     method public android.print.PrinterId getPrinterId();
     method public int getState();
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
@@ -31787,7 +31812,7 @@
     field public static final java.lang.String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
   }
 
-  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
+  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
     field public static final java.lang.String QUERY_PARAMETER_SIP_ADDRESS = "sip";
@@ -34593,7 +34618,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
   }
 
-  public static abstract interface CarrierMessagingService.ResultCallback {
+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
   }
 
@@ -34745,7 +34770,7 @@
     field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
-  public class MediaBrowserService.Result {
+  public class MediaBrowserService.Result<T> {
     method public void detach();
     method public void sendResult(T);
   }
@@ -34791,6 +34816,8 @@
     method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
+    method public static final void requestRebind(android.content.ComponentName);
+    method public final void requestUnbind();
     field public static final java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
     field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
@@ -35499,6 +35526,7 @@
     method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static int gettid();
     method public static int getuid();
+    method public static byte[] getxattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static java.lang.String if_indextoname(int);
     method public static int if_nametoindex(java.lang.String);
     method public static java.net.InetAddress inet_pton(int, java.lang.String);
@@ -35507,6 +35535,7 @@
     method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
     method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.lang.String[] listxattr(java.lang.String) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
     method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
     method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
@@ -35533,6 +35562,7 @@
     method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
+    method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -35544,6 +35574,7 @@
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
     method public static void setuid(int) throws android.system.ErrnoException;
+    method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
     method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -36872,6 +36903,7 @@
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
+    field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -36881,11 +36913,14 @@
     field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+    field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -36931,7 +36966,9 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+    field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -37662,14 +37699,14 @@
 
 package android.test {
 
-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -37684,7 +37721,7 @@
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -37730,7 +37767,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -37756,8 +37793,8 @@
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
     method public void injectInstrumentation(android.app.Instrumentation);
-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
     method public void sendKeys(java.lang.String);
     method public void sendKeys(int...);
@@ -37797,7 +37834,7 @@
 
   public class LoaderTestCase extends android.test.AndroidTestCase {
     ctor public LoaderTestCase();
-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
   public final deprecated class MoreAsserts {
@@ -37852,20 +37889,20 @@
     method public abstract void startTiming(boolean);
   }
 
-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
@@ -37873,11 +37910,11 @@
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
     method public void makeExistingFilesAndDbsAccessible();
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -37890,7 +37927,7 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
@@ -38245,7 +38282,7 @@
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
     method public java.lang.String getEnclosingClassname();
     method public java.lang.String getName();
@@ -38693,7 +38730,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
     method public int getTextWatcherDepth();
     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
@@ -38715,7 +38752,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public final int length();
     method public int nextSpanTransition(int, int, java.lang.Class);
     method public final java.lang.String toString();
@@ -38725,7 +38762,7 @@
     method public abstract int getSpanEnd(java.lang.Object);
     method public abstract int getSpanFlags(java.lang.Object);
     method public abstract int getSpanStart(java.lang.Object);
-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public abstract int nextSpanTransition(int, int, java.lang.Class);
     field public static final int SPAN_COMPOSING = 256; // 0x100
     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
@@ -39703,7 +39740,7 @@
     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
   }
 
-  public static class TtsSpan.Builder {
+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
     ctor public TtsSpan.Builder(java.lang.String);
     method public android.text.style.TtsSpan build();
     method public C setIntArgument(java.lang.String, int);
@@ -39799,7 +39836,7 @@
     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
   }
 
-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
     method public C setAnimacy(java.lang.String);
     method public C setCase(java.lang.String);
@@ -40206,7 +40243,7 @@
     ctor public AndroidRuntimeException(java.lang.Exception);
   }
 
-  public final class ArrayMap implements java.util.Map {
+  public final class ArrayMap<K, V> implements java.util.Map {
     ctor public ArrayMap();
     ctor public ArrayMap(int);
     ctor public ArrayMap(android.util.ArrayMap<K, V>);
@@ -40234,7 +40271,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public final class ArraySet implements java.util.Collection java.util.Set {
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
     ctor public ArraySet();
     ctor public ArraySet(int);
     ctor public ArraySet(android.util.ArraySet<E>);
@@ -40255,7 +40292,7 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
     method public E valueAt(int);
   }
 
@@ -40400,13 +40437,13 @@
   public deprecated class FloatMath {
   }
 
-  public abstract class FloatProperty extends android.util.Property {
+  public abstract class FloatProperty<T> extends android.util.Property {
     ctor public FloatProperty(java.lang.String);
     method public final void set(T, java.lang.Float);
     method public abstract void setValue(T, float);
   }
 
-  public abstract class IntProperty extends android.util.Property {
+  public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
     method public abstract void setValue(T, int);
@@ -40506,7 +40543,7 @@
     method public void println(java.lang.String);
   }
 
-  public class LongSparseArray implements java.lang.Cloneable {
+  public class LongSparseArray<E> implements java.lang.Cloneable {
     ctor public LongSparseArray();
     ctor public LongSparseArray(int);
     method public void append(long, E);
@@ -40527,7 +40564,7 @@
     method public E valueAt(int);
   }
 
-  public class LruCache {
+  public class LruCache<K, V> {
     ctor public LruCache(int);
     method protected V create(K);
     method public final synchronized int createCount();
@@ -40615,9 +40652,9 @@
     ctor public NoSuchPropertyException(java.lang.String);
   }
 
-  public class Pair {
+  public class Pair<F, S> {
     ctor public Pair(F, S);
-    method public static android.util.Pair<A, B> create(A, B);
+    method public static <A, B> android.util.Pair<A, B> create(A, B);
     field public final F first;
     field public final S second;
   }
@@ -40650,22 +40687,22 @@
     method public abstract void println(java.lang.String);
   }
 
-  public abstract class Property {
+  public abstract class Property<T, V> {
     ctor public Property(java.lang.Class<V>, java.lang.String);
     method public abstract V get(T);
     method public java.lang.String getName();
     method public java.lang.Class<V> getType();
     method public boolean isReadOnly();
-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
     method public void set(T, V);
   }
 
-  public final class Range {
+  public final class Range<T extends java.lang.Comparable<? super T>> {
     ctor public Range(T, T);
     method public T clamp(T);
     method public boolean contains(T);
     method public boolean contains(android.util.Range<T>);
-    method public static android.util.Range<T> create(T, T);
+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
     method public android.util.Range<T> extend(android.util.Range<T>);
     method public android.util.Range<T> extend(T, T);
     method public android.util.Range<T> extend(T);
@@ -40709,7 +40746,7 @@
     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
   }
 
-  public class SparseArray implements java.lang.Cloneable {
+  public class SparseArray<E> implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
     method public void append(int, E);
@@ -42151,7 +42188,11 @@
 
   public final class PixelCopy {
     method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.SurfaceView, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Surface, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
     field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
     field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -43176,6 +43217,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 +44041,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
@@ -45438,7 +45481,7 @@
     method public static java.lang.String stripAnchor(java.lang.String);
   }
 
-  public abstract interface ValueCallback {
+  public abstract interface ValueCallback<T> {
     method public abstract void onReceiveValue(T);
   }
 
@@ -45799,13 +45842,15 @@
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
     method public android.webkit.WebView.HitTestResult getHitTestResult();
-    method public java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
+    method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
+    method public android.webkit.WebChromeClient getWebChromeClient();
+    method public android.webkit.WebViewClient getWebViewClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
@@ -45842,7 +45887,7 @@
     method public void setDownloadListener(android.webkit.DownloadListener);
     method public void setFindListener(android.webkit.WebView.FindListener);
     method public deprecated void setHorizontalScrollbarOverlay(boolean);
-    method public void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public void setInitialScale(int);
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
@@ -45940,10 +45985,12 @@
     method public abstract void clearFormData();
     method public abstract void clearHttpAuthUsernamePassword();
     method public abstract deprecated void clearUsernamePassword();
+    method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
     method public abstract boolean hasFormData();
     method public abstract boolean hasHttpAuthUsernamePassword();
     method public abstract deprecated boolean hasUsernamePassword();
+    method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
   }
 
   public class WebViewFragment extends android.app.Fragment {
@@ -46172,7 +46219,7 @@
     field public static final int NO_SELECTION = -2147483648; // 0x80000000
   }
 
-  public abstract class AdapterView extends android.view.ViewGroup {
+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
     ctor public AdapterView(android.content.Context);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
@@ -46295,7 +46342,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -46356,7 +46403,7 @@
     method protected void performFiltering(java.lang.CharSequence, int);
     method public void performValidation();
     method protected void replaceText(java.lang.CharSequence);
-    method public void setAdapter(T);
+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
     method public void setCompletionHint(java.lang.CharSequence);
     method public void setDropDownAnchor(int);
     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -46624,7 +46671,7 @@
     method public abstract void onDateChanged(android.widget.DatePicker, int, int, int);
   }
 
-  public class DialerFilter extends android.widget.RelativeLayout {
+  public deprecated class DialerFilter extends android.widget.RelativeLayout {
     ctor public DialerFilter(android.content.Context);
     ctor public DialerFilter(android.content.Context, android.util.AttributeSet);
     method public void append(java.lang.String);
@@ -47293,8 +47340,8 @@
   public class OverScroller {
     ctor public OverScroller(android.content.Context);
     ctor public OverScroller(android.content.Context, android.view.animation.Interpolator);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
     method public void abortAnimation();
     method public boolean computeScrollOffset();
     method public void fling(int, int, int, int, int, int, int, int);
@@ -48596,7 +48643,7 @@
     method public abstract android.widget.ListAdapter getWrappedAdapter();
   }
 
-  public class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
+  public deprecated class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
     ctor public ZoomButton(android.content.Context);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet, int);
@@ -48605,7 +48652,7 @@
     method public void setZoomSpeed(long);
   }
 
-  public class ZoomButtonsController implements android.view.View.OnTouchListener {
+  public deprecated class ZoomButtonsController implements android.view.View.OnTouchListener {
     ctor public ZoomButtonsController(android.view.View);
     method public android.view.ViewGroup getContainer();
     method public android.view.View getZoomControls();
@@ -48642,7 +48689,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -50714,20 +50761,22 @@
     enum_constant public static final java.lang.Character.UnicodeScript YI;
   }
 
-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
     method public T cast(java.lang.Object);
     method public boolean desiredAssertionStatus();
     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getCanonicalName();
     method public java.lang.ClassLoader getClassLoader();
     method public java.lang.Class<?>[] getClasses();
     method public java.lang.Class<?> getComponentType();
     method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?>[] getDeclaredClasses();
     method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
@@ -50757,6 +50806,7 @@
     method public java.lang.Object[] getSigners();
     method public java.lang.String getSimpleName();
     method public java.lang.Class<? super T> getSuperclass();
+    method public java.lang.String getTypeName();
     method public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
     method public boolean isAnnotation();
     method public boolean isAnonymousClass();
@@ -50770,6 +50820,7 @@
     method public boolean isPrimitive();
     method public boolean isSynthetic();
     method public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public java.lang.String toGenericString();
   }
 
   public class ClassCastException extends java.lang.RuntimeException {
@@ -50837,7 +50888,7 @@
   public abstract interface Cloneable {
   }
 
-  public abstract interface Comparable {
+  public abstract interface Comparable<T> {
     method public abstract int compareTo(T);
   }
 
@@ -50891,7 +50942,7 @@
     field public static final java.lang.Class<java.lang.Double> TYPE;
   }
 
-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
     ctor protected Enum(java.lang.String, int);
     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
     method public final int compareTo(E);
@@ -50901,7 +50952,7 @@
     method public final int hashCode();
     method public final java.lang.String name();
     method public final int ordinal();
-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
   }
 
   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
@@ -51020,7 +51071,7 @@
     ctor public IndexOutOfBoundsException(java.lang.String);
   }
 
-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
     ctor public InheritableThreadLocal();
     method protected T childValue(T);
   }
@@ -51099,7 +51150,7 @@
     ctor public InterruptedException(java.lang.String);
   }
 
-  public abstract interface Iterable {
+  public abstract interface Iterable<T> {
     method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
     method public default java.util.Spliterator<T> spliterator();
@@ -51314,12 +51365,12 @@
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
-    method public A[] getAnnotationsByType(java.lang.Class<A>);
-    method public A getDeclaredAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getImplementationTitle();
     method public java.lang.String getImplementationVendor();
     method public java.lang.String getImplementationVersion();
@@ -51918,13 +51969,13 @@
     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
   }
 
-  public class ThreadLocal {
+  public class ThreadLocal<T> {
     ctor public ThreadLocal();
     method public T get();
     method protected T initialValue();
     method public void remove();
     method public void set(T);
-    method public static java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
+    method public static <S> java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
   }
 
   public class Throwable implements java.io.Serializable {
@@ -52027,6 +52078,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -52062,30 +52115,30 @@
 
 package java.lang.ref {
 
-  public class PhantomReference extends java.lang.ref.Reference {
+  public class PhantomReference<T> extends java.lang.ref.Reference {
     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public abstract class Reference {
+  public abstract class Reference<T> {
     method public void clear();
     method public boolean enqueue();
     method public T get();
     method public boolean isEnqueued();
   }
 
-  public class ReferenceQueue {
+  public class ReferenceQueue<T> {
     ctor public ReferenceQueue();
     method public java.lang.ref.Reference<? extends T> poll();
     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
   }
 
-  public class SoftReference extends java.lang.ref.Reference {
+  public class SoftReference<T> extends java.lang.ref.Reference {
     ctor public SoftReference(T);
     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public class WeakReference extends java.lang.ref.Reference {
+  public class WeakReference<T> extends java.lang.ref.Reference {
     ctor public WeakReference(T);
     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
@@ -52096,7 +52149,7 @@
 
   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
     ctor protected AccessibleObject();
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.annotation.Annotation[] getAnnotations();
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public boolean isAccessible();
@@ -52105,12 +52158,12 @@
   }
 
   public abstract interface AnnotatedElement {
-    method public abstract T getAnnotation(java.lang.Class<T>);
+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
   }
 
@@ -52138,27 +52191,38 @@
     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
   }
 
-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Constructor<T> extends java.lang.reflect.Executable {
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public int getModifiers();
     method public java.lang.String getName();
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
     method public java.lang.String toGenericString();
   }
 
+  public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.Class<?>[] getExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericParameterTypes();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
+    method public int getParameterCount();
+    method public abstract java.lang.Class<?>[] getParameterTypes();
+    method public java.lang.reflect.Parameter[] getParameters();
+    method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
+    method public final boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+    method public abstract java.lang.String toGenericString();
+  }
+
   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public A getAnnotation(java.lang.Class<A>);
     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -52172,7 +52236,6 @@
     method public java.lang.String getName();
     method public short getShort(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public java.lang.Class<?> getType();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isEnumConstant();
     method public boolean isSynthetic();
     method public void set(java.lang.Object, java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -52191,7 +52254,7 @@
     method public abstract java.lang.reflect.Type getGenericComponentType();
   }
 
-  public abstract interface GenericDeclaration {
+  public abstract interface GenericDeclaration implements java.lang.reflect.AnnotatedElement {
     method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
   }
 
@@ -52223,13 +52286,10 @@
     field public static final int PUBLIC = 0; // 0x0
   }
 
-  public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Method extends java.lang.reflect.Executable {
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public java.lang.reflect.Type getGenericReturnType();
     method public int getModifiers();
     method public java.lang.String getName();
@@ -52240,8 +52300,6 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isBridge();
     method public boolean isDefault();
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public java.lang.String toGenericString();
   }
 
@@ -52264,6 +52322,7 @@
     method public static boolean isTransient(int);
     method public static boolean isVolatile(int);
     method public static int methodModifiers();
+    method public static int parameterModifiers();
     method public static java.lang.String toString(int);
     field public static final int ABSTRACT = 1024; // 0x400
     field public static final int FINAL = 16; // 0x10
@@ -52279,6 +52338,21 @@
     field public static final int VOLATILE = 64; // 0x40
   }
 
+  public final class Parameter implements java.lang.reflect.AnnotatedElement {
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+    method public java.lang.reflect.Executable getDeclaringExecutable();
+    method public int getModifiers();
+    method public java.lang.String getName();
+    method public java.lang.reflect.Type getParameterizedType();
+    method public java.lang.Class<?> getType();
+    method public boolean isImplicit();
+    method public boolean isNamePresent();
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+  }
+
   public abstract interface ParameterizedType implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getActualTypeArguments();
     method public abstract java.lang.reflect.Type getOwnerType();
@@ -52302,7 +52376,7 @@
   public abstract interface Type {
   }
 
-  public abstract interface TypeVariable implements java.lang.reflect.Type {
+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getBounds();
     method public abstract D getGenericDeclaration();
     method public abstract java.lang.String getName();
@@ -53091,7 +53165,7 @@
     method public abstract java.net.SocketImpl createSocketImpl();
   }
 
-  public abstract interface SocketOption {
+  public abstract interface SocketOption<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -53212,8 +53286,6 @@
     method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
     method public final java.io.InputStream openStream() throws java.io.IOException;
     method public boolean sameFile(java.net.URL);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
     method public java.lang.String toExternalForm();
     method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -53623,9 +53695,9 @@
   }
 
   public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
-    method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
   }
 
@@ -53653,25 +53725,25 @@
   public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
     ctor protected AsynchronousFileChannel();
     method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public abstract <A> void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public final <A> void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
     method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
     method public abstract long size() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
     method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
   }
 
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
-    method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
+    method public abstract <A> void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
     method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
@@ -53679,30 +53751,30 @@
     method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
   }
 
   public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
+    method public abstract <A> void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
-    method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <A> void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <T> java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
   }
 
   public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
@@ -53742,7 +53814,7 @@
     ctor public ClosedSelectorException();
   }
 
-  public abstract interface CompletionHandler {
+  public abstract interface CompletionHandler<V, A> {
     method public abstract void completed(V, A);
     method public abstract void failed(java.lang.Throwable, A);
   }
@@ -53766,7 +53838,7 @@
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.DatagramSocket socket();
     method public final int validOps();
     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
@@ -53871,8 +53943,8 @@
   public abstract interface NetworkChannel implements java.nio.channels.Channel {
     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
   }
 
@@ -53994,7 +54066,7 @@
     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.ServerSocket socket();
     method public final int validOps();
   }
@@ -54017,7 +54089,7 @@
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
     method public abstract java.net.Socket socket();
@@ -54302,11 +54374,11 @@
     ctor public DirectoryNotEmptyException(java.lang.String);
   }
 
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
+  public abstract interface DirectoryStream<T> implements java.io.Closeable java.lang.Iterable {
     method public abstract java.util.Iterator<T> iterator();
   }
 
-  public static abstract interface DirectoryStream.Filter {
+  public static abstract interface DirectoryStream.Filter<T> {
     method public abstract boolean accept(T) throws java.io.IOException;
   }
 
@@ -54318,7 +54390,7 @@
   public abstract class FileStore {
     ctor protected FileStore();
     method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(java.lang.Class<V>);
     method public abstract long getTotalSpace() throws java.io.IOException;
     method public abstract long getUnallocatedSpace() throws java.io.IOException;
     method public abstract long getUsableSpace() throws java.io.IOException;
@@ -54390,7 +54462,7 @@
     enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
   }
 
-  public abstract interface FileVisitor {
+  public abstract interface FileVisitor<T> {
     method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -54415,7 +54487,7 @@
     method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
     method public static java.util.stream.Stream<java.nio.file.Path> find(java.nio.file.Path, int, java.util.function.BiPredicate<java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes>, java.nio.file.FileVisitOption...) throws java.io.IOException;
     method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public static <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54448,7 +54520,7 @@
     method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54556,17 +54628,17 @@
     ctor public ReadOnlyFileSystemException();
   }
 
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
+  public abstract interface SecureDirectoryStream<T> implements java.nio.file.DirectoryStream {
     method public abstract void deleteDirectory(T) throws java.io.IOException;
     method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
   }
 
-  public class SimpleFileVisitor implements java.nio.file.FileVisitor {
+  public class SimpleFileVisitor<T> implements java.nio.file.FileVisitor {
     ctor protected SimpleFileVisitor();
     method public java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -54604,13 +54676,13 @@
     field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
   }
 
-  public abstract interface WatchEvent {
+  public abstract interface WatchEvent<T> {
     method public abstract T context();
     method public abstract int count();
     method public abstract java.nio.file.WatchEvent.Kind<T> kind();
   }
 
-  public static abstract interface WatchEvent.Kind {
+  public static abstract interface WatchEvent.Kind<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -54746,7 +54818,7 @@
     method public abstract boolean isSystem();
   }
 
-  public abstract interface FileAttribute {
+  public abstract interface FileAttribute<T> {
     method public abstract java.lang.String name();
     method public abstract T value();
   }
@@ -54843,7 +54915,7 @@
     method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
     method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
     method public abstract java.nio.file.Path getPath(java.net.URI);
@@ -54860,7 +54932,7 @@
     method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
     method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54890,12 +54962,12 @@
 
   public final class AccessController {
     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
     method public static java.security.AccessControlContext getContext();
   }
 
@@ -54934,7 +55006,7 @@
     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method public final void init(byte[]) throws java.io.IOException;
@@ -54946,7 +55018,7 @@
     ctor public AlgorithmParametersSpi();
     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(byte[]) throws java.io.IOException;
     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
@@ -55041,6 +55113,13 @@
     method public abstract java.security.ProtectionDomain[] combine(java.security.ProtectionDomain[], java.security.ProtectionDomain[]);
   }
 
+  public final class DomainLoadStoreParameter implements java.security.KeyStore.LoadStoreParameter {
+    ctor public DomainLoadStoreParameter(java.net.URI, java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter>);
+    method public java.net.URI getConfiguration();
+    method public java.security.KeyStore.ProtectionParameter getProtectionParameter();
+    method public java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter> getProtectionParams();
+  }
+
   public class GeneralSecurityException extends java.lang.Exception {
     ctor public GeneralSecurityException();
     ctor public GeneralSecurityException(java.lang.String);
@@ -55131,7 +55210,7 @@
     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
@@ -55140,7 +55219,7 @@
     ctor public KeyFactorySpi();
     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
 
@@ -55237,6 +55316,12 @@
   }
 
   public static abstract interface KeyStore.Entry {
+    method public default java.util.Set<java.security.KeyStore.Entry.Attribute> getAttributes();
+  }
+
+  public static abstract interface KeyStore.Entry.Attribute {
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.String getValue();
   }
 
   public static abstract interface KeyStore.LoadStoreParameter {
@@ -55245,11 +55330,15 @@
 
   public static class KeyStore.PasswordProtection implements javax.security.auth.Destroyable java.security.KeyStore.ProtectionParameter {
     ctor public KeyStore.PasswordProtection(char[]);
+    ctor public KeyStore.PasswordProtection(char[], java.lang.String, java.security.spec.AlgorithmParameterSpec);
     method public synchronized char[] getPassword();
+    method public java.lang.String getProtectionAlgorithm();
+    method public java.security.spec.AlgorithmParameterSpec getProtectionParameters();
   }
 
   public static final class KeyStore.PrivateKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[]);
+    ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[], java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getCertificate();
     method public java.security.cert.Certificate[] getCertificateChain();
     method public java.security.PrivateKey getPrivateKey();
@@ -55260,11 +55349,13 @@
 
   public static final class KeyStore.SecretKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey);
+    ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public javax.crypto.SecretKey getSecretKey();
   }
 
   public static final class KeyStore.TrustedCertificateEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate);
+    ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getTrustedCertificate();
   }
 
@@ -55343,6 +55434,14 @@
     ctor public NoSuchProviderException(java.lang.String);
   }
 
+  public final class PKCS12Attribute implements java.security.KeyStore.Entry.Attribute {
+    ctor public PKCS12Attribute(java.lang.String, java.lang.String);
+    ctor public PKCS12Attribute(byte[]);
+    method public byte[] getEncoded();
+    method public java.lang.String getName();
+    method public java.lang.String getValue();
+  }
+
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
@@ -55400,14 +55499,15 @@
     method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getName();
     method public abstract int hashCode();
+    method public default boolean implies(javax.security.auth.Subject);
     method public abstract java.lang.String toString();
   }
 
-  public abstract interface PrivateKey implements java.security.Key {
+  public abstract interface PrivateKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
   }
 
-  public abstract interface PrivilegedAction {
+  public abstract interface PrivilegedAction<T> {
     method public abstract T run();
   }
 
@@ -55416,7 +55516,7 @@
     method public java.lang.Exception getException();
   }
 
-  public abstract interface PrivilegedExceptionAction {
+  public abstract interface PrivilegedExceptionAction<T> {
     method public abstract T run() throws java.lang.Exception;
   }
 
@@ -55432,16 +55532,25 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized java.lang.Object compute(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfAbsent(java.lang.Object, java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfPresent(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
+    method public synchronized java.lang.Object getOrDefault(java.lang.Object, java.lang.Object);
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
     method public synchronized java.util.Set<java.security.Provider.Service> getServices();
     method public double getVersion();
+    method public synchronized java.lang.Object merge(java.lang.Object, java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized java.lang.Object put(java.lang.Object, java.lang.Object);
     method public synchronized void putAll(java.util.Map<?, ?>);
+    method public synchronized java.lang.Object putIfAbsent(java.lang.Object, java.lang.Object);
     method protected synchronized void putService(java.security.Provider.Service);
     method protected synchronized void removeService(java.security.Provider.Service);
+    method public synchronized boolean replace(java.lang.Object, java.lang.Object, java.lang.Object);
+    method public synchronized java.lang.Object replace(java.lang.Object, java.lang.Object);
+    method public synchronized void replaceAll(java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
   }
 
   public static class Provider.Service {
@@ -55483,6 +55592,7 @@
     method public static java.security.SecureRandom getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.SecureRandom getInstanceStrong() throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public static byte[] getSeed(int);
     method protected final int next(int);
@@ -55855,6 +55965,7 @@
     method public abstract java.lang.String toString();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
     method protected java.lang.Object writeReplace() throws java.io.ObjectStreamException;
   }
 
@@ -56100,6 +56211,7 @@
     method public abstract int getVersion();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract class X509CRLEntry implements java.security.cert.X509Extension {
@@ -56213,7 +56325,6 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
-    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -56417,6 +56528,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;
@@ -57598,11 +57710,11 @@
     method public abstract void free() throws java.sql.SQLException;
     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract java.lang.String getString() throws java.sql.SQLException;
     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
   }
 
@@ -57726,7 +57838,7 @@
 
   public abstract interface Wrapper {
     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
   }
 
 }
@@ -58259,7 +58371,7 @@
 
 package java.util {
 
-  public abstract class AbstractCollection implements java.util.Collection {
+  public abstract class AbstractCollection<E> implements java.util.Collection {
     ctor protected AbstractCollection();
     method public boolean add(E);
     method public boolean addAll(java.util.Collection<? extends E>);
@@ -58273,10 +58385,10 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
     ctor protected AbstractList();
     method public void add(int, E);
     method public boolean addAll(int, java.util.Collection<? extends E>);
@@ -58293,7 +58405,7 @@
     field protected transient int modCount;
   }
 
-  public abstract class AbstractMap implements java.util.Map {
+  public abstract class AbstractMap<K, V> implements java.util.Map {
     ctor protected AbstractMap();
     method public void clear();
     method public boolean containsKey(java.lang.Object);
@@ -58309,7 +58421,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleEntry(K, V);
     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -58317,7 +58429,7 @@
     method public V setValue(V);
   }
 
-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleImmutableEntry(K, V);
     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -58325,23 +58437,23 @@
     method public V setValue(V);
   }
 
-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
     ctor protected AbstractQueue();
     method public E element();
     method public E remove();
   }
 
-  public abstract class AbstractSequentialList extends java.util.AbstractList {
+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
     ctor protected AbstractSequentialList();
     method public E get(int);
     method public abstract java.util.ListIterator<E> listIterator(int);
   }
 
-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
     ctor protected AbstractSet();
   }
 
-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
     ctor public ArrayDeque();
     ctor public ArrayDeque(int);
     ctor public ArrayDeque(java.util.Collection<? extends E>);
@@ -58373,7 +58485,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public ArrayList(int);
     ctor public ArrayList();
     ctor public ArrayList(java.util.Collection<? extends E>);
@@ -58390,7 +58502,7 @@
   }
 
   public class Arrays {
-    method public static java.util.List<T> asList(T...);
+    method public static <T> java.util.List<T> asList(T...);
     method public static int binarySearch(long[], long);
     method public static int binarySearch(long[], int, int, long);
     method public static int binarySearch(int[], int);
@@ -58407,10 +58519,10 @@
     method public static int binarySearch(float[], int, int, float);
     method public static int binarySearch(java.lang.Object[], java.lang.Object);
     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
-    method public static T[] copyOf(T[], int);
-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
+    method public static <T> T[] copyOf(T[], int);
+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOf(byte[], int);
     method public static short[] copyOf(short[], int);
     method public static int[] copyOf(int[], int);
@@ -58419,8 +58531,8 @@
     method public static float[] copyOf(float[], int);
     method public static double[] copyOf(double[], int);
     method public static boolean[] copyOf(boolean[], int);
-    method public static T[] copyOfRange(T[], int, int);
-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
+    method public static <T> T[] copyOfRange(T[], int, int);
+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOfRange(byte[], int, int);
     method public static short[] copyOfRange(short[], int, int);
     method public static int[] copyOfRange(int[], int, int);
@@ -58468,15 +58580,15 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
@@ -58494,11 +58606,11 @@
     method public static void parallelSort(float[], int, int);
     method public static void parallelSort(double[]);
     method public static void parallelSort(double[], int, int);
-    method public static void parallelSort(T[]);
-    method public static void parallelSort(T[], int, int);
-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void setAll(int[], java.util.function.IntUnaryOperator);
     method public static void setAll(long[], java.util.function.IntToLongFunction);
     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
@@ -58518,18 +58630,18 @@
     method public static void sort(double[], int, int);
     method public static void sort(java.lang.Object[]);
     method public static void sort(java.lang.Object[], int, int);
-    method public static void sort(T[], java.util.Comparator<? super T>);
-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
-    method public static java.util.Spliterator<T> spliterator(T[]);
-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[]);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[]);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[]);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
-    method public static java.util.stream.Stream<T> stream(T[]);
-    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static <T> java.util.stream.Stream<T> stream(T[]);
+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
     method public static java.util.stream.IntStream stream(int[]);
     method public static java.util.stream.IntStream stream(int[], int, int);
     method public static java.util.stream.LongStream stream(long[]);
@@ -58547,6 +58659,33 @@
     method public static java.lang.String toString(java.lang.Object[]);
   }
 
+  public class Base64 {
+    method public static java.util.Base64.Decoder getDecoder();
+    method public static java.util.Base64.Encoder getEncoder();
+    method public static java.util.Base64.Decoder getMimeDecoder();
+    method public static java.util.Base64.Encoder getMimeEncoder();
+    method public static java.util.Base64.Encoder getMimeEncoder(int, byte[]);
+    method public static java.util.Base64.Decoder getUrlDecoder();
+    method public static java.util.Base64.Encoder getUrlEncoder();
+  }
+
+  public static class Base64.Decoder {
+    method public byte[] decode(byte[]);
+    method public byte[] decode(java.lang.String);
+    method public int decode(byte[], byte[]);
+    method public java.nio.ByteBuffer decode(java.nio.ByteBuffer);
+    method public java.io.InputStream wrap(java.io.InputStream);
+  }
+
+  public static class Base64.Encoder {
+    method public byte[] encode(byte[]);
+    method public int encode(byte[], byte[]);
+    method public java.nio.ByteBuffer encode(java.nio.ByteBuffer);
+    method public java.lang.String encodeToString(byte[]);
+    method public java.util.Base64.Encoder withoutPadding();
+    method public java.io.OutputStream wrap(java.io.OutputStream);
+  }
+
   public class BitSet implements java.lang.Cloneable java.io.Serializable {
     ctor public BitSet();
     ctor public BitSet(int);
@@ -58686,7 +58825,7 @@
     field protected long time;
   }
 
-  public abstract interface Collection implements java.lang.Iterable {
+  public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -58704,86 +58843,86 @@
     method public abstract int size();
     method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class Collections {
-    method public static boolean addAll(java.util.Collection<? super T>, T...);
-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
-    method public static java.util.Enumeration<T> emptyEnumeration();
-    method public static java.util.Iterator<T> emptyIterator();
-    method public static final java.util.List<T> emptyList();
-    method public static java.util.ListIterator<T> emptyListIterator();
-    method public static final java.util.Map<K, V> emptyMap();
-    method public static final java.util.Set<T> emptySet();
-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
-    method public static void fill(java.util.List<? super T>, T);
+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
+    method public static <T> java.util.Iterator<T> emptyIterator();
+    method public static final <T> java.util.List<T> emptyList();
+    method public static <T> java.util.ListIterator<T> emptyListIterator();
+    method public static final <K, V> java.util.Map<K, V> emptyMap();
+    method public static final <T> java.util.Set<T> emptySet();
+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
+    method public static <T> void fill(java.util.List<? super T>, T);
     method public static int frequency(java.util.Collection<?>, java.lang.Object);
     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
-    method public static T max(java.util.Collection<? extends T>);
-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static T min(java.util.Collection<? extends T>);
-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static java.util.List<T> nCopies(int, T);
-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
-    method public static boolean replaceAll(java.util.List<T>, T, T);
+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T> java.util.List<T> nCopies(int, T);
+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
     method public static void reverse(java.util.List<?>);
-    method public static java.util.Comparator<T> reverseOrder();
-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
+    method public static <T> java.util.Comparator<T> reverseOrder();
+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
     method public static void rotate(java.util.List<?>, int);
     method public static void shuffle(java.util.List<?>);
     method public static void shuffle(java.util.List<?>, java.util.Random);
-    method public static java.util.Set<E> singleton(E);
-    method public static java.util.List<E> singletonList(E);
-    method public static java.util.Map<K, V> singletonMap(K, V);
-    method public static void sort(java.util.List<T>);
-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
+    method public static <E> java.util.Set<E> singleton(E);
+    method public static <E> java.util.List<E> singletonList(E);
+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
     method public static void swap(java.util.List<?>, int, int);
-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
     field public static final java.util.List EMPTY_LIST;
     field public static final java.util.Map EMPTY_MAP;
     field public static final java.util.Set EMPTY_SET;
   }
 
-  public abstract interface Comparator {
+  public abstract interface Comparator<T> {
     method public abstract int compare(T, T);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
-    method public static java.util.Comparator<T> naturalOrder();
-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> reverseOrder();
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
     method public default java.util.Comparator<T> reversed();
     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
@@ -58842,7 +58981,7 @@
     method public deprecated java.lang.String toLocaleString();
   }
 
-  public abstract interface Deque implements java.util.Queue {
+  public abstract interface Deque<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -58872,7 +59011,7 @@
     method public abstract int size();
   }
 
-  public abstract class Dictionary {
+  public abstract class Dictionary<K, V> {
     ctor public Dictionary();
     method public abstract java.util.Enumeration<V> elements();
     method public abstract V get(java.lang.Object);
@@ -58903,7 +59042,7 @@
     ctor public EmptyStackException();
   }
 
-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
     ctor public EnumMap(java.lang.Class<K>);
     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
     ctor public EnumMap(java.util.Map<K, ? extends V>);
@@ -58911,23 +59050,23 @@
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
   }
 
-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
     method public java.util.EnumSet<E> clone();
-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
-    method public static java.util.EnumSet<E> of(E);
-    method public static java.util.EnumSet<E> of(E, E);
-    method public static java.util.EnumSet<E> of(E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E...);
-    method public static java.util.EnumSet<E> range(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
   }
 
-  public abstract interface Enumeration {
+  public abstract interface Enumeration<E> {
     method public abstract boolean hasMoreElements();
     method public abstract E nextElement();
   }
@@ -58935,7 +59074,7 @@
   public abstract interface EventListener {
   }
 
-  public abstract class EventListenerProxy implements java.util.EventListener {
+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
     ctor public EventListenerProxy(T);
     method public T getListener();
   }
@@ -59021,19 +59160,27 @@
     field public static final int BC = 0; // 0x0
   }
 
-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public HashMap(int, float);
     ctor public HashMap(int);
     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>);
   }
 
-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public HashSet();
     ctor public HashSet(java.util.Collection<? extends E>);
     ctor public HashSet(int, float);
@@ -59044,7 +59191,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public Hashtable(int, float);
     ctor public Hashtable(int);
     ctor public Hashtable();
@@ -59079,7 +59226,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public IdentityHashMap();
     ctor public IdentityHashMap(int);
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
@@ -59146,14 +59293,14 @@
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
-  public abstract interface Iterator {
+  public abstract interface Iterator<E> {
     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
     method public default void remove();
   }
 
-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
     ctor public LinkedHashMap(int, float);
     ctor public LinkedHashMap(int);
     ctor public LinkedHashMap();
@@ -59162,14 +59309,14 @@
     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
   }
 
-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public LinkedHashSet(int, float);
     ctor public LinkedHashSet(int);
     ctor public LinkedHashSet();
     ctor public LinkedHashSet(java.util.Collection<? extends E>);
   }
 
-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
     ctor public LinkedList();
     ctor public LinkedList(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -59200,7 +59347,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface List implements java.util.Collection {
+  public abstract interface List<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract void add(int, E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -59227,10 +59374,10 @@
     method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
-  public abstract interface ListIterator implements java.util.Iterator {
+  public abstract interface ListIterator<E> implements java.util.Iterator {
     method public abstract void add(E);
     method public abstract boolean hasNext();
     method public abstract boolean hasPrevious();
@@ -59281,8 +59428,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
@@ -59347,7 +59496,7 @@
     method public final long getSum();
   }
 
-  public abstract interface Map {
+  public abstract interface Map<K, V> {
     method public abstract void clear();
     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
@@ -59375,11 +59524,11 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public static abstract interface Map.Entry {
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
+  public static abstract interface Map.Entry<K, V> {
+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -59403,7 +59552,7 @@
     method public java.lang.String getKey();
   }
 
-  public abstract interface NavigableMap implements java.util.SortedMap {
+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
     method public abstract K ceilingKey(K);
     method public abstract java.util.NavigableSet<K> descendingKeySet();
@@ -59427,7 +59576,7 @@
     method public abstract java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public abstract interface NavigableSet implements java.util.SortedSet {
+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
     method public abstract E ceiling(E);
     method public abstract java.util.Iterator<E> descendingIterator();
     method public abstract java.util.NavigableSet<E> descendingSet();
@@ -59451,16 +59600,16 @@
   }
 
   public final class Objects {
-    method public static int compare(T, T, java.util.Comparator<? super T>);
+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
     method public static boolean equals(java.lang.Object, java.lang.Object);
     method public static int hash(java.lang.Object...);
     method public static int hashCode(java.lang.Object);
     method public static boolean isNull(java.lang.Object);
     method public static boolean nonNull(java.lang.Object);
-    method public static T requireNonNull(T);
-    method public static T requireNonNull(T, java.lang.String);
-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
+    method public static <T> T requireNonNull(T);
+    method public static <T> T requireNonNull(T, java.lang.String);
+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
     method public static java.lang.String toString(java.lang.Object);
     method public static java.lang.String toString(java.lang.Object, java.lang.String);
   }
@@ -59482,19 +59631,19 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
-  public final class Optional {
-    method public static java.util.Optional<T> empty();
+  public final class Optional<T> {
+    method public static <T> java.util.Optional<T> empty();
     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
     method public T get();
     method public void ifPresent(java.util.function.Consumer<? super T>);
     method public boolean isPresent();
-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Optional<T> of(T);
-    method public static java.util.Optional<T> ofNullable(T);
+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Optional<T> of(T);
+    method public static <T> java.util.Optional<T> ofNullable(T);
     method public T orElse(T);
     method public T orElseGet(java.util.function.Supplier<? extends T>);
-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
   }
 
   public final class OptionalDouble {
@@ -59505,7 +59654,7 @@
     method public static java.util.OptionalDouble of(double);
     method public double orElse(double);
     method public double orElseGet(java.util.function.DoubleSupplier);
-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalInt {
@@ -59516,7 +59665,7 @@
     method public static java.util.OptionalInt of(int);
     method public int orElse(int);
     method public int orElseGet(java.util.function.IntSupplier);
-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalLong {
@@ -59527,10 +59676,10 @@
     method public static java.util.OptionalLong of(long);
     method public long orElse(long);
     method public long orElseGet(java.util.function.LongSupplier);
-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
-  public abstract interface PrimitiveIterator implements java.util.Iterator {
+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
     method public abstract void forEachRemaining(T_CONS);
   }
 
@@ -59555,7 +59704,7 @@
     method public abstract long nextLong();
   }
 
-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
     ctor public PriorityQueue(java.util.Comparator<? super E>);
@@ -59604,7 +59753,7 @@
     method public java.lang.Object handleGetObject(java.lang.String);
   }
 
-  public abstract interface Queue implements java.util.Collection {
+  public abstract interface Queue<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract E element();
     method public abstract boolean offer(E);
@@ -59648,6 +59797,7 @@
     method public static final void clearCache();
     method public static final void clearCache(java.lang.ClassLoader);
     method public boolean containsKey(java.lang.String);
+    method public java.lang.String getBaseBundleName();
     method public static final java.util.ResourceBundle getBundle(java.lang.String);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.ResourceBundle.Control);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale);
@@ -59756,15 +59906,15 @@
     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
   }
 
-  public final class ServiceLoader implements java.lang.Iterable {
+  public final class ServiceLoader<S> implements java.lang.Iterable {
     method public java.util.Iterator<S> iterator();
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
     method public void reload();
   }
 
-  public abstract interface Set implements java.util.Collection {
+  public abstract interface Set<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -59779,7 +59929,7 @@
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class SimpleTimeZone extends java.util.TimeZone {
@@ -59805,7 +59955,7 @@
     field public static final int WALL_TIME = 0; // 0x0
   }
 
-  public abstract interface SortedMap implements java.util.Map {
+  public abstract interface SortedMap<K, V> implements java.util.Map {
     method public abstract java.util.Comparator<? super K> comparator();
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract K firstKey();
@@ -59817,7 +59967,7 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public abstract interface SortedSet implements java.util.Set {
+  public abstract interface SortedSet<E> implements java.util.Set {
     method public abstract java.util.Comparator<? super E> comparator();
     method public abstract E first();
     method public abstract java.util.SortedSet<E> headSet(E);
@@ -59826,7 +59976,7 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
-  public abstract interface Spliterator {
+  public abstract interface Spliterator<T> {
     method public abstract int characteristics();
     method public abstract long estimateSize();
     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
@@ -59869,7 +60019,7 @@
     method public abstract java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
     method public default void forEachRemaining(T_CONS);
     method public abstract boolean tryAdvance(T_CONS);
     method public abstract T_SPLITR trySplit();
@@ -59879,25 +60029,25 @@
     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
-    method public static java.util.Spliterator<T> emptySpliterator();
-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static <T> java.util.Spliterator<T> emptySpliterator();
+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
@@ -59924,7 +60074,7 @@
     method public java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
     ctor protected Spliterators.AbstractSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
@@ -59959,7 +60109,7 @@
     method public java.util.SplittableRandom split();
   }
 
-  public class Stack extends java.util.Vector {
+  public class Stack<E> extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
     method public synchronized E peek();
@@ -60043,7 +60193,7 @@
     ctor public TooManyListenersException(java.lang.String);
   }
 
-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
     ctor public TreeMap();
     ctor public TreeMap(java.util.Comparator<? super K>);
     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
@@ -60080,7 +60230,7 @@
     method public java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public TreeSet();
     ctor public TreeSet(java.util.Comparator<? super E>);
     ctor public TreeSet(java.util.Collection<? extends E>);
@@ -60133,7 +60283,7 @@
     method public java.lang.String getFlags();
   }
 
-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public Vector(int, int);
     ctor public Vector(int);
     ctor public Vector();
@@ -60168,7 +60318,7 @@
     field protected java.lang.Object[] elementData;
   }
 
-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
     ctor public WeakHashMap(int, float);
     ctor public WeakHashMap(int);
     ctor public WeakHashMap();
@@ -60184,18 +60334,18 @@
 
   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
     ctor public AbstractExecutorService();
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
   }
 
-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public ArrayBlockingQueue(int);
     ctor public ArrayBlockingQueue(int, boolean);
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
@@ -60214,7 +60364,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -60246,7 +60396,7 @@
     method public abstract E takeLast() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingQueue implements java.util.Queue {
+  public abstract interface BlockingQueue<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract boolean contains(java.lang.Object);
     method public abstract int drainTo(java.util.Collection<? super E>);
@@ -60265,7 +60415,7 @@
     ctor public BrokenBarrierException(java.lang.String);
   }
 
-  public abstract interface Callable {
+  public abstract interface Callable<V> {
     method public abstract V call() throws java.lang.Exception;
   }
 
@@ -60274,28 +60424,28 @@
     ctor public CancellationException(java.lang.String);
   }
 
-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
     ctor public CompletableFuture();
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public boolean cancel(boolean);
     method public boolean complete(T);
     method public boolean completeExceptionally(java.lang.Throwable);
-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public T getNow(T);
     method public int getNumberOfDependents();
-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public boolean isCancelled();
     method public boolean isCompletedExceptionally();
     method public boolean isDone();
@@ -60310,23 +60460,23 @@
     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -60346,7 +60496,7 @@
     ctor public CompletionException(java.lang.Throwable);
   }
 
-  public abstract interface CompletionService {
+  public abstract interface CompletionService<V> {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
@@ -60354,17 +60504,17 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface CompletionStage {
+  public abstract interface CompletionStage<T> {
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
@@ -60374,18 +60524,18 @@
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -60395,7 +60545,7 @@
     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
   }
 
-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
@@ -60409,29 +60559,29 @@
     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 void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachKey(long, java.util.function.Consumer<? super K>);
-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachValue(long, java.util.function.Consumer<? super V>);
-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
     method public long mappingCount();
     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
@@ -60439,7 +60589,7 @@
     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
@@ -60447,13 +60597,13 @@
     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>);
-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
   }
 
-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
     method public final void clear();
     method public abstract boolean contains(java.lang.Object);
     method public final boolean containsAll(java.util.Collection<?>);
@@ -60465,11 +60615,11 @@
     method public final boolean retainAll(java.util.Collection<?>);
     method public final int size();
     method public final java.lang.Object[] toArray();
-    method public final T[] toArray(T[]);
+    method public final <T> T[] toArray(T[]);
     method public final java.lang.String toString();
   }
 
-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
     method public boolean add(K);
     method public boolean addAll(java.util.Collection<? extends K>);
     method public boolean contains(java.lang.Object);
@@ -60480,7 +60630,7 @@
     method public java.util.Spliterator<K> spliterator();
   }
 
-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
     ctor public ConcurrentLinkedDeque();
     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -60510,7 +60660,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
     method public java.util.Iterator<E> iterator();
@@ -60521,14 +60671,14 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface ConcurrentMap implements java.util.Map {
+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
     method public abstract V putIfAbsent(K, V);
     method public abstract boolean remove(java.lang.Object, java.lang.Object);
     method public abstract boolean replace(K, V, V);
     method public abstract V replace(K, V);
   }
 
-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
     method public abstract java.util.NavigableSet<K> descendingKeySet();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
@@ -60541,7 +60691,7 @@
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
     ctor public ConcurrentSkipListMap();
     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
@@ -60585,7 +60735,7 @@
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public ConcurrentSkipListSet();
     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
@@ -60613,7 +60763,7 @@
     method public java.util.NavigableSet<E> tailSet(E);
   }
 
-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
@@ -60645,10 +60795,10 @@
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
     method public void forEach(java.util.function.Consumer<? super E>);
@@ -60666,7 +60816,7 @@
     method public long getCount();
   }
 
-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
     ctor protected CountedCompleter();
@@ -60703,7 +60853,7 @@
     method public void reset();
   }
 
-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
     ctor public DelayQueue();
     ctor public DelayQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -60724,7 +60874,7 @@
     method public abstract long getDelay(java.util.concurrent.TimeUnit);
   }
 
-  public class Exchanger {
+  public class Exchanger<V> {
     ctor public Exchanger();
     method public V exchange(V) throws java.lang.InterruptedException;
     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -60741,7 +60891,7 @@
     method public abstract void execute(java.lang.Runnable);
   }
 
-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
     method public java.util.concurrent.Future<V> poll();
@@ -60753,21 +60903,21 @@
 
   public abstract interface ExecutorService implements java.util.concurrent.Executor {
     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public abstract boolean isShutdown();
     method public abstract boolean isTerminated();
     method public abstract void shutdown();
     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
   }
 
   public class Executors {
-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
@@ -60784,8 +60934,8 @@
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
@@ -60813,7 +60963,7 @@
     method public long getStealCount();
     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
     method public boolean hasQueuedSubmissions();
-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
     method public boolean isQuiescent();
     method public boolean isShutdown();
     method public boolean isTerminated();
@@ -60822,7 +60972,7 @@
     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
     method public void shutdown();
     method public java.util.List<java.lang.Runnable> shutdownNow();
-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
   }
 
@@ -60835,11 +60985,11 @@
     method public abstract boolean isReleasable();
   }
 
-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
     ctor public ForkJoinTask();
     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
     method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
@@ -60859,7 +61009,7 @@
     method public final V invoke();
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
     method public final boolean isCancelled();
     method public final boolean isCompletedAbnormally();
     method public final boolean isCompletedNormally();
@@ -60885,7 +61035,7 @@
     method protected void onTermination(java.lang.Throwable);
   }
 
-  public abstract interface Future {
+  public abstract interface Future<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -60893,7 +61043,7 @@
     method public abstract boolean isDone();
   }
 
-  public class FutureTask implements java.util.concurrent.RunnableFuture {
+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
     ctor public FutureTask(java.util.concurrent.Callable<V>);
     ctor public FutureTask(java.lang.Runnable, V);
     method public boolean cancel(boolean);
@@ -60908,7 +61058,7 @@
     method protected void setException(java.lang.Throwable);
   }
 
-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
     ctor public LinkedBlockingDeque();
     ctor public LinkedBlockingDeque(int);
     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
@@ -60952,7 +61102,7 @@
     method public E takeLast() throws java.lang.InterruptedException;
   }
 
-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public LinkedBlockingQueue();
     ctor public LinkedBlockingQueue(int);
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
@@ -60971,7 +61121,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
     ctor public LinkedTransferQueue();
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -61018,7 +61168,7 @@
     method public int register();
   }
 
-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
@@ -61047,7 +61197,7 @@
     method protected final void setRawResult(java.lang.Void);
   }
 
-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
     ctor public RecursiveTask();
     method protected abstract V compute();
     method protected final boolean exec();
@@ -61066,22 +61216,22 @@
     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
     method public abstract void run();
   }
 
-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
     method public abstract boolean isPeriodic();
   }
 
   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
   }
 
-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
   }
 
   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
@@ -61089,13 +61239,13 @@
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
     method public boolean getRemoveOnCancelPolicy();
     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
@@ -61125,7 +61275,7 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
     method public int drainTo(java.util.Collection<? super E>);
@@ -61243,7 +61393,7 @@
     ctor public TimeoutException(java.lang.String);
   }
 
-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
     method public abstract int getWaitingConsumerCount();
     method public abstract boolean hasWaitingConsumer();
     method public abstract void transfer(E) throws java.lang.InterruptedException;
@@ -61313,7 +61463,7 @@
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
-  public abstract class AtomicIntegerFieldUpdater {
+  public abstract class AtomicIntegerFieldUpdater<T> {
     ctor protected AtomicIntegerFieldUpdater();
     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
@@ -61328,7 +61478,7 @@
     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
@@ -61381,7 +61531,7 @@
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
-  public abstract class AtomicLongFieldUpdater {
+  public abstract class AtomicLongFieldUpdater<T> {
     ctor protected AtomicLongFieldUpdater();
     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
@@ -61396,13 +61546,13 @@
     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
-  public class AtomicMarkableReference {
+  public class AtomicMarkableReference<V> {
     ctor public AtomicMarkableReference(V, boolean);
     method public boolean attemptMark(V, boolean);
     method public boolean compareAndSet(V, V, boolean, boolean);
@@ -61413,7 +61563,7 @@
     method public boolean weakCompareAndSet(V, V, boolean, boolean);
   }
 
-  public class AtomicReference implements java.io.Serializable {
+  public class AtomicReference<V> implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
@@ -61428,7 +61578,7 @@
     method public final boolean weakCompareAndSet(V, V);
   }
 
-  public class AtomicReferenceArray implements java.io.Serializable {
+  public class AtomicReferenceArray<E> implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
@@ -61444,7 +61594,7 @@
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
-  public abstract class AtomicReferenceFieldUpdater {
+  public abstract class AtomicReferenceFieldUpdater<T, V> {
     ctor protected AtomicReferenceFieldUpdater();
     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
@@ -61453,13 +61603,13 @@
     method public V getAndSet(T, V);
     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
-  public class AtomicStampedReference {
+  public class AtomicStampedReference<V> {
     ctor public AtomicStampedReference(V, int);
     method public boolean attemptStamp(V, int);
     method public boolean compareAndSet(V, V, int, int);
@@ -61762,33 +61912,33 @@
 
 package java.util.function {
 
-  public abstract interface BiConsumer {
+  public abstract interface BiConsumer<T, U> {
     method public abstract void accept(T, U);
     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
   }
 
-  public abstract interface BiFunction {
-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface BiFunction<T, U, R> {
+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T, U);
   }
 
-  public abstract interface BiPredicate {
+  public abstract interface BiPredicate<T, U> {
     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
     method public default java.util.function.BiPredicate<T, U> negate();
     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
     method public abstract boolean test(T, U);
   }
 
-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
   }
 
   public abstract interface BooleanSupplier {
     method public abstract boolean getAsBoolean();
   }
 
-  public abstract interface Consumer {
+  public abstract interface Consumer<T> {
     method public abstract void accept(T);
     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
   }
@@ -61802,7 +61952,7 @@
     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
   }
 
-  public abstract interface DoubleFunction {
+  public abstract interface DoubleFunction<R> {
     method public abstract R apply(double);
   }
 
@@ -61832,11 +61982,11 @@
     method public static java.util.function.DoubleUnaryOperator identity();
   }
 
-  public abstract interface Function {
-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface Function<T, R> {
+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T);
-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
-    method public static java.util.function.Function<T, T> identity();
+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+    method public static <T> java.util.function.Function<T, T> identity();
   }
 
   public abstract interface IntBinaryOperator {
@@ -61848,7 +61998,7 @@
     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
   }
 
-  public abstract interface IntFunction {
+  public abstract interface IntFunction<R> {
     method public abstract R apply(int);
   }
 
@@ -61887,7 +62037,7 @@
     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
   }
 
-  public abstract interface LongFunction {
+  public abstract interface LongFunction<R> {
     method public abstract R apply(long);
   }
 
@@ -61917,56 +62067,56 @@
     method public static java.util.function.LongUnaryOperator identity();
   }
 
-  public abstract interface ObjDoubleConsumer {
+  public abstract interface ObjDoubleConsumer<T> {
     method public abstract void accept(T, double);
   }
 
-  public abstract interface ObjIntConsumer {
+  public abstract interface ObjIntConsumer<T> {
     method public abstract void accept(T, int);
   }
 
-  public abstract interface ObjLongConsumer {
+  public abstract interface ObjLongConsumer<T> {
     method public abstract void accept(T, long);
   }
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
     method public default java.util.function.Predicate<T> negate();
     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
     method public abstract boolean test(T);
   }
 
-  public abstract interface Supplier {
+  public abstract interface Supplier<T> {
     method public abstract T get();
   }
 
-  public abstract interface ToDoubleBiFunction {
+  public abstract interface ToDoubleBiFunction<T, U> {
     method public abstract double applyAsDouble(T, U);
   }
 
-  public abstract interface ToDoubleFunction {
+  public abstract interface ToDoubleFunction<T> {
     method public abstract double applyAsDouble(T);
   }
 
-  public abstract interface ToIntBiFunction {
+  public abstract interface ToIntBiFunction<T, U> {
     method public abstract int applyAsInt(T, U);
   }
 
-  public abstract interface ToIntFunction {
+  public abstract interface ToIntFunction<T> {
     method public abstract int applyAsInt(T);
   }
 
-  public abstract interface ToLongBiFunction {
+  public abstract interface ToLongBiFunction<T, U> {
     method public abstract long applyAsLong(T, U);
   }
 
-  public abstract interface ToLongFunction {
+  public abstract interface ToLongFunction<T> {
     method public abstract long applyAsLong(T);
   }
 
-  public abstract interface UnaryOperator implements java.util.function.Function {
-    method public static java.util.function.UnaryOperator<T> identity();
+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
+    method public static <T> java.util.function.UnaryOperator<T> identity();
   }
 
 }
@@ -62554,7 +62704,7 @@
 
 package java.util.stream {
 
-  public abstract interface BaseStream implements java.lang.AutoCloseable {
+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
     method public abstract void close();
     method public abstract boolean isParallel();
     method public abstract java.util.Iterator<T> iterator();
@@ -62565,13 +62715,13 @@
     method public abstract S unordered();
   }
 
-  public abstract interface Collector {
+  public abstract interface Collector<T, A, R> {
     method public abstract java.util.function.BiConsumer<A, T> accumulator();
     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
     method public abstract java.util.function.BinaryOperator<A> combiner();
     method public abstract java.util.function.Function<A, R> finisher();
-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
     method public abstract java.util.function.Supplier<A> supplier();
   }
 
@@ -62584,43 +62734,43 @@
   }
 
   public final class Collectors {
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
   }
 
   public abstract interface DoubleStream implements java.util.stream.BaseStream {
@@ -62629,7 +62779,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
     method public static java.util.stream.DoubleStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
     method public abstract long count();
     method public abstract java.util.stream.DoubleStream distinct();
@@ -62647,7 +62797,7 @@
     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
     method public abstract java.util.OptionalDouble max();
     method public abstract java.util.OptionalDouble min();
     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
@@ -62680,7 +62830,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
     method public static java.util.stream.IntStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
     method public abstract long count();
     method public abstract java.util.stream.IntStream distinct();
@@ -62698,7 +62848,7 @@
     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
     method public abstract java.util.OptionalInt max();
     method public abstract java.util.OptionalInt min();
     method public abstract boolean noneMatch(java.util.function.IntPredicate);
@@ -62732,7 +62882,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
     method public static java.util.stream.LongStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
     method public abstract long count();
     method public abstract java.util.stream.LongStream distinct();
@@ -62750,7 +62900,7 @@
     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
     method public abstract java.util.OptionalLong max();
     method public abstract java.util.OptionalLong min();
     method public abstract boolean noneMatch(java.util.function.LongPredicate);
@@ -62777,49 +62927,49 @@
     method public abstract java.util.stream.LongStream build();
   }
 
-  public abstract interface Stream implements java.util.stream.BaseStream {
+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream.Builder<T> builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public static <T> java.util.stream.Stream.Builder<T> builder();
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
     method public abstract long count();
     method public abstract java.util.stream.Stream<T> distinct();
-    method public static java.util.stream.Stream<T> empty();
+    method public static <T> java.util.stream.Stream<T> empty();
     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
     method public abstract java.util.Optional<T> findAny();
     method public abstract java.util.Optional<T> findFirst();
-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
     method public abstract void forEach(java.util.function.Consumer<? super T>);
     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
     method public abstract java.util.stream.Stream<T> limit(long);
-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream<T> of(T);
-    method public static java.util.stream.Stream<T> of(T...);
+    method public static <T> java.util.stream.Stream<T> of(T);
+    method public static <T> java.util.stream.Stream<T> of(T...);
     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
     method public abstract java.util.stream.Stream<T> skip(long);
     method public abstract java.util.stream.Stream<T> sorted();
     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
     method public abstract java.lang.Object[] toArray();
-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
   }
 
-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
     method public abstract void accept(T);
     method public default java.util.stream.Stream.Builder<T> add(T);
     method public abstract java.util.stream.Stream<T> build();
@@ -62832,8 +62982,8 @@
     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
   }
 
 }
@@ -63475,7 +63625,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 +63636,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 +63644,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 +63762,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();
   }
 
@@ -65004,16 +65156,16 @@
   public final class Subject implements java.io.Serializable {
     ctor public Subject();
     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
     method public java.util.Set<java.security.Principal> getPrincipals();
-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPrivateCredentials();
-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPublicCredentials();
-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
     method public boolean isReadOnly();
     method public void setReadOnly();
diff --git a/api/removed.txt b/api/removed.txt
index 94ba452..683a695 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -167,6 +167,13 @@
 
 package android.net {
 
+  public abstract class PskKeyManager {
+    ctor public PskKeyManager();
+    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
+  }
+
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
@@ -179,6 +186,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..2b5c33d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3036,11 +3036,11 @@
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
   }
 
-  public abstract interface AccountManagerCallback {
+  public abstract interface AccountManagerCallback<V> {
     method public abstract void run(android.accounts.AccountManagerFuture<V>);
   }
 
-  public abstract interface AccountManagerFuture {
+  public abstract interface AccountManagerFuture<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -3186,7 +3186,7 @@
     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
   }
 
-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract T convertBack(V);
     method public android.animation.BidirectionalTypeConverter<V, T> invert();
@@ -3278,26 +3278,26 @@
     method public java.lang.String getPropertyName();
     method public java.lang.Object getTarget();
     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
     method public void setAutoCancel(boolean);
     method public void setProperty(android.util.Property);
@@ -3321,17 +3321,17 @@
     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public void setConverter(android.animation.TypeConverter);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
@@ -3368,12 +3368,12 @@
     method public abstract float getInterpolation(float);
   }
 
-  public abstract class TypeConverter {
+  public abstract class TypeConverter<T, V> {
     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract V convert(T);
   }
 
-  public abstract interface TypeEvaluator {
+  public abstract interface TypeEvaluator<T> {
     method public abstract T evaluate(float, T, T);
   }
 
@@ -4172,6 +4172,7 @@
     field public static final java.lang.String OPSTR_MOCK_LOCATION = "android:mock_location";
     field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
     field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
+    field public static final java.lang.String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";
     field public static final java.lang.String OPSTR_READ_CALENDAR = "android:read_calendar";
     field public static final java.lang.String OPSTR_READ_CALL_LOG = "android:read_call_log";
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
@@ -4733,7 +4734,7 @@
     method public android.os.Parcelable saveAllState();
   }
 
-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
     method public void onAttachFragment(android.app.Fragment);
     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -5000,12 +5001,12 @@
     method public abstract void destroyLoader(int);
     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public static void enableDebugLogging(boolean);
-    method public abstract android.content.Loader<D> getLoader(int);
-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> getLoader(int);
+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
   }
 
-  public static abstract interface LoaderManager.LoaderCallbacks {
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
     method public abstract void onLoadFinished(android.content.Loader<D>, D);
     method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -5068,6 +5069,7 @@
     method public int describeContents();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5258,6 +5260,7 @@
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChannel(java.lang.String);
     method public android.app.Notification.Builder setChronometerCountDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
@@ -5406,6 +5409,7 @@
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
     method public java.util.List<android.app.Notification.Action> getActions();
     method public android.graphics.Bitmap getBackground();
+    method public java.lang.String getBridgeTag();
     method public int getContentAction();
     method public int getContentIcon();
     method public int getContentIconGravity();
@@ -5424,6 +5428,7 @@
     method public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
     method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
     method public android.app.Notification.WearableExtender setContentAction(int);
     method public android.app.Notification.WearableExtender setContentIcon(int);
     method public android.app.Notification.WearableExtender setContentIconGravity(int);
@@ -5451,17 +5456,48 @@
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
+  public final class NotificationChannel implements android.os.Parcelable {
+    ctor public NotificationChannel(java.lang.String, java.lang.CharSequence);
+    ctor protected NotificationChannel(android.os.Parcel);
+    method public boolean canBypassDnd();
+    method public int describeContents();
+    method public android.net.Uri getDefaultRingtone();
+    method public java.lang.String getId();
+    method public int getImportance();
+    method public int getLockscreenVisibility();
+    method public java.lang.CharSequence getName();
+    method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
+    method public void setBypassDnd(boolean);
+    method public void setDefaultRingtone(android.net.Uri);
+    method public void setImportance(int);
+    method public void setLights(boolean);
+    method public void setLockscreenVisibility(int);
+    method public void setName(java.lang.CharSequence);
+    method public void setVibration(boolean);
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public org.json.JSONObject toJson() throws org.json.JSONException;
+    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+    field public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
+    field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
   public class NotificationManager {
     method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
+    method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -5470,6 +5506,7 @@
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
+    method public void updateNotificationChannel(android.app.NotificationChannel);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5563,7 +5600,7 @@
     method public void onDisplayRemoved();
   }
 
-  public class ProgressDialog extends android.app.AlertDialog {
+  public deprecated class ProgressDialog extends android.app.AlertDialog {
     ctor public ProgressDialog(android.content.Context);
     ctor public ProgressDialog(android.content.Context, int);
     method public int getMax();
@@ -7962,7 +7999,7 @@
     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
   }
 
-  public abstract class AsyncTaskLoader extends android.content.Loader {
+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
     method public void cancelLoadInBackground();
     method public boolean isLoadInBackgroundCanceled();
@@ -8144,7 +8181,7 @@
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
@@ -8157,7 +8194,7 @@
     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public static abstract interface ContentProvider.PipeDataWriter {
+  public static abstract interface ContentProvider.PipeDataWriter<T> {
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
@@ -8430,7 +8467,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
-    method public final T getSystemService(java.lang.Class<T>);
+    method public final <T> T getSystemService(java.lang.Class<T>);
     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
@@ -8801,8 +8838,8 @@
     method public long getLongExtra(java.lang.String, long);
     method public java.lang.String getPackage();
     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
-    method public T getParcelableExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
     method public java.lang.String getScheme();
     method public android.content.Intent getSelector();
     method public java.io.Serializable getSerializableExtra(java.lang.String);
@@ -9289,7 +9326,7 @@
     ctor public IntentSender.SendIntentException(java.lang.Exception);
   }
 
-  public class Loader {
+  public class Loader<D> {
     ctor public Loader(android.content.Context);
     method public void abandon();
     method public boolean cancelLoad();
@@ -9326,11 +9363,11 @@
     ctor public Loader.ForceLoadContentObserver();
   }
 
-  public static abstract interface Loader.OnLoadCanceledListener {
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
     method public abstract void onLoadCanceled(android.content.Loader<D>);
   }
 
-  public static abstract interface Loader.OnLoadCompleteListener {
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
 
@@ -11299,7 +11336,7 @@
     method public boolean isNull(int);
   }
 
-  public abstract class Observable {
+  public abstract class Observable<T> {
     ctor public Observable();
     method public void registerObserver(T);
     method public void unregisterAll();
@@ -13104,6 +13141,7 @@
   public class SurfaceTexture {
     ctor public SurfaceTexture(int);
     ctor public SurfaceTexture(int, boolean);
+    ctor public SurfaceTexture(boolean);
     method public void attachToGLContext(int);
     method public void detachFromGLContext();
     method public long getTimestamp();
@@ -13190,7 +13228,7 @@
   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
     ctor public AnimatedStateListDrawable();
     method public void addState(int[], android.graphics.drawable.Drawable, int);
-    method public void addTransition(int, int, T, boolean);
+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
   }
 
   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
@@ -14291,6 +14329,7 @@
     method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
+    method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CameraDevice getDevice();
     method public abstract android.view.Surface getInputSurface();
     method public abstract boolean isReprocessable();
@@ -14322,7 +14361,7 @@
   }
 
   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
@@ -14407,7 +14446,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
   }
 
-  public static final class CameraCharacteristics.Key {
+  public static final class CameraCharacteristics.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14472,7 +14511,7 @@
     method public void onTorchModeUnavailable(java.lang.String);
   }
 
-  public abstract class CameraMetadata {
+  public abstract class CameraMetadata<TKey> {
     method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
@@ -14680,7 +14719,7 @@
 
   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
     method public int describeContents();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
     method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
@@ -14743,20 +14782,20 @@
   public static final class CaptureRequest.Builder {
     method public void addTarget(android.view.Surface);
     method public android.hardware.camera2.CaptureRequest build();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public void removeTarget(android.view.Surface);
-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
     method public void setTag(java.lang.Object);
   }
 
-  public static final class CaptureRequest.Key {
+  public static final class CaptureRequest.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
   }
 
   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
     method public long getFrameNumber();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
@@ -14837,7 +14876,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
-  public static final class CaptureResult.Key {
+  public static final class CaptureResult.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14931,10 +14970,12 @@
     ctor public OutputConfiguration(int, android.view.Surface);
     ctor public OutputConfiguration(android.view.Surface, int);
     ctor public OutputConfiguration(int, android.view.Surface, int);
+    ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
     method public int describeContents();
     method public int getRotation();
     method public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
+    method public void setDeferredSurface(android.view.Surface);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int ROTATION_0 = 0; // 0x0
@@ -14969,14 +15010,14 @@
     method public android.util.Size[] getInputSizes(int);
     method public final int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
     method public final int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
@@ -15944,6 +15985,7 @@
     method public java.lang.String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
+    method public boolean resetDevice();
     method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
     method public boolean setInterface(android.hardware.usb.UsbInterface);
   }
@@ -17424,7 +17466,7 @@
 
 package android.icu.text {
 
-  public final class AlphabeticIndex implements java.lang.Iterable {
+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
     ctor public AlphabeticIndex(android.icu.util.ULocale);
     ctor public AlphabeticIndex(java.util.Locale);
     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
@@ -17450,7 +17492,7 @@
     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
   }
 
-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
     method public java.lang.String getLabel();
     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
@@ -17466,14 +17508,14 @@
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
   }
 
-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
     method public int getBucketCount();
     method public int getBucketIndex(java.lang.CharSequence);
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
   }
 
-  public static class AlphabeticIndex.Record {
+  public static class AlphabeticIndex.Record<V> {
     method public V getData();
     method public java.lang.CharSequence getName();
   }
@@ -18986,8 +19028,8 @@
     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
-    method public android.icu.text.UnicodeSet addAll(T...);
-    method public T addAllTo(T);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -19015,15 +19057,15 @@
     method public final boolean contains(java.lang.CharSequence);
     method public boolean containsAll(android.icu.text.UnicodeSet);
     method public boolean containsAll(java.lang.String);
-    method public boolean containsAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
     method public boolean containsNone(int, int);
     method public boolean containsNone(android.icu.text.UnicodeSet);
     method public boolean containsNone(java.lang.CharSequence);
-    method public boolean containsNone(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
     method public final boolean containsSome(int, int);
     method public final boolean containsSome(android.icu.text.UnicodeSet);
     method public final boolean containsSome(java.lang.CharSequence);
-    method public final boolean containsSome(java.lang.Iterable<T>);
+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet freeze();
     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
@@ -19041,14 +19083,14 @@
     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet set(int, int);
     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
     method public int size();
@@ -19458,7 +19500,7 @@
     method public long getToDate();
   }
 
-  public abstract interface Freezable implements java.lang.Cloneable {
+  public abstract interface Freezable<T> implements java.lang.Cloneable {
     method public abstract T cloneAsThawed();
     method public abstract T freeze();
     method public abstract boolean isFrozen();
@@ -19740,7 +19782,7 @@
     field public static final android.icu.util.TimeUnit YEAR;
   }
 
-  public class Output {
+  public class Output<T> {
     ctor public Output();
     ctor public Output(T);
     field public T value;
@@ -22952,6 +22994,7 @@
     field public static final int AMR_NB = 3; // 0x3
     field public static final int AMR_WB = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
+    field public static final int MPEG_2_TS = 8; // 0x8
     field public static final int MPEG_4 = 2; // 0x2
     field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
@@ -24179,8 +24222,8 @@
     method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
-    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
@@ -24229,7 +24272,7 @@
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
     method public void setRepeatMode(int);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -24258,7 +24301,7 @@
     method public void setRatingType(int);
     method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -24282,7 +24325,7 @@
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
     method public void onSetRepeatMode(int);
-    method public void onSetShuffleMode(boolean);
+    method public void onSetShuffleModeEnabled(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -24344,7 +24387,7 @@
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
     field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
-    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
@@ -25716,19 +25759,6 @@
     field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
   }
 
-  public abstract class PskKeyManager {
-    ctor public PskKeyManager();
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
-    method public java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
-    method public java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
-    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
-  }
-
   public final class RouteInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.IpPrefix getDestination();
@@ -30714,7 +30744,7 @@
 
 package android.os {
 
-  public abstract class AsyncTask {
+  public abstract class AsyncTask<Params, Progress, Result> {
     ctor public AsyncTask();
     method public final boolean cancel(boolean);
     method protected abstract Result doInBackground(Params...);
@@ -30848,6 +30878,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -30864,7 +30895,7 @@
     field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
@@ -30943,16 +30974,16 @@
     method public float getFloat(java.lang.String, float);
     method public float[] getFloatArray(java.lang.String);
     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
-    method public T getParcelable(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
     method public java.io.Serializable getSerializable(java.lang.String);
     method public short getShort(java.lang.String);
     method public short getShort(java.lang.String, short);
     method public short[] getShortArray(java.lang.String);
     method public android.util.Size getSize(java.lang.String);
     method public android.util.SizeF getSizeF(java.lang.String);
-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
     method public boolean hasFileDescriptors();
     method public void putAll(android.os.Bundle);
@@ -31457,8 +31488,8 @@
     method public final long[] createLongArray();
     method public final java.lang.String[] createStringArray();
     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
     method public final int dataAvail();
     method public final int dataCapacity();
     method public final int dataPosition();
@@ -31491,7 +31522,7 @@
     method public final long readLong();
     method public final void readLongArray(long[]);
     method public final void readMap(java.util.Map, java.lang.ClassLoader);
-    method public final T readParcelable(java.lang.ClassLoader);
+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
     method public final android.os.PersistableBundle readPersistableBundle();
     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
@@ -31504,9 +31535,9 @@
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
     method public final android.os.IBinder readStrongBinder();
-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
     method public final java.lang.Object readValue(java.lang.ClassLoader);
     method public final void recycle();
     method public final void setDataCapacity(int);
@@ -31537,7 +31568,7 @@
     method public final void writeMap(java.util.Map);
     method public final void writeNoException();
     method public final void writeParcelable(android.os.Parcelable, int);
-    method public final void writeParcelableArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
     method public final void writePersistableBundle(android.os.PersistableBundle);
     method public final void writeSerializable(java.io.Serializable);
     method public final void writeSize(android.util.Size);
@@ -31549,9 +31580,9 @@
     method public final void writeStringList(java.util.List<java.lang.String>);
     method public final void writeStrongBinder(android.os.IBinder);
     method public final void writeStrongInterface(android.os.IInterface);
-    method public final void writeTypedArray(T[], int);
-    method public final void writeTypedList(java.util.List<T>);
-    method public final void writeTypedObject(T, int);
+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
     method public final void writeValue(java.lang.Object);
     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
   }
@@ -31629,11 +31660,11 @@
     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
   }
 
-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
   }
 
-  public static abstract interface Parcelable.Creator {
+  public static abstract interface Parcelable.Creator<T> {
     method public abstract T createFromParcel(android.os.Parcel);
     method public abstract T[] newArray(int);
   }
@@ -31776,7 +31807,7 @@
     method public abstract void onResult(android.os.Bundle);
   }
 
-  public class RemoteCallbackList {
+  public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
     method public void finishBroadcast();
@@ -32876,6 +32907,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -32884,6 +32917,7 @@
     method public android.print.PageRange[] getPages();
     method public android.print.PrinterId getPrinterId();
     method public int getState();
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
@@ -34432,7 +34466,7 @@
     field public static final java.lang.String STATE = "state";
   }
 
-  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
+  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
     field public static final java.lang.String QUERY_PARAMETER_SIP_ADDRESS = "sip";
@@ -37343,7 +37377,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
   }
 
-  public static abstract interface CarrierMessagingService.ResultCallback {
+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
   }
 
@@ -37495,7 +37529,7 @@
     field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
-  public class MediaBrowserService.Result {
+  public class MediaBrowserService.Result<T> {
     method public void detach();
     method public void sendResult(T);
   }
@@ -37558,6 +37592,8 @@
     method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
+    method public static final void requestRebind(android.content.ComponentName);
+    method public final void requestUnbind();
     field public static final java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
     field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
@@ -37643,6 +37679,7 @@
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     field public static final int REASON_APP_CANCEL = 8; // 0x8
     field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
+    field public static final int REASON_CHANNEL_BANNED = 17; // 0x11
     field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
     field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
     field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
@@ -38358,6 +38395,7 @@
     method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static int gettid();
     method public static int getuid();
+    method public static byte[] getxattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static java.lang.String if_indextoname(int);
     method public static int if_nametoindex(java.lang.String);
     method public static java.net.InetAddress inet_pton(int, java.lang.String);
@@ -38366,6 +38404,7 @@
     method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
     method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.lang.String[] listxattr(java.lang.String) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
     method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
     method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
@@ -38392,6 +38431,7 @@
     method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
+    method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -38403,6 +38443,7 @@
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
     method public static void setuid(int) throws android.system.ErrnoException;
+    method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
     method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -39953,6 +39994,7 @@
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
+    field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -39962,11 +40004,14 @@
     field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+    field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -40012,7 +40057,9 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+    field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -40819,14 +40866,14 @@
 
 package android.test {
 
-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -40841,7 +40888,7 @@
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -40887,7 +40934,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -40913,8 +40960,8 @@
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
     method public void injectInstrumentation(android.app.Instrumentation);
-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
     method public void sendKeys(java.lang.String);
     method public void sendKeys(int...);
@@ -40954,7 +41001,7 @@
 
   public class LoaderTestCase extends android.test.AndroidTestCase {
     ctor public LoaderTestCase();
-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
   public final deprecated class MoreAsserts {
@@ -41009,20 +41056,20 @@
     method public abstract void startTiming(boolean);
   }
 
-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
@@ -41030,11 +41077,11 @@
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
     method public void makeExistingFilesAndDbsAccessible();
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -41047,7 +41094,7 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
@@ -41415,7 +41462,7 @@
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
     method public java.lang.String getEnclosingClassname();
     method public java.lang.String getName();
@@ -41863,7 +41910,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
     method public int getTextWatcherDepth();
     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
@@ -41885,7 +41932,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public final int length();
     method public int nextSpanTransition(int, int, java.lang.Class);
     method public final java.lang.String toString();
@@ -41895,7 +41942,7 @@
     method public abstract int getSpanEnd(java.lang.Object);
     method public abstract int getSpanFlags(java.lang.Object);
     method public abstract int getSpanStart(java.lang.Object);
-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public abstract int nextSpanTransition(int, int, java.lang.Class);
     field public static final int SPAN_COMPOSING = 256; // 0x100
     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
@@ -42873,7 +42920,7 @@
     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
   }
 
-  public static class TtsSpan.Builder {
+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
     ctor public TtsSpan.Builder(java.lang.String);
     method public android.text.style.TtsSpan build();
     method public C setIntArgument(java.lang.String, int);
@@ -42969,7 +43016,7 @@
     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
   }
 
-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
     method public C setAnimacy(java.lang.String);
     method public C setCase(java.lang.String);
@@ -43376,7 +43423,7 @@
     ctor public AndroidRuntimeException(java.lang.Exception);
   }
 
-  public final class ArrayMap implements java.util.Map {
+  public final class ArrayMap<K, V> implements java.util.Map {
     ctor public ArrayMap();
     ctor public ArrayMap(int);
     ctor public ArrayMap(android.util.ArrayMap<K, V>);
@@ -43404,7 +43451,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public final class ArraySet implements java.util.Collection java.util.Set {
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
     ctor public ArraySet();
     ctor public ArraySet(int);
     ctor public ArraySet(android.util.ArraySet<E>);
@@ -43425,7 +43472,7 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
     method public E valueAt(int);
   }
 
@@ -43570,13 +43617,13 @@
   public deprecated class FloatMath {
   }
 
-  public abstract class FloatProperty extends android.util.Property {
+  public abstract class FloatProperty<T> extends android.util.Property {
     ctor public FloatProperty(java.lang.String);
     method public final void set(T, java.lang.Float);
     method public abstract void setValue(T, float);
   }
 
-  public abstract class IntProperty extends android.util.Property {
+  public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
     method public abstract void setValue(T, int);
@@ -43676,7 +43723,7 @@
     method public void println(java.lang.String);
   }
 
-  public class LongSparseArray implements java.lang.Cloneable {
+  public class LongSparseArray<E> implements java.lang.Cloneable {
     ctor public LongSparseArray();
     ctor public LongSparseArray(int);
     method public void append(long, E);
@@ -43697,7 +43744,7 @@
     method public E valueAt(int);
   }
 
-  public class LruCache {
+  public class LruCache<K, V> {
     ctor public LruCache(int);
     method protected V create(K);
     method public final synchronized int createCount();
@@ -43785,9 +43832,9 @@
     ctor public NoSuchPropertyException(java.lang.String);
   }
 
-  public class Pair {
+  public class Pair<F, S> {
     ctor public Pair(F, S);
-    method public static android.util.Pair<A, B> create(A, B);
+    method public static <A, B> android.util.Pair<A, B> create(A, B);
     field public final F first;
     field public final S second;
   }
@@ -43820,22 +43867,22 @@
     method public abstract void println(java.lang.String);
   }
 
-  public abstract class Property {
+  public abstract class Property<T, V> {
     ctor public Property(java.lang.Class<V>, java.lang.String);
     method public abstract V get(T);
     method public java.lang.String getName();
     method public java.lang.Class<V> getType();
     method public boolean isReadOnly();
-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
     method public void set(T, V);
   }
 
-  public final class Range {
+  public final class Range<T extends java.lang.Comparable<? super T>> {
     ctor public Range(T, T);
     method public T clamp(T);
     method public boolean contains(T);
     method public boolean contains(android.util.Range<T>);
-    method public static android.util.Range<T> create(T, T);
+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
     method public android.util.Range<T> extend(android.util.Range<T>);
     method public android.util.Range<T> extend(T, T);
     method public android.util.Range<T> extend(T);
@@ -43879,7 +43926,7 @@
     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
   }
 
-  public class SparseArray implements java.lang.Cloneable {
+  public class SparseArray<E> implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
     method public void append(int, E);
@@ -45321,7 +45368,11 @@
 
   public final class PixelCopy {
     method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.SurfaceView, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Surface, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
     field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
     field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -46346,6 +46397,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 +47224,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
@@ -48684,7 +48737,7 @@
     method public static java.lang.String stripAnchor(java.lang.String);
   }
 
-  public abstract interface ValueCallback {
+  public abstract interface ValueCallback<T> {
     method public abstract void onReceiveValue(T);
   }
 
@@ -49065,13 +49118,15 @@
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
     method public android.webkit.WebView.HitTestResult getHitTestResult();
-    method public java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
+    method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
+    method public android.webkit.WebChromeClient getWebChromeClient();
+    method public android.webkit.WebViewClient getWebViewClient();
     method public android.webkit.WebViewProvider getWebViewProvider();
     method public void goBack();
     method public void goBackOrForward(int);
@@ -49109,7 +49164,7 @@
     method public void setDownloadListener(android.webkit.DownloadListener);
     method public void setFindListener(android.webkit.WebView.FindListener);
     method public deprecated void setHorizontalScrollbarOverlay(boolean);
-    method public void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public void setInitialScale(int);
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
@@ -49238,10 +49293,12 @@
     method public abstract void clearFormData();
     method public abstract void clearHttpAuthUsernamePassword();
     method public abstract deprecated void clearUsernamePassword();
+    method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
     method public abstract boolean hasFormData();
     method public abstract boolean hasHttpAuthUsernamePassword();
     method public abstract deprecated boolean hasUsernamePassword();
+    method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
   }
 
   public final class WebViewDelegate {
@@ -49350,6 +49407,8 @@
     method public abstract java.lang.String getUrl();
     method public abstract android.webkit.WebViewProvider.ViewDelegate getViewDelegate();
     method public abstract int getVisibleTitleHeight();
+    method public abstract android.webkit.WebChromeClient getWebChromeClient();
+    method public abstract android.webkit.WebViewClient getWebViewClient();
     method public abstract android.view.View getZoomControls();
     method public abstract void goBack();
     method public abstract void goBackOrForward(int);
@@ -49699,7 +49758,7 @@
     field public static final int NO_SELECTION = -2147483648; // 0x80000000
   }
 
-  public abstract class AdapterView extends android.view.ViewGroup {
+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
     ctor public AdapterView(android.content.Context);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
@@ -49822,7 +49881,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -49883,7 +49942,7 @@
     method protected void performFiltering(java.lang.CharSequence, int);
     method public void performValidation();
     method protected void replaceText(java.lang.CharSequence);
-    method public void setAdapter(T);
+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
     method public void setCompletionHint(java.lang.CharSequence);
     method public void setDropDownAnchor(int);
     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -50151,7 +50210,7 @@
     method public abstract void onDateChanged(android.widget.DatePicker, int, int, int);
   }
 
-  public class DialerFilter extends android.widget.RelativeLayout {
+  public deprecated class DialerFilter extends android.widget.RelativeLayout {
     ctor public DialerFilter(android.content.Context);
     ctor public DialerFilter(android.content.Context, android.util.AttributeSet);
     method public void append(java.lang.String);
@@ -50820,8 +50879,8 @@
   public class OverScroller {
     ctor public OverScroller(android.content.Context);
     ctor public OverScroller(android.content.Context, android.view.animation.Interpolator);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
     method public void abortAnimation();
     method public boolean computeScrollOffset();
     method public void fling(int, int, int, int, int, int, int, int);
@@ -52123,7 +52182,7 @@
     method public abstract android.widget.ListAdapter getWrappedAdapter();
   }
 
-  public class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
+  public deprecated class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
     ctor public ZoomButton(android.content.Context);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet, int);
@@ -52132,7 +52191,7 @@
     method public void setZoomSpeed(long);
   }
 
-  public class ZoomButtonsController implements android.view.View.OnTouchListener {
+  public deprecated class ZoomButtonsController implements android.view.View.OnTouchListener {
     ctor public ZoomButtonsController(android.view.View);
     method public android.view.ViewGroup getContainer();
     method public android.view.View getZoomControls();
@@ -52169,7 +52228,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -54241,20 +54300,22 @@
     enum_constant public static final java.lang.Character.UnicodeScript YI;
   }
 
-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
     method public T cast(java.lang.Object);
     method public boolean desiredAssertionStatus();
     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getCanonicalName();
     method public java.lang.ClassLoader getClassLoader();
     method public java.lang.Class<?>[] getClasses();
     method public java.lang.Class<?> getComponentType();
     method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?>[] getDeclaredClasses();
     method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
@@ -54284,6 +54345,7 @@
     method public java.lang.Object[] getSigners();
     method public java.lang.String getSimpleName();
     method public java.lang.Class<? super T> getSuperclass();
+    method public java.lang.String getTypeName();
     method public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
     method public boolean isAnnotation();
     method public boolean isAnonymousClass();
@@ -54297,6 +54359,7 @@
     method public boolean isPrimitive();
     method public boolean isSynthetic();
     method public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public java.lang.String toGenericString();
   }
 
   public class ClassCastException extends java.lang.RuntimeException {
@@ -54364,7 +54427,7 @@
   public abstract interface Cloneable {
   }
 
-  public abstract interface Comparable {
+  public abstract interface Comparable<T> {
     method public abstract int compareTo(T);
   }
 
@@ -54418,7 +54481,7 @@
     field public static final java.lang.Class<java.lang.Double> TYPE;
   }
 
-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
     ctor protected Enum(java.lang.String, int);
     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
     method public final int compareTo(E);
@@ -54428,7 +54491,7 @@
     method public final int hashCode();
     method public final java.lang.String name();
     method public final int ordinal();
-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
   }
 
   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
@@ -54547,7 +54610,7 @@
     ctor public IndexOutOfBoundsException(java.lang.String);
   }
 
-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
     ctor public InheritableThreadLocal();
     method protected T childValue(T);
   }
@@ -54626,7 +54689,7 @@
     ctor public InterruptedException(java.lang.String);
   }
 
-  public abstract interface Iterable {
+  public abstract interface Iterable<T> {
     method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
     method public default java.util.Spliterator<T> spliterator();
@@ -54841,12 +54904,12 @@
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
-    method public A[] getAnnotationsByType(java.lang.Class<A>);
-    method public A getDeclaredAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getImplementationTitle();
     method public java.lang.String getImplementationVendor();
     method public java.lang.String getImplementationVersion();
@@ -55445,13 +55508,13 @@
     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
   }
 
-  public class ThreadLocal {
+  public class ThreadLocal<T> {
     ctor public ThreadLocal();
     method public T get();
     method protected T initialValue();
     method public void remove();
     method public void set(T);
-    method public static java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
+    method public static <S> java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
   }
 
   public class Throwable implements java.io.Serializable {
@@ -55554,6 +55617,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -55589,30 +55654,30 @@
 
 package java.lang.ref {
 
-  public class PhantomReference extends java.lang.ref.Reference {
+  public class PhantomReference<T> extends java.lang.ref.Reference {
     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public abstract class Reference {
+  public abstract class Reference<T> {
     method public void clear();
     method public boolean enqueue();
     method public T get();
     method public boolean isEnqueued();
   }
 
-  public class ReferenceQueue {
+  public class ReferenceQueue<T> {
     ctor public ReferenceQueue();
     method public java.lang.ref.Reference<? extends T> poll();
     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
   }
 
-  public class SoftReference extends java.lang.ref.Reference {
+  public class SoftReference<T> extends java.lang.ref.Reference {
     ctor public SoftReference(T);
     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public class WeakReference extends java.lang.ref.Reference {
+  public class WeakReference<T> extends java.lang.ref.Reference {
     ctor public WeakReference(T);
     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
@@ -55623,7 +55688,7 @@
 
   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
     ctor protected AccessibleObject();
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.annotation.Annotation[] getAnnotations();
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public boolean isAccessible();
@@ -55632,12 +55697,12 @@
   }
 
   public abstract interface AnnotatedElement {
-    method public abstract T getAnnotation(java.lang.Class<T>);
+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
   }
 
@@ -55665,27 +55730,38 @@
     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
   }
 
-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Constructor<T> extends java.lang.reflect.Executable {
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public int getModifiers();
     method public java.lang.String getName();
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
     method public java.lang.String toGenericString();
   }
 
+  public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.Class<?>[] getExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericParameterTypes();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
+    method public int getParameterCount();
+    method public abstract java.lang.Class<?>[] getParameterTypes();
+    method public java.lang.reflect.Parameter[] getParameters();
+    method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
+    method public final boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+    method public abstract java.lang.String toGenericString();
+  }
+
   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public A getAnnotation(java.lang.Class<A>);
     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -55699,7 +55775,6 @@
     method public java.lang.String getName();
     method public short getShort(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public java.lang.Class<?> getType();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isEnumConstant();
     method public boolean isSynthetic();
     method public void set(java.lang.Object, java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -55718,7 +55793,7 @@
     method public abstract java.lang.reflect.Type getGenericComponentType();
   }
 
-  public abstract interface GenericDeclaration {
+  public abstract interface GenericDeclaration implements java.lang.reflect.AnnotatedElement {
     method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
   }
 
@@ -55750,13 +55825,10 @@
     field public static final int PUBLIC = 0; // 0x0
   }
 
-  public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Method extends java.lang.reflect.Executable {
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public java.lang.reflect.Type getGenericReturnType();
     method public int getModifiers();
     method public java.lang.String getName();
@@ -55767,8 +55839,6 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isBridge();
     method public boolean isDefault();
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public java.lang.String toGenericString();
   }
 
@@ -55791,6 +55861,7 @@
     method public static boolean isTransient(int);
     method public static boolean isVolatile(int);
     method public static int methodModifiers();
+    method public static int parameterModifiers();
     method public static java.lang.String toString(int);
     field public static final int ABSTRACT = 1024; // 0x400
     field public static final int FINAL = 16; // 0x10
@@ -55806,6 +55877,21 @@
     field public static final int VOLATILE = 64; // 0x40
   }
 
+  public final class Parameter implements java.lang.reflect.AnnotatedElement {
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+    method public java.lang.reflect.Executable getDeclaringExecutable();
+    method public int getModifiers();
+    method public java.lang.String getName();
+    method public java.lang.reflect.Type getParameterizedType();
+    method public java.lang.Class<?> getType();
+    method public boolean isImplicit();
+    method public boolean isNamePresent();
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+  }
+
   public abstract interface ParameterizedType implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getActualTypeArguments();
     method public abstract java.lang.reflect.Type getOwnerType();
@@ -55829,7 +55915,7 @@
   public abstract interface Type {
   }
 
-  public abstract interface TypeVariable implements java.lang.reflect.Type {
+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getBounds();
     method public abstract D getGenericDeclaration();
     method public abstract java.lang.String getName();
@@ -56618,7 +56704,7 @@
     method public abstract java.net.SocketImpl createSocketImpl();
   }
 
-  public abstract interface SocketOption {
+  public abstract interface SocketOption<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -56739,8 +56825,6 @@
     method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
     method public final java.io.InputStream openStream() throws java.io.IOException;
     method public boolean sameFile(java.net.URL);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
     method public java.lang.String toExternalForm();
     method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -57150,9 +57234,9 @@
   }
 
   public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
-    method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
   }
 
@@ -57180,25 +57264,25 @@
   public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
     ctor protected AsynchronousFileChannel();
     method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public abstract <A> void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public final <A> void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
     method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
     method public abstract long size() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
     method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
   }
 
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
-    method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
+    method public abstract <A> void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
     method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
@@ -57206,30 +57290,30 @@
     method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
   }
 
   public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
+    method public abstract <A> void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
-    method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <A> void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <T> java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
   }
 
   public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
@@ -57269,7 +57353,7 @@
     ctor public ClosedSelectorException();
   }
 
-  public abstract interface CompletionHandler {
+  public abstract interface CompletionHandler<V, A> {
     method public abstract void completed(V, A);
     method public abstract void failed(java.lang.Throwable, A);
   }
@@ -57293,7 +57377,7 @@
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.DatagramSocket socket();
     method public final int validOps();
     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
@@ -57398,8 +57482,8 @@
   public abstract interface NetworkChannel implements java.nio.channels.Channel {
     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
   }
 
@@ -57521,7 +57605,7 @@
     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.ServerSocket socket();
     method public final int validOps();
   }
@@ -57544,7 +57628,7 @@
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
     method public abstract java.net.Socket socket();
@@ -57829,11 +57913,11 @@
     ctor public DirectoryNotEmptyException(java.lang.String);
   }
 
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
+  public abstract interface DirectoryStream<T> implements java.io.Closeable java.lang.Iterable {
     method public abstract java.util.Iterator<T> iterator();
   }
 
-  public static abstract interface DirectoryStream.Filter {
+  public static abstract interface DirectoryStream.Filter<T> {
     method public abstract boolean accept(T) throws java.io.IOException;
   }
 
@@ -57845,7 +57929,7 @@
   public abstract class FileStore {
     ctor protected FileStore();
     method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(java.lang.Class<V>);
     method public abstract long getTotalSpace() throws java.io.IOException;
     method public abstract long getUnallocatedSpace() throws java.io.IOException;
     method public abstract long getUsableSpace() throws java.io.IOException;
@@ -57917,7 +58001,7 @@
     enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
   }
 
-  public abstract interface FileVisitor {
+  public abstract interface FileVisitor<T> {
     method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -57942,7 +58026,7 @@
     method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
     method public static java.util.stream.Stream<java.nio.file.Path> find(java.nio.file.Path, int, java.util.function.BiPredicate<java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes>, java.nio.file.FileVisitOption...) throws java.io.IOException;
     method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public static <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -57975,7 +58059,7 @@
     method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -58083,17 +58167,17 @@
     ctor public ReadOnlyFileSystemException();
   }
 
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
+  public abstract interface SecureDirectoryStream<T> implements java.nio.file.DirectoryStream {
     method public abstract void deleteDirectory(T) throws java.io.IOException;
     method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
   }
 
-  public class SimpleFileVisitor implements java.nio.file.FileVisitor {
+  public class SimpleFileVisitor<T> implements java.nio.file.FileVisitor {
     ctor protected SimpleFileVisitor();
     method public java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -58131,13 +58215,13 @@
     field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
   }
 
-  public abstract interface WatchEvent {
+  public abstract interface WatchEvent<T> {
     method public abstract T context();
     method public abstract int count();
     method public abstract java.nio.file.WatchEvent.Kind<T> kind();
   }
 
-  public static abstract interface WatchEvent.Kind {
+  public static abstract interface WatchEvent.Kind<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -58273,7 +58357,7 @@
     method public abstract boolean isSystem();
   }
 
-  public abstract interface FileAttribute {
+  public abstract interface FileAttribute<T> {
     method public abstract java.lang.String name();
     method public abstract T value();
   }
@@ -58370,7 +58454,7 @@
     method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
     method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
     method public abstract java.nio.file.Path getPath(java.net.URI);
@@ -58387,7 +58471,7 @@
     method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
     method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -58417,12 +58501,12 @@
 
   public final class AccessController {
     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
     method public static java.security.AccessControlContext getContext();
   }
 
@@ -58461,7 +58545,7 @@
     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method public final void init(byte[]) throws java.io.IOException;
@@ -58473,7 +58557,7 @@
     ctor public AlgorithmParametersSpi();
     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(byte[]) throws java.io.IOException;
     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
@@ -58568,6 +58652,13 @@
     method public abstract java.security.ProtectionDomain[] combine(java.security.ProtectionDomain[], java.security.ProtectionDomain[]);
   }
 
+  public final class DomainLoadStoreParameter implements java.security.KeyStore.LoadStoreParameter {
+    ctor public DomainLoadStoreParameter(java.net.URI, java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter>);
+    method public java.net.URI getConfiguration();
+    method public java.security.KeyStore.ProtectionParameter getProtectionParameter();
+    method public java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter> getProtectionParams();
+  }
+
   public class GeneralSecurityException extends java.lang.Exception {
     ctor public GeneralSecurityException();
     ctor public GeneralSecurityException(java.lang.String);
@@ -58658,7 +58749,7 @@
     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
@@ -58667,7 +58758,7 @@
     ctor public KeyFactorySpi();
     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
 
@@ -58764,6 +58855,12 @@
   }
 
   public static abstract interface KeyStore.Entry {
+    method public default java.util.Set<java.security.KeyStore.Entry.Attribute> getAttributes();
+  }
+
+  public static abstract interface KeyStore.Entry.Attribute {
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.String getValue();
   }
 
   public static abstract interface KeyStore.LoadStoreParameter {
@@ -58772,11 +58869,15 @@
 
   public static class KeyStore.PasswordProtection implements javax.security.auth.Destroyable java.security.KeyStore.ProtectionParameter {
     ctor public KeyStore.PasswordProtection(char[]);
+    ctor public KeyStore.PasswordProtection(char[], java.lang.String, java.security.spec.AlgorithmParameterSpec);
     method public synchronized char[] getPassword();
+    method public java.lang.String getProtectionAlgorithm();
+    method public java.security.spec.AlgorithmParameterSpec getProtectionParameters();
   }
 
   public static final class KeyStore.PrivateKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[]);
+    ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[], java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getCertificate();
     method public java.security.cert.Certificate[] getCertificateChain();
     method public java.security.PrivateKey getPrivateKey();
@@ -58787,11 +58888,13 @@
 
   public static final class KeyStore.SecretKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey);
+    ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public javax.crypto.SecretKey getSecretKey();
   }
 
   public static final class KeyStore.TrustedCertificateEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate);
+    ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getTrustedCertificate();
   }
 
@@ -58870,6 +58973,14 @@
     ctor public NoSuchProviderException(java.lang.String);
   }
 
+  public final class PKCS12Attribute implements java.security.KeyStore.Entry.Attribute {
+    ctor public PKCS12Attribute(java.lang.String, java.lang.String);
+    ctor public PKCS12Attribute(byte[]);
+    method public byte[] getEncoded();
+    method public java.lang.String getName();
+    method public java.lang.String getValue();
+  }
+
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
@@ -58927,14 +59038,15 @@
     method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getName();
     method public abstract int hashCode();
+    method public default boolean implies(javax.security.auth.Subject);
     method public abstract java.lang.String toString();
   }
 
-  public abstract interface PrivateKey implements java.security.Key {
+  public abstract interface PrivateKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
   }
 
-  public abstract interface PrivilegedAction {
+  public abstract interface PrivilegedAction<T> {
     method public abstract T run();
   }
 
@@ -58943,7 +59055,7 @@
     method public java.lang.Exception getException();
   }
 
-  public abstract interface PrivilegedExceptionAction {
+  public abstract interface PrivilegedExceptionAction<T> {
     method public abstract T run() throws java.lang.Exception;
   }
 
@@ -58959,16 +59071,25 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized java.lang.Object compute(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfAbsent(java.lang.Object, java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfPresent(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
+    method public synchronized java.lang.Object getOrDefault(java.lang.Object, java.lang.Object);
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
     method public synchronized java.util.Set<java.security.Provider.Service> getServices();
     method public double getVersion();
+    method public synchronized java.lang.Object merge(java.lang.Object, java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized java.lang.Object put(java.lang.Object, java.lang.Object);
     method public synchronized void putAll(java.util.Map<?, ?>);
+    method public synchronized java.lang.Object putIfAbsent(java.lang.Object, java.lang.Object);
     method protected synchronized void putService(java.security.Provider.Service);
     method protected synchronized void removeService(java.security.Provider.Service);
+    method public synchronized boolean replace(java.lang.Object, java.lang.Object, java.lang.Object);
+    method public synchronized java.lang.Object replace(java.lang.Object, java.lang.Object);
+    method public synchronized void replaceAll(java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
   }
 
   public static class Provider.Service {
@@ -59010,6 +59131,7 @@
     method public static java.security.SecureRandom getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.SecureRandom getInstanceStrong() throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public static byte[] getSeed(int);
     method protected final int next(int);
@@ -59382,6 +59504,7 @@
     method public abstract java.lang.String toString();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
     method protected java.lang.Object writeReplace() throws java.io.ObjectStreamException;
   }
 
@@ -59627,6 +59750,7 @@
     method public abstract int getVersion();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract class X509CRLEntry implements java.security.cert.X509Extension {
@@ -59740,7 +59864,6 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
-    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -59944,6 +60067,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;
@@ -61125,11 +61249,11 @@
     method public abstract void free() throws java.sql.SQLException;
     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract java.lang.String getString() throws java.sql.SQLException;
     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
   }
 
@@ -61253,7 +61377,7 @@
 
   public abstract interface Wrapper {
     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
   }
 
 }
@@ -61786,7 +61910,7 @@
 
 package java.util {
 
-  public abstract class AbstractCollection implements java.util.Collection {
+  public abstract class AbstractCollection<E> implements java.util.Collection {
     ctor protected AbstractCollection();
     method public boolean add(E);
     method public boolean addAll(java.util.Collection<? extends E>);
@@ -61800,10 +61924,10 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
     ctor protected AbstractList();
     method public void add(int, E);
     method public boolean addAll(int, java.util.Collection<? extends E>);
@@ -61820,7 +61944,7 @@
     field protected transient int modCount;
   }
 
-  public abstract class AbstractMap implements java.util.Map {
+  public abstract class AbstractMap<K, V> implements java.util.Map {
     ctor protected AbstractMap();
     method public void clear();
     method public boolean containsKey(java.lang.Object);
@@ -61836,7 +61960,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleEntry(K, V);
     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -61844,7 +61968,7 @@
     method public V setValue(V);
   }
 
-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleImmutableEntry(K, V);
     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -61852,23 +61976,23 @@
     method public V setValue(V);
   }
 
-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
     ctor protected AbstractQueue();
     method public E element();
     method public E remove();
   }
 
-  public abstract class AbstractSequentialList extends java.util.AbstractList {
+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
     ctor protected AbstractSequentialList();
     method public E get(int);
     method public abstract java.util.ListIterator<E> listIterator(int);
   }
 
-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
     ctor protected AbstractSet();
   }
 
-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
     ctor public ArrayDeque();
     ctor public ArrayDeque(int);
     ctor public ArrayDeque(java.util.Collection<? extends E>);
@@ -61900,7 +62024,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public ArrayList(int);
     ctor public ArrayList();
     ctor public ArrayList(java.util.Collection<? extends E>);
@@ -61917,7 +62041,7 @@
   }
 
   public class Arrays {
-    method public static java.util.List<T> asList(T...);
+    method public static <T> java.util.List<T> asList(T...);
     method public static int binarySearch(long[], long);
     method public static int binarySearch(long[], int, int, long);
     method public static int binarySearch(int[], int);
@@ -61934,10 +62058,10 @@
     method public static int binarySearch(float[], int, int, float);
     method public static int binarySearch(java.lang.Object[], java.lang.Object);
     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
-    method public static T[] copyOf(T[], int);
-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
+    method public static <T> T[] copyOf(T[], int);
+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOf(byte[], int);
     method public static short[] copyOf(short[], int);
     method public static int[] copyOf(int[], int);
@@ -61946,8 +62070,8 @@
     method public static float[] copyOf(float[], int);
     method public static double[] copyOf(double[], int);
     method public static boolean[] copyOf(boolean[], int);
-    method public static T[] copyOfRange(T[], int, int);
-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
+    method public static <T> T[] copyOfRange(T[], int, int);
+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOfRange(byte[], int, int);
     method public static short[] copyOfRange(short[], int, int);
     method public static int[] copyOfRange(int[], int, int);
@@ -61995,15 +62119,15 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
@@ -62021,11 +62145,11 @@
     method public static void parallelSort(float[], int, int);
     method public static void parallelSort(double[]);
     method public static void parallelSort(double[], int, int);
-    method public static void parallelSort(T[]);
-    method public static void parallelSort(T[], int, int);
-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void setAll(int[], java.util.function.IntUnaryOperator);
     method public static void setAll(long[], java.util.function.IntToLongFunction);
     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
@@ -62045,18 +62169,18 @@
     method public static void sort(double[], int, int);
     method public static void sort(java.lang.Object[]);
     method public static void sort(java.lang.Object[], int, int);
-    method public static void sort(T[], java.util.Comparator<? super T>);
-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
-    method public static java.util.Spliterator<T> spliterator(T[]);
-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[]);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[]);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[]);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
-    method public static java.util.stream.Stream<T> stream(T[]);
-    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static <T> java.util.stream.Stream<T> stream(T[]);
+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
     method public static java.util.stream.IntStream stream(int[]);
     method public static java.util.stream.IntStream stream(int[], int, int);
     method public static java.util.stream.LongStream stream(long[]);
@@ -62074,6 +62198,33 @@
     method public static java.lang.String toString(java.lang.Object[]);
   }
 
+  public class Base64 {
+    method public static java.util.Base64.Decoder getDecoder();
+    method public static java.util.Base64.Encoder getEncoder();
+    method public static java.util.Base64.Decoder getMimeDecoder();
+    method public static java.util.Base64.Encoder getMimeEncoder();
+    method public static java.util.Base64.Encoder getMimeEncoder(int, byte[]);
+    method public static java.util.Base64.Decoder getUrlDecoder();
+    method public static java.util.Base64.Encoder getUrlEncoder();
+  }
+
+  public static class Base64.Decoder {
+    method public byte[] decode(byte[]);
+    method public byte[] decode(java.lang.String);
+    method public int decode(byte[], byte[]);
+    method public java.nio.ByteBuffer decode(java.nio.ByteBuffer);
+    method public java.io.InputStream wrap(java.io.InputStream);
+  }
+
+  public static class Base64.Encoder {
+    method public byte[] encode(byte[]);
+    method public int encode(byte[], byte[]);
+    method public java.nio.ByteBuffer encode(java.nio.ByteBuffer);
+    method public java.lang.String encodeToString(byte[]);
+    method public java.util.Base64.Encoder withoutPadding();
+    method public java.io.OutputStream wrap(java.io.OutputStream);
+  }
+
   public class BitSet implements java.lang.Cloneable java.io.Serializable {
     ctor public BitSet();
     ctor public BitSet(int);
@@ -62213,7 +62364,7 @@
     field protected long time;
   }
 
-  public abstract interface Collection implements java.lang.Iterable {
+  public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -62231,86 +62382,86 @@
     method public abstract int size();
     method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class Collections {
-    method public static boolean addAll(java.util.Collection<? super T>, T...);
-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
-    method public static java.util.Enumeration<T> emptyEnumeration();
-    method public static java.util.Iterator<T> emptyIterator();
-    method public static final java.util.List<T> emptyList();
-    method public static java.util.ListIterator<T> emptyListIterator();
-    method public static final java.util.Map<K, V> emptyMap();
-    method public static final java.util.Set<T> emptySet();
-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
-    method public static void fill(java.util.List<? super T>, T);
+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
+    method public static <T> java.util.Iterator<T> emptyIterator();
+    method public static final <T> java.util.List<T> emptyList();
+    method public static <T> java.util.ListIterator<T> emptyListIterator();
+    method public static final <K, V> java.util.Map<K, V> emptyMap();
+    method public static final <T> java.util.Set<T> emptySet();
+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
+    method public static <T> void fill(java.util.List<? super T>, T);
     method public static int frequency(java.util.Collection<?>, java.lang.Object);
     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
-    method public static T max(java.util.Collection<? extends T>);
-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static T min(java.util.Collection<? extends T>);
-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static java.util.List<T> nCopies(int, T);
-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
-    method public static boolean replaceAll(java.util.List<T>, T, T);
+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T> java.util.List<T> nCopies(int, T);
+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
     method public static void reverse(java.util.List<?>);
-    method public static java.util.Comparator<T> reverseOrder();
-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
+    method public static <T> java.util.Comparator<T> reverseOrder();
+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
     method public static void rotate(java.util.List<?>, int);
     method public static void shuffle(java.util.List<?>);
     method public static void shuffle(java.util.List<?>, java.util.Random);
-    method public static java.util.Set<E> singleton(E);
-    method public static java.util.List<E> singletonList(E);
-    method public static java.util.Map<K, V> singletonMap(K, V);
-    method public static void sort(java.util.List<T>);
-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
+    method public static <E> java.util.Set<E> singleton(E);
+    method public static <E> java.util.List<E> singletonList(E);
+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
     method public static void swap(java.util.List<?>, int, int);
-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
     field public static final java.util.List EMPTY_LIST;
     field public static final java.util.Map EMPTY_MAP;
     field public static final java.util.Set EMPTY_SET;
   }
 
-  public abstract interface Comparator {
+  public abstract interface Comparator<T> {
     method public abstract int compare(T, T);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
-    method public static java.util.Comparator<T> naturalOrder();
-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> reverseOrder();
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
     method public default java.util.Comparator<T> reversed();
     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
@@ -62369,7 +62520,7 @@
     method public deprecated java.lang.String toLocaleString();
   }
 
-  public abstract interface Deque implements java.util.Queue {
+  public abstract interface Deque<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -62399,7 +62550,7 @@
     method public abstract int size();
   }
 
-  public abstract class Dictionary {
+  public abstract class Dictionary<K, V> {
     ctor public Dictionary();
     method public abstract java.util.Enumeration<V> elements();
     method public abstract V get(java.lang.Object);
@@ -62430,7 +62581,7 @@
     ctor public EmptyStackException();
   }
 
-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
     ctor public EnumMap(java.lang.Class<K>);
     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
     ctor public EnumMap(java.util.Map<K, ? extends V>);
@@ -62438,23 +62589,23 @@
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
   }
 
-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
     method public java.util.EnumSet<E> clone();
-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
-    method public static java.util.EnumSet<E> of(E);
-    method public static java.util.EnumSet<E> of(E, E);
-    method public static java.util.EnumSet<E> of(E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E...);
-    method public static java.util.EnumSet<E> range(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
   }
 
-  public abstract interface Enumeration {
+  public abstract interface Enumeration<E> {
     method public abstract boolean hasMoreElements();
     method public abstract E nextElement();
   }
@@ -62462,7 +62613,7 @@
   public abstract interface EventListener {
   }
 
-  public abstract class EventListenerProxy implements java.util.EventListener {
+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
     ctor public EventListenerProxy(T);
     method public T getListener();
   }
@@ -62548,19 +62699,27 @@
     field public static final int BC = 0; // 0x0
   }
 
-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public HashMap(int, float);
     ctor public HashMap(int);
     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>);
   }
 
-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public HashSet();
     ctor public HashSet(java.util.Collection<? extends E>);
     ctor public HashSet(int, float);
@@ -62571,7 +62730,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public Hashtable(int, float);
     ctor public Hashtable(int);
     ctor public Hashtable();
@@ -62606,7 +62765,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public IdentityHashMap();
     ctor public IdentityHashMap(int);
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
@@ -62673,14 +62832,14 @@
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
-  public abstract interface Iterator {
+  public abstract interface Iterator<E> {
     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
     method public default void remove();
   }
 
-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
     ctor public LinkedHashMap(int, float);
     ctor public LinkedHashMap(int);
     ctor public LinkedHashMap();
@@ -62689,14 +62848,14 @@
     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
   }
 
-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public LinkedHashSet(int, float);
     ctor public LinkedHashSet(int);
     ctor public LinkedHashSet();
     ctor public LinkedHashSet(java.util.Collection<? extends E>);
   }
 
-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
     ctor public LinkedList();
     ctor public LinkedList(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -62727,7 +62886,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface List implements java.util.Collection {
+  public abstract interface List<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract void add(int, E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -62754,10 +62913,10 @@
     method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
-  public abstract interface ListIterator implements java.util.Iterator {
+  public abstract interface ListIterator<E> implements java.util.Iterator {
     method public abstract void add(E);
     method public abstract boolean hasNext();
     method public abstract boolean hasPrevious();
@@ -62808,8 +62967,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
@@ -62874,7 +63035,7 @@
     method public final long getSum();
   }
 
-  public abstract interface Map {
+  public abstract interface Map<K, V> {
     method public abstract void clear();
     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
@@ -62902,11 +63063,11 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public static abstract interface Map.Entry {
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
+  public static abstract interface Map.Entry<K, V> {
+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -62930,7 +63091,7 @@
     method public java.lang.String getKey();
   }
 
-  public abstract interface NavigableMap implements java.util.SortedMap {
+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
     method public abstract K ceilingKey(K);
     method public abstract java.util.NavigableSet<K> descendingKeySet();
@@ -62954,7 +63115,7 @@
     method public abstract java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public abstract interface NavigableSet implements java.util.SortedSet {
+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
     method public abstract E ceiling(E);
     method public abstract java.util.Iterator<E> descendingIterator();
     method public abstract java.util.NavigableSet<E> descendingSet();
@@ -62978,16 +63139,16 @@
   }
 
   public final class Objects {
-    method public static int compare(T, T, java.util.Comparator<? super T>);
+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
     method public static boolean equals(java.lang.Object, java.lang.Object);
     method public static int hash(java.lang.Object...);
     method public static int hashCode(java.lang.Object);
     method public static boolean isNull(java.lang.Object);
     method public static boolean nonNull(java.lang.Object);
-    method public static T requireNonNull(T);
-    method public static T requireNonNull(T, java.lang.String);
-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
+    method public static <T> T requireNonNull(T);
+    method public static <T> T requireNonNull(T, java.lang.String);
+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
     method public static java.lang.String toString(java.lang.Object);
     method public static java.lang.String toString(java.lang.Object, java.lang.String);
   }
@@ -63009,19 +63170,19 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
-  public final class Optional {
-    method public static java.util.Optional<T> empty();
+  public final class Optional<T> {
+    method public static <T> java.util.Optional<T> empty();
     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
     method public T get();
     method public void ifPresent(java.util.function.Consumer<? super T>);
     method public boolean isPresent();
-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Optional<T> of(T);
-    method public static java.util.Optional<T> ofNullable(T);
+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Optional<T> of(T);
+    method public static <T> java.util.Optional<T> ofNullable(T);
     method public T orElse(T);
     method public T orElseGet(java.util.function.Supplier<? extends T>);
-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
   }
 
   public final class OptionalDouble {
@@ -63032,7 +63193,7 @@
     method public static java.util.OptionalDouble of(double);
     method public double orElse(double);
     method public double orElseGet(java.util.function.DoubleSupplier);
-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalInt {
@@ -63043,7 +63204,7 @@
     method public static java.util.OptionalInt of(int);
     method public int orElse(int);
     method public int orElseGet(java.util.function.IntSupplier);
-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalLong {
@@ -63054,10 +63215,10 @@
     method public static java.util.OptionalLong of(long);
     method public long orElse(long);
     method public long orElseGet(java.util.function.LongSupplier);
-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
-  public abstract interface PrimitiveIterator implements java.util.Iterator {
+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
     method public abstract void forEachRemaining(T_CONS);
   }
 
@@ -63082,7 +63243,7 @@
     method public abstract long nextLong();
   }
 
-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
     ctor public PriorityQueue(java.util.Comparator<? super E>);
@@ -63131,7 +63292,7 @@
     method public java.lang.Object handleGetObject(java.lang.String);
   }
 
-  public abstract interface Queue implements java.util.Collection {
+  public abstract interface Queue<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract E element();
     method public abstract boolean offer(E);
@@ -63175,6 +63336,7 @@
     method public static final void clearCache();
     method public static final void clearCache(java.lang.ClassLoader);
     method public boolean containsKey(java.lang.String);
+    method public java.lang.String getBaseBundleName();
     method public static final java.util.ResourceBundle getBundle(java.lang.String);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.ResourceBundle.Control);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale);
@@ -63283,15 +63445,15 @@
     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
   }
 
-  public final class ServiceLoader implements java.lang.Iterable {
+  public final class ServiceLoader<S> implements java.lang.Iterable {
     method public java.util.Iterator<S> iterator();
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
     method public void reload();
   }
 
-  public abstract interface Set implements java.util.Collection {
+  public abstract interface Set<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -63306,7 +63468,7 @@
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class SimpleTimeZone extends java.util.TimeZone {
@@ -63332,7 +63494,7 @@
     field public static final int WALL_TIME = 0; // 0x0
   }
 
-  public abstract interface SortedMap implements java.util.Map {
+  public abstract interface SortedMap<K, V> implements java.util.Map {
     method public abstract java.util.Comparator<? super K> comparator();
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract K firstKey();
@@ -63344,7 +63506,7 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public abstract interface SortedSet implements java.util.Set {
+  public abstract interface SortedSet<E> implements java.util.Set {
     method public abstract java.util.Comparator<? super E> comparator();
     method public abstract E first();
     method public abstract java.util.SortedSet<E> headSet(E);
@@ -63353,7 +63515,7 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
-  public abstract interface Spliterator {
+  public abstract interface Spliterator<T> {
     method public abstract int characteristics();
     method public abstract long estimateSize();
     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
@@ -63396,7 +63558,7 @@
     method public abstract java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
     method public default void forEachRemaining(T_CONS);
     method public abstract boolean tryAdvance(T_CONS);
     method public abstract T_SPLITR trySplit();
@@ -63406,25 +63568,25 @@
     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
-    method public static java.util.Spliterator<T> emptySpliterator();
-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static <T> java.util.Spliterator<T> emptySpliterator();
+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
@@ -63451,7 +63613,7 @@
     method public java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
     ctor protected Spliterators.AbstractSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
@@ -63486,7 +63648,7 @@
     method public java.util.SplittableRandom split();
   }
 
-  public class Stack extends java.util.Vector {
+  public class Stack<E> extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
     method public synchronized E peek();
@@ -63570,7 +63732,7 @@
     ctor public TooManyListenersException(java.lang.String);
   }
 
-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
     ctor public TreeMap();
     ctor public TreeMap(java.util.Comparator<? super K>);
     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
@@ -63607,7 +63769,7 @@
     method public java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public TreeSet();
     ctor public TreeSet(java.util.Comparator<? super E>);
     ctor public TreeSet(java.util.Collection<? extends E>);
@@ -63660,7 +63822,7 @@
     method public java.lang.String getFlags();
   }
 
-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public Vector(int, int);
     ctor public Vector(int);
     ctor public Vector();
@@ -63695,7 +63857,7 @@
     field protected java.lang.Object[] elementData;
   }
 
-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
     ctor public WeakHashMap(int, float);
     ctor public WeakHashMap(int);
     ctor public WeakHashMap();
@@ -63711,18 +63873,18 @@
 
   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
     ctor public AbstractExecutorService();
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
   }
 
-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public ArrayBlockingQueue(int);
     ctor public ArrayBlockingQueue(int, boolean);
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
@@ -63741,7 +63903,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -63773,7 +63935,7 @@
     method public abstract E takeLast() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingQueue implements java.util.Queue {
+  public abstract interface BlockingQueue<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract boolean contains(java.lang.Object);
     method public abstract int drainTo(java.util.Collection<? super E>);
@@ -63792,7 +63954,7 @@
     ctor public BrokenBarrierException(java.lang.String);
   }
 
-  public abstract interface Callable {
+  public abstract interface Callable<V> {
     method public abstract V call() throws java.lang.Exception;
   }
 
@@ -63801,28 +63963,28 @@
     ctor public CancellationException(java.lang.String);
   }
 
-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
     ctor public CompletableFuture();
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public boolean cancel(boolean);
     method public boolean complete(T);
     method public boolean completeExceptionally(java.lang.Throwable);
-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public T getNow(T);
     method public int getNumberOfDependents();
-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public boolean isCancelled();
     method public boolean isCompletedExceptionally();
     method public boolean isDone();
@@ -63837,23 +63999,23 @@
     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -63873,7 +64035,7 @@
     ctor public CompletionException(java.lang.Throwable);
   }
 
-  public abstract interface CompletionService {
+  public abstract interface CompletionService<V> {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
@@ -63881,17 +64043,17 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface CompletionStage {
+  public abstract interface CompletionStage<T> {
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
@@ -63901,18 +64063,18 @@
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -63922,7 +64084,7 @@
     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
   }
 
-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
@@ -63936,29 +64098,29 @@
     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 void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachKey(long, java.util.function.Consumer<? super K>);
-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachValue(long, java.util.function.Consumer<? super V>);
-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
     method public long mappingCount();
     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
@@ -63966,7 +64128,7 @@
     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
@@ -63974,13 +64136,13 @@
     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>);
-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
   }
 
-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
     method public final void clear();
     method public abstract boolean contains(java.lang.Object);
     method public final boolean containsAll(java.util.Collection<?>);
@@ -63992,11 +64154,11 @@
     method public final boolean retainAll(java.util.Collection<?>);
     method public final int size();
     method public final java.lang.Object[] toArray();
-    method public final T[] toArray(T[]);
+    method public final <T> T[] toArray(T[]);
     method public final java.lang.String toString();
   }
 
-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
     method public boolean add(K);
     method public boolean addAll(java.util.Collection<? extends K>);
     method public boolean contains(java.lang.Object);
@@ -64007,7 +64169,7 @@
     method public java.util.Spliterator<K> spliterator();
   }
 
-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
     ctor public ConcurrentLinkedDeque();
     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -64037,7 +64199,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
     method public java.util.Iterator<E> iterator();
@@ -64048,14 +64210,14 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface ConcurrentMap implements java.util.Map {
+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
     method public abstract V putIfAbsent(K, V);
     method public abstract boolean remove(java.lang.Object, java.lang.Object);
     method public abstract boolean replace(K, V, V);
     method public abstract V replace(K, V);
   }
 
-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
     method public abstract java.util.NavigableSet<K> descendingKeySet();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
@@ -64068,7 +64230,7 @@
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
     ctor public ConcurrentSkipListMap();
     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
@@ -64112,7 +64274,7 @@
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public ConcurrentSkipListSet();
     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
@@ -64140,7 +64302,7 @@
     method public java.util.NavigableSet<E> tailSet(E);
   }
 
-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
@@ -64172,10 +64334,10 @@
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
     method public void forEach(java.util.function.Consumer<? super E>);
@@ -64193,7 +64355,7 @@
     method public long getCount();
   }
 
-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
     ctor protected CountedCompleter();
@@ -64230,7 +64392,7 @@
     method public void reset();
   }
 
-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
     ctor public DelayQueue();
     ctor public DelayQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -64251,7 +64413,7 @@
     method public abstract long getDelay(java.util.concurrent.TimeUnit);
   }
 
-  public class Exchanger {
+  public class Exchanger<V> {
     ctor public Exchanger();
     method public V exchange(V) throws java.lang.InterruptedException;
     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -64268,7 +64430,7 @@
     method public abstract void execute(java.lang.Runnable);
   }
 
-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
     method public java.util.concurrent.Future<V> poll();
@@ -64280,21 +64442,21 @@
 
   public abstract interface ExecutorService implements java.util.concurrent.Executor {
     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public abstract boolean isShutdown();
     method public abstract boolean isTerminated();
     method public abstract void shutdown();
     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
   }
 
   public class Executors {
-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
@@ -64311,8 +64473,8 @@
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
@@ -64340,7 +64502,7 @@
     method public long getStealCount();
     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
     method public boolean hasQueuedSubmissions();
-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
     method public boolean isQuiescent();
     method public boolean isShutdown();
     method public boolean isTerminated();
@@ -64349,7 +64511,7 @@
     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
     method public void shutdown();
     method public java.util.List<java.lang.Runnable> shutdownNow();
-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
   }
 
@@ -64362,11 +64524,11 @@
     method public abstract boolean isReleasable();
   }
 
-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
     ctor public ForkJoinTask();
     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
     method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
@@ -64386,7 +64548,7 @@
     method public final V invoke();
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
     method public final boolean isCancelled();
     method public final boolean isCompletedAbnormally();
     method public final boolean isCompletedNormally();
@@ -64412,7 +64574,7 @@
     method protected void onTermination(java.lang.Throwable);
   }
 
-  public abstract interface Future {
+  public abstract interface Future<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -64420,7 +64582,7 @@
     method public abstract boolean isDone();
   }
 
-  public class FutureTask implements java.util.concurrent.RunnableFuture {
+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
     ctor public FutureTask(java.util.concurrent.Callable<V>);
     ctor public FutureTask(java.lang.Runnable, V);
     method public boolean cancel(boolean);
@@ -64435,7 +64597,7 @@
     method protected void setException(java.lang.Throwable);
   }
 
-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
     ctor public LinkedBlockingDeque();
     ctor public LinkedBlockingDeque(int);
     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
@@ -64479,7 +64641,7 @@
     method public E takeLast() throws java.lang.InterruptedException;
   }
 
-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public LinkedBlockingQueue();
     ctor public LinkedBlockingQueue(int);
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
@@ -64498,7 +64660,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
     ctor public LinkedTransferQueue();
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -64545,7 +64707,7 @@
     method public int register();
   }
 
-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
@@ -64574,7 +64736,7 @@
     method protected final void setRawResult(java.lang.Void);
   }
 
-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
     ctor public RecursiveTask();
     method protected abstract V compute();
     method protected final boolean exec();
@@ -64593,22 +64755,22 @@
     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
     method public abstract void run();
   }
 
-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
     method public abstract boolean isPeriodic();
   }
 
   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
   }
 
-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
   }
 
   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
@@ -64616,13 +64778,13 @@
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
     method public boolean getRemoveOnCancelPolicy();
     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
@@ -64652,7 +64814,7 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
     method public int drainTo(java.util.Collection<? super E>);
@@ -64770,7 +64932,7 @@
     ctor public TimeoutException(java.lang.String);
   }
 
-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
     method public abstract int getWaitingConsumerCount();
     method public abstract boolean hasWaitingConsumer();
     method public abstract void transfer(E) throws java.lang.InterruptedException;
@@ -64840,7 +65002,7 @@
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
-  public abstract class AtomicIntegerFieldUpdater {
+  public abstract class AtomicIntegerFieldUpdater<T> {
     ctor protected AtomicIntegerFieldUpdater();
     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
@@ -64855,7 +65017,7 @@
     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
@@ -64908,7 +65070,7 @@
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
-  public abstract class AtomicLongFieldUpdater {
+  public abstract class AtomicLongFieldUpdater<T> {
     ctor protected AtomicLongFieldUpdater();
     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
@@ -64923,13 +65085,13 @@
     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
-  public class AtomicMarkableReference {
+  public class AtomicMarkableReference<V> {
     ctor public AtomicMarkableReference(V, boolean);
     method public boolean attemptMark(V, boolean);
     method public boolean compareAndSet(V, V, boolean, boolean);
@@ -64940,7 +65102,7 @@
     method public boolean weakCompareAndSet(V, V, boolean, boolean);
   }
 
-  public class AtomicReference implements java.io.Serializable {
+  public class AtomicReference<V> implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
@@ -64955,7 +65117,7 @@
     method public final boolean weakCompareAndSet(V, V);
   }
 
-  public class AtomicReferenceArray implements java.io.Serializable {
+  public class AtomicReferenceArray<E> implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
@@ -64971,7 +65133,7 @@
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
-  public abstract class AtomicReferenceFieldUpdater {
+  public abstract class AtomicReferenceFieldUpdater<T, V> {
     ctor protected AtomicReferenceFieldUpdater();
     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
@@ -64980,13 +65142,13 @@
     method public V getAndSet(T, V);
     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
-  public class AtomicStampedReference {
+  public class AtomicStampedReference<V> {
     ctor public AtomicStampedReference(V, int);
     method public boolean attemptStamp(V, int);
     method public boolean compareAndSet(V, V, int, int);
@@ -65289,33 +65451,33 @@
 
 package java.util.function {
 
-  public abstract interface BiConsumer {
+  public abstract interface BiConsumer<T, U> {
     method public abstract void accept(T, U);
     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
   }
 
-  public abstract interface BiFunction {
-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface BiFunction<T, U, R> {
+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T, U);
   }
 
-  public abstract interface BiPredicate {
+  public abstract interface BiPredicate<T, U> {
     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
     method public default java.util.function.BiPredicate<T, U> negate();
     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
     method public abstract boolean test(T, U);
   }
 
-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
   }
 
   public abstract interface BooleanSupplier {
     method public abstract boolean getAsBoolean();
   }
 
-  public abstract interface Consumer {
+  public abstract interface Consumer<T> {
     method public abstract void accept(T);
     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
   }
@@ -65329,7 +65491,7 @@
     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
   }
 
-  public abstract interface DoubleFunction {
+  public abstract interface DoubleFunction<R> {
     method public abstract R apply(double);
   }
 
@@ -65359,11 +65521,11 @@
     method public static java.util.function.DoubleUnaryOperator identity();
   }
 
-  public abstract interface Function {
-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface Function<T, R> {
+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T);
-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
-    method public static java.util.function.Function<T, T> identity();
+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+    method public static <T> java.util.function.Function<T, T> identity();
   }
 
   public abstract interface IntBinaryOperator {
@@ -65375,7 +65537,7 @@
     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
   }
 
-  public abstract interface IntFunction {
+  public abstract interface IntFunction<R> {
     method public abstract R apply(int);
   }
 
@@ -65414,7 +65576,7 @@
     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
   }
 
-  public abstract interface LongFunction {
+  public abstract interface LongFunction<R> {
     method public abstract R apply(long);
   }
 
@@ -65444,56 +65606,56 @@
     method public static java.util.function.LongUnaryOperator identity();
   }
 
-  public abstract interface ObjDoubleConsumer {
+  public abstract interface ObjDoubleConsumer<T> {
     method public abstract void accept(T, double);
   }
 
-  public abstract interface ObjIntConsumer {
+  public abstract interface ObjIntConsumer<T> {
     method public abstract void accept(T, int);
   }
 
-  public abstract interface ObjLongConsumer {
+  public abstract interface ObjLongConsumer<T> {
     method public abstract void accept(T, long);
   }
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
     method public default java.util.function.Predicate<T> negate();
     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
     method public abstract boolean test(T);
   }
 
-  public abstract interface Supplier {
+  public abstract interface Supplier<T> {
     method public abstract T get();
   }
 
-  public abstract interface ToDoubleBiFunction {
+  public abstract interface ToDoubleBiFunction<T, U> {
     method public abstract double applyAsDouble(T, U);
   }
 
-  public abstract interface ToDoubleFunction {
+  public abstract interface ToDoubleFunction<T> {
     method public abstract double applyAsDouble(T);
   }
 
-  public abstract interface ToIntBiFunction {
+  public abstract interface ToIntBiFunction<T, U> {
     method public abstract int applyAsInt(T, U);
   }
 
-  public abstract interface ToIntFunction {
+  public abstract interface ToIntFunction<T> {
     method public abstract int applyAsInt(T);
   }
 
-  public abstract interface ToLongBiFunction {
+  public abstract interface ToLongBiFunction<T, U> {
     method public abstract long applyAsLong(T, U);
   }
 
-  public abstract interface ToLongFunction {
+  public abstract interface ToLongFunction<T> {
     method public abstract long applyAsLong(T);
   }
 
-  public abstract interface UnaryOperator implements java.util.function.Function {
-    method public static java.util.function.UnaryOperator<T> identity();
+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
+    method public static <T> java.util.function.UnaryOperator<T> identity();
   }
 
 }
@@ -66081,7 +66243,7 @@
 
 package java.util.stream {
 
-  public abstract interface BaseStream implements java.lang.AutoCloseable {
+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
     method public abstract void close();
     method public abstract boolean isParallel();
     method public abstract java.util.Iterator<T> iterator();
@@ -66092,13 +66254,13 @@
     method public abstract S unordered();
   }
 
-  public abstract interface Collector {
+  public abstract interface Collector<T, A, R> {
     method public abstract java.util.function.BiConsumer<A, T> accumulator();
     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
     method public abstract java.util.function.BinaryOperator<A> combiner();
     method public abstract java.util.function.Function<A, R> finisher();
-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
     method public abstract java.util.function.Supplier<A> supplier();
   }
 
@@ -66111,43 +66273,43 @@
   }
 
   public final class Collectors {
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
   }
 
   public abstract interface DoubleStream implements java.util.stream.BaseStream {
@@ -66156,7 +66318,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
     method public static java.util.stream.DoubleStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
     method public abstract long count();
     method public abstract java.util.stream.DoubleStream distinct();
@@ -66174,7 +66336,7 @@
     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
     method public abstract java.util.OptionalDouble max();
     method public abstract java.util.OptionalDouble min();
     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
@@ -66207,7 +66369,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
     method public static java.util.stream.IntStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
     method public abstract long count();
     method public abstract java.util.stream.IntStream distinct();
@@ -66225,7 +66387,7 @@
     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
     method public abstract java.util.OptionalInt max();
     method public abstract java.util.OptionalInt min();
     method public abstract boolean noneMatch(java.util.function.IntPredicate);
@@ -66259,7 +66421,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
     method public static java.util.stream.LongStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
     method public abstract long count();
     method public abstract java.util.stream.LongStream distinct();
@@ -66277,7 +66439,7 @@
     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
     method public abstract java.util.OptionalLong max();
     method public abstract java.util.OptionalLong min();
     method public abstract boolean noneMatch(java.util.function.LongPredicate);
@@ -66304,49 +66466,49 @@
     method public abstract java.util.stream.LongStream build();
   }
 
-  public abstract interface Stream implements java.util.stream.BaseStream {
+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream.Builder<T> builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public static <T> java.util.stream.Stream.Builder<T> builder();
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
     method public abstract long count();
     method public abstract java.util.stream.Stream<T> distinct();
-    method public static java.util.stream.Stream<T> empty();
+    method public static <T> java.util.stream.Stream<T> empty();
     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
     method public abstract java.util.Optional<T> findAny();
     method public abstract java.util.Optional<T> findFirst();
-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
     method public abstract void forEach(java.util.function.Consumer<? super T>);
     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
     method public abstract java.util.stream.Stream<T> limit(long);
-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream<T> of(T);
-    method public static java.util.stream.Stream<T> of(T...);
+    method public static <T> java.util.stream.Stream<T> of(T);
+    method public static <T> java.util.stream.Stream<T> of(T...);
     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
     method public abstract java.util.stream.Stream<T> skip(long);
     method public abstract java.util.stream.Stream<T> sorted();
     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
     method public abstract java.lang.Object[] toArray();
-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
   }
 
-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
     method public abstract void accept(T);
     method public default java.util.stream.Stream.Builder<T> add(T);
     method public abstract java.util.stream.Stream<T> build();
@@ -66359,8 +66521,8 @@
     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
   }
 
 }
@@ -67002,7 +67164,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 +67175,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 +67183,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 +67301,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();
   }
 
@@ -68531,16 +68695,16 @@
   public final class Subject implements java.io.Serializable {
     ctor public Subject();
     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
     method public java.util.Set<java.security.Principal> getPrincipals();
-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPrivateCredentials();
-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPublicCredentials();
-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
     method public boolean isReadOnly();
     method public void setReadOnly();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 3811e22..98e7953 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -165,6 +165,13 @@
 
 package android.net {
 
+  public abstract class PskKeyManager {
+    ctor public PskKeyManager();
+    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
+  }
+
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 5293a04..4de2c61 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2921,11 +2921,11 @@
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
   }
 
-  public abstract interface AccountManagerCallback {
+  public abstract interface AccountManagerCallback<V> {
     method public abstract void run(android.accounts.AccountManagerFuture<V>);
   }
 
-  public abstract interface AccountManagerFuture {
+  public abstract interface AccountManagerFuture<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
@@ -3071,7 +3071,7 @@
     method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
   }
 
-  public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter {
+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
     ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract T convertBack(V);
     method public android.animation.BidirectionalTypeConverter<V, T> invert();
@@ -3163,26 +3163,26 @@
     method public java.lang.String getPropertyName();
     method public java.lang.Object getTarget();
     method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
-    method public static android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
     method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
-    method public static android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
     method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
-    method public static android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
     method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
     method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
     method public void setAutoCancel(boolean);
     method public void setProperty(android.util.Property);
@@ -3206,17 +3206,17 @@
     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
     method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
     method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
-    method public static android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
+    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
     method public void setConverter(android.animation.TypeConverter);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
@@ -3253,12 +3253,12 @@
     method public abstract float getInterpolation(float);
   }
 
-  public abstract class TypeConverter {
+  public abstract class TypeConverter<T, V> {
     ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
     method public abstract V convert(T);
   }
 
-  public abstract interface TypeEvaluator {
+  public abstract interface TypeEvaluator<T> {
     method public abstract T evaluate(float, T, T);
   }
 
@@ -3270,6 +3270,7 @@
     method public java.lang.Object getAnimatedValue(java.lang.String);
     method public long getCurrentPlayTime();
     method public long getDuration();
+    method public static float getDurationScale();
     method public static long getFrameDelay();
     method public int getRepeatCount();
     method public int getRepeatMode();
@@ -3287,6 +3288,7 @@
     method public void setCurrentFraction(float);
     method public void setCurrentPlayTime(long);
     method public android.animation.ValueAnimator setDuration(long);
+    method public static void setDurationScale(float);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
     method public static void setFrameDelay(long);
@@ -4043,6 +4045,7 @@
     field public static final java.lang.String OPSTR_MOCK_LOCATION = "android:mock_location";
     field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
     field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
+    field public static final java.lang.String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";
     field public static final java.lang.String OPSTR_READ_CALENDAR = "android:read_calendar";
     field public static final java.lang.String OPSTR_READ_CALL_LOG = "android:read_call_log";
     field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
@@ -4589,7 +4592,7 @@
     method public android.os.Parcelable saveAllState();
   }
 
-  public abstract class FragmentHostCallback extends android.app.FragmentContainer {
+  public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
     ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
     method public void onAttachFragment(android.app.Fragment);
     method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -4856,12 +4859,12 @@
     method public abstract void destroyLoader(int);
     method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public static void enableDebugLogging(boolean);
-    method public abstract android.content.Loader<D> getLoader(int);
-    method public abstract android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> getLoader(int);
+    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
   }
 
-  public static abstract interface LoaderManager.LoaderCallbacks {
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
     method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
     method public abstract void onLoadFinished(android.content.Loader<D>, D);
     method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -4924,6 +4927,7 @@
     method public int describeContents();
     method public java.lang.String getGroup();
     method public android.graphics.drawable.Icon getLargeIcon();
+    method public java.lang.String getNotificationChannel();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5112,6 +5116,7 @@
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setChannel(java.lang.String);
     method public android.app.Notification.Builder setChronometerCountDown(boolean);
     method public android.app.Notification.Builder setColor(int);
     method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
@@ -5260,6 +5265,7 @@
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
     method public java.util.List<android.app.Notification.Action> getActions();
     method public android.graphics.Bitmap getBackground();
+    method public java.lang.String getBridgeTag();
     method public int getContentAction();
     method public int getContentIcon();
     method public int getContentIconGravity();
@@ -5278,6 +5284,7 @@
     method public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
     method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
     method public android.app.Notification.WearableExtender setContentAction(int);
     method public android.app.Notification.WearableExtender setContentIcon(int);
     method public android.app.Notification.WearableExtender setContentIconGravity(int);
@@ -5305,17 +5312,40 @@
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
+  public final class NotificationChannel implements android.os.Parcelable {
+    ctor public NotificationChannel(java.lang.String, java.lang.CharSequence);
+    ctor protected NotificationChannel(android.os.Parcel);
+    method public boolean canBypassDnd();
+    method public int describeContents();
+    method public android.net.Uri getDefaultRingtone();
+    method public java.lang.String getId();
+    method public int getImportance();
+    method public java.lang.CharSequence getName();
+    method public void setDefaultRingtone(android.net.Uri);
+    method public void setLights(boolean);
+    method public void setVibration(boolean);
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
+    field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
   public class NotificationManager {
     method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void deleteNotificationChannel(java.lang.String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
     method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
+    method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+    method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
@@ -5324,6 +5354,7 @@
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
+    method public void updateNotificationChannel(android.app.NotificationChannel);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5417,7 +5448,7 @@
     method public void onDisplayRemoved();
   }
 
-  public class ProgressDialog extends android.app.AlertDialog {
+  public deprecated class ProgressDialog extends android.app.AlertDialog {
     ctor public ProgressDialog(android.content.Context);
     ctor public ProgressDialog(android.content.Context, int);
     method public int getMax();
@@ -5646,6 +5677,7 @@
   public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
     ctor public TimePickerDialog(android.content.Context, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
     ctor public TimePickerDialog(android.content.Context, int, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
+    method public android.widget.TimePicker getTimePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onTimeChanged(android.widget.TimePicker, int, int);
     method public void updateTime(int, int);
@@ -7655,7 +7687,7 @@
     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
   }
 
-  public abstract class AsyncTaskLoader extends android.content.Loader {
+  public abstract class AsyncTaskLoader<D> extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
     method public void cancelLoadInBackground();
     method public boolean isLoadInBackgroundCanceled();
@@ -7837,7 +7869,7 @@
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
+    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
@@ -7850,7 +7882,7 @@
     method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public static abstract interface ContentProvider.PipeDataWriter {
+  public static abstract interface ContentProvider.PipeDataWriter<T> {
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
@@ -8122,7 +8154,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
-    method public final T getSystemService(java.lang.Class<T>);
+    method public final <T> T getSystemService(java.lang.Class<T>);
     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
@@ -8479,8 +8511,8 @@
     method public long getLongExtra(java.lang.String, long);
     method public java.lang.String getPackage();
     method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
-    method public T getParcelableExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
     method public java.lang.String getScheme();
     method public android.content.Intent getSelector();
     method public java.io.Serializable getSerializableExtra(java.lang.String);
@@ -8955,7 +8987,7 @@
     ctor public IntentSender.SendIntentException(java.lang.Exception);
   }
 
-  public class Loader {
+  public class Loader<D> {
     ctor public Loader(android.content.Context);
     method public void abandon();
     method public boolean cancelLoad();
@@ -8992,11 +9024,11 @@
     ctor public Loader.ForceLoadContentObserver();
   }
 
-  public static abstract interface Loader.OnLoadCanceledListener {
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
     method public abstract void onLoadCanceled(android.content.Loader<D>);
   }
 
-  public static abstract interface Loader.OnLoadCompleteListener {
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
 
@@ -10873,7 +10905,7 @@
     method public boolean isNull(int);
   }
 
-  public abstract class Observable {
+  public abstract class Observable<T> {
     ctor public Observable();
     method public void registerObserver(T);
     method public void unregisterAll();
@@ -12678,6 +12710,7 @@
   public class SurfaceTexture {
     ctor public SurfaceTexture(int);
     ctor public SurfaceTexture(int, boolean);
+    ctor public SurfaceTexture(boolean);
     method public void attachToGLContext(int);
     method public void detachFromGLContext();
     method public long getTimestamp();
@@ -12764,7 +12797,7 @@
   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
     ctor public AnimatedStateListDrawable();
     method public void addState(int[], android.graphics.drawable.Drawable, int);
-    method public void addTransition(int, int, T, boolean);
+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
   }
 
   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
@@ -13857,6 +13890,7 @@
     method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
+    method public abstract void finishDeferredConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CameraDevice getDevice();
     method public abstract android.view.Surface getInputSurface();
     method public abstract boolean isReprocessable();
@@ -13888,7 +13922,7 @@
   }
 
   public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
+    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
@@ -13973,7 +14007,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS;
   }
 
-  public static final class CameraCharacteristics.Key {
+  public static final class CameraCharacteristics.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14038,7 +14072,7 @@
     method public void onTorchModeUnavailable(java.lang.String);
   }
 
-  public abstract class CameraMetadata {
+  public abstract class CameraMetadata<TKey> {
     method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
@@ -14246,7 +14280,7 @@
 
   public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
     method public int describeContents();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
     method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
@@ -14309,20 +14343,20 @@
   public static final class CaptureRequest.Builder {
     method public void addTarget(android.view.Surface);
     method public android.hardware.camera2.CaptureRequest build();
-    method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public void removeTarget(android.view.Surface);
-    method public void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
+    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
     method public void setTag(java.lang.Object);
   }
 
-  public static final class CaptureRequest.Key {
+  public static final class CaptureRequest.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
   }
 
   public class CaptureResult extends android.hardware.camera2.CameraMetadata {
-    method public T get(android.hardware.camera2.CaptureResult.Key<T>);
+    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
     method public long getFrameNumber();
     method public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
@@ -14403,7 +14437,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
-  public static final class CaptureResult.Key {
+  public static final class CaptureResult.Key<T> {
     method public final boolean equals(java.lang.Object);
     method public java.lang.String getName();
     method public final int hashCode();
@@ -14495,9 +14529,11 @@
   public final class OutputConfiguration implements android.os.Parcelable {
     ctor public OutputConfiguration(android.view.Surface);
     ctor public OutputConfiguration(int, android.view.Surface);
+    ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
     method public int describeContents();
     method public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
+    method public void setDeferredSurface(android.view.Surface);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -14528,14 +14564,14 @@
     method public android.util.Size[] getInputSizes(int);
     method public final int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
     method public final int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
@@ -16236,7 +16272,7 @@
 
 package android.icu.text {
 
-  public final class AlphabeticIndex implements java.lang.Iterable {
+  public final class AlphabeticIndex<V> implements java.lang.Iterable {
     ctor public AlphabeticIndex(android.icu.util.ULocale);
     ctor public AlphabeticIndex(java.util.Locale);
     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
@@ -16262,7 +16298,7 @@
     method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
   }
 
-  public static class AlphabeticIndex.Bucket implements java.lang.Iterable {
+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
     method public java.lang.String getLabel();
     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
@@ -16278,14 +16314,14 @@
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
   }
 
-  public static final class AlphabeticIndex.ImmutableIndex implements java.lang.Iterable {
+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
     method public int getBucketCount();
     method public int getBucketIndex(java.lang.CharSequence);
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
   }
 
-  public static class AlphabeticIndex.Record {
+  public static class AlphabeticIndex.Record<V> {
     method public V getData();
     method public java.lang.CharSequence getName();
   }
@@ -17798,8 +17834,8 @@
     method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
-    method public android.icu.text.UnicodeSet addAll(T...);
-    method public T addAllTo(T);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
+    method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
     method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
@@ -17827,15 +17863,15 @@
     method public final boolean contains(java.lang.CharSequence);
     method public boolean containsAll(android.icu.text.UnicodeSet);
     method public boolean containsAll(java.lang.String);
-    method public boolean containsAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
     method public boolean containsNone(int, int);
     method public boolean containsNone(android.icu.text.UnicodeSet);
     method public boolean containsNone(java.lang.CharSequence);
-    method public boolean containsNone(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
     method public final boolean containsSome(int, int);
     method public final boolean containsSome(android.icu.text.UnicodeSet);
     method public final boolean containsSome(java.lang.CharSequence);
-    method public final boolean containsSome(java.lang.Iterable<T>);
+    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet freeze();
     method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
     method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
@@ -17853,14 +17889,14 @@
     method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
     method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
     method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
     method public android.icu.text.UnicodeSet set(int, int);
     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
     method public int size();
@@ -18270,7 +18306,7 @@
     method public long getToDate();
   }
 
-  public abstract interface Freezable implements java.lang.Cloneable {
+  public abstract interface Freezable<T> implements java.lang.Cloneable {
     method public abstract T cloneAsThawed();
     method public abstract T freeze();
     method public abstract boolean isFrozen();
@@ -18552,7 +18588,7 @@
     field public static final android.icu.util.TimeUnit YEAR;
   }
 
-  public class Output {
+  public class Output<T> {
     ctor public Output();
     ctor public Output(T);
     field public T value;
@@ -21499,6 +21535,7 @@
     field public static final int AMR_NB = 3; // 0x3
     field public static final int AMR_WB = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
+    field public static final int MPEG_2_TS = 8; // 0x8
     field public static final int MPEG_4 = 2; // 0x2
     field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
@@ -22654,8 +22691,8 @@
     method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
-    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
@@ -22704,7 +22741,7 @@
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
     method public void setRepeatMode(int);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -22733,7 +22770,7 @@
     method public void setRatingType(int);
     method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
-    method public void setShuffleMode(boolean);
+    method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -22757,7 +22794,7 @@
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
     method public void onSetRepeatMode(int);
-    method public void onSetShuffleMode(boolean);
+    method public void onSetShuffleModeEnabled(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -22819,7 +22856,7 @@
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
     field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
-    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
@@ -23936,19 +23973,6 @@
     field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
   }
 
-  public abstract class PskKeyManager {
-    ctor public PskKeyManager();
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
-    method public java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
-    method public java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
-    method public java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
-    method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
-    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
-    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
-  }
-
   public final class RouteInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.IpPrefix getDestination();
@@ -28303,7 +28327,7 @@
 
 package android.os {
 
-  public abstract class AsyncTask {
+  public abstract class AsyncTask<Params, Progress, Result> {
     ctor public AsyncTask();
     method public final boolean cancel(boolean);
     method protected abstract Result doInBackground(Params...);
@@ -28437,6 +28461,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -28452,7 +28477,7 @@
     field public static final java.lang.String MODEL;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
@@ -28531,16 +28556,16 @@
     method public float getFloat(java.lang.String, float);
     method public float[] getFloatArray(java.lang.String);
     method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
-    method public T getParcelable(java.lang.String);
+    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
     method public android.os.Parcelable[] getParcelableArray(java.lang.String);
-    method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
+    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
     method public java.io.Serializable getSerializable(java.lang.String);
     method public short getShort(java.lang.String);
     method public short getShort(java.lang.String, short);
     method public short[] getShortArray(java.lang.String);
     method public android.util.Size getSize(java.lang.String);
     method public android.util.SizeF getSizeF(java.lang.String);
-    method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
+    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
     method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
     method public boolean hasFileDescriptors();
     method public void putAll(android.os.Bundle);
@@ -29045,8 +29070,8 @@
     method public final long[] createLongArray();
     method public final java.lang.String[] createStringArray();
     method public final java.util.ArrayList<java.lang.String> createStringArrayList();
-    method public final T[] createTypedArray(android.os.Parcelable.Creator<T>);
-    method public final java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+    method public final <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
+    method public final <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
     method public final int dataAvail();
     method public final int dataCapacity();
     method public final int dataPosition();
@@ -29079,7 +29104,7 @@
     method public final long readLong();
     method public final void readLongArray(long[]);
     method public final void readMap(java.util.Map, java.lang.ClassLoader);
-    method public final T readParcelable(java.lang.ClassLoader);
+    method public final <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
     method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
     method public final android.os.PersistableBundle readPersistableBundle();
     method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
@@ -29092,9 +29117,9 @@
     method public final void readStringArray(java.lang.String[]);
     method public final void readStringList(java.util.List<java.lang.String>);
     method public final android.os.IBinder readStrongBinder();
-    method public final void readTypedArray(T[], android.os.Parcelable.Creator<T>);
-    method public final void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
-    method public final T readTypedObject(android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
+    method public final <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
+    method public final <T> T readTypedObject(android.os.Parcelable.Creator<T>);
     method public final java.lang.Object readValue(java.lang.ClassLoader);
     method public final void recycle();
     method public final void setDataCapacity(int);
@@ -29125,7 +29150,7 @@
     method public final void writeMap(java.util.Map);
     method public final void writeNoException();
     method public final void writeParcelable(android.os.Parcelable, int);
-    method public final void writeParcelableArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
     method public final void writePersistableBundle(android.os.PersistableBundle);
     method public final void writeSerializable(java.io.Serializable);
     method public final void writeSize(android.util.Size);
@@ -29137,9 +29162,9 @@
     method public final void writeStringList(java.util.List<java.lang.String>);
     method public final void writeStrongBinder(android.os.IBinder);
     method public final void writeStrongInterface(android.os.IInterface);
-    method public final void writeTypedArray(T[], int);
-    method public final void writeTypedList(java.util.List<T>);
-    method public final void writeTypedObject(T, int);
+    method public final <T extends android.os.Parcelable> void writeTypedArray(T[], int);
+    method public final <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
+    method public final <T extends android.os.Parcelable> void writeTypedObject(T, int);
     method public final void writeValue(java.lang.Object);
     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
   }
@@ -29217,11 +29242,11 @@
     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
   }
 
-  public static abstract interface Parcelable.ClassLoaderCreator implements android.os.Parcelable.Creator {
+  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
     method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
   }
 
-  public static abstract interface Parcelable.Creator {
+  public static abstract interface Parcelable.Creator<T> {
     method public abstract T createFromParcel(android.os.Parcel);
     method public abstract T[] newArray(int);
   }
@@ -29337,7 +29362,7 @@
     method public abstract void onProgress(int);
   }
 
-  public class RemoteCallbackList {
+  public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
     method public void finishBroadcast();
@@ -30357,6 +30382,8 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAdvancedIntOption(java.lang.String);
+    method public java.lang.String getAdvancedStringOption(java.lang.String);
     method public android.print.PrintAttributes getAttributes();
     method public int getCopies();
     method public long getCreationTime();
@@ -30367,6 +30394,7 @@
     method public float getProgress();
     method public int getState();
     method public java.lang.CharSequence getStatus(android.content.pm.PackageManager);
+    method public boolean hasAdvancedOption(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
@@ -31862,7 +31890,7 @@
     field public static final java.lang.String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
   }
 
-  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
+  public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
     field public static final java.lang.String QUERY_PARAMETER_SIP_ADDRESS = "sip";
@@ -34671,7 +34699,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
   }
 
-  public static abstract interface CarrierMessagingService.ResultCallback {
+  public static abstract interface CarrierMessagingService.ResultCallback<T> {
     method public abstract void onReceiveResult(T) throws android.os.RemoteException;
   }
 
@@ -34823,7 +34851,7 @@
     field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
-  public class MediaBrowserService.Result {
+  public class MediaBrowserService.Result<T> {
     method public void detach();
     method public void sendResult(T);
   }
@@ -34869,6 +34897,8 @@
     method public void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
+    method public static final void requestRebind(android.content.ComponentName);
+    method public final void requestUnbind();
     field public static final java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
     field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
@@ -35577,6 +35607,7 @@
     method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static int gettid();
     method public static int getuid();
+    method public static byte[] getxattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static java.lang.String if_indextoname(int);
     method public static int if_nametoindex(java.lang.String);
     method public static java.net.InetAddress inet_pton(int, java.lang.String);
@@ -35585,6 +35616,7 @@
     method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
     method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.lang.String[] listxattr(java.lang.String) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
     method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
     method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
@@ -35611,6 +35643,7 @@
     method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
+    method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -35622,6 +35655,7 @@
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
     method public static void setuid(int) throws android.system.ErrnoException;
+    method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
     method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -36950,6 +36984,7 @@
     field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
+    field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
@@ -36959,11 +36994,14 @@
     field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+    field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -37009,7 +37047,9 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
     field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+    field public static final java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -37740,14 +37780,14 @@
 
 package android.test {
 
-  public abstract deprecated class ActivityInstrumentationTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -37762,7 +37802,7 @@
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -37808,7 +37848,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -37834,8 +37874,8 @@
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
     method public void injectInstrumentation(android.app.Instrumentation);
-    method public final T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
-    method public final T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
+    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
+    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
     method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
     method public void sendKeys(java.lang.String);
     method public void sendKeys(int...);
@@ -37875,7 +37915,7 @@
 
   public class LoaderTestCase extends android.test.AndroidTestCase {
     ctor public LoaderTestCase();
-    method public T getLoaderResultSynchronously(android.content.Loader<T>);
+    method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
   public final deprecated class MoreAsserts {
@@ -37930,20 +37970,20 @@
     method public abstract void startTiming(boolean);
   }
 
-  public abstract deprecated class ProviderTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
     ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ProviderTestCase2 extends android.test.AndroidTestCase {
+  public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
     ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
@@ -37951,11 +37991,11 @@
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
     method public void makeExistingFilesAndDbsAccessible();
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -37968,7 +38008,7 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
@@ -38325,7 +38365,7 @@
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
     method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
     method public java.lang.String getEnclosingClassname();
     method public java.lang.String getName();
@@ -38773,7 +38813,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
     method public int getTextWatcherDepth();
     method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
@@ -38795,7 +38835,7 @@
     method public int getSpanEnd(java.lang.Object);
     method public int getSpanFlags(java.lang.Object);
     method public int getSpanStart(java.lang.Object);
-    method public T[] getSpans(int, int, java.lang.Class<T>);
+    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public final int length();
     method public int nextSpanTransition(int, int, java.lang.Class);
     method public final java.lang.String toString();
@@ -38805,7 +38845,7 @@
     method public abstract int getSpanEnd(java.lang.Object);
     method public abstract int getSpanFlags(java.lang.Object);
     method public abstract int getSpanStart(java.lang.Object);
-    method public abstract T[] getSpans(int, int, java.lang.Class<T>);
+    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
     method public abstract int nextSpanTransition(int, int, java.lang.Class);
     field public static final int SPAN_COMPOSING = 256; // 0x100
     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
@@ -39783,7 +39823,7 @@
     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
   }
 
-  public static class TtsSpan.Builder {
+  public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
     ctor public TtsSpan.Builder(java.lang.String);
     method public android.text.style.TtsSpan build();
     method public C setIntArgument(java.lang.String, int);
@@ -39879,7 +39919,7 @@
     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
   }
 
-  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
     ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
     method public C setAnimacy(java.lang.String);
     method public C setCase(java.lang.String);
@@ -40287,7 +40327,7 @@
     ctor public AndroidRuntimeException(java.lang.Exception);
   }
 
-  public final class ArrayMap implements java.util.Map {
+  public final class ArrayMap<K, V> implements java.util.Map {
     ctor public ArrayMap();
     ctor public ArrayMap(int);
     ctor public ArrayMap(android.util.ArrayMap<K, V>);
@@ -40315,7 +40355,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public final class ArraySet implements java.util.Collection java.util.Set {
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
     ctor public ArraySet();
     ctor public ArraySet(int);
     ctor public ArraySet(android.util.ArraySet<E>);
@@ -40336,7 +40376,7 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
     method public E valueAt(int);
   }
 
@@ -40481,13 +40521,13 @@
   public deprecated class FloatMath {
   }
 
-  public abstract class FloatProperty extends android.util.Property {
+  public abstract class FloatProperty<T> extends android.util.Property {
     ctor public FloatProperty(java.lang.String);
     method public final void set(T, java.lang.Float);
     method public abstract void setValue(T, float);
   }
 
-  public abstract class IntProperty extends android.util.Property {
+  public abstract class IntProperty<T> extends android.util.Property {
     ctor public IntProperty(java.lang.String);
     method public final void set(T, java.lang.Integer);
     method public abstract void setValue(T, int);
@@ -40587,7 +40627,7 @@
     method public void println(java.lang.String);
   }
 
-  public class LongSparseArray implements java.lang.Cloneable {
+  public class LongSparseArray<E> implements java.lang.Cloneable {
     ctor public LongSparseArray();
     ctor public LongSparseArray(int);
     method public void append(long, E);
@@ -40608,7 +40648,7 @@
     method public E valueAt(int);
   }
 
-  public class LruCache {
+  public class LruCache<K, V> {
     ctor public LruCache(int);
     method protected V create(K);
     method public final synchronized int createCount();
@@ -40696,9 +40736,9 @@
     ctor public NoSuchPropertyException(java.lang.String);
   }
 
-  public class Pair {
+  public class Pair<F, S> {
     ctor public Pair(F, S);
-    method public static android.util.Pair<A, B> create(A, B);
+    method public static <A, B> android.util.Pair<A, B> create(A, B);
     field public final F first;
     field public final S second;
   }
@@ -40731,22 +40771,22 @@
     method public abstract void println(java.lang.String);
   }
 
-  public abstract class Property {
+  public abstract class Property<T, V> {
     ctor public Property(java.lang.Class<V>, java.lang.String);
     method public abstract V get(T);
     method public java.lang.String getName();
     method public java.lang.Class<V> getType();
     method public boolean isReadOnly();
-    method public static android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
+    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
     method public void set(T, V);
   }
 
-  public final class Range {
+  public final class Range<T extends java.lang.Comparable<? super T>> {
     ctor public Range(T, T);
     method public T clamp(T);
     method public boolean contains(T);
     method public boolean contains(android.util.Range<T>);
-    method public static android.util.Range<T> create(T, T);
+    method public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> create(T, T);
     method public android.util.Range<T> extend(android.util.Range<T>);
     method public android.util.Range<T> extend(T, T);
     method public android.util.Range<T> extend(T);
@@ -40790,7 +40830,7 @@
     method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
   }
 
-  public class SparseArray implements java.lang.Cloneable {
+  public class SparseArray<E> implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
     method public void append(int, E);
@@ -42088,6 +42128,8 @@
     method public final void offsetLocation(float, float);
     method public final void recycle();
     method public final void setAction(int);
+    method public final void setActionButton(int);
+    method public final void setButtonState(int);
     method public final void setEdgeFlags(int);
     method public final void setLocation(float, float);
     method public final void setSource(int);
@@ -42232,7 +42274,11 @@
 
   public final class PixelCopy {
     method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.SurfaceView, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Surface, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(android.view.Window, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
     field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
     field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
     field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -43257,6 +43303,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 +44127,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
@@ -44312,6 +44360,7 @@
     method public void setMaxTextLength(int);
     method public void setMovementGranularities(int);
     method public void setMultiLine(boolean);
+    method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
     method public void setPackageName(java.lang.CharSequence);
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
@@ -44517,6 +44566,7 @@
     method public static android.view.accessibility.AccessibilityWindowInfo obtain();
     method public static android.view.accessibility.AccessibilityWindowInfo obtain(android.view.accessibility.AccessibilityWindowInfo);
     method public void recycle();
+    method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityWindowInfo> CREATOR;
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
@@ -45519,7 +45569,7 @@
     method public static java.lang.String stripAnchor(java.lang.String);
   }
 
-  public abstract interface ValueCallback {
+  public abstract interface ValueCallback<T> {
     method public abstract void onReceiveValue(T);
   }
 
@@ -45880,13 +45930,15 @@
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
     method public android.webkit.WebView.HitTestResult getHitTestResult();
-    method public java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
+    method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
     method public java.lang.String getUrl();
+    method public android.webkit.WebChromeClient getWebChromeClient();
+    method public android.webkit.WebViewClient getWebViewClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
@@ -45923,7 +45975,7 @@
     method public void setDownloadListener(android.webkit.DownloadListener);
     method public void setFindListener(android.webkit.WebView.FindListener);
     method public deprecated void setHorizontalScrollbarOverlay(boolean);
-    method public void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public void setInitialScale(int);
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
@@ -46021,10 +46073,12 @@
     method public abstract void clearFormData();
     method public abstract void clearHttpAuthUsernamePassword();
     method public abstract deprecated void clearUsernamePassword();
+    method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
     method public abstract boolean hasFormData();
     method public abstract boolean hasHttpAuthUsernamePassword();
     method public abstract deprecated boolean hasUsernamePassword();
+    method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
   }
 
   public class WebViewFragment extends android.app.Fragment {
@@ -46253,7 +46307,7 @@
     field public static final int NO_SELECTION = -2147483648; // 0x80000000
   }
 
-  public abstract class AdapterView extends android.view.ViewGroup {
+  public abstract class AdapterView<T extends android.widget.Adapter> extends android.view.ViewGroup {
     ctor public AdapterView(android.content.Context);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
@@ -46376,7 +46430,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
+  public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -46437,7 +46491,7 @@
     method protected void performFiltering(java.lang.CharSequence, int);
     method public void performValidation();
     method protected void replaceText(java.lang.CharSequence);
-    method public void setAdapter(T);
+    method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
     method public void setCompletionHint(java.lang.CharSequence);
     method public void setDropDownAnchor(int);
     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
@@ -46689,6 +46743,7 @@
     method public int getFirstDayOfWeek();
     method public long getMaxDate();
     method public long getMinDate();
+    method public int getMode();
     method public int getMonth();
     method public deprecated boolean getSpinnersShown();
     method public int getYear();
@@ -46700,13 +46755,15 @@
     method public void setOnDateChangedListener(android.widget.DatePicker.OnDateChangedListener);
     method public deprecated void setSpinnersShown(boolean);
     method public void updateDate(int, int, int);
+    field public static final int MODE_CALENDAR = 2; // 0x2
+    field public static final int MODE_SPINNER = 1; // 0x1
   }
 
   public static abstract interface DatePicker.OnDateChangedListener {
     method public abstract void onDateChanged(android.widget.DatePicker, int, int, int);
   }
 
-  public class DialerFilter extends android.widget.RelativeLayout {
+  public deprecated class DialerFilter extends android.widget.RelativeLayout {
     ctor public DialerFilter(android.content.Context);
     ctor public DialerFilter(android.content.Context, android.util.AttributeSet);
     method public void append(java.lang.String);
@@ -47376,8 +47433,8 @@
   public class OverScroller {
     ctor public OverScroller(android.content.Context);
     ctor public OverScroller(android.content.Context, android.view.animation.Interpolator);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
-    ctor public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
+    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
     method public void abortAnimation();
     method public boolean computeScrollOffset();
     method public void fling(int, int, int, int, int, int, int, int);
@@ -48469,6 +48526,7 @@
     method public android.view.View getHourView();
     method public int getMinute();
     method public android.view.View getMinuteView();
+    method public int getMode();
     method public android.view.View getPmView();
     method public boolean is24HourView();
     method public deprecated void setCurrentHour(java.lang.Integer);
@@ -48477,6 +48535,8 @@
     method public void setIs24HourView(java.lang.Boolean);
     method public void setMinute(int);
     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+    field public static final int MODE_CLOCK = 2; // 0x2
+    field public static final int MODE_SPINNER = 1; // 0x1
   }
 
   public static abstract interface TimePicker.OnTimeChangedListener {
@@ -48685,7 +48745,7 @@
     method public abstract android.widget.ListAdapter getWrappedAdapter();
   }
 
-  public class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
+  public deprecated class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
     ctor public ZoomButton(android.content.Context);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet);
     ctor public ZoomButton(android.content.Context, android.util.AttributeSet, int);
@@ -48694,7 +48754,7 @@
     method public void setZoomSpeed(long);
   }
 
-  public class ZoomButtonsController implements android.view.View.OnTouchListener {
+  public deprecated class ZoomButtonsController implements android.view.View.OnTouchListener {
     ctor public ZoomButtonsController(android.view.View);
     method public android.view.ViewGroup getContainer();
     method public android.view.View getZoomControls();
@@ -48731,7 +48791,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -50803,20 +50863,22 @@
     enum_constant public static final java.lang.Character.UnicodeScript YI;
   }
 
-  public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
-    method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
+  public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
+    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
     method public T cast(java.lang.Object);
     method public boolean desiredAssertionStatus();
     method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
     method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getCanonicalName();
     method public java.lang.ClassLoader getClassLoader();
     method public java.lang.Class<?>[] getClasses();
     method public java.lang.Class<?> getComponentType();
     method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?>[] getDeclaredClasses();
     method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
@@ -50846,6 +50908,7 @@
     method public java.lang.Object[] getSigners();
     method public java.lang.String getSimpleName();
     method public java.lang.Class<? super T> getSuperclass();
+    method public java.lang.String getTypeName();
     method public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
     method public boolean isAnnotation();
     method public boolean isAnonymousClass();
@@ -50859,6 +50922,7 @@
     method public boolean isPrimitive();
     method public boolean isSynthetic();
     method public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public java.lang.String toGenericString();
   }
 
   public class ClassCastException extends java.lang.RuntimeException {
@@ -50926,7 +50990,7 @@
   public abstract interface Cloneable {
   }
 
-  public abstract interface Comparable {
+  public abstract interface Comparable<T> {
     method public abstract int compareTo(T);
   }
 
@@ -50980,7 +51044,7 @@
     field public static final java.lang.Class<java.lang.Double> TYPE;
   }
 
-  public abstract class Enum implements java.lang.Comparable java.io.Serializable {
+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
     ctor protected Enum(java.lang.String, int);
     method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
     method public final int compareTo(E);
@@ -50990,7 +51054,7 @@
     method public final int hashCode();
     method public final java.lang.String name();
     method public final int ordinal();
-    method public static T valueOf(java.lang.Class<T>, java.lang.String);
+    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
   }
 
   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
@@ -51109,7 +51173,7 @@
     ctor public IndexOutOfBoundsException(java.lang.String);
   }
 
-  public class InheritableThreadLocal extends java.lang.ThreadLocal {
+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
     ctor public InheritableThreadLocal();
     method protected T childValue(T);
   }
@@ -51188,7 +51252,7 @@
     ctor public InterruptedException(java.lang.String);
   }
 
-  public abstract interface Iterable {
+  public abstract interface Iterable<T> {
     method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
     method public default java.util.Spliterator<T> spliterator();
@@ -51403,12 +51467,12 @@
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
-    method public A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
-    method public A[] getAnnotationsByType(java.lang.Class<A>);
-    method public A getDeclaredAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
     method public java.lang.String getImplementationTitle();
     method public java.lang.String getImplementationVendor();
     method public java.lang.String getImplementationVersion();
@@ -52007,13 +52071,13 @@
     method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
   }
 
-  public class ThreadLocal {
+  public class ThreadLocal<T> {
     ctor public ThreadLocal();
     method public T get();
     method protected T initialValue();
     method public void remove();
     method public void set(T);
-    method public static java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
+    method public static <S> java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
   }
 
   public class Throwable implements java.io.Serializable {
@@ -52116,6 +52180,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -52151,30 +52217,30 @@
 
 package java.lang.ref {
 
-  public class PhantomReference extends java.lang.ref.Reference {
+  public class PhantomReference<T> extends java.lang.ref.Reference {
     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public abstract class Reference {
+  public abstract class Reference<T> {
     method public void clear();
     method public boolean enqueue();
     method public T get();
     method public boolean isEnqueued();
   }
 
-  public class ReferenceQueue {
+  public class ReferenceQueue<T> {
     ctor public ReferenceQueue();
     method public java.lang.ref.Reference<? extends T> poll();
     method public java.lang.ref.Reference<? extends T> remove(long) throws java.lang.IllegalArgumentException, java.lang.InterruptedException;
     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
   }
 
-  public class SoftReference extends java.lang.ref.Reference {
+  public class SoftReference<T> extends java.lang.ref.Reference {
     ctor public SoftReference(T);
     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public class WeakReference extends java.lang.ref.Reference {
+  public class WeakReference<T> extends java.lang.ref.Reference {
     ctor public WeakReference(T);
     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
@@ -52185,7 +52251,7 @@
 
   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
     ctor protected AccessibleObject();
-    method public T getAnnotation(java.lang.Class<T>);
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public java.lang.annotation.Annotation[] getAnnotations();
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public boolean isAccessible();
@@ -52194,12 +52260,12 @@
   }
 
   public abstract interface AnnotatedElement {
-    method public abstract T getAnnotation(java.lang.Class<T>);
+    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
-    method public default T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public default T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
   }
 
@@ -52227,27 +52293,38 @@
     method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
   }
 
-  public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Constructor<T> extends java.lang.reflect.Executable {
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public int getModifiers();
     method public java.lang.String getName();
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
     method public java.lang.String toGenericString();
   }
 
+  public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.Class<?>[] getExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericExceptionTypes();
+    method public java.lang.reflect.Type[] getGenericParameterTypes();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
+    method public int getParameterCount();
+    method public abstract java.lang.Class<?>[] getParameterTypes();
+    method public java.lang.reflect.Parameter[] getParameters();
+    method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
+    method public final boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+    method public abstract java.lang.String toGenericString();
+  }
+
   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
     method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public A getAnnotation(java.lang.Class<A>);
     method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -52261,7 +52338,6 @@
     method public java.lang.String getName();
     method public short getShort(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public java.lang.Class<?> getType();
-    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isEnumConstant();
     method public boolean isSynthetic();
     method public void set(java.lang.Object, java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
@@ -52280,7 +52356,7 @@
     method public abstract java.lang.reflect.Type getGenericComponentType();
   }
 
-  public abstract interface GenericDeclaration {
+  public abstract interface GenericDeclaration implements java.lang.reflect.AnnotatedElement {
     method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
   }
 
@@ -52312,13 +52388,10 @@
     field public static final int PUBLIC = 0; // 0x0
   }
 
-  public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public A getAnnotation(java.lang.Class<A>);
+  public final class Method extends java.lang.reflect.Executable {
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericExceptionTypes();
-    method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public java.lang.reflect.Type getGenericReturnType();
     method public int getModifiers();
     method public java.lang.String getName();
@@ -52329,8 +52402,6 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isBridge();
     method public boolean isDefault();
-    method public boolean isSynthetic();
-    method public boolean isVarArgs();
     method public java.lang.String toGenericString();
   }
 
@@ -52353,6 +52424,7 @@
     method public static boolean isTransient(int);
     method public static boolean isVolatile(int);
     method public static int methodModifiers();
+    method public static int parameterModifiers();
     method public static java.lang.String toString(int);
     field public static final int ABSTRACT = 1024; // 0x400
     field public static final int FINAL = 16; // 0x10
@@ -52368,6 +52440,21 @@
     field public static final int VOLATILE = 64; // 0x40
   }
 
+  public final class Parameter implements java.lang.reflect.AnnotatedElement {
+    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+    method public java.lang.reflect.Executable getDeclaringExecutable();
+    method public int getModifiers();
+    method public java.lang.String getName();
+    method public java.lang.reflect.Type getParameterizedType();
+    method public java.lang.Class<?> getType();
+    method public boolean isImplicit();
+    method public boolean isNamePresent();
+    method public boolean isSynthetic();
+    method public boolean isVarArgs();
+  }
+
   public abstract interface ParameterizedType implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getActualTypeArguments();
     method public abstract java.lang.reflect.Type getOwnerType();
@@ -52391,7 +52478,7 @@
   public abstract interface Type {
   }
 
-  public abstract interface TypeVariable implements java.lang.reflect.Type {
+  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
     method public abstract java.lang.reflect.Type[] getBounds();
     method public abstract D getGenericDeclaration();
     method public abstract java.lang.String getName();
@@ -53180,7 +53267,7 @@
     method public abstract java.net.SocketImpl createSocketImpl();
   }
 
-  public abstract interface SocketOption {
+  public abstract interface SocketOption<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -53301,8 +53388,6 @@
     method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
     method public final java.io.InputStream openStream() throws java.io.IOException;
     method public boolean sameFile(java.net.URL);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
-    method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
     method public java.lang.String toExternalForm();
     method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -53712,9 +53797,9 @@
   }
 
   public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
-    method public abstract void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
   }
 
@@ -53742,25 +53827,25 @@
   public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
     ctor protected AsynchronousFileChannel();
     method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public abstract <A> void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public final <A> void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
     method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
     method public abstract long size() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
     method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
   }
 
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
-    method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
+    method public abstract <A> void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
     method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
@@ -53768,30 +53853,30 @@
     method public static java.nio.channels.AsynchronousServerSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousServerSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.AsynchronousServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
   }
 
   public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public abstract void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
+    method public abstract <A> void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
-    method public abstract java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <A> void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <T> java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public final <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
-    method public abstract void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
   }
 
   public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
@@ -53831,7 +53916,7 @@
     ctor public ClosedSelectorException();
   }
 
-  public abstract interface CompletionHandler {
+  public abstract interface CompletionHandler<V, A> {
     method public abstract void completed(V, A);
     method public abstract void failed(java.lang.Throwable, A);
   }
@@ -53855,7 +53940,7 @@
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
     method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
-    method public abstract java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.DatagramSocket socket();
     method public final int validOps();
     method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
@@ -53960,8 +54045,8 @@
   public abstract interface NetworkChannel implements java.nio.channels.Channel {
     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
-    method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
-    method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
   }
 
@@ -54083,7 +54168,7 @@
     method public abstract java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
-    method public abstract java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.net.ServerSocket socket();
     method public final int validOps();
   }
@@ -54106,7 +54191,7 @@
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
     method public final long read(java.nio.ByteBuffer[]) throws java.io.IOException;
-    method public abstract java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public abstract <T> java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.SocketChannel shutdownOutput() throws java.io.IOException;
     method public abstract java.net.Socket socket();
@@ -54391,11 +54476,11 @@
     ctor public DirectoryNotEmptyException(java.lang.String);
   }
 
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
+  public abstract interface DirectoryStream<T> implements java.io.Closeable java.lang.Iterable {
     method public abstract java.util.Iterator<T> iterator();
   }
 
-  public static abstract interface DirectoryStream.Filter {
+  public static abstract interface DirectoryStream.Filter<T> {
     method public abstract boolean accept(T) throws java.io.IOException;
   }
 
@@ -54407,7 +54492,7 @@
   public abstract class FileStore {
     ctor protected FileStore();
     method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(java.lang.Class<V>);
     method public abstract long getTotalSpace() throws java.io.IOException;
     method public abstract long getUnallocatedSpace() throws java.io.IOException;
     method public abstract long getUsableSpace() throws java.io.IOException;
@@ -54479,7 +54564,7 @@
     enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
   }
 
-  public abstract interface FileVisitor {
+  public abstract interface FileVisitor<T> {
     method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
     method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -54504,7 +54589,7 @@
     method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
     method public static java.util.stream.Stream<java.nio.file.Path> find(java.nio.file.Path, int, java.util.function.BiPredicate<java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes>, java.nio.file.FileVisitOption...) throws java.io.IOException;
     method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public static <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54537,7 +54622,7 @@
     method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54645,17 +54730,17 @@
     ctor public ReadOnlyFileSystemException();
   }
 
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
+  public abstract interface SecureDirectoryStream<T> implements java.nio.file.DirectoryStream {
     method public abstract void deleteDirectory(T) throws java.io.IOException;
     method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.lang.Class<V>);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
   }
 
-  public class SimpleFileVisitor implements java.nio.file.FileVisitor {
+  public class SimpleFileVisitor<T> implements java.nio.file.FileVisitor {
     ctor protected SimpleFileVisitor();
     method public java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -54693,13 +54778,13 @@
     field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
   }
 
-  public abstract interface WatchEvent {
+  public abstract interface WatchEvent<T> {
     method public abstract T context();
     method public abstract int count();
     method public abstract java.nio.file.WatchEvent.Kind<T> kind();
   }
 
-  public static abstract interface WatchEvent.Kind {
+  public static abstract interface WatchEvent.Kind<T> {
     method public abstract java.lang.String name();
     method public abstract java.lang.Class<T> type();
   }
@@ -54835,7 +54920,7 @@
     method public abstract boolean isSystem();
   }
 
-  public abstract interface FileAttribute {
+  public abstract interface FileAttribute<T> {
     method public abstract java.lang.String name();
     method public abstract T value();
   }
@@ -54932,7 +55017,7 @@
     method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
     method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
     method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
     method public abstract java.nio.file.Path getPath(java.net.URI);
@@ -54949,7 +55034,7 @@
     method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
     method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
     method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
     method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -54979,12 +55064,12 @@
 
   public final class AccessController {
     method public static void checkPermission(java.security.Permission) throws java.security.AccessControlException;
-    method public static T doPrivileged(java.security.PrivilegedAction<T>);
-    method public static T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
-    method public static T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivileged(java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivileged(java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedAction<T>);
+    method public static <T> T doPrivilegedWithCombiner(java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
     method public static java.security.AccessControlContext getContext();
   }
 
@@ -55023,7 +55108,7 @@
     method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method public final void init(byte[]) throws java.io.IOException;
@@ -55035,7 +55120,7 @@
     ctor public AlgorithmParametersSpi();
     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
     method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
-    method protected abstract T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(byte[]) throws java.io.IOException;
     method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
@@ -55130,6 +55215,13 @@
     method public abstract java.security.ProtectionDomain[] combine(java.security.ProtectionDomain[], java.security.ProtectionDomain[]);
   }
 
+  public final class DomainLoadStoreParameter implements java.security.KeyStore.LoadStoreParameter {
+    ctor public DomainLoadStoreParameter(java.net.URI, java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter>);
+    method public java.net.URI getConfiguration();
+    method public java.security.KeyStore.ProtectionParameter getProtectionParameter();
+    method public java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter> getProtectionParams();
+  }
+
   public class GeneralSecurityException extends java.lang.Exception {
     ctor public GeneralSecurityException();
     ctor public GeneralSecurityException(java.lang.String);
@@ -55220,7 +55312,7 @@
     method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
@@ -55229,7 +55321,7 @@
     ctor public KeyFactorySpi();
     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
 
@@ -55326,6 +55418,12 @@
   }
 
   public static abstract interface KeyStore.Entry {
+    method public default java.util.Set<java.security.KeyStore.Entry.Attribute> getAttributes();
+  }
+
+  public static abstract interface KeyStore.Entry.Attribute {
+    method public abstract java.lang.String getName();
+    method public abstract java.lang.String getValue();
   }
 
   public static abstract interface KeyStore.LoadStoreParameter {
@@ -55334,11 +55432,15 @@
 
   public static class KeyStore.PasswordProtection implements javax.security.auth.Destroyable java.security.KeyStore.ProtectionParameter {
     ctor public KeyStore.PasswordProtection(char[]);
+    ctor public KeyStore.PasswordProtection(char[], java.lang.String, java.security.spec.AlgorithmParameterSpec);
     method public synchronized char[] getPassword();
+    method public java.lang.String getProtectionAlgorithm();
+    method public java.security.spec.AlgorithmParameterSpec getProtectionParameters();
   }
 
   public static final class KeyStore.PrivateKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[]);
+    ctor public KeyStore.PrivateKeyEntry(java.security.PrivateKey, java.security.cert.Certificate[], java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getCertificate();
     method public java.security.cert.Certificate[] getCertificateChain();
     method public java.security.PrivateKey getPrivateKey();
@@ -55349,11 +55451,13 @@
 
   public static final class KeyStore.SecretKeyEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey);
+    ctor public KeyStore.SecretKeyEntry(javax.crypto.SecretKey, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public javax.crypto.SecretKey getSecretKey();
   }
 
   public static final class KeyStore.TrustedCertificateEntry implements java.security.KeyStore.Entry {
     ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate);
+    ctor public KeyStore.TrustedCertificateEntry(java.security.cert.Certificate, java.util.Set<java.security.KeyStore.Entry.Attribute>);
     method public java.security.cert.Certificate getTrustedCertificate();
   }
 
@@ -55432,6 +55536,14 @@
     ctor public NoSuchProviderException(java.lang.String);
   }
 
+  public final class PKCS12Attribute implements java.security.KeyStore.Entry.Attribute {
+    ctor public PKCS12Attribute(java.lang.String, java.lang.String);
+    ctor public PKCS12Attribute(byte[]);
+    method public byte[] getEncoded();
+    method public java.lang.String getName();
+    method public java.lang.String getValue();
+  }
+
   public abstract class Permission implements java.security.Guard java.io.Serializable {
     ctor public Permission(java.lang.String);
     method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
@@ -55489,14 +55601,15 @@
     method public abstract boolean equals(java.lang.Object);
     method public abstract java.lang.String getName();
     method public abstract int hashCode();
+    method public default boolean implies(javax.security.auth.Subject);
     method public abstract java.lang.String toString();
   }
 
-  public abstract interface PrivateKey implements java.security.Key {
+  public abstract interface PrivateKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
   }
 
-  public abstract interface PrivilegedAction {
+  public abstract interface PrivilegedAction<T> {
     method public abstract T run();
   }
 
@@ -55505,7 +55618,7 @@
     method public java.lang.Exception getException();
   }
 
-  public abstract interface PrivilegedExceptionAction {
+  public abstract interface PrivilegedExceptionAction<T> {
     method public abstract T run() throws java.lang.Exception;
   }
 
@@ -55521,16 +55634,25 @@
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized java.lang.Object compute(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfAbsent(java.lang.Object, java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>);
+    method public synchronized java.lang.Object computeIfPresent(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
+    method public synchronized java.lang.Object getOrDefault(java.lang.Object, java.lang.Object);
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
     method public synchronized java.util.Set<java.security.Provider.Service> getServices();
     method public double getVersion();
+    method public synchronized java.lang.Object merge(java.lang.Object, java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
     method public synchronized java.lang.Object put(java.lang.Object, java.lang.Object);
     method public synchronized void putAll(java.util.Map<?, ?>);
+    method public synchronized java.lang.Object putIfAbsent(java.lang.Object, java.lang.Object);
     method protected synchronized void putService(java.security.Provider.Service);
     method protected synchronized void removeService(java.security.Provider.Service);
+    method public synchronized boolean replace(java.lang.Object, java.lang.Object, java.lang.Object);
+    method public synchronized java.lang.Object replace(java.lang.Object, java.lang.Object);
+    method public synchronized void replaceAll(java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
   }
 
   public static class Provider.Service {
@@ -55572,6 +55694,7 @@
     method public static java.security.SecureRandom getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.SecureRandom getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.SecureRandom getInstanceStrong() throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public static byte[] getSeed(int);
     method protected final int next(int);
@@ -55944,6 +56067,7 @@
     method public abstract java.lang.String toString();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
     method protected java.lang.Object writeReplace() throws java.io.ObjectStreamException;
   }
 
@@ -56189,6 +56313,7 @@
     method public abstract int getVersion();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract class X509CRLEntry implements java.security.cert.X509Extension {
@@ -56302,7 +56427,6 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
-    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -56506,6 +56630,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;
@@ -57687,11 +57812,11 @@
     method public abstract void free() throws java.sql.SQLException;
     method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
-    method public abstract T getSource(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract java.lang.String getString() throws java.sql.SQLException;
     method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
     method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
-    method public abstract T setResult(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
     method public abstract void setString(java.lang.String) throws java.sql.SQLException;
   }
 
@@ -57815,7 +57940,7 @@
 
   public abstract interface Wrapper {
     method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
-    method public abstract T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
+    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
   }
 
 }
@@ -58348,7 +58473,7 @@
 
 package java.util {
 
-  public abstract class AbstractCollection implements java.util.Collection {
+  public abstract class AbstractCollection<E> implements java.util.Collection {
     ctor protected AbstractCollection();
     method public boolean add(E);
     method public boolean addAll(java.util.Collection<? extends E>);
@@ -58362,10 +58487,10 @@
     method public boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public abstract class AbstractList extends java.util.AbstractCollection implements java.util.List {
+  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
     ctor protected AbstractList();
     method public void add(int, E);
     method public boolean addAll(int, java.util.Collection<? extends E>);
@@ -58382,7 +58507,7 @@
     field protected transient int modCount;
   }
 
-  public abstract class AbstractMap implements java.util.Map {
+  public abstract class AbstractMap<K, V> implements java.util.Map {
     ctor protected AbstractMap();
     method public void clear();
     method public boolean containsKey(java.lang.Object);
@@ -58398,7 +58523,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public static class AbstractMap.SimpleEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleEntry(K, V);
     ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -58406,7 +58531,7 @@
     method public V setValue(V);
   }
 
-  public static class AbstractMap.SimpleImmutableEntry implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
     ctor public AbstractMap.SimpleImmutableEntry(K, V);
     ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
     method public K getKey();
@@ -58414,23 +58539,23 @@
     method public V setValue(V);
   }
 
-  public abstract class AbstractQueue extends java.util.AbstractCollection implements java.util.Queue {
+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
     ctor protected AbstractQueue();
     method public E element();
     method public E remove();
   }
 
-  public abstract class AbstractSequentialList extends java.util.AbstractList {
+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
     ctor protected AbstractSequentialList();
     method public E get(int);
     method public abstract java.util.ListIterator<E> listIterator(int);
   }
 
-  public abstract class AbstractSet extends java.util.AbstractCollection implements java.util.Set {
+  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
     ctor protected AbstractSet();
   }
 
-  public class ArrayDeque extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
+  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
     ctor public ArrayDeque();
     ctor public ArrayDeque(int);
     ctor public ArrayDeque(java.util.Collection<? extends E>);
@@ -58462,7 +58587,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ArrayList extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public ArrayList(int);
     ctor public ArrayList();
     ctor public ArrayList(java.util.Collection<? extends E>);
@@ -58479,7 +58604,7 @@
   }
 
   public class Arrays {
-    method public static java.util.List<T> asList(T...);
+    method public static <T> java.util.List<T> asList(T...);
     method public static int binarySearch(long[], long);
     method public static int binarySearch(long[], int, int, long);
     method public static int binarySearch(int[], int);
@@ -58496,10 +58621,10 @@
     method public static int binarySearch(float[], int, int, float);
     method public static int binarySearch(java.lang.Object[], java.lang.Object);
     method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
-    method public static int binarySearch(T[], T, java.util.Comparator<? super T>);
-    method public static int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
-    method public static T[] copyOf(T[], int);
-    method public static T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
+    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
+    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
+    method public static <T> T[] copyOf(T[], int);
+    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOf(byte[], int);
     method public static short[] copyOf(short[], int);
     method public static int[] copyOf(int[], int);
@@ -58508,8 +58633,8 @@
     method public static float[] copyOf(float[], int);
     method public static double[] copyOf(double[], int);
     method public static boolean[] copyOf(boolean[], int);
-    method public static T[] copyOfRange(T[], int, int);
-    method public static T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
+    method public static <T> T[] copyOfRange(T[], int, int);
+    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
     method public static byte[] copyOfRange(byte[], int, int);
     method public static short[] copyOfRange(short[], int, int);
     method public static int[] copyOfRange(int[], int, int);
@@ -58557,15 +58682,15 @@
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
     method public static int hashCode(java.lang.Object[]);
-    method public static void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
-    method public static void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
     method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
     method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
     method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
     method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
-    method public static void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
     method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
     method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
@@ -58583,11 +58708,11 @@
     method public static void parallelSort(float[], int, int);
     method public static void parallelSort(double[]);
     method public static void parallelSort(double[], int, int);
-    method public static void parallelSort(T[]);
-    method public static void parallelSort(T[], int, int);
-    method public static void parallelSort(T[], java.util.Comparator<? super T>);
-    method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
-    method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
+    method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
+    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
+    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
     method public static void setAll(int[], java.util.function.IntUnaryOperator);
     method public static void setAll(long[], java.util.function.IntToLongFunction);
     method public static void setAll(double[], java.util.function.IntToDoubleFunction);
@@ -58607,18 +58732,18 @@
     method public static void sort(double[], int, int);
     method public static void sort(java.lang.Object[]);
     method public static void sort(java.lang.Object[], int, int);
-    method public static void sort(T[], java.util.Comparator<? super T>);
-    method public static void sort(T[], int, int, java.util.Comparator<? super T>);
-    method public static java.util.Spliterator<T> spliterator(T[]);
-    method public static java.util.Spliterator<T> spliterator(T[], int, int);
+    method public static <T> void sort(T[], java.util.Comparator<? super T>);
+    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
+    method public static <T> java.util.Spliterator<T> spliterator(T[]);
+    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[]);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[]);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[]);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
-    method public static java.util.stream.Stream<T> stream(T[]);
-    method public static java.util.stream.Stream<T> stream(T[], int, int);
+    method public static <T> java.util.stream.Stream<T> stream(T[]);
+    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
     method public static java.util.stream.IntStream stream(int[]);
     method public static java.util.stream.IntStream stream(int[], int, int);
     method public static java.util.stream.LongStream stream(long[]);
@@ -58636,6 +58761,33 @@
     method public static java.lang.String toString(java.lang.Object[]);
   }
 
+  public class Base64 {
+    method public static java.util.Base64.Decoder getDecoder();
+    method public static java.util.Base64.Encoder getEncoder();
+    method public static java.util.Base64.Decoder getMimeDecoder();
+    method public static java.util.Base64.Encoder getMimeEncoder();
+    method public static java.util.Base64.Encoder getMimeEncoder(int, byte[]);
+    method public static java.util.Base64.Decoder getUrlDecoder();
+    method public static java.util.Base64.Encoder getUrlEncoder();
+  }
+
+  public static class Base64.Decoder {
+    method public byte[] decode(byte[]);
+    method public byte[] decode(java.lang.String);
+    method public int decode(byte[], byte[]);
+    method public java.nio.ByteBuffer decode(java.nio.ByteBuffer);
+    method public java.io.InputStream wrap(java.io.InputStream);
+  }
+
+  public static class Base64.Encoder {
+    method public byte[] encode(byte[]);
+    method public int encode(byte[], byte[]);
+    method public java.nio.ByteBuffer encode(java.nio.ByteBuffer);
+    method public java.lang.String encodeToString(byte[]);
+    method public java.util.Base64.Encoder withoutPadding();
+    method public java.io.OutputStream wrap(java.io.OutputStream);
+  }
+
   public class BitSet implements java.lang.Cloneable java.io.Serializable {
     ctor public BitSet();
     ctor public BitSet(int);
@@ -58775,7 +58927,7 @@
     field protected long time;
   }
 
-  public abstract interface Collection implements java.lang.Iterable {
+  public abstract interface Collection<E> implements java.lang.Iterable {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -58793,86 +58945,86 @@
     method public abstract int size();
     method public default java.util.stream.Stream<E> stream();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class Collections {
-    method public static boolean addAll(java.util.Collection<? super T>, T...);
-    method public static java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
-    method public static int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
-    method public static int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
-    method public static java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
-    method public static java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
-    method public static java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
-    method public static java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
-    method public static void copy(java.util.List<? super T>, java.util.List<? extends T>);
+    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
+    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
+    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
+    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
+    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
+    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
+    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
+    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
     method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
-    method public static java.util.Enumeration<T> emptyEnumeration();
-    method public static java.util.Iterator<T> emptyIterator();
-    method public static final java.util.List<T> emptyList();
-    method public static java.util.ListIterator<T> emptyListIterator();
-    method public static final java.util.Map<K, V> emptyMap();
-    method public static final java.util.Set<T> emptySet();
-    method public static java.util.Enumeration<T> enumeration(java.util.Collection<T>);
-    method public static void fill(java.util.List<? super T>, T);
+    method public static <T> java.util.Enumeration<T> emptyEnumeration();
+    method public static <T> java.util.Iterator<T> emptyIterator();
+    method public static final <T> java.util.List<T> emptyList();
+    method public static <T> java.util.ListIterator<T> emptyListIterator();
+    method public static final <K, V> java.util.Map<K, V> emptyMap();
+    method public static final <T> java.util.Set<T> emptySet();
+    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
+    method public static <T> void fill(java.util.List<? super T>, T);
     method public static int frequency(java.util.Collection<?>, java.lang.Object);
     method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
     method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
-    method public static java.util.ArrayList<T> list(java.util.Enumeration<T>);
-    method public static T max(java.util.Collection<? extends T>);
-    method public static T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static T min(java.util.Collection<? extends T>);
-    method public static T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static java.util.List<T> nCopies(int, T);
-    method public static java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
-    method public static boolean replaceAll(java.util.List<T>, T, T);
+    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
+    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
+    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
+    method public static <T> java.util.List<T> nCopies(int, T);
+    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
+    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
     method public static void reverse(java.util.List<?>);
-    method public static java.util.Comparator<T> reverseOrder();
-    method public static java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
+    method public static <T> java.util.Comparator<T> reverseOrder();
+    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
     method public static void rotate(java.util.List<?>, int);
     method public static void shuffle(java.util.List<?>);
     method public static void shuffle(java.util.List<?>, java.util.Random);
-    method public static java.util.Set<E> singleton(E);
-    method public static java.util.List<E> singletonList(E);
-    method public static java.util.Map<K, V> singletonMap(K, V);
-    method public static void sort(java.util.List<T>);
-    method public static void sort(java.util.List<T>, java.util.Comparator<? super T>);
+    method public static <E> java.util.Set<E> singleton(E);
+    method public static <E> java.util.List<E> singletonList(E);
+    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
+    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
+    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
     method public static void swap(java.util.List<?>, int, int);
-    method public static java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
-    method public static java.util.List<T> synchronizedList(java.util.List<T>);
-    method public static java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
-    method public static java.util.Set<T> synchronizedSet(java.util.Set<T>);
-    method public static java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
-    method public static java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
-    method public static java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
-    method public static java.util.List<T> unmodifiableList(java.util.List<? extends T>);
-    method public static java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
-    method public static java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
-    method public static java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
-    method public static java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
+    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
+    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
+    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
+    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
+    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
+    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
+    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
+    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
+    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
     field public static final java.util.List EMPTY_LIST;
     field public static final java.util.Map EMPTY_MAP;
     field public static final java.util.Set EMPTY_SET;
   }
 
-  public abstract interface Comparator {
+  public abstract interface Comparator<T> {
     method public abstract int compare(T, T);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public static java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
     method public abstract boolean equals(java.lang.Object);
-    method public static java.util.Comparator<T> naturalOrder();
-    method public static java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
-    method public static java.util.Comparator<T> reverseOrder();
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
+    method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
+    method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
+    method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
     method public default java.util.Comparator<T> reversed();
     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public default java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
@@ -58931,7 +59083,7 @@
     method public deprecated java.lang.String toLocaleString();
   }
 
-  public abstract interface Deque implements java.util.Queue {
+  public abstract interface Deque<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -58961,7 +59113,7 @@
     method public abstract int size();
   }
 
-  public abstract class Dictionary {
+  public abstract class Dictionary<K, V> {
     ctor public Dictionary();
     method public abstract java.util.Enumeration<V> elements();
     method public abstract V get(java.lang.Object);
@@ -58992,7 +59144,7 @@
     ctor public EmptyStackException();
   }
 
-  public class EnumMap extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
     ctor public EnumMap(java.lang.Class<K>);
     ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
     ctor public EnumMap(java.util.Map<K, ? extends V>);
@@ -59000,23 +59152,23 @@
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
   }
 
-  public abstract class EnumSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
-    method public static java.util.EnumSet<E> allOf(java.lang.Class<E>);
+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
     method public java.util.EnumSet<E> clone();
-    method public static java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
-    method public static java.util.EnumSet<E> copyOf(java.util.Collection<E>);
-    method public static java.util.EnumSet<E> noneOf(java.lang.Class<E>);
-    method public static java.util.EnumSet<E> of(E);
-    method public static java.util.EnumSet<E> of(E, E);
-    method public static java.util.EnumSet<E> of(E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E, E, E, E);
-    method public static java.util.EnumSet<E> of(E, E...);
-    method public static java.util.EnumSet<E> range(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
   }
 
-  public abstract interface Enumeration {
+  public abstract interface Enumeration<E> {
     method public abstract boolean hasMoreElements();
     method public abstract E nextElement();
   }
@@ -59024,7 +59176,7 @@
   public abstract interface EventListener {
   }
 
-  public abstract class EventListenerProxy implements java.util.EventListener {
+  public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
     ctor public EventListenerProxy(T);
     method public T getListener();
   }
@@ -59110,19 +59262,27 @@
     field public static final int BC = 0; // 0x0
   }
 
-  public class HashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public HashMap(int, float);
     ctor public HashMap(int);
     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>);
   }
 
-  public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public HashSet();
     ctor public HashSet(java.util.Collection<? extends E>);
     ctor public HashSet(int, float);
@@ -59133,7 +59293,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class Hashtable extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public Hashtable(int, float);
     ctor public Hashtable(int);
     ctor public Hashtable();
@@ -59168,7 +59328,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public class IdentityHashMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
     ctor public IdentityHashMap();
     ctor public IdentityHashMap(int);
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
@@ -59235,14 +59395,14 @@
     ctor public InvalidPropertiesFormatException(java.lang.String);
   }
 
-  public abstract interface Iterator {
+  public abstract interface Iterator<E> {
     method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
     method public default void remove();
   }
 
-  public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
+  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
     ctor public LinkedHashMap(int, float);
     ctor public LinkedHashMap(int);
     ctor public LinkedHashMap();
@@ -59251,14 +59411,14 @@
     method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
   }
 
-  public class LinkedHashSet extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
     ctor public LinkedHashSet(int, float);
     ctor public LinkedHashSet(int);
     ctor public LinkedHashSet();
     ctor public LinkedHashSet(java.util.Collection<? extends E>);
   }
 
-  public class LinkedList extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
+  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
     ctor public LinkedList();
     ctor public LinkedList(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -59289,7 +59449,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface List implements java.util.Collection {
+  public abstract interface List<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract void add(int, E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
@@ -59316,10 +59476,10 @@
     method public default void sort(java.util.Comparator<? super E>);
     method public abstract java.util.List<E> subList(int, int);
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
-  public abstract interface ListIterator implements java.util.Iterator {
+  public abstract interface ListIterator<E> implements java.util.Iterator {
     method public abstract void add(E);
     method public abstract boolean hasNext();
     method public abstract boolean hasPrevious();
@@ -59370,8 +59530,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
@@ -59436,7 +59598,7 @@
     method public final long getSum();
   }
 
-  public abstract interface Map {
+  public abstract interface Map<K, V> {
     method public abstract void clear();
     method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
@@ -59464,11 +59626,11 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public static abstract interface Map.Entry {
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
-    method public static java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
+  public static abstract interface Map.Entry<K, V> {
+    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
+    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
+    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
     method public abstract boolean equals(java.lang.Object);
     method public abstract K getKey();
     method public abstract V getValue();
@@ -59492,7 +59654,7 @@
     method public java.lang.String getKey();
   }
 
-  public abstract interface NavigableMap implements java.util.SortedMap {
+  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
     method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
     method public abstract K ceilingKey(K);
     method public abstract java.util.NavigableSet<K> descendingKeySet();
@@ -59516,7 +59678,7 @@
     method public abstract java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public abstract interface NavigableSet implements java.util.SortedSet {
+  public abstract interface NavigableSet<E> implements java.util.SortedSet {
     method public abstract E ceiling(E);
     method public abstract java.util.Iterator<E> descendingIterator();
     method public abstract java.util.NavigableSet<E> descendingSet();
@@ -59540,16 +59702,16 @@
   }
 
   public final class Objects {
-    method public static int compare(T, T, java.util.Comparator<? super T>);
+    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
     method public static boolean equals(java.lang.Object, java.lang.Object);
     method public static int hash(java.lang.Object...);
     method public static int hashCode(java.lang.Object);
     method public static boolean isNull(java.lang.Object);
     method public static boolean nonNull(java.lang.Object);
-    method public static T requireNonNull(T);
-    method public static T requireNonNull(T, java.lang.String);
-    method public static T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
+    method public static <T> T requireNonNull(T);
+    method public static <T> T requireNonNull(T, java.lang.String);
+    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
     method public static java.lang.String toString(java.lang.Object);
     method public static java.lang.String toString(java.lang.Object, java.lang.String);
   }
@@ -59571,19 +59733,19 @@
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
-  public final class Optional {
-    method public static java.util.Optional<T> empty();
+  public final class Optional<T> {
+    method public static <T> java.util.Optional<T> empty();
     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
-    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
     method public T get();
     method public void ifPresent(java.util.function.Consumer<? super T>);
     method public boolean isPresent();
-    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.Optional<T> of(T);
-    method public static java.util.Optional<T> ofNullable(T);
+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static <T> java.util.Optional<T> of(T);
+    method public static <T> java.util.Optional<T> ofNullable(T);
     method public T orElse(T);
     method public T orElseGet(java.util.function.Supplier<? extends T>);
-    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
   }
 
   public final class OptionalDouble {
@@ -59594,7 +59756,7 @@
     method public static java.util.OptionalDouble of(double);
     method public double orElse(double);
     method public double orElseGet(java.util.function.DoubleSupplier);
-    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalInt {
@@ -59605,7 +59767,7 @@
     method public static java.util.OptionalInt of(int);
     method public int orElse(int);
     method public int orElseGet(java.util.function.IntSupplier);
-    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
   public final class OptionalLong {
@@ -59616,10 +59778,10 @@
     method public static java.util.OptionalLong of(long);
     method public long orElse(long);
     method public long orElseGet(java.util.function.LongSupplier);
-    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
   }
 
-  public abstract interface PrimitiveIterator implements java.util.Iterator {
+  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
     method public abstract void forEachRemaining(T_CONS);
   }
 
@@ -59644,7 +59806,7 @@
     method public abstract long nextLong();
   }
 
-  public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
+  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
     ctor public PriorityQueue(java.util.Comparator<? super E>);
@@ -59693,7 +59855,7 @@
     method public java.lang.Object handleGetObject(java.lang.String);
   }
 
-  public abstract interface Queue implements java.util.Collection {
+  public abstract interface Queue<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract E element();
     method public abstract boolean offer(E);
@@ -59737,6 +59899,7 @@
     method public static final void clearCache();
     method public static final void clearCache(java.lang.ClassLoader);
     method public boolean containsKey(java.lang.String);
+    method public java.lang.String getBaseBundleName();
     method public static final java.util.ResourceBundle getBundle(java.lang.String);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.ResourceBundle.Control);
     method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale);
@@ -59845,15 +60008,15 @@
     ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
   }
 
-  public final class ServiceLoader implements java.lang.Iterable {
+  public final class ServiceLoader<S> implements java.lang.Iterable {
     method public java.util.Iterator<S> iterator();
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
-    method public static java.util.ServiceLoader<S> load(java.lang.Class<S>);
-    method public static java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
+    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
     method public void reload();
   }
 
-  public abstract interface Set implements java.util.Collection {
+  public abstract interface Set<E> implements java.util.Collection {
     method public abstract boolean add(E);
     method public abstract boolean addAll(java.util.Collection<? extends E>);
     method public abstract void clear();
@@ -59868,7 +60031,7 @@
     method public abstract boolean retainAll(java.util.Collection<?>);
     method public abstract int size();
     method public abstract java.lang.Object[] toArray();
-    method public abstract T[] toArray(T[]);
+    method public abstract <T> T[] toArray(T[]);
   }
 
   public class SimpleTimeZone extends java.util.TimeZone {
@@ -59894,7 +60057,7 @@
     field public static final int WALL_TIME = 0; // 0x0
   }
 
-  public abstract interface SortedMap implements java.util.Map {
+  public abstract interface SortedMap<K, V> implements java.util.Map {
     method public abstract java.util.Comparator<? super K> comparator();
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract K firstKey();
@@ -59906,7 +60069,7 @@
     method public abstract java.util.Collection<V> values();
   }
 
-  public abstract interface SortedSet implements java.util.Set {
+  public abstract interface SortedSet<E> implements java.util.Set {
     method public abstract java.util.Comparator<? super E> comparator();
     method public abstract E first();
     method public abstract java.util.SortedSet<E> headSet(E);
@@ -59915,7 +60078,7 @@
     method public abstract java.util.SortedSet<E> tailSet(E);
   }
 
-  public abstract interface Spliterator {
+  public abstract interface Spliterator<T> {
     method public abstract int characteristics();
     method public abstract long estimateSize();
     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
@@ -59958,7 +60121,7 @@
     method public abstract java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract interface Spliterator.OfPrimitive implements java.util.Spliterator {
+  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
     method public default void forEachRemaining(T_CONS);
     method public abstract boolean tryAdvance(T_CONS);
     method public abstract T_SPLITR trySplit();
@@ -59968,25 +60131,25 @@
     method public static java.util.Spliterator.OfDouble emptyDoubleSpliterator();
     method public static java.util.Spliterator.OfInt emptyIntSpliterator();
     method public static java.util.Spliterator.OfLong emptyLongSpliterator();
-    method public static java.util.Spliterator<T> emptySpliterator();
-    method public static java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
+    method public static <T> java.util.Spliterator<T> emptySpliterator();
+    method public static <T> java.util.Iterator<T> iterator(java.util.Spliterator<? extends T>);
     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int);
-    method public static java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int, int, int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int);
     method public static java.util.Spliterator.OfDouble spliterator(double[], int, int, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
-    method public static java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Collection<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliterator(java.util.Iterator<? extends T>, long, int);
     method public static java.util.Spliterator.OfInt spliterator(java.util.PrimitiveIterator.OfInt, long, int);
     method public static java.util.Spliterator.OfLong spliterator(java.util.PrimitiveIterator.OfLong, long, int);
     method public static java.util.Spliterator.OfDouble spliterator(java.util.PrimitiveIterator.OfDouble, long, int);
-    method public static java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
+    method public static <T> java.util.Spliterator<T> spliteratorUnknownSize(java.util.Iterator<? extends T>, int);
     method public static java.util.Spliterator.OfInt spliteratorUnknownSize(java.util.PrimitiveIterator.OfInt, int);
     method public static java.util.Spliterator.OfLong spliteratorUnknownSize(java.util.PrimitiveIterator.OfLong, int);
     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
@@ -60013,7 +60176,7 @@
     method public java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract class Spliterators.AbstractSpliterator implements java.util.Spliterator {
+  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
     ctor protected Spliterators.AbstractSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
@@ -60048,7 +60211,7 @@
     method public java.util.SplittableRandom split();
   }
 
-  public class Stack extends java.util.Vector {
+  public class Stack<E> extends java.util.Vector {
     ctor public Stack();
     method public boolean empty();
     method public synchronized E peek();
@@ -60132,7 +60295,7 @@
     ctor public TooManyListenersException(java.lang.String);
   }
 
-  public class TreeMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
+  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
     ctor public TreeMap();
     ctor public TreeMap(java.util.Comparator<? super K>);
     ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
@@ -60169,7 +60332,7 @@
     method public java.util.SortedMap<K, V> tailMap(K);
   }
 
-  public class TreeSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public TreeSet();
     ctor public TreeSet(java.util.Comparator<? super E>);
     ctor public TreeSet(java.util.Collection<? extends E>);
@@ -60222,7 +60385,7 @@
     method public java.lang.String getFlags();
   }
 
-  public class Vector extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public Vector(int, int);
     ctor public Vector(int);
     ctor public Vector();
@@ -60257,7 +60420,7 @@
     field protected java.lang.Object[] elementData;
   }
 
-  public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {
+  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
     ctor public WeakHashMap(int, float);
     ctor public WeakHashMap(int);
     ctor public WeakHashMap();
@@ -60273,18 +60436,18 @@
 
   public abstract class AbstractExecutorService implements java.util.concurrent.ExecutorService {
     ctor public AbstractExecutorService();
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
-    method protected java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
     method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
-    method public java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
-    method public java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
   }
 
-  public class ArrayBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public ArrayBlockingQueue(int);
     ctor public ArrayBlockingQueue(int, boolean);
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
@@ -60303,7 +60466,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingDeque implements java.util.concurrent.BlockingQueue java.util.Deque {
+  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
     method public abstract boolean add(E);
     method public abstract void addFirst(E);
     method public abstract void addLast(E);
@@ -60335,7 +60498,7 @@
     method public abstract E takeLast() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingQueue implements java.util.Queue {
+  public abstract interface BlockingQueue<E> implements java.util.Queue {
     method public abstract boolean add(E);
     method public abstract boolean contains(java.lang.Object);
     method public abstract int drainTo(java.util.Collection<? super E>);
@@ -60354,7 +60517,7 @@
     ctor public BrokenBarrierException(java.lang.String);
   }
 
-  public abstract interface Callable {
+  public abstract interface Callable<V> {
     method public abstract V call() throws java.lang.Exception;
   }
 
@@ -60363,28 +60526,28 @@
     ctor public CancellationException(java.lang.String);
   }
 
-  public class CompletableFuture implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
     ctor public CompletableFuture();
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
-    method public java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public boolean cancel(boolean);
     method public boolean complete(T);
     method public boolean completeExceptionally(java.lang.Throwable);
-    method public static java.util.concurrent.CompletableFuture<U> completedFuture(U);
+    method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
     method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public T getNow(T);
     method public int getNumberOfDependents();
-    method public java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public boolean isCancelled();
     method public boolean isCompletedExceptionally();
     method public boolean isDone();
@@ -60399,23 +60562,23 @@
     method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
-    method public static java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
+    method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -60435,7 +60598,7 @@
     ctor public CompletionException(java.lang.Throwable);
   }
 
-  public abstract interface CompletionService {
+  public abstract interface CompletionService<V> {
     method public abstract java.util.concurrent.Future<V> poll();
     method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
@@ -60443,17 +60606,17 @@
     method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface CompletionStage {
+  public abstract interface CompletionStage<T> {
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
-    method public abstract java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
@@ -60463,18 +60626,18 @@
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
+    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
+    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
     method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
@@ -60484,7 +60647,7 @@
     method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
   }
 
-  public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
@@ -60498,29 +60661,29 @@
     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 void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
-    method public void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
-    method public void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachKey(long, java.util.function.Consumer<? super K>);
-    method public void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
     method public void forEachValue(long, java.util.function.Consumer<? super V>);
-    method public void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
+    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
     method public V getOrDefault(java.lang.Object, V);
     method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
     method public java.util.Enumeration<K> keys();
     method public long mappingCount();
     method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
-    method public static java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
+    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
     method public V putIfAbsent(K, V);
-    method public U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
-    method public U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
     method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
     method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
-    method public U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
     method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
@@ -60528,7 +60691,7 @@
     method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
     method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
+    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
     method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
     method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
     method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
@@ -60536,13 +60699,13 @@
     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>);
-    method public U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
-    method public U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
-    method public U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
-    method public U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
+    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
+    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
+    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
   }
 
-   static abstract class ConcurrentHashMap.CollectionView implements java.util.Collection java.io.Serializable {
+   static abstract class ConcurrentHashMap.CollectionView<K, V, E> implements java.util.Collection java.io.Serializable {
     method public final void clear();
     method public abstract boolean contains(java.lang.Object);
     method public final boolean containsAll(java.util.Collection<?>);
@@ -60554,11 +60717,11 @@
     method public final boolean retainAll(java.util.Collection<?>);
     method public final int size();
     method public final java.lang.Object[] toArray();
-    method public final T[] toArray(T[]);
+    method public final <T> T[] toArray(T[]);
     method public final java.lang.String toString();
   }
 
-  public static class ConcurrentHashMap.KeySetView extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
+  public static class ConcurrentHashMap.KeySetView<K, V> extends java.util.concurrent.ConcurrentHashMap.CollectionView implements java.io.Serializable java.util.Set {
     method public boolean add(K);
     method public boolean addAll(java.util.Collection<? extends K>);
     method public boolean contains(java.lang.Object);
@@ -60569,7 +60732,7 @@
     method public java.util.Spliterator<K> spliterator();
   }
 
-  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
     ctor public ConcurrentLinkedDeque();
     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -60599,7 +60762,7 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
     method public java.util.Iterator<E> iterator();
@@ -60610,14 +60773,14 @@
     method public java.util.Spliterator<E> spliterator();
   }
 
-  public abstract interface ConcurrentMap implements java.util.Map {
+  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
     method public abstract V putIfAbsent(K, V);
     method public abstract boolean remove(java.lang.Object, java.lang.Object);
     method public abstract boolean replace(K, V, V);
     method public abstract V replace(K, V);
   }
 
-  public abstract interface ConcurrentNavigableMap implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
+  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
     method public abstract java.util.NavigableSet<K> descendingKeySet();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
@@ -60630,7 +60793,7 @@
     method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListMap extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
     ctor public ConcurrentSkipListMap();
     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
     ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
@@ -60674,7 +60837,7 @@
     method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
   }
 
-  public class ConcurrentSkipListSet extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
     ctor public ConcurrentSkipListSet();
     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
@@ -60702,7 +60865,7 @@
     method public java.util.NavigableSet<E> tailSet(E);
   }
 
-  public class CopyOnWriteArrayList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
     ctor public CopyOnWriteArrayList();
     ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
@@ -60734,10 +60897,10 @@
     method public int size();
     method public java.util.List<E> subList(int, int);
     method public java.lang.Object[] toArray();
-    method public T[] toArray(T[]);
+    method public <T> T[] toArray(T[]);
   }
 
-  public class CopyOnWriteArraySet extends java.util.AbstractSet implements java.io.Serializable {
+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
     method public void forEach(java.util.function.Consumer<? super E>);
@@ -60755,7 +60918,7 @@
     method public long getCount();
   }
 
-  public abstract class CountedCompleter extends java.util.concurrent.ForkJoinTask {
+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
     ctor protected CountedCompleter();
@@ -60792,7 +60955,7 @@
     method public void reset();
   }
 
-  public class DelayQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
     ctor public DelayQueue();
     ctor public DelayQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -60813,7 +60976,7 @@
     method public abstract long getDelay(java.util.concurrent.TimeUnit);
   }
 
-  public class Exchanger {
+  public class Exchanger<V> {
     ctor public Exchanger();
     method public V exchange(V) throws java.lang.InterruptedException;
     method public V exchange(V, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -60830,7 +60993,7 @@
     method public abstract void execute(java.lang.Runnable);
   }
 
-  public class ExecutorCompletionService implements java.util.concurrent.CompletionService {
+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
     method public java.util.concurrent.Future<V> poll();
@@ -60842,21 +61005,21 @@
 
   public abstract interface ExecutorService implements java.util.concurrent.Executor {
     method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public abstract java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public abstract T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public abstract boolean isShutdown();
     method public abstract boolean isTerminated();
     method public abstract void shutdown();
     method public abstract java.util.List<java.lang.Runnable> shutdownNow();
-    method public abstract java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
-    method public abstract java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
     method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
   }
 
   public class Executors {
-    method public static java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
@@ -60873,8 +61036,8 @@
     method public static java.util.concurrent.ScheduledExecutorService newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool(int);
     method public static java.util.concurrent.ExecutorService newWorkStealingPool();
-    method public static java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
-    method public static java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallable(java.util.concurrent.Callable<T>);
+    method public static <T> java.util.concurrent.Callable<T> privilegedCallableUsingCurrentClassLoader(java.util.concurrent.Callable<T>);
     method public static java.util.concurrent.ThreadFactory privilegedThreadFactory();
     method public static java.util.concurrent.ExecutorService unconfigurableExecutorService(java.util.concurrent.ExecutorService);
     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
@@ -60902,7 +61065,7 @@
     method public long getStealCount();
     method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
     method public boolean hasQueuedSubmissions();
-    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> T invoke(java.util.concurrent.ForkJoinTask<T>);
     method public boolean isQuiescent();
     method public boolean isShutdown();
     method public boolean isTerminated();
@@ -60911,7 +61074,7 @@
     method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
     method public void shutdown();
     method public java.util.List<java.lang.Runnable> shutdownNow();
-    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
   }
 
@@ -60924,11 +61087,11 @@
     method public abstract boolean isReleasable();
   }
 
-  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
     ctor public ForkJoinTask();
     method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
-    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
     method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
@@ -60948,7 +61111,7 @@
     method public final V invoke();
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
     method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
-    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
+    method public static <T extends java.util.concurrent.ForkJoinTask<?>> java.util.Collection<T> invokeAll(java.util.Collection<T>);
     method public final boolean isCancelled();
     method public final boolean isCompletedAbnormally();
     method public final boolean isCompletedNormally();
@@ -60974,7 +61137,7 @@
     method protected void onTermination(java.lang.Throwable);
   }
 
-  public abstract interface Future {
+  public abstract interface Future<V> {
     method public abstract boolean cancel(boolean);
     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -60982,7 +61145,7 @@
     method public abstract boolean isDone();
   }
 
-  public class FutureTask implements java.util.concurrent.RunnableFuture {
+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
     ctor public FutureTask(java.util.concurrent.Callable<V>);
     ctor public FutureTask(java.lang.Runnable, V);
     method public boolean cancel(boolean);
@@ -60997,7 +61160,7 @@
     method protected void setException(java.lang.Throwable);
   }
 
-  public class LinkedBlockingDeque extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
     ctor public LinkedBlockingDeque();
     ctor public LinkedBlockingDeque(int);
     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
@@ -61041,7 +61204,7 @@
     method public E takeLast() throws java.lang.InterruptedException;
   }
 
-  public class LinkedBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public LinkedBlockingQueue();
     ctor public LinkedBlockingQueue(int);
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
@@ -61060,7 +61223,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
     ctor public LinkedTransferQueue();
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -61107,7 +61270,7 @@
     method public int register();
   }
 
-  public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
@@ -61136,7 +61299,7 @@
     method protected final void setRawResult(java.lang.Void);
   }
 
-  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
     ctor public RecursiveTask();
     method protected abstract V compute();
     method protected final boolean exec();
@@ -61155,22 +61318,22 @@
     method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
-  public abstract interface RunnableFuture implements java.util.concurrent.Future java.lang.Runnable {
+  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
     method public abstract void run();
   }
 
-  public abstract interface RunnableScheduledFuture implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
+  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
     method public abstract boolean isPeriodic();
   }
 
   public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
     method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public abstract java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
   }
 
-  public abstract interface ScheduledFuture implements java.util.concurrent.Delayed java.util.concurrent.Future {
+  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
   }
 
   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
@@ -61178,13 +61341,13 @@
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
-    method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
     method public boolean getRemoveOnCancelPolicy();
     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
@@ -61214,7 +61377,7 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
-  public class SynchronousQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
     method public int drainTo(java.util.Collection<? super E>);
@@ -61332,7 +61495,7 @@
     ctor public TimeoutException(java.lang.String);
   }
 
-  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
+  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
     method public abstract int getWaitingConsumerCount();
     method public abstract boolean hasWaitingConsumer();
     method public abstract void transfer(E) throws java.lang.InterruptedException;
@@ -61402,7 +61565,7 @@
     method public final boolean weakCompareAndSet(int, int, int);
   }
 
-  public abstract class AtomicIntegerFieldUpdater {
+  public abstract class AtomicIntegerFieldUpdater<T> {
     ctor protected AtomicIntegerFieldUpdater();
     method public final int accumulateAndGet(T, int, java.util.function.IntBinaryOperator);
     method public int addAndGet(T, int);
@@ -61417,7 +61580,7 @@
     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
-    method public static java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, int);
     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
@@ -61470,7 +61633,7 @@
     method public final boolean weakCompareAndSet(int, long, long);
   }
 
-  public abstract class AtomicLongFieldUpdater {
+  public abstract class AtomicLongFieldUpdater<T> {
     ctor protected AtomicLongFieldUpdater();
     method public final long accumulateAndGet(T, long, java.util.function.LongBinaryOperator);
     method public long addAndGet(T, long);
@@ -61485,13 +61648,13 @@
     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
-    method public static java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
     method public abstract void set(T, long);
     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
   }
 
-  public class AtomicMarkableReference {
+  public class AtomicMarkableReference<V> {
     ctor public AtomicMarkableReference(V, boolean);
     method public boolean attemptMark(V, boolean);
     method public boolean compareAndSet(V, V, boolean, boolean);
@@ -61502,7 +61665,7 @@
     method public boolean weakCompareAndSet(V, V, boolean, boolean);
   }
 
-  public class AtomicReference implements java.io.Serializable {
+  public class AtomicReference<V> implements java.io.Serializable {
     ctor public AtomicReference(V);
     ctor public AtomicReference();
     method public final V accumulateAndGet(V, java.util.function.BinaryOperator<V>);
@@ -61517,7 +61680,7 @@
     method public final boolean weakCompareAndSet(V, V);
   }
 
-  public class AtomicReferenceArray implements java.io.Serializable {
+  public class AtomicReferenceArray<E> implements java.io.Serializable {
     ctor public AtomicReferenceArray(int);
     ctor public AtomicReferenceArray(E[]);
     method public final E accumulateAndGet(int, E, java.util.function.BinaryOperator<E>);
@@ -61533,7 +61696,7 @@
     method public final boolean weakCompareAndSet(int, E, E);
   }
 
-  public abstract class AtomicReferenceFieldUpdater {
+  public abstract class AtomicReferenceFieldUpdater<T, V> {
     ctor protected AtomicReferenceFieldUpdater();
     method public final V accumulateAndGet(T, V, java.util.function.BinaryOperator<V>);
     method public abstract boolean compareAndSet(T, V, V);
@@ -61542,13 +61705,13 @@
     method public V getAndSet(T, V);
     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
-    method public static java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
     method public abstract void set(T, V);
     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
   }
 
-  public class AtomicStampedReference {
+  public class AtomicStampedReference<V> {
     ctor public AtomicStampedReference(V, int);
     method public boolean attemptStamp(V, int);
     method public boolean compareAndSet(V, V, int, int);
@@ -61851,33 +62014,33 @@
 
 package java.util.function {
 
-  public abstract interface BiConsumer {
+  public abstract interface BiConsumer<T, U> {
     method public abstract void accept(T, U);
     method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
   }
 
-  public abstract interface BiFunction {
-    method public default java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface BiFunction<T, U, R> {
+    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T, U);
   }
 
-  public abstract interface BiPredicate {
+  public abstract interface BiPredicate<T, U> {
     method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
     method public default java.util.function.BiPredicate<T, U> negate();
     method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
     method public abstract boolean test(T, U);
   }
 
-  public abstract interface BinaryOperator implements java.util.function.BiFunction {
-    method public static java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
+  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
+    method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
   }
 
   public abstract interface BooleanSupplier {
     method public abstract boolean getAsBoolean();
   }
 
-  public abstract interface Consumer {
+  public abstract interface Consumer<T> {
     method public abstract void accept(T);
     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
   }
@@ -61891,7 +62054,7 @@
     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
   }
 
-  public abstract interface DoubleFunction {
+  public abstract interface DoubleFunction<R> {
     method public abstract R apply(double);
   }
 
@@ -61921,11 +62084,11 @@
     method public static java.util.function.DoubleUnaryOperator identity();
   }
 
-  public abstract interface Function {
-    method public default java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
+  public abstract interface Function<T, R> {
+    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
     method public abstract R apply(T);
-    method public default java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
-    method public static java.util.function.Function<T, T> identity();
+    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
+    method public static <T> java.util.function.Function<T, T> identity();
   }
 
   public abstract interface IntBinaryOperator {
@@ -61937,7 +62100,7 @@
     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
   }
 
-  public abstract interface IntFunction {
+  public abstract interface IntFunction<R> {
     method public abstract R apply(int);
   }
 
@@ -61976,7 +62139,7 @@
     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
   }
 
-  public abstract interface LongFunction {
+  public abstract interface LongFunction<R> {
     method public abstract R apply(long);
   }
 
@@ -62006,56 +62169,56 @@
     method public static java.util.function.LongUnaryOperator identity();
   }
 
-  public abstract interface ObjDoubleConsumer {
+  public abstract interface ObjDoubleConsumer<T> {
     method public abstract void accept(T, double);
   }
 
-  public abstract interface ObjIntConsumer {
+  public abstract interface ObjIntConsumer<T> {
     method public abstract void accept(T, int);
   }
 
-  public abstract interface ObjLongConsumer {
+  public abstract interface ObjLongConsumer<T> {
     method public abstract void accept(T, long);
   }
 
-  public abstract interface Predicate {
+  public abstract interface Predicate<T> {
     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
-    method public static java.util.function.Predicate<T> isEqual(java.lang.Object);
+    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
     method public default java.util.function.Predicate<T> negate();
     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
     method public abstract boolean test(T);
   }
 
-  public abstract interface Supplier {
+  public abstract interface Supplier<T> {
     method public abstract T get();
   }
 
-  public abstract interface ToDoubleBiFunction {
+  public abstract interface ToDoubleBiFunction<T, U> {
     method public abstract double applyAsDouble(T, U);
   }
 
-  public abstract interface ToDoubleFunction {
+  public abstract interface ToDoubleFunction<T> {
     method public abstract double applyAsDouble(T);
   }
 
-  public abstract interface ToIntBiFunction {
+  public abstract interface ToIntBiFunction<T, U> {
     method public abstract int applyAsInt(T, U);
   }
 
-  public abstract interface ToIntFunction {
+  public abstract interface ToIntFunction<T> {
     method public abstract int applyAsInt(T);
   }
 
-  public abstract interface ToLongBiFunction {
+  public abstract interface ToLongBiFunction<T, U> {
     method public abstract long applyAsLong(T, U);
   }
 
-  public abstract interface ToLongFunction {
+  public abstract interface ToLongFunction<T> {
     method public abstract long applyAsLong(T);
   }
 
-  public abstract interface UnaryOperator implements java.util.function.Function {
-    method public static java.util.function.UnaryOperator<T> identity();
+  public abstract interface UnaryOperator<T> implements java.util.function.Function {
+    method public static <T> java.util.function.UnaryOperator<T> identity();
   }
 
 }
@@ -62643,7 +62806,7 @@
 
 package java.util.stream {
 
-  public abstract interface BaseStream implements java.lang.AutoCloseable {
+  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
     method public abstract void close();
     method public abstract boolean isParallel();
     method public abstract java.util.Iterator<T> iterator();
@@ -62654,13 +62817,13 @@
     method public abstract S unordered();
   }
 
-  public abstract interface Collector {
+  public abstract interface Collector<T, A, R> {
     method public abstract java.util.function.BiConsumer<A, T> accumulator();
     method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
     method public abstract java.util.function.BinaryOperator<A> combiner();
     method public abstract java.util.function.Function<A, R> finisher();
-    method public static java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
-    method public static java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
     method public abstract java.util.function.Supplier<A> supplier();
   }
 
@@ -62673,43 +62836,43 @@
   }
 
   public final class Collectors {
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> counting();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
     method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public static java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
-    method public static java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
-    method public static java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.List<T>> toList();
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
+    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
   }
 
   public abstract interface DoubleStream implements java.util.stream.BaseStream {
@@ -62718,7 +62881,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Double> boxed();
     method public static java.util.stream.DoubleStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
     method public abstract long count();
     method public abstract java.util.stream.DoubleStream distinct();
@@ -62736,7 +62899,7 @@
     method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
     method public abstract java.util.OptionalDouble max();
     method public abstract java.util.OptionalDouble min();
     method public abstract boolean noneMatch(java.util.function.DoublePredicate);
@@ -62769,7 +62932,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
     method public static java.util.stream.IntStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
     method public abstract long count();
     method public abstract java.util.stream.IntStream distinct();
@@ -62787,7 +62950,7 @@
     method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
     method public abstract java.util.OptionalInt max();
     method public abstract java.util.OptionalInt min();
     method public abstract boolean noneMatch(java.util.function.IntPredicate);
@@ -62821,7 +62984,7 @@
     method public abstract java.util.OptionalDouble average();
     method public abstract java.util.stream.Stream<java.lang.Long> boxed();
     method public static java.util.stream.LongStream.Builder builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
     method public abstract long count();
     method public abstract java.util.stream.LongStream distinct();
@@ -62839,7 +63002,7 @@
     method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
-    method public abstract java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
     method public abstract java.util.OptionalLong max();
     method public abstract java.util.OptionalLong min();
     method public abstract boolean noneMatch(java.util.function.LongPredicate);
@@ -62866,49 +63029,49 @@
     method public abstract java.util.stream.LongStream build();
   }
 
-  public abstract interface Stream implements java.util.stream.BaseStream {
+  public abstract interface Stream<T> implements java.util.stream.BaseStream {
     method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
     method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream.Builder<T> builder();
-    method public abstract R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
-    method public abstract R collect(java.util.stream.Collector<? super T, A, R>);
-    method public static java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
+    method public static <T> java.util.stream.Stream.Builder<T> builder();
+    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
+    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
+    method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
     method public abstract long count();
     method public abstract java.util.stream.Stream<T> distinct();
-    method public static java.util.stream.Stream<T> empty();
+    method public static <T> java.util.stream.Stream<T> empty();
     method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
     method public abstract java.util.Optional<T> findAny();
     method public abstract java.util.Optional<T> findFirst();
-    method public abstract java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
+    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
     method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
     method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
     method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
     method public abstract void forEach(java.util.function.Consumer<? super T>);
     method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
-    method public static java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
-    method public static java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
+    method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
+    method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
     method public abstract java.util.stream.Stream<T> limit(long);
-    method public abstract java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
+    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
     method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
     method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
     method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
     method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
     method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
     method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
-    method public static java.util.stream.Stream<T> of(T);
-    method public static java.util.stream.Stream<T> of(T...);
+    method public static <T> java.util.stream.Stream<T> of(T);
+    method public static <T> java.util.stream.Stream<T> of(T...);
     method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
     method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
     method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
-    method public abstract U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
+    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
     method public abstract java.util.stream.Stream<T> skip(long);
     method public abstract java.util.stream.Stream<T> sorted();
     method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
     method public abstract java.lang.Object[] toArray();
-    method public abstract A[] toArray(java.util.function.IntFunction<A[]>);
+    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
   }
 
-  public static abstract interface Stream.Builder implements java.util.function.Consumer {
+  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
     method public abstract void accept(T);
     method public default java.util.stream.Stream.Builder<T> add(T);
     method public abstract java.util.stream.Stream<T> build();
@@ -62921,8 +63084,8 @@
     method public static java.util.stream.IntStream intStream(java.util.function.Supplier<? extends java.util.Spliterator.OfInt>, int, boolean);
     method public static java.util.stream.LongStream longStream(java.util.Spliterator.OfLong, boolean);
     method public static java.util.stream.LongStream longStream(java.util.function.Supplier<? extends java.util.Spliterator.OfLong>, int, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
-    method public static java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.Spliterator<T>, boolean);
+    method public static <T> java.util.stream.Stream<T> stream(java.util.function.Supplier<? extends java.util.Spliterator<T>>, int, boolean);
   }
 
 }
@@ -63564,7 +63727,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 +63738,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 +63746,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 +63864,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();
   }
 
@@ -65093,16 +65258,16 @@
   public final class Subject implements java.io.Serializable {
     ctor public Subject();
     ctor public Subject(boolean, java.util.Set<? extends java.security.Principal>, java.util.Set<?>, java.util.Set<?>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
-    method public static T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
-    method public static T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedAction<T>);
+    method public static <T> T doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>) throws java.security.PrivilegedActionException;
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
+    method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
     method public java.util.Set<java.security.Principal> getPrincipals();
-    method public java.util.Set<T> getPrincipals(java.lang.Class<T>);
+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPrivateCredentials();
-    method public java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
     method public java.util.Set<java.lang.Object> getPublicCredentials();
-    method public java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
     method public boolean isReadOnly();
     method public void setReadOnly();
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 94ba452..683a695 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -167,6 +167,13 @@
 
 package android.net {
 
+  public abstract class PskKeyManager {
+    ctor public PskKeyManager();
+    field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+    field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
+  }
+
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
@@ -179,6 +186,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/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d6c0058..3759de2 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,7 +26,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
 import android.app.IActivityContainer;
 import android.app.IActivityController;
 import android.app.IActivityManager;
@@ -46,7 +45,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.ParceledListSlice;
-import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -55,10 +53,11 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -72,6 +71,7 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -96,6 +96,7 @@
     // Amount we reduce the stack size by when testing a task re-size.
     private static final int STACK_BOUNDS_INSET = 10;
 
+    public static final String NO_CLASS_ERROR_CODE = "Error type 3";
     private IActivityManager mAm;
     private IPackageManager mPm;
 
@@ -198,7 +199,7 @@
                 "    --track-allocation: enable tracking of object allocations\n" +
                 "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                 "        specified then run as the current user.\n" +
-                "    --stack <STACK_ID>: Specify into which stack should the activity be put." +
+                "    --stack <STACK_ID>: Specify into which stack should the activity be put.\n" +
                 "\n" +
                 "am startservice: start a Service.  Options are:\n" +
                 "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
@@ -385,17 +386,13 @@
         String op = nextArgRequired();
 
         if (op.equals("start")) {
-            runStart();
+            runAmCmd(getRawArgs());
         } else if (op.equals("startservice")) {
             runStartService();
         } else if (op.equals("stopservice")) {
             runStopService();
-        } else if (op.equals("force-stop")) {
-            runForceStop();
-        } else if (op.equals("kill")) {
-            runKill();
-        } else if (op.equals("kill-all")) {
-            runKillAll();
+        } else if (op.equals("force-stop") || op.equals("kill") || op.equals("kill-all")) {
+            runAmCmd(getRawArgs());
         } else if (op.equals("instrument")) {
             runInstrument();
         } else if (op.equals("trace-ipc")) {
@@ -475,6 +472,49 @@
         return userId;
     }
 
+    static final class MyShellCallback extends ShellCallback {
+        @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+            File file = new File(path);
+            //System.err.println("Opening file: " + file.getAbsolutePath());
+            //Log.i("Am", "Opening file: " + file.getAbsolutePath());
+            final ParcelFileDescriptor fd;
+            try {
+                fd = ParcelFileDescriptor.open(file,
+                        ParcelFileDescriptor.MODE_CREATE |
+                        ParcelFileDescriptor.MODE_TRUNCATE |
+                        ParcelFileDescriptor.MODE_WRITE_ONLY);
+            } catch (FileNotFoundException e) {
+                String msg = "Unable to open file " + path + ": " + e;
+                System.err.println(msg);
+                throw new IllegalArgumentException(msg);
+            }
+            if (seLinuxContext != null) {
+                final String tcon = SELinux.getFileContext(file.getAbsolutePath());
+                if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                    }
+                    String msg = "System server has no access to file context " + tcon;
+                    System.err.println(msg + " (from path " + file.getAbsolutePath()
+                            + ", context " + seLinuxContext + ")");
+                    throw new IllegalArgumentException(msg);
+                }
+            }
+            return fd;
+        }
+    }
+
+    void runAmCmd(String[] args) throws AndroidException {
+        try {
+            mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
+                    args, new MyShellCallback(), new ResultReceiver(null) { });
+        } catch (RemoteException e) {
+            System.err.println(NO_SYSTEM_ERROR_CODE);
+            throw new AndroidException("Can't call activity manager; is the system running?");
+        }
+    }
+
     private Intent makeIntent(int defUser) throws URISyntaxException {
         mStartFlags = 0;
         mWaitOption = false;
@@ -558,211 +598,6 @@
         }
     }
 
-    private void runStart() throws Exception {
-        Intent intent = makeIntent(UserHandle.USER_CURRENT);
-
-        if (mUserId == UserHandle.USER_ALL) {
-            System.err.println("Error: Can't start service with user 'all'");
-            return;
-        }
-
-        String mimeType = intent.getType();
-        if (mimeType == null && intent.getData() != null
-                && "content".equals(intent.getData().getScheme())) {
-            mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);
-        }
-
-
-        do {
-            if (mStopOption) {
-                String packageName;
-                if (intent.getComponent() != null) {
-                    packageName = intent.getComponent().getPackageName();
-                } else {
-                    List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
-                            mUserId).getList();
-                    if (activities == null || activities.size() <= 0) {
-                        System.err.println("Error: Intent does not match any activities: "
-                                + intent);
-                        return;
-                    } else if (activities.size() > 1) {
-                        System.err.println("Error: Intent matches multiple activities; can't stop: "
-                                + intent);
-                        return;
-                    }
-                    packageName = activities.get(0).activityInfo.packageName;
-                }
-                System.out.println("Stopping: " + packageName);
-                mAm.forceStopPackage(packageName, mUserId);
-                Thread.sleep(250);
-            }
-
-            System.out.println("Starting: " + intent);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-            ParcelFileDescriptor fd = null;
-            ProfilerInfo profilerInfo = null;
-
-            if (mProfileFile != null) {
-                try {
-                    fd = openForSystemServer(
-                            new File(mProfileFile),
-                            ParcelFileDescriptor.MODE_CREATE |
-                            ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_WRITE_ONLY);
-                } catch (FileNotFoundException e) {
-                    System.err.println("Error: Unable to open file: " + mProfileFile);
-                    System.err.println("Consider using a file under /data/local/tmp/");
-                    return;
-                }
-                profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop);
-            }
-
-            IActivityManager.WaitResult result = null;
-            int res;
-            final long startTime = SystemClock.uptimeMillis();
-            ActivityOptions options = null;
-            if (mStackId != INVALID_STACK_ID) {
-                options = ActivityOptions.makeBasic();
-                options.setLaunchStackId(mStackId);
-            }
-            if (mWaitOption) {
-                result = mAm.startActivityAndWait(null, null, intent, mimeType,
-                        null, null, 0, mStartFlags, profilerInfo,
-                        options != null ? options.toBundle() : null, mUserId);
-                res = result.result;
-            } else {
-                res = mAm.startActivityAsUser(null, null, intent, mimeType,
-                        null, null, 0, mStartFlags, profilerInfo,
-                        options != null ? options.toBundle() : null, mUserId);
-            }
-            final long endTime = SystemClock.uptimeMillis();
-            PrintStream out = mWaitOption ? System.out : System.err;
-            boolean launched = false;
-            switch (res) {
-                case ActivityManager.START_SUCCESS:
-                    launched = true;
-                    break;
-                case ActivityManager.START_SWITCHES_CANCELED:
-                    launched = true;
-                    out.println(
-                            "Warning: Activity not started because the "
-                            + " current activity is being kept for the user.");
-                    break;
-                case ActivityManager.START_DELIVERED_TO_TOP:
-                    launched = true;
-                    out.println(
-                            "Warning: Activity not started, intent has "
-                            + "been delivered to currently running "
-                            + "top-most instance.");
-                    break;
-                case ActivityManager.START_RETURN_INTENT_TO_CALLER:
-                    launched = true;
-                    out.println(
-                            "Warning: Activity not started because intent "
-                            + "should be handled by the caller");
-                    break;
-                case ActivityManager.START_TASK_TO_FRONT:
-                    launched = true;
-                    out.println(
-                            "Warning: Activity not started, its current "
-                            + "task has been brought to the front");
-                    break;
-                case ActivityManager.START_INTENT_NOT_RESOLVED:
-                    out.println(
-                            "Error: Activity not started, unable to "
-                            + "resolve " + intent.toString());
-                    break;
-                case ActivityManager.START_CLASS_NOT_FOUND:
-                    out.println(NO_CLASS_ERROR_CODE);
-                    out.println("Error: Activity class " +
-                            intent.getComponent().toShortString()
-                            + " does not exist.");
-                    break;
-                case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
-                    out.println(
-                            "Error: Activity not started, you requested to "
-                            + "both forward and receive its result");
-                    break;
-                case ActivityManager.START_PERMISSION_DENIED:
-                    out.println(
-                            "Error: Activity not started, you do not "
-                            + "have permission to access it.");
-                    break;
-                case ActivityManager.START_NOT_VOICE_COMPATIBLE:
-                    out.println(
-                            "Error: Activity not started, voice control not allowed for: "
-                                    + intent);
-                    break;
-                case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:
-                    out.println(
-                            "Error: Not allowed to start background user activity"
-                            + " that shouldn't be displayed for all users.");
-                    break;
-                default:
-                    out.println(
-                            "Error: Activity not started, unknown error code " + res);
-                    break;
-            }
-            if (mWaitOption && launched) {
-                if (result == null) {
-                    result = new IActivityManager.WaitResult();
-                    result.who = intent.getComponent();
-                }
-                System.out.println("Status: " + (result.timeout ? "timeout" : "ok"));
-                if (result.who != null) {
-                    System.out.println("Activity: " + result.who.flattenToShortString());
-                }
-                if (result.thisTime >= 0) {
-                    System.out.println("ThisTime: " + result.thisTime);
-                }
-                if (result.totalTime >= 0) {
-                    System.out.println("TotalTime: " + result.totalTime);
-                }
-                System.out.println("WaitTime: " + (endTime-startTime));
-                System.out.println("Complete");
-            }
-            mRepeat--;
-            if (mRepeat > 0) {
-                mAm.unhandledBack();
-            }
-        } while (mRepeat > 0);
-    }
-
-    private void runForceStop() throws Exception {
-        int userId = UserHandle.USER_ALL;
-
-        String opt;
-        while ((opt=nextOption()) != null) {
-            if (opt.equals("--user")) {
-                userId = parseUserArg(nextArgRequired());
-            } else {
-                System.err.println("Error: Unknown option: " + opt);
-                return;
-            }
-        }
-        mAm.forceStopPackage(nextArgRequired(), userId);
-    }
-
-    private void runKill() throws Exception {
-        int userId = UserHandle.USER_ALL;
-
-        String opt;
-        while ((opt=nextOption()) != null) {
-            if (opt.equals("--user")) {
-                userId = parseUserArg(nextArgRequired());
-            } else {
-                System.err.println("Error: Unknown option: " + opt);
-                return;
-            }
-        }
-        mAm.killBackgroundProcesses(nextArgRequired(), userId);
-    }
-
-    private void runKillAll() throws Exception {
-        mAm.killAllBackgroundProcesses();
-    }
-
     private void sendBroadcast() throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
         IntentReceiver receiver = new IntentReceiver();
@@ -2523,8 +2358,7 @@
                 return;
         }
         if (!mAm.setProcessMemoryTrimLevel(proc, userId, level)) {
-            System.err.println("Error: Failure to set the level - probably Unknown Process: " +
-                               proc);
+            System.err.println("Unknown error: failed to set trim level");
         }
     }
 
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 72a21e3..18ad43e 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>
@@ -186,12 +185,7 @@
 int main(int argc, char* const argv[])
 {
     if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
-        // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
-        // EINVAL. Don't die on such kernels.
-        if (errno != EINVAL) {
-            LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
-            return 12;
-        }
+        LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
     }
 
     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
@@ -310,6 +304,5 @@
         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
         app_usage();
         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
-        return 10;
     }
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index beb550c..3c2efd8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -68,15 +68,25 @@
 static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
 static const char SYSTEM_TIME_DIR_NAME[] = "time";
 static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
+static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
+static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
 static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
 static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
 static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
 static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
 // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
 static const long long ACCURATE_TIME_EPOCH = 946684800000;
+static constexpr char FONT_BEGIN_CHAR = ' ';
+static constexpr char FONT_END_CHAR = '~' + 1;
+static constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1;
+static constexpr size_t FONT_NUM_COLS = 16;
+static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS;
+static const int TEXT_CENTER_VALUE = INT_MAX;
+static const int TEXT_MISSING_VALUE = INT_MIN;
 static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
 static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
 static const int ANIM_ENTRY_NAME_MAX = 256;
+static constexpr size_t TEXT_POS_LEN_MAX = 16;
 static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
 static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
 // bootreasons list in "system/core/bootstat/bootstat.cpp".
@@ -177,23 +187,22 @@
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
     return NO_ERROR;
 }
 
-status_t BootAnimation::initTexture(const Animation::Frame& frame)
+status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
 {
-    //StopWatch watch("blah");
-
     SkBitmap bitmap;
-    sk_sp<SkData> data = SkData::MakeWithoutCopy(frame.map->getDataPtr(),
-            frame.map->getDataLength());
+    sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(),
+            map->getDataLength());
     sk_sp<SkImage> image = SkImage::MakeFromEncoded(data);
     image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode);
 
     // FileMap memory is never released until application exit.
     // Release it now as the texture is already loaded and the memory used for
     // the packed resource can be released.
-    delete frame.map;
+    delete map;
 
     // ensure we can call getPixels(). No need to call unlock, since the
     // bitmap will go out of scope when we return from this method.
@@ -239,6 +248,9 @@
 
     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
 
+    *width = w;
+    *height = h;
+
     return NO_ERROR;
 }
 
@@ -402,7 +414,6 @@
     return false;
 }
 
-
 void BootAnimation::checkExit() {
     // Allow surface flinger to gracefully request shutdown
     char value[PROPERTY_VALUE_MAX];
@@ -413,6 +424,47 @@
     }
 }
 
+bool BootAnimation::validClock(const Animation::Part& part) {
+    return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE;
+}
+
+bool parseTextCoord(const char* str, int* dest) {
+    if (strcmp("c", str) == 0) {
+        *dest = TEXT_CENTER_VALUE;
+        return true;
+    }
+
+    char* end;
+    int val = (int) strtol(str, &end, 0);
+    if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) {
+        return false;
+    }
+    *dest = val;
+    return true;
+}
+
+// Parse two position coordinates. If only string is non-empty, treat it as the y value.
+void parsePosition(const char* str1, const char* str2, int* x, int* y) {
+    bool success = false;
+    if (strlen(str1) == 0) {  // No values were specified
+        // success = false
+    } else if (strlen(str2) == 0) {  // we have only one value
+        if (parseTextCoord(str1, y)) {
+            *x = TEXT_CENTER_VALUE;
+            success = true;
+        }
+    } else {
+        if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) {
+            success = true;
+        }
+    }
+
+    if (!success) {
+        *x = TEXT_MISSING_VALUE;
+        *y = TEXT_MISSING_VALUE;
+    }
+}
+
 // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
 // characters in str is a hex number in [0, 255], which are converted to
 // floating point values in the range [0.0, 1.0] and placed in the
@@ -459,24 +511,87 @@
     return true;
 }
 
-// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
-// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
-// We render 24 hour time.
-void BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
-    static constexpr char TIME_FORMAT[] = "%H:%M";
-    static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
+// The font image should be a 96x2 array of character images.  The
+// columns are the printable ASCII characters 0x20 - 0x7f.  The
+// top row is regular text; the bottom row is bold.
+status_t BootAnimation::initFont(Font* font, const char* fallback) {
+    status_t status = NO_ERROR;
 
-    static constexpr int DIGIT_HEIGHT = 64;
-    static constexpr int DIGIT_WIDTH = 40;
-    static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
-    static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
+    if (font->map != nullptr) {
+        glGenTextures(1, &font->texture.name);
+        glBindTexture(GL_TEXTURE_2D, font->texture.name);
 
-    if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
-        ALOGE("Clock texture is too small; abandoning boot animation clock");
-        mClockEnabled = false;
-        return;
+        status = initTexture(font->map, &font->texture.w, &font->texture.h);
+
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    } else if (fallback != nullptr) {
+        status = initTexture(&font->texture, mAssets, fallback);
+    } else {
+        return NO_INIT;
     }
 
+    if (status == NO_ERROR) {
+        font->char_width = font->texture.w / FONT_NUM_COLS;
+        font->char_height = font->texture.h / FONT_NUM_ROWS / 2;  // There are bold and regular rows
+    }
+
+    return status;
+}
+
+void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
+    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
+    glBindTexture(GL_TEXTURE_2D, font.texture.name);
+
+    const int len = strlen(str);
+    const int strWidth = font.char_width * len;
+
+    if (*x == TEXT_CENTER_VALUE) {
+        *x = (mWidth - strWidth) / 2;
+    } else if (*x < 0) {
+        *x = mWidth + *x - strWidth;
+    }
+    if (*y == TEXT_CENTER_VALUE) {
+        *y = (mHeight - font.char_height) / 2;
+    } else if (*y < 0) {
+        *y = mHeight + *y - font.char_height;
+    }
+
+    int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
+
+    for (int i = 0; i < len; i++) {
+        char c = str[i];
+
+        if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) {
+            c = '?';
+        }
+
+        // Crop the texture to only the pixels in the current glyph
+        const int charPos = (c - FONT_BEGIN_CHAR);  // Position in the list of valid characters
+        const int row = charPos / FONT_NUM_COLS;
+        const int col = charPos % FONT_NUM_COLS;
+        cropRect[0] = col * font.char_width;  // Left of column
+        cropRect[1] = row * font.char_height * 2; // Top of row
+        // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
+        cropRect[1] += bold ? 2 * font.char_height : font.char_height;
+        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+        glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
+
+        *x += font.char_width;
+    }
+
+    glDisable(GL_BLEND);  // Return to the animation's default behaviour
+    glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+// We render 24 hour time.
+void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
+    static constexpr char TIME_FORMAT[] = "%H:%M";
+    static constexpr int TIME_LENGTH = 6;
+
     time_t rawtime;
     time(&rawtime);
     struct tm* timeInfo = localtime(&rawtime);
@@ -490,36 +605,9 @@
         return;
     }
 
-    glEnable(GL_BLEND);  // Allow us to draw on top of the animation
-    glBindTexture(GL_TEXTURE_2D, clockTex.name);
-
-    int xPos = (mWidth - TIME_WIDTH) / 2;
-    int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
-
-    for (int i = 0; i < TIME_LENGTH - 1; i++) {
-        char c = timeBuff[i];
-        int width = DIGIT_WIDTH;
-        int pos = c - '0';  // Position in the character list
-        if (pos < 0 || pos > 10) {
-            continue;
-        }
-        if (c == ':') {
-            width = COLON_WIDTH;
-        }
-
-        // Crop the texture to only the pixels in the current glyph
-        int left = pos * DIGIT_WIDTH;
-        cropRect[0] = left;
-        cropRect[2] = width;
-        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
-
-        glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
-
-        xPos += width;
-    }
-
-    glDisable(GL_BLEND);  // Return to the animation's default behaviour
-    glBindTexture(GL_TEXTURE_2D, 0);
+    int x = xPos;
+    int y = yPos;
+    drawText(timeBuff, font, false, &x, &y);
 }
 
 bool BootAnimation::parseAnimationDesc(Animation& animation)
@@ -542,9 +630,10 @@
         int height = 0;
         int count = 0;
         int pause = 0;
-        int clockPosY = -1;
         char path[ANIM_ENTRY_NAME_MAX];
         char color[7] = "000000"; // default to black if unspecified
+        char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
+        char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
 
         char pathType;
         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
@@ -552,15 +641,15 @@
             animation.width = width;
             animation.height = height;
             animation.fps = fps;
-        } else if (sscanf(l, " %c %d %d %s #%6s %d",
-                          &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
-            // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
+        } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
+                          &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
+            //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
+            //    pathType, count, pause, path, color, clockPos1, clockPos2);
             Animation::Part part;
             part.playUntilComplete = pathType == 'c';
             part.count = count;
             part.pause = pause;
             part.path = path;
-            part.clockPosY = clockPosY;
             part.audioData = NULL;
             part.animation = NULL;
             if (!parseColor(color, part.backgroundColor)) {
@@ -569,6 +658,7 @@
                 part.backgroundColor[1] = 0.0f;
                 part.backgroundColor[2] = 0.0f;
             }
+            parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY);
             animation.parts.add(part);
         }
         else if (strcmp(l, "$SYSTEM") == 0) {
@@ -612,6 +702,14 @@
         const String8 path(entryName.getPathDir());
         const String8 leaf(entryName.getPathLeaf());
         if (leaf.size() > 0) {
+            if (entryName == CLOCK_FONT_ZIP_NAME) {
+                FileMap* map = zip->createEntryFileMap(entry);
+                if (map) {
+                    animation.clockFont.map = map;
+                }
+                continue;
+            }
+
             for (size_t j = 0; j < pcount; j++) {
                 if (path == animation.parts[j].path) {
                     uint16_t method;
@@ -696,7 +794,7 @@
 
     bool anyPartHasClock = false;
     for (size_t i=0; i < animation->parts.size(); i++) {
-        if(animation->parts[i].clockPosY >= 0) {
+        if(validClock(animation->parts[i])) {
             anyPartHasClock = true;
             break;
         }
@@ -734,10 +832,11 @@
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
-    bool clockTextureInitialized = false;
+    bool clockFontInitialized = false;
     if (mClockEnabled) {
-        clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
-        mClockEnabled = clockTextureInitialized;
+        clockFontInitialized =
+            (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
+        mClockEnabled = clockFontInitialized;
     }
 
     if (mClockEnabled && !updateIsTimeAccurate()) {
@@ -754,8 +853,8 @@
 
     releaseAnimation(animation);
 
-    if (clockTextureInitialized) {
-        glDeleteTextures(1, &mClock.name);
+    if (clockFontInitialized) {
+        glDeleteTextures(1, &animation->clockFont.texture.name);
     }
 
     return false;
@@ -811,7 +910,8 @@
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                     }
-                    initTexture(frame);
+                    int w, h;
+                    initTexture(frame.map, &w, &h);
                 }
 
                 const int xc = animationX + frame.trimX;
@@ -833,8 +933,8 @@
                 // which is equivalent to mHeight - (yc + frame.trimHeight)
                 glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
                               0, frame.trimWidth, frame.trimHeight);
-                if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
-                    drawTime(mClock, part.clockPosY);
+                if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
+                    drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
                 }
 
                 eglSwapBuffers(mDisplay, mSurface);
@@ -913,6 +1013,7 @@
     Animation *animation =  new Animation;
     animation->fileName = fn;
     animation->zip = zip;
+    animation->clockFont.map = nullptr;
     mLoadedFiles.add(animation->fileName);
 
     parseAnimationDesc(*animation);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index fd497a3..42759f1 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -74,6 +74,13 @@
         GLuint  name;
     };
 
+    struct Font {
+        FileMap* map;
+        Texture texture;
+        int char_width;
+        int char_height;
+    };
+
     struct Animation {
         struct Frame {
             String8 name;
@@ -90,8 +97,12 @@
         struct Part {
             int count;  // The number of times this part should repeat, 0 for infinite
             int pause;  // The number of frames to pause for at the end of this part
-            int clockPosY;  // The y position of the clock, in pixels, from the bottom of the
-                            // display (the clock is centred horizontally). -1 to disable the clock
+            int clockPosX;  // The x position of the clock, in pixels. Positive values offset from
+                            // the left of the screen, negative values offset from the right.
+            int clockPosY;  // The y position of the clock, in pixels. Positive values offset from
+                            // the bottom of the screen, negative values offset from the top.
+                            // If either of the above are INT_MIN the clock is disabled, if INT_MAX
+                            // the clock is centred on that axis.
             String8 path;
             String8 trimData;
             SortedVector<Frame> frames;
@@ -108,13 +119,17 @@
         String8 audioConf;
         String8 fileName;
         ZipFileRO* zip;
+        Font clockFont;
     };
 
     status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
-    status_t initTexture(const Animation::Frame& frame);
+    status_t initTexture(FileMap* map, int* width, int* height);
+    status_t initFont(Font* font, const char* fallback);
     bool android();
     bool movie();
-    void drawTime(const Texture& clockTex, const int yPos);
+    void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
+    void drawClock(const Font& font, const int xPos, const int yPos);
+    bool validClock(const Animation::Part& part);
     Animation* loadAnimation(const String8&);
     bool playAnimation(const Animation&);
     void releaseAnimation(Animation*) const;
@@ -127,7 +142,6 @@
     sp<SurfaceComposerClient>       mSession;
     AssetManager mAssets;
     Texture     mAndroid[2];
-    Texture     mClock;
     int         mWidth;
     int         mHeight;
     bool        mUseNpotTextures = false;
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
index 4983b9a..c546072 100644
--- a/cmds/bootanimation/audioplay.cpp
+++ b/cmds/bootanimation/audioplay.cpp
@@ -141,13 +141,27 @@
     // configure audio source
     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
 
+    // Determine channelMask from num_channels
+    SLuint32 channelMask;
+    switch (chunkFormat->num_channels) {
+        case 1:
+            channelMask = SL_SPEAKER_FRONT_CENTER;
+            break;
+        case 2:
+            channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+            break;
+        default:
+            // Default of 0 will derive mask from num_channels and log a warning.
+            channelMask = 0;
+    }
+
     SLDataFormat_PCM format_pcm = {
         SL_DATAFORMAT_PCM,
         chunkFormat->num_channels,
         chunkFormat->sample_rate * 1000,  // convert to milliHz
         chunkFormat->bits_per_sample,
         16,
-        SL_SPEAKER_FRONT_CENTER,
+        channelMask,
         SL_BYTEORDER_LITTLEENDIAN
     };
     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index d43b8c5..c7474a11 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -72,59 +72,64 @@
 public class Content {
 
     private static final String USAGE =
-        "usage: adb shell content [subcommand] [options]\n"
-        + "\n"
-        + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
-                + " --bind <BINDING> [--bind <BINDING>...]\n"
-        + "  <URI> a content provider URI.\n"
-        + "  <BINDING> binds a typed value to a column and is formatted:\n"
-        + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
-        + "  <TYPE> specifies data type such as:\n"
-        + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
-        + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
-        + "  Example:\n"
-        + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
-        + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
-                + " --bind value:s:new_value\n"
-        + "\n"
-        + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
-        + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
-                + " - see example below).\n"
-        + "  Example:\n"
-        + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
-        + "  adb shell content update --uri content://settings/secure --bind"
-                + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
-        + "\n"
-        + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
-                + " [--bind <BINDING>...] [--where <WHERE>]\n"
-        + "  Example:\n"
-        + "  # Remove \"new_setting\" secure setting.\n"
-        + "  adb shell content delete --uri content://settings/secure "
-                + "--where \"name=\'new_setting\'\"\n"
-        + "\n"
-        + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
-                + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
-        + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
-        + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
-        + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
-        + "  Example:\n"
-        + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
-                + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
-        + "  adb shell content query --uri content://settings/secure --projection name:value"
-                + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
-        + "\n"
-        + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n"
-        + "       [--extra <BINDING> ...]\n"
-        + "  <METHOD> is the name of a provider-defined method\n"
-        + "  <ARG> is an optional string argument\n"
-        + "  <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
-        + "\n"
-        + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
-        + "  Example:\n"
-        + "  # cat default ringtone to a file, then pull to host\n"
-        + "  adb shell 'content read --uri content://settings/system/ringtone >"
-                + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
-        + "\n";
+            "usage: adb shell content [subcommand] [options]\n"
+                    + "\n"
+                    + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
+                    + " --bind <BINDING> [--bind <BINDING>...]\n"
+                    + "  <URI> a content provider URI.\n"
+                    + "  <BINDING> binds a typed value to a column and is formatted:\n"
+                    + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
+                    + "  <TYPE> specifies data type such as:\n"
+                    + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
+                    + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
+                    + "  Example:\n"
+                    + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
+                    + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+                    + " --bind value:s:new_value\n"
+                    + "\n"
+                    + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+                    + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+                    + " - see example below).\n"
+                    + "  Example:\n"
+                    + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
+                    + "  adb shell content update --uri content://settings/secure --bind"
+                    + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+                    + "\n"
+                    + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
+                    + " [--bind <BINDING>...] [--where <WHERE>]\n"
+                    + "  Example:\n"
+                    + "  # Remove \"new_setting\" secure setting.\n"
+                    + "  adb shell content delete --uri content://settings/secure "
+                    + "--where \"name=\'new_setting\'\"\n"
+                    + "\n"
+                    + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
+                    + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+                    + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
+                    + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+                    + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
+                    + "  Example:\n"
+                    + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
+                    + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
+                    + "  adb shell content query --uri content://settings/secure --projection name:value"
+                    + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
+                    + "\n"
+                    + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n"
+                    + "       [--extra <BINDING> ...]\n"
+                    + "  <METHOD> is the name of a provider-defined method\n"
+                    + "  <ARG> is an optional string argument\n"
+                    + "  <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
+                    + "\n"
+                    + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
+                    + "  Example:\n"
+                    + "  # cat default ringtone to a file, then pull to host\n"
+                    + "  adb shell 'content read --uri content://settings/system/ringtone >"
+                    + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
+                    + "\n"
+                    + "usage: adb shell content gettype --uri <URI> [--user <USER_ID>]\n"
+                    + "  Example:\n"
+                    + "  # Show the mime-type of the URI\n"
+                    + "  adb shell content gettype --uri content://media/internal/audio/media/\n"
+                    + "\n";
 
     private static class Parser {
         private static final String ARGUMENT_INSERT = "insert";
@@ -133,6 +138,7 @@
         private static final String ARGUMENT_QUERY = "query";
         private static final String ARGUMENT_CALL = "call";
         private static final String ARGUMENT_READ = "read";
+        private static final String ARGUMENT_GET_TYPE = "gettype";
         private static final String ARGUMENT_WHERE = "--where";
         private static final String ARGUMENT_BIND = "--bind";
         private static final String ARGUMENT_URI = "--uri";
@@ -172,6 +178,8 @@
                     return parseCallCommand();
                 } else if (ARGUMENT_READ.equals(operation)) {
                     return parseReadCommand();
+                } else if (ARGUMENT_GET_TYPE.equals(operation)) {
+                    return parseGetTypeCommand();
                 } else {
                     throw new IllegalArgumentException("Unsupported operation: " + operation);
                 }
@@ -291,6 +299,26 @@
             return new CallCommand(uri, userId, method, arg, values);
         }
 
+        private GetTypeCommand parseGetTypeCommand() {
+            Uri uri = null;
+            int userId = UserHandle.USER_SYSTEM;
+
+            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_USER.equals(argument)) {
+                    userId = Integer.parseInt(argumentValueRequired(argument));
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            return new GetTypeCommand(uri, userId);
+        }
+
         private ReadCommand parseReadCommand() {
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
@@ -511,6 +539,18 @@
         }
     }
 
+    private static class GetTypeCommand extends Command {
+        public GetTypeCommand(Uri uri, int userId) {
+            super(uri, userId);
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            String type = provider.getType(mUri);
+            System.out.println("Result: " + type);
+        }
+    }
+
     private static class ReadCommand extends Command {
         public ReadCommand(Uri uri, int userId) {
             super(uri, userId);
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 754d3f5..9ee11f8 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -23,6 +23,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -118,6 +119,19 @@
                                 duration);
                         return;
                 }
+            } else if (command.equals("draganddrop")) {
+                int duration = -1;
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+                switch (length) {
+                    case 6:
+                        duration = Integer.parseInt(args[index+5]);
+                    case 5:
+                        sendDragAndDrop(inputSource,
+                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
+                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
+                                duration);
+                        return;
+                }
             } else if (command.equals("press")) {
                 inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
                 if (length == 1) {
@@ -216,6 +230,31 @@
         injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
     }
 
+    private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2,
+            int dragDuration) {
+        if (dragDuration < 0) {
+            dragDuration = 300;
+        }
+        long now = SystemClock.uptimeMillis();
+        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
+        try {
+            Thread.sleep(ViewConfiguration.getLongPressTimeout());
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        now = SystemClock.uptimeMillis();
+        long startTime = now;
+        long endTime = startTime + dragDuration;
+        while (now < endTime) {
+            long elapsedTime = now - startTime;
+            float alpha = (float) elapsedTime / dragDuration;
+            injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
+                    lerp(y1, y2, alpha), 1.0f);
+            now = SystemClock.uptimeMillis();
+        }
+        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
+    }
+
     /**
      * Sends a simple zero-pressure move event.
      *
@@ -294,6 +333,8 @@
         System.err.println("      tap <x> <y> (Default: touchscreen)");
         System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
                 + " (Default: touchscreen)");
+        System.err.println("      draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
+                + " (Default: touchscreen)");
         System.err.println("      press (Default: trackball)");
         System.err.println("      roll <dx> <dy> (Default: trackball)");
     }
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 2e9d0d6..0e0ecd0 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -230,8 +230,8 @@
         }
 
         @Override
-        public void onShuffleModeChanged(boolean shuffleMode) throws RemoteException {
-            System.out.println("onShuffleModeChanged " + shuffleMode);
+        public void onShuffleModeChanged(boolean enabled) throws RemoteException {
+            System.out.println("onShuffleModeChanged " + enabled);
         }
 
         void printUsageMessage() {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 32a8088..ace4e32 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -49,9 +49,12 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IUserManager;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -68,6 +71,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -284,13 +288,45 @@
         }
     }
 
+    static final class MyShellCallback extends ShellCallback {
+        @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+            File file = new File(path);
+            final ParcelFileDescriptor fd;
+            try {
+                fd = ParcelFileDescriptor.open(file,
+                            ParcelFileDescriptor.MODE_CREATE |
+                            ParcelFileDescriptor.MODE_TRUNCATE |
+                            ParcelFileDescriptor.MODE_WRITE_ONLY);
+            } catch (FileNotFoundException e) {
+                String msg = "Unable to open file " + path + ": " + e;
+                System.err.println(msg);
+                throw new IllegalArgumentException(msg);
+            }
+            if (seLinuxContext != null) {
+                final String tcon = SELinux.getFileContext(file.getAbsolutePath());
+                if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                    }
+                    String msg = "System server has no access to file context " + tcon;
+                    System.err.println(msg + " (from path " + file.getAbsolutePath()
+                            + ", context " + seLinuxContext + ")");
+                    throw new IllegalArgumentException(msg);
+                }
+            }
+            return fd;
+        }
+    }
+
     private int runShellCommand(String serviceName, String[] args) {
         final HandlerThread handlerThread = new HandlerThread("results");
         handlerThread.start();
         try {
             ServiceManager.getService(serviceName).shellCommand(
                     FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
-                    args, new ResultReceiver(new Handler(handlerThread.getLooper())));
+                    args, new MyShellCallback(),
+                    new ResultReceiver(new Handler(handlerThread.getLooper())));
             return 0;
         } catch (RemoteException e) {
             e.printStackTrace();
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index f7f7c88..84fb626 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -21,15 +21,22 @@
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
+import android.system.Os;
 import android.view.Display;
 import android.view.IWindowManager;
 import com.android.internal.os.BaseCommand;
 
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.DataInputStream;
 import java.io.PrintStream;
+import java.lang.Runtime;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -68,7 +75,9 @@
                 "wm screen-capture: enable/disable screen capture.\n" +
                 "\n" +
                 "wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if " +
-                "necessary.\n"
+                "necessary.\n" +
+                "\n" +
+                "wm surface-trace: log surface commands to stdout in a binary format.\n"
                 );
     }
 
@@ -95,12 +104,29 @@
             runSetScreenCapture();
         } else if (op.equals("dismiss-keyguard")) {
             runDismissKeyguard();
+        } else if (op.equals("surface-trace")) {
+            runSurfaceTrace();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
         }
     }
 
+    private void runSurfaceTrace() throws Exception {
+        ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(FileDescriptor.out);
+        mWm.enableSurfaceTrace(pfd);
+
+        try {
+            // No one is going to wake us up, we are just waiting on SIGINT. Otherwise
+            // the WM can happily continue writing to our stdout.
+            synchronized (this) {
+                this.wait();
+            }
+        } finally {
+            mWm.disableSurfaceTrace();
+        }
+    }
+
     private void runSetScreenCapture() throws Exception {
         String userIdStr = nextArg();
         String enableStr = nextArg();
@@ -201,9 +227,11 @@
         try {
             if (density > 0) {
                 // TODO(multidisplay): For now Configuration only applies to main screen.
-                mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
+                mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+                        UserHandle.USER_CURRENT);
             } else {
-                mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+                mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+                        UserHandle.USER_CURRENT);
             }
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index c4eaccc..163e7d2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -53,7 +53,7 @@
 import java.util.List;
 
 /**
- * Accessibility services are intended to assist users with disabilities in using
+ * Accessibility services should only be used to assist users with disabilities in using
  * Android devices and apps. They run in the background and receive callbacks by the system
  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
  * in the user interface, for example, the focus has changed, a button has been clicked,
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 7b83a30..b6e85f1 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -16,9 +16,19 @@
 
 package android.accounts;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Set;
 
 /**
  * Value type that represents an Account in the {@link AccountManager}. This object is
@@ -26,8 +36,14 @@
  * suitable for use as the key of a {@link java.util.Map}
  */
 public class Account implements Parcelable {
+    private static final String TAG = "Account";
+
+    @GuardedBy("sAccessedAccounts")
+    private static final Set<Account> sAccessedAccounts = new ArraySet<>();
+
     public final String name;
     public final String type;
+    private final @Nullable String accessId;
 
     public boolean equals(Object o) {
         if (o == this) return true;
@@ -44,6 +60,20 @@
     }
 
     public Account(String name, String type) {
+        this(name, type, null);
+    }
+
+    /**
+     * @hide
+     */
+    public Account(@NonNull Account other, @NonNull String accessId) {
+        this(other.name, other.type, accessId);
+    }
+
+    /**
+     * @hide
+     */
+    public Account(String name, String type, String accessId) {
         if (TextUtils.isEmpty(name)) {
             throw new IllegalArgumentException("the name must not be empty: " + name);
         }
@@ -52,11 +82,31 @@
         }
         this.name = name;
         this.type = type;
+        this.accessId = accessId;
     }
 
     public Account(Parcel in) {
         this.name = in.readString();
         this.type = in.readString();
+        this.accessId = in.readString();
+        if (accessId != null) {
+            synchronized (sAccessedAccounts) {
+                if (sAccessedAccounts.add(this)) {
+                    try {
+                        IAccountManager accountManager = IAccountManager.Stub.asInterface(
+                                ServiceManager.getService(Context.ACCOUNT_SERVICE));
+                        accountManager.onAccountAccessed(accessId);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error noting account access", e);
+                    }
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public String getAccessId() {
+        return accessId;
     }
 
     public int describeContents() {
@@ -66,6 +116,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(name);
         dest.writeString(type);
+        dest.writeString(accessId);
     }
 
     public static final Creator<Account> CREATOR = new Creator<Account>() {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 59d2f18..1ad43fa 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -28,6 +28,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;
@@ -178,6 +179,14 @@
     public static final String KEY_ACCOUNT_TYPE = "accountType";
 
     /**
+     * Bundle key used for the account access id used for noting the
+     * account was accessed when unmarshaled from a parcel.
+     *
+     * @hide
+     */
+    public static final String KEY_ACCOUNT_ACCESS_ID = "accountAccessId";
+
+    /**
      * Bundle key used for the auth token value in results
      * from {@link #getAuthToken} and friends.
      */
@@ -261,6 +270,15 @@
             "android.accounts.AccountAuthenticator";
     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
 
+    /**
+     * Token type for the special case where a UID has access only to an account
+     * but no authenticator specific auth token types.
+     *
+     * @hide
+     */
+    public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
+            "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
+
     private final Context mContext;
     private final IAccountManager mService;
     private final Handler mMainHandler;
@@ -908,7 +926,8 @@
             public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
                 String name = bundle.getString(KEY_ACCOUNT_NAME);
                 String type = bundle.getString(KEY_ACCOUNT_TYPE);
-                return new Account(name, type);
+                String accessId = bundle.getString(KEY_ACCOUNT_ACCESS_ID);
+                return new Account(name, type, accessId);
             }
         }.start();
     }
@@ -2368,6 +2387,7 @@
                                     result.putString(KEY_ACCOUNT_NAME, null);
                                     result.putString(KEY_ACCOUNT_TYPE, null);
                                     result.putString(KEY_AUTHTOKEN, null);
+                                    result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
                                     try {
                                         mResponse.onResult(result);
                                     } catch (RemoteException e) {
@@ -2393,9 +2413,11 @@
                                         public void onResult(Bundle value) throws RemoteException {
                                             Account account = new Account(
                                                     value.getString(KEY_ACCOUNT_NAME),
-                                                    value.getString(KEY_ACCOUNT_TYPE));
-                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
-                                                    mActivity, mMyCallback, mHandler);
+                                                    value.getString(KEY_ACCOUNT_TYPE),
+                                                    value.getString(KEY_ACCOUNT_ACCESS_ID));
+                                            mFuture = getAuthToken(account, mAuthTokenType,
+                                                    mLoginOptions,  mActivity, mMyCallback,
+                                                    mHandler);
                                         }
 
                                         @Override
@@ -2442,7 +2464,8 @@
                         setException(new AuthenticatorException("account not in result"));
                         return;
                     }
-                    final Account account = new Account(accountName, accountType);
+                    final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
+                    final Account account = new Account(accountName, accountType, accessId);
                     mNumAccounts = 1;
                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
                             mMyCallback, mHandler);
@@ -2785,8 +2808,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 +2893,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 +3082,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..68c17c3
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -0,0 +1,90 @@
+/*
+ * 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 {
+
+    /**
+     * Listener for explicit UID account access grant changes.
+     */
+    public interface OnAppPermissionChangeListener {
+
+        /**
+         * Called when the explicit grant state for a given UID to
+         * access an account changes.
+         *
+         * @param account The account
+         * @param uid The UID for which the grant changed
+         */
+        public void onAppPermissionChanged(Account account, int uid);
+    }
+
+    /**
+     * 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);
+
+    /**
+     * Check whether the given UID has access to the account.
+     *
+     * @param account The account
+     * @param uid The UID
+     * @return Whether the UID can access the account
+     */
+    public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
+
+    /**
+     * Adds a listener for explicit UID account access grant changes.
+     *
+     * @param listener The listener
+     */
+    public abstract void addOnAppPermissionChangeListener(
+            @NonNull OnAppPermissionChangeListener listener);
+
+    /**
+     * Backups the account access permissions.
+     * @param userId The user for which to backup.
+     * @return The backup data.
+     */
+    public abstract byte[] backupAccountAccessPermissions(int userId);
+
+    /**
+     * Restores the account access permissions.
+     * @param data The restore data.
+     * @param userId The user for which to restore.
+     */
+    public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
+}
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 133df2b..aed7a36 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -399,7 +399,7 @@
      * useless.
      */
     private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {
-        setTheme(R.style.Theme_Material_Light_Dialog_NoActionBar);
+        setTheme(R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
         super.onCreate(savedInstanceState);
     }
 
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 12b2b9c..38eab29 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_TYPE.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..fc10990 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,12 @@
     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);
+
+    void onAccountAccessed(String token);
 }
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/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index cdd72be..5a23fdd 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -62,7 +62,11 @@
  * layout will run (closing the gap created in the layout when the item was removed). If this
  * default choreography behavior is not desired, the {@link #setDuration(int, long)} and
  * {@link #setStartDelay(int, long)} of any or all of the animations can be changed as
- * appropriate.</p>
+ * appropriate. Keep in mind, however, that if you start an APPEARING animation before a
+ * DISAPPEARING animation is completed, the DISAPPEARING animation stops, and any effects from
+ * the DISAPPEARING animation are reverted. If you instead start a DISAPPEARING animation
+ * before an APPEARING animation is completed, a similar set of effects occurs for the
+ * APPEARING animation.</p>
  *
  * <p>The animations specified for the transition, both the defaults and any custom animations
  * set on the transition object, are templates only. That is, these animations exist to hold the
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 9a2aa30..0c21c4f 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -977,8 +977,9 @@
     @Override
     void animateValue(float fraction) {
         final Object target = getTarget();
-        if (target == null) {
-            // We lost the target reference, cancel and clean up.
+        if (mTarget != null && target == null) {
+            // We lost the target reference, cancel and clean up. Note: we allow null target if the
+            /// target has never been set.
             cancel();
             return;
         }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f93a1d8..a09c920 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -261,6 +262,7 @@
     /**
      * @hide
      */
+    @TestApi
     public static void setDurationScale(float durationScale) {
         sDurationScale = durationScale;
     }
@@ -268,6 +270,7 @@
     /**
      * @hide
      */
+    @TestApi
     public static float getDurationScale() {
         return sDurationScale;
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5f8350f..cb3eba6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -176,11 +176,11 @@
  * part of the platform's application model. For a detailed perspective on the structure of an
  * Android application and how activities behave, please read the
  * <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> and
- * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
+ * <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a>
  * developer guides.</p>
  *
  * <p>You can also find a detailed discussion about how to create activities in the
- * <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>
+ * <a href="{@docRoot}guide/components/activities.html">Activities</a>
  * developer guide.</p>
  * </div>
  *
@@ -3363,7 +3363,7 @@
      * should override the method {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}
      * to supply those arguments.</p>
      *
-     * <p>See <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
+     * <p>See <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a>
      * from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
      * from the design guide for more information about navigating within your app.</p>
      *
@@ -4483,7 +4483,7 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see {@link #startActivity(Intent, Bundle)}
+     * @see #startActivity(Intent, Bundle)
      * @see #startActivityForResult
      */
     @Override
@@ -4510,7 +4510,7 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see {@link #startActivity(Intent)}
+     * @see #startActivity(Intent)
      * @see #startActivityForResult
      */
     @Override
@@ -4532,7 +4532,7 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see {@link #startActivities(Intent[], Bundle)}
+     * @see #startActivities(Intent[], Bundle)
      * @see #startActivityForResult
      */
     @Override
@@ -4559,7 +4559,7 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see {@link #startActivities(Intent[])}
+     * @see #startActivities(Intent[])
      * @see #startActivityForResult
      */
     @Override
@@ -4941,7 +4941,7 @@
      * <p>As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN} an alternative
      * to using this with starting activities is to supply the desired animation
      * information through a {@link ActivityOptions} bundle to
-     * {@link #startActivity(Intent, Bundle) or a related function.  This allows
+     * {@link #startActivity(Intent, Bundle)} or a related function.  This allows
      * you to specify a custom animation even when starting an activity from
      * outside the context of the current top activity.
      *
@@ -6129,7 +6129,6 @@
      *      the return value must be checked.
      *
      * @see #onVisibleBehindCanceled()
-     * @see #onBackgroundVisibleBehindChanged(boolean)
      */
     public boolean requestVisibleBehind(boolean visible) {
         if (!mResumed) {
@@ -6157,7 +6156,6 @@
      * process. Otherwise {@link #onStop()} will be called following return.
      *
      * @see #requestVisibleBehind(boolean)
-     * @see #onBackgroundVisibleBehindChanged(boolean)
      */
     @CallSuper
     public void onVisibleBehindCanceled() {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 419f723..0d9be5f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -32,6 +32,7 @@
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.RoSystemProperties;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
 
@@ -716,6 +717,11 @@
         public static boolean hasMovementAnimations(int stackId) {
             return stackId != PINNED_STACK_ID;
         }
+
+        /** Returns true if the input stack and its content can affect the device orientation. */
+        public static boolean canSpecifyOrientation(int stackId) {
+            return stackId == HOME_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID;
+        }
     }
 
     /**
@@ -895,7 +901,7 @@
 
     /** @hide */
     public static boolean isLowRamDeviceStatic() {
-        return "true".equals(SystemProperties.get("ro.config.low_ram", "false"));
+        return RoSystemProperties.CONFIG_LOW_RAM;
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c7f19a2..f798512 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -3025,6 +3025,14 @@
             reply.writeNoException();
             return true;
         }
+        case CAN_BYPASS_WORK_CHALLENGE: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
+            final boolean result = canBypassWorkChallenge(intent);
+            reply.writeNoException();
+            reply.writeInt(result ? 1 : 0);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3234,7 +3242,7 @@
             data.writeInt(0);
         }
         data.writeInt(userId);
-        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
+        mRemote.transact(START_ACTIVITY_WITH_CONFIG_TRANSACTION, data, reply, 0);
         reply.readException();
         int result = reply.readInt();
         reply.recycle();
@@ -5600,7 +5608,7 @@
         data.writeInt(mode);
         data.writeInt(sourceUserId);
         data.writeInt(targetUserId);
-        mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        mRemote.transact(GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5620,7 +5628,7 @@
         }
         data.writeInt(mode);
         data.writeInt(userId);
-        mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
+        mRemote.transact(REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -7109,6 +7117,20 @@
         reply.recycle();
         return;
     }
+    @Override
+    public boolean canBypassWorkChallenge(PendingIntent intent)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        intent.writeToParcel(data, 0);
+        mRemote.transact(CAN_BYPASS_WORK_CHALLENGE, data, reply, 0);
+        reply.readException();
+        final int result = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return result != 0;
+    }
 
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4ca1af8..3a8b6c7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -108,6 +108,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.ErrnoException;
+import android.webkit.WebView;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IVoiceInteractor;
@@ -128,6 +129,8 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.net.InetAddress;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -433,8 +436,10 @@
     static final class NewIntentData {
         List<ReferrerIntent> intents;
         IBinder token;
+        boolean andPause;
         public String toString() {
-            return "NewIntentData{intents=" + intents + " token=" + token + "}";
+            return "NewIntentData{intents=" + intents + " token=" + token
+                    + " andPause=" + andPause +"}";
         }
     }
 
@@ -517,6 +522,7 @@
         boolean persistent;
         Configuration config;
         CompatibilityInfo compatInfo;
+        String buildSerial;
 
         /** Initial values for {@link Profiler}. */
         ProfilerInfo initProfilerInfo;
@@ -751,10 +757,12 @@
                     configChanges, notResumed, config, overrideConfig, true, preserveWindow);
         }
 
-        public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
+        public final void scheduleNewIntent(
+                List<ReferrerIntent> intents, IBinder token, boolean andPause) {
             NewIntentData data = new NewIntentData();
             data.intents = intents;
             data.token = token;
+            data.andPause = andPause;
 
             sendMessage(H.NEW_INTENT, data);
         }
@@ -851,7 +859,8 @@
                 IUiAutomationConnection instrumentationUiConnection, int debugMode,
                 boolean enableBinderTracking, boolean trackAllocation,
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
-                CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
+                CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+                String buildSerial) {
 
             if (services != null) {
                 // Setup the service cache in the ServiceManager
@@ -876,6 +885,7 @@
             data.config = config;
             data.compatInfo = compatInfo;
             data.initProfilerInfo = profilerInfo;
+            data.buildSerial = buildSerial;
             sendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -1037,10 +1047,21 @@
             long dalvikMax = runtime.totalMemory() / 1024;
             long dalvikFree = runtime.freeMemory() / 1024;
             long dalvikAllocated = dalvikMax - dalvikFree;
+
+            Class[] classesToCount = new Class[] {
+                    ContextImpl.class,
+                    Activity.class,
+                    WebView.class,
+                    OpenSSLSocketImpl.class
+            };
+            long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
+            long appContextInstanceCount = instanceCounts[0];
+            long activityInstanceCount = instanceCounts[1];
+            long webviewInstanceCount = instanceCounts[2];
+            long openSslSocketCount = instanceCounts[3];
+
             long viewInstanceCount = ViewDebug.getViewInstanceCount();
             long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
-            long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
-            long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
             int globalAssetCount = AssetManager.getGlobalAssetCount();
             int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
             int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
@@ -1048,7 +1069,6 @@
             int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
             long parcelSize = Parcel.getGlobalAllocSize();
             long parcelCount = Parcel.getGlobalAllocCount();
-            long openSslSocketCount = Debug.countInstancesOfClass(OpenSSLSocketImpl.class);
             SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
 
             dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly,
@@ -1111,6 +1131,7 @@
                     "Parcel count:", parcelCount);
             printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
                     "OpenSSL Sockets:", openSslSocketCount);
+            printRow(pw, ONE_COUNT_COLUMN, "WebViews:", webviewInstanceCount);
 
             // SQLite mem info
             pw.println(" ");
@@ -2792,24 +2813,34 @@
         }
     }
 
-    public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
-        ActivityClientRecord r = mActivities.get(token);
-        if (r != null) {
-            final boolean resumed = !r.paused;
-            if (resumed) {
-                r.activity.mTemporaryPause = true;
-                mInstrumentation.callActivityOnPause(r.activity);
-            }
-            deliverNewIntents(r, intents);
-            if (resumed) {
-                r.activity.performResume();
-                r.activity.mTemporaryPause = false;
-            }
+    void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
+        final ActivityClientRecord r = mActivities.get(token);
+        if (r == null) {
+            return;
+        }
+
+        final boolean resumed = !r.paused;
+        if (resumed) {
+            r.activity.mTemporaryPause = true;
+            mInstrumentation.callActivityOnPause(r.activity);
+        }
+        deliverNewIntents(r, intents);
+        if (resumed) {
+            r.activity.performResume();
+            r.activity.mTemporaryPause = false;
+        }
+
+        if (r.paused && andPause) {
+            // In this case the activity was in the paused state when we delivered the intent,
+            // to guarantee onResume gets called after onNewIntent we temporarily resume the
+            // activity and pause again as the caller wanted.
+            performResumeActivity(token, false, "performNewIntents");
+            performPauseActivityIfNeeded(r, "performNewIntents");
         }
     }
 
     private void handleNewIntent(NewIntentData data) {
-        performNewIntents(data.token, data.intents);
+        performNewIntents(data.token, data.intents, data.andPause);
     }
 
     public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
@@ -3790,7 +3821,7 @@
      * than our client -- for the server, stop means to save state and give
      * it the result when it is done, but the window may still be visible.
      * For the client, we want to call onStop()/onStart() to indicate when
-     * the activity's UI visibillity changes.
+     * the activity's UI visibility changes.
      */
     private void performStopActivityInner(ActivityClientRecord r,
             StopInfo info, boolean keepShown, boolean saveState, String reason) {
@@ -3964,6 +3995,9 @@
         mSomeActivitiesChanged = true;
     }
 
+    // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to
+    // stop operation on the activity to reduce code duplication and the chance of fixing a bug in
+    // one place and missing the other.
     private void handleSleeping(IBinder token, boolean sleeping) {
         ActivityClientRecord r = mActivities.get(token);
 
@@ -3974,6 +4008,10 @@
 
         if (sleeping) {
             if (!r.stopped && !r.isPreHoneycomb()) {
+                if (!r.activity.mFinished && r.state == null) {
+                    callCallActivityOnSaveInstanceState(r);
+                }
+
                 try {
                     // Now we are idle.
                     r.activity.performStop(false /*preserveWindow*/);
@@ -5182,6 +5220,18 @@
             StrictMode.enableDeathOnFileUriExposure();
         }
 
+        // We deprecated Build.SERIAL and only apps that target pre NMR1
+        // SDK can see it. Since access to the serial is now behind a
+        // permission we push down the value and here we fix it up
+        // before any app code has been loaded.
+        try {
+            Field field = Build.class.getDeclaredField("SERIAL");
+            field.setAccessible(true);
+            field.set(Build.class, data.buildSerial);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            /* ignore */
+        }
+
         if (data.debugMode != IApplicationThread.DEBUG_OFF) {
             // XXX should have option to change the port.
             Debug.changeDebugPort(8100);
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 2219238..60046b5 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -15,6 +15,7 @@
  */
 package android.app;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.transition.Transition;
@@ -166,7 +167,11 @@
                 restoreExitedViews();
                 int result = mEnterActivityOptions.getResultCode();
                 if (result != 0) {
-                    activity.onActivityReenter(result, mEnterActivityOptions.getResultData());
+                    Intent intent = mEnterActivityOptions.getResultData();
+                    if (intent != null) {
+                        intent.setExtrasClassLoader(activity.getClassLoader());
+                    }
+                    activity.onActivityReenter(result, intent);
                 }
             }
         }
@@ -337,11 +342,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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1e4ffbe..191cc49 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -311,6 +311,9 @@
     /** Access APIs for SIP calling over VOIP or WiFi */
     public static final String OPSTR_USE_SIP
             = "android:use_sip";
+    /** Access APIs for diverting outgoing calls */
+    public static final String OPSTR_PROCESS_OUTGOING_CALLS
+            = "android:process_outgoing_calls";
     /** Use the fingerprint API. */
     public static final String OPSTR_USE_FINGERPRINT
             = "android:use_fingerprint";
@@ -403,8 +406,8 @@
             OP_WRITE_SMS,
             OP_RECEIVE_SMS,
             OP_RECEIVE_SMS,
-            OP_RECEIVE_SMS,
-            OP_RECEIVE_SMS,
+            OP_RECEIVE_MMS,
+            OP_RECEIVE_WAP_PUSH,
             OP_SEND_SMS,
             OP_READ_SMS,
             OP_WRITE_SMS,
@@ -510,7 +513,7 @@
             OPSTR_READ_PHONE_STATE,
             OPSTR_ADD_VOICEMAIL,
             OPSTR_USE_SIP,
-            null,
+            OPSTR_PROCESS_OUTGOING_CALLS,
             OPSTR_USE_FINGERPRINT,
             OPSTR_BODY_SENSORS,
             OPSTR_READ_CELL_BROADCASTS,
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 3063d98..12e527e 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -190,7 +190,8 @@
             data.enforceInterface(IApplicationThread.descriptor);
             List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
             IBinder b = data.readStrongBinder();
-            scheduleNewIntent(pi, b);
+            final boolean andPause = data.readInt() == 1;
+            scheduleNewIntent(pi, b, andPause);
             return true;
         }
 
@@ -301,10 +302,11 @@
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
             HashMap<String, IBinder> services = data.readHashMap(null);
             Bundle coreSettings = data.readBundle();
+            String buildSerial = data.readString();
             bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
                     testWatcher, uiAutomationConnection, testMode, enableBinderTracking,
                     trackAllocation, restrictedBackupMode, persistent, config, compatInfo, services,
-                    coreSettings);
+                    coreSettings, buildSerial);
             return true;
         }
 
@@ -915,12 +917,13 @@
         data.recycle();
     }
 
-    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token)
+    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token, boolean andPause)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeTypedList(intents);
         data.writeStrongBinder(token);
+        data.writeInt(andPause ? 1 : 0);
         mRemote.transact(SCHEDULE_NEW_INTENT_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -1058,7 +1061,8 @@
             IUiAutomationConnection uiAutomationConnection, int debugMode,
             boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
             boolean persistent, Configuration config, CompatibilityInfo compatInfo,
-            Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
+            Map<String, IBinder> services, Bundle coreSettings, String buildSerial)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeString(packageName);
@@ -1088,6 +1092,7 @@
         compatInfo.writeToParcel(data, 0);
         data.writeMap(services);
         data.writeBundle(coreSettings);
+        data.writeString(buildSerial);
         mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
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/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 03fcf47..462f66f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1112,7 +1112,7 @@
             if (cursor.moveToFirst()) {
                 int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
                 if (DownloadManager.STATUS_SUCCESSFUL == status) {
-                    return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, id);
+                    return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
                 }
             }
         } finally {
@@ -1448,7 +1448,7 @@
      * @hide
      */
     public Uri getDownloadUri(long id) {
-        return ContentUris.withAppendedId(mBaseUri, id);
+        return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
     }
 
     /**
@@ -1552,7 +1552,7 @@
 
             // return content URI for cache download
             long downloadId = getLong(getColumnIndex(Downloads.Impl._ID));
-            return ContentUris.withAppendedId(mBaseUri, downloadId).toString();
+            return ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, downloadId).toString();
         }
 
         private long getReason(int status) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 1367280..6ea170e 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -194,7 +194,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using fragments, read the
- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
  * </div>
  *
  * <a name="OlderPlatforms"></a>
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index e1d7136..d869168 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -340,6 +340,11 @@
     }
 
     void restoreLoaderNonConfig(ArrayMap<String, LoaderManager> loaderManagers) {
+        if (loaderManagers != null) {
+            for (int i = 0, N = loaderManagers.size(); i < N; i++) {
+                ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
+            }
+        }
         mAllLoaderManagers = loaderManagers;
     }
 
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 7394c7f..674c3f7 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -59,7 +59,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using fragments, read the
- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
  * </div>
  *
  * While the FragmentManager API was introduced in
@@ -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/IActivityManager.java b/core/java/android/app/IActivityManager.java
index dfeea57..096f0cb 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -265,8 +265,20 @@
     public void finishInstrumentation(IApplicationThread target,
             int resultCode, Bundle results) throws RemoteException;
 
+    /**
+     * @return A copy of global {@link Configuration}, contains general settings for the entire
+     *         system. Corresponds to the configuration of the default display.
+     * @throws RemoteException
+     */
     public Configuration getConfiguration() throws RemoteException;
+
+    /**
+     * Updates global configuration and applies changes to the entire system.
+     * @param values Update values for global configuration.
+     * @throws RemoteException
+     */
     public void updateConfiguration(Configuration values) throws RemoteException;
+
     public void setRequestedOrientation(IBinder token,
             int requestedOrientation) throws RemoteException;
     public int getRequestedOrientation(IBinder token) throws RemoteException;
@@ -672,6 +684,18 @@
      */
     public void setHasTopUi(boolean hasTopUi) throws RemoteException;
 
+    /**
+     * Returns if the target of the PendingIntent can be fired directly, without triggering
+     * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
+     * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
+     * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
+     * @param intent the {@link  PendingIntent} to be tested.
+     * @return {@code true} if the intent should not trigger a work challenge, {@code false}
+     *     otherwise.
+     * @throws RemoteException
+     */
+    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -1062,6 +1086,7 @@
     int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
     int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378;
     int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379;
+    int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380;
 
     // Start of O transactions
     int REQUEST_ACTIVITY_RELAUNCH = IBinder.FIRST_CALL_TRANSACTION+400;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 7732157..4189dd9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -67,7 +67,8 @@
             List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
             Configuration config, Configuration overrideConfig, boolean preserveWindow)
             throws RemoteException;
-    void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
+    void scheduleNewIntent(
+            List<ReferrerIntent> intent, IBinder token, boolean andPause) throws RemoteException;
     void scheduleDestroyActivity(IBinder token, boolean finished,
             int configChanges) throws RemoteException;
     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
@@ -98,8 +99,8 @@
             IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
             int debugMode, boolean enableBinderTracking, boolean trackAllocation,
             boolean restrictedBackupMode, boolean persistent, Configuration config,
-            CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings)
-            throws RemoteException;
+            CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+            String buildSerial) throws RemoteException;
     void scheduleExit() throws RemoteException;
     void scheduleSuicide() throws RemoteException;
     void scheduleConfigurationChanged(Configuration config) throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ee80ec3..28224e8 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -19,6 +19,7 @@
 
 import android.app.ITransientNotification;
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -57,6 +58,15 @@
     int getImportance(String pkg, int uid);
     int getPackageImportance(String pkg);
 
+    void createNotificationChannel(String pkg, in NotificationChannel channel);
+    void updateNotificationChannel(String pkg, in NotificationChannel channel);
+    void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
+    NotificationChannel getNotificationChannel(String pkg, String channelId);
+    NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId);
+    void deleteNotificationChannel(String pkg, String channelId);
+    ParceledListSlice getNotificationChannels(String pkg);
+    ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid);
+
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
     StatusBarNotification[] getActiveNotifications(String callingPkg);
@@ -70,6 +80,8 @@
 
     void requestBindListener(in ComponentName component);
     void requestUnbindListener(in INotificationListener token);
+    void requestBindProvider(in ComponentName component);
+    void requestUnbindProvider(in IConditionProvider token);
 
     void setNotificationsShownFromListener(in INotificationListener token, in String[] keys);
 
diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index 35b53a4..d5b3ed0 100644
--- a/core/java/android/app/ITransientNotification.aidl
+++ b/core/java/android/app/ITransientNotification.aidl
@@ -19,7 +19,7 @@
 
 /** @hide */
 oneway interface ITransientNotification {
-    void show();
+    void show(IBinder windowToken);
     void hide();
 }
 
diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl
index caee14f..234da8f 100644
--- a/core/java/android/app/IUserSwitchObserver.aidl
+++ b/core/java/android/app/IUserSwitchObserver.aidl
@@ -23,4 +23,5 @@
     void onUserSwitching(int newUserId, IRemoteCallback reply);
     void onUserSwitchComplete(int newUserId);
     void onForegroundProfileSwitch(int newProfileId);
+    void onLockedBootComplete(int newUserId);
 }
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/IntentService.java b/core/java/android/app/IntentService.java
index f33af39..e4a22c4 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -46,7 +46,8 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For a detailed discussion about how to create services, read the
- * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/services.html">Services</a> developer
+ * guide.</p>
  * </div>
  *
  * @see android.os.AsyncTask
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index c14dec9..bedf31a 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -195,6 +195,9 @@
     public static void enableDebugLogging(boolean enabled) {
         LoaderManagerImpl.DEBUG = enabled;
     }
+
+    /** @hide for internal testing only */
+    public FragmentHostCallback getFragmentHostCallback() { return null; }
 }
 
 class LoaderManagerImpl extends LoaderManager {
@@ -542,6 +545,10 @@
     void updateHostController(FragmentHostCallback host) {
         mHost = host;
     }
+
+    public FragmentHostCallback getFragmentHostCallback() {
+        return mHost;
+    }
     
     private LoaderInfo createLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 2a1e3c2..3b273bc 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -314,7 +314,7 @@
                     ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
                     intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
                     if (localLOGV) Log.v(TAG, r.id + ": new intent");
-                    mActivityThread.performNewIntents(r, intents);
+                    mActivityThread.performNewIntents(r, intents, false /* andPause */);
                     r.intent = intent;
                     moveToState(r, mCurState);
                     if (mSingleMode) {
diff --git a/core/java/android/app/Notification.aidl b/core/java/android/app/Notification.aidl
index 3f1d113..9d8129c 100644
--- a/core/java/android/app/Notification.aidl
+++ b/core/java/android/app/Notification.aidl
@@ -17,4 +17,3 @@
 package android.app;
 
 parcelable Notification;
-parcelable Notification.Topic;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2028572..680e518 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -992,6 +992,8 @@
     private Icon mSmallIcon;
     private Icon mLargeIcon;
 
+    private String mChannelId;
+
     /**
      * Structure to encapsulate a named action that can be shown as part of this notification.
      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
@@ -1231,7 +1233,7 @@
                     getIcon(),
                     title,
                     actionIntent, // safe to alias
-                    new Bundle(mExtras),
+                    mExtras == null ? new Bundle() : new Bundle(mExtras),
                     getRemoteInputs(),
                     getAllowGeneratedReplies());
         }
@@ -1675,6 +1677,10 @@
         }
 
         color = parcel.readInt();
+
+        if (parcel.readInt() != 0) {
+            mChannelId = parcel.readString();
+        }
     }
 
     @Override
@@ -1780,6 +1786,8 @@
 
         that.color = this.color;
 
+        that.mChannelId = this.mChannelId;
+
         if (!heavy) {
             that.lightenPayload(); // will clean out extras
         }
@@ -2028,6 +2036,13 @@
         }
 
         parcel.writeInt(color);
+
+        if (mChannelId != null) {
+            parcel.writeInt(1);
+            parcel.writeString(mChannelId);
+        } else {
+            parcel.writeInt(0);
+        }
     }
 
     /**
@@ -2218,6 +2233,13 @@
     }
 
     /**
+     * Returns the id of the channel this notification posts to.
+     */
+    public String getNotificationChannel() {
+        return mChannelId;
+    }
+
+    /**
      * The small icon representing this notification in the status bar and content view.
      *
      * @return the small icon representing this notification.
@@ -2406,6 +2428,14 @@
         }
 
         /**
+         * Specifies the channel the notification should be delivered on.
+         */
+        public Builder setChannel(String channelId) {
+            mN.mChannelId = channelId;
+            return this;
+        }
+
+        /**
          * Add a timestamp pertaining to the notification (usually the time the event occurred).
          *
          * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this time is not
@@ -2887,8 +2917,7 @@
         }
 
         /**
-         * Make this notification automatically dismissed when the user touches it. The
-         * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
+         * Make this notification automatically dismissed when the user touches it.
          *
          * @see Notification#FLAG_AUTO_CANCEL
          */
@@ -2988,7 +3017,8 @@
         /**
          * Set this notification to be the group summary for a group of notifications.
          * Grouped notifications may display in a cluster or stack on devices which
-         * support such rendering. Requires a group key also be set using {@link #setGroup}.
+         * support such rendering. If thereRequires a group key also be set using {@link #setGroup}.
+         * The group summary may be suppressed if too few notifications are included in the group.
          * @param isGroupSummary Whether this notification should be a group summary.
          * @return this object for method chaining
          */
@@ -5834,6 +5864,7 @@
         private static final String KEY_GRAVITY = "gravity";
         private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
         private static final String KEY_DISMISSAL_ID = "dismissalId";
+        private static final String KEY_BRIDGE_TAG = "bridgeTag";
 
         // Flags bitwise-ored to mFlags
         private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
@@ -5863,6 +5894,7 @@
         private int mGravity = DEFAULT_GRAVITY;
         private int mHintScreenTimeout;
         private String mDismissalId;
+        private String mBridgeTag;
 
         /**
          * Create a {@link android.app.Notification.WearableExtender} with default
@@ -5900,6 +5932,7 @@
                 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
                 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
                 mDismissalId = wearableBundle.getString(KEY_DISMISSAL_ID);
+                mBridgeTag = wearableBundle.getString(KEY_BRIDGE_TAG);
             }
         }
 
@@ -5953,6 +5986,9 @@
             if (mDismissalId != null) {
                 wearableBundle.putString(KEY_DISMISSAL_ID, mDismissalId);
             }
+            if (mBridgeTag != null) {
+                wearableBundle.putString(KEY_BRIDGE_TAG, mBridgeTag);
+            }
 
             builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
             return builder;
@@ -5974,6 +6010,7 @@
             that.mGravity = this.mGravity;
             that.mHintScreenTimeout = this.mHintScreenTimeout;
             that.mDismissalId = this.mDismissalId;
+            that.mBridgeTag = this.mBridgeTag;
             return that;
         }
 
@@ -6462,12 +6499,11 @@
         }
 
         /**
-         * When you post a notification, if you set the dismissal id field, then when that
-         * notification is canceled, notifications on other wearables and the paired Android phone
-         * having that same dismissal id will also be canceled.  Note that this only works if you
-         * have notification bridge mode set to NO_BRIDGING in your Wear app manifest.  See
+         * Sets the dismissal id for this notification. If a notification is posted with a
+         * dismissal id, then when that notification is canceled, notifications on other wearables
+         * and the paired Android phone having that same dismissal id will also be canceled. See
          * <a href="{@docRoot}wear/notifications/index.html">Adding Wearable Features to
-         * Notifications</a> for more information on how to use the bridge mode feature.
+         * Notifications</a> for more information.
          * @param dismissalId the dismissal id of the notification.
          * @return this object for method chaining
          */
@@ -6484,6 +6520,27 @@
             return mDismissalId;
         }
 
+        /**
+         * Sets a bridge tag for this notification. A bridge tag can be set for notifications
+         * posted from a phone to provide finer-grained control on what notifications are bridged
+         * to wearables. See <a href="{@docRoot}wear/notifications/index.html">Adding Wearable
+         * Features to Notifications</a> for more information.
+         * @param bridgeTag the bridge tag of the notification.
+         * @return this object for method chaining
+         */
+        public WearableExtender setBridgeTag(String bridgeTag) {
+            mBridgeTag = bridgeTag;
+            return this;
+        }
+
+        /**
+         * Returns the bridge tag of the notification.
+         * @return the bridge tag or null if not present.
+         */
+        public String getBridgeTag() {
+            return mBridgeTag;
+        }
+
         private void setFlag(int mask, boolean value) {
             if (value) {
                 mFlags |= mask;
diff --git a/core/java/android/app/NotificationChannel.aidl b/core/java/android/app/NotificationChannel.aidl
new file mode 100644
index 0000000..53e6863
--- /dev/null
+++ b/core/java/android/app/NotificationChannel.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app;
+
+parcelable NotificationChannel;
\ No newline at end of file
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
new file mode 100644
index 0000000..530b8bb
--- /dev/null
+++ b/core/java/android/app/NotificationChannel.java
@@ -0,0 +1,382 @@
+package android.app;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.notification.NotificationListenerService;
+import android.text.TextUtils;
+
+import java.io.IOException;
+
+/**
+ * A representation of settings that apply to a collection of similarly themed notifications.
+ */
+public final class NotificationChannel implements Parcelable {
+
+    /**
+     * The id of the default channel for an app. All notifications posted without a notification
+     * channel specified are posted to this channel.
+     */
+    public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+
+    private static final String TAG_CHANNEL = "channel";
+    private static final String ATT_NAME = "name";
+    private static final String ATT_ID = "id";
+    private static final String ATT_PRIORITY = "priority";
+    private static final String ATT_VISIBILITY = "visibility";
+    private static final String ATT_IMPORTANCE = "importance";
+    private static final String ATT_LIGHTS = "lights";
+    private static final String ATT_VIBRATION = "vibration";
+    private static final String ATT_DEFAULT_RINGTONE = "ringtone";
+
+    private static final int DEFAULT_VISIBILITY =
+            NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+    private static final int DEFAULT_IMPORTANCE =
+            NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+
+    private final String mId;
+    private CharSequence mName;
+    private int mImportance = DEFAULT_IMPORTANCE;
+    private boolean mBypassDnd;
+    private int mLockscreenVisibility = DEFAULT_VISIBILITY;
+    private Uri mRingtone;
+    private boolean mLights;
+    private boolean mVibration;
+
+    /**
+     * Creates a notification channel.
+     *
+     * @param id The id of the channel. Must be unique per package.
+     * @param name The user visible name of the channel.
+     */
+    public NotificationChannel(String id, CharSequence name) {
+        this.mId = id;
+        this.mName = name;
+    }
+
+    protected NotificationChannel(Parcel in) {
+        if (in.readByte() != 0) {
+            mId = in.readString();
+        } else {
+            mId = null;
+        }
+        mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mImportance = in.readInt();
+        mBypassDnd = in.readByte() != 0;
+        mLockscreenVisibility = in.readInt();
+        if (in.readByte() != 0) {
+            mRingtone = Uri.CREATOR.createFromParcel(in);
+        } else {
+            mRingtone = null;
+        }
+        mLights = in.readByte() != 0;
+        mVibration = in.readByte() != 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mId != null) {
+            dest.writeByte((byte) 1);
+            dest.writeString(mId);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        TextUtils.writeToParcel(mName, dest, flags);
+        dest.writeInt(mImportance);
+        dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
+        dest.writeInt(mLockscreenVisibility);
+        if (mRingtone != null) {
+            dest.writeByte((byte) 1);
+            mRingtone.writeToParcel(dest, 0);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        dest.writeByte(mLights ? (byte) 1 : (byte) 0);
+        dest.writeByte(mVibration ? (byte) 1 : (byte) 0);
+    }
+
+    // Only modifiable by users.
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void setName(CharSequence name) {
+        this.mName = name;
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void setImportance(int importance) {
+        this.mImportance = importance;
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void setBypassDnd(boolean bypassDnd) {
+        this.mBypassDnd = bypassDnd;
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void setLockscreenVisibility(int lockscreenVisibility) {
+        this.mLockscreenVisibility = lockscreenVisibility;
+    }
+
+    // Modifiable by apps.
+
+    /**
+     * Sets the ringtone that should be played for notifications posted to this channel if
+     * the notifications don't supply a ringtone.
+     */
+    public void setDefaultRingtone(Uri defaultRingtone) {
+        this.mRingtone = defaultRingtone;
+    }
+
+    /**
+     * Sets whether notifications posted to this channel should display notification lights,
+     * on devices that support that feature.
+     */
+    public void setLights(boolean lights) {
+        this.mLights = lights;
+    }
+
+    /**
+     * Sets whether notification posted to this channel should vibrate, even if individual
+     * notifications are marked as having vibration.
+     */
+    public void setVibration(boolean vibration) {
+        this.mVibration = vibration;
+    }
+
+    /**
+     * Returns the id of this channel.
+     */
+    public String getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the user visible name of this channel.
+     */
+    public CharSequence getName() {
+        return mName;
+    }
+
+    /**
+     * Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
+     * notifications posted to this channel.
+     */
+    public int getImportance() {
+        return mImportance;
+    }
+
+    /**
+     * Whether or not notifications posted to this channel can bypass the Do Not Disturb
+     * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode.
+     */
+    public boolean canBypassDnd() {
+        return mBypassDnd;
+    }
+
+    /**
+     * Returns the notification sound for this channel.
+     */
+    public Uri getDefaultRingtone() {
+        return mRingtone;
+    }
+
+    /**
+     * Returns whether notifications posted to this channel trigger notification lights.
+     */
+    public boolean shouldShowLights() {
+        return mLights;
+    }
+
+    /**
+     * Returns whether notifications posted to this channel always vibrate.
+     */
+    public boolean shouldVibrate() {
+        return mVibration;
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public int getLockscreenVisibility() {
+        return mLockscreenVisibility;
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void populateFromXml(XmlPullParser parser) {
+        // Name and id are set in the constructor.
+        setImportance(safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE));
+        setBypassDnd(Notification.PRIORITY_DEFAULT
+                != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
+        setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
+        setDefaultRingtone(safeUri(parser, ATT_DEFAULT_RINGTONE));
+        setLights(safeBool(parser, ATT_LIGHTS, false));
+        setVibration(safeBool(parser, ATT_VIBRATION, false));
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void writeXml(XmlSerializer out) throws IOException {
+        out.startTag(null, TAG_CHANNEL);
+        out.attribute(null, ATT_ID, getId());
+        out.attribute(null, ATT_NAME, getName().toString());
+        if (getImportance() != DEFAULT_IMPORTANCE) {
+            out.attribute(
+                    null, ATT_IMPORTANCE, Integer.toString(getImportance()));
+        }
+        if (canBypassDnd()) {
+            out.attribute(
+                    null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
+        }
+        if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
+            out.attribute(null, ATT_VISIBILITY,
+                    Integer.toString(getLockscreenVisibility()));
+        }
+        if (getDefaultRingtone() != null) {
+            out.attribute(null, ATT_DEFAULT_RINGTONE, getDefaultRingtone().toString());
+        }
+        if (shouldShowLights()) {
+            out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+        }
+        if (shouldVibrate()) {
+            out.attribute(null, ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+        }
+        out.endTag(null, TAG_CHANNEL);
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public JSONObject toJson() throws JSONException {
+        JSONObject record = new JSONObject();
+        record.put(ATT_ID, getId());
+        record.put(ATT_NAME, getName());
+        if (getImportance() != DEFAULT_IMPORTANCE) {
+            record.put(ATT_IMPORTANCE,
+                    NotificationListenerService.Ranking.importanceToString(getImportance()));
+        }
+        if (canBypassDnd()) {
+            record.put(ATT_PRIORITY, Notification.PRIORITY_MAX);
+        }
+        if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
+            record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility()));
+        }
+        if (getDefaultRingtone() != null) {
+            record.put(ATT_DEFAULT_RINGTONE, getDefaultRingtone().toString());
+        }
+        record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+        record.put(ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+
+        return record;
+    }
+
+    private static Uri safeUri(XmlPullParser parser, String att) {
+        final String val = parser.getAttributeValue(null, att);
+        return val == null ? null : Uri.parse(val);
+    }
+
+    private static int safeInt(XmlPullParser parser, String att, int defValue) {
+        final String val = parser.getAttributeValue(null, att);
+        return tryParseInt(val, defValue);
+    }
+
+    private static int tryParseInt(String value, int defValue) {
+        if (TextUtils.isEmpty(value)) return defValue;
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            return defValue;
+        }
+    }
+
+    private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
+        final String value = parser.getAttributeValue(null, att);
+        if (TextUtils.isEmpty(value)) return defValue;
+        return Boolean.parseBoolean(value);
+    }
+
+    public static final Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
+        @Override
+        public NotificationChannel createFromParcel(Parcel in) {
+            return new NotificationChannel(in);
+        }
+
+        @Override
+        public NotificationChannel[] newArray(int size) {
+            return new NotificationChannel[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        NotificationChannel that = (NotificationChannel) o;
+
+        if (mImportance != that.mImportance) return false;
+        if (mBypassDnd != that.mBypassDnd) return false;
+        if (mLockscreenVisibility != that.mLockscreenVisibility) return false;
+        if (mLights != that.mLights) return false;
+        if (mVibration != that.mVibration) return false;
+        if (!mId.equals(that.mId)) return false;
+        if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
+        return mRingtone != null ? mRingtone.equals(
+                that.mRingtone) : that.mRingtone == null;
+    }
+
+    @Override
+    public String toString() {
+        return "NotificationChannel{" +
+                "mId='" + mId + '\'' +
+                ", mName=" + mName +
+                ", mImportance=" + mImportance +
+                ", mBypassDnd=" + mBypassDnd +
+                ", mLockscreenVisibility=" + mLockscreenVisibility +
+                ", mRingtone='" + mRingtone + '\'' +
+                ", mLights=" + mLights +
+                ", mVibration=" + mVibration +
+                '}';
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mId.hashCode();
+        result = 31 * result + (mName != null ? mName.hashCode() : 0);
+        result = 31 * result + mImportance;
+        result = 31 * result + (mBypassDnd ? 1 : 0);
+        result = 31 * result + mLockscreenVisibility;
+        result = 31 * result + (mRingtone != null ? mRingtone.hashCode() : 0);
+        result = 31 * result + (mLights ? 1 : 0);
+        result = 31 * result + (mVibration ? 1 : 0);
+        return result;
+    }
+}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ff514bd..39cd2b5 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -378,6 +378,66 @@
     }
 
     /**
+     * Creates a notification channel that notifications can be posted to.
+     */
+    public void createNotificationChannel(NotificationChannel channel) {
+        INotificationManager service = getService();
+        try {
+            service.createNotificationChannel(mContext.getPackageName(), channel);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the notification channel settings for a given channel id.
+     */
+    public NotificationChannel getNotificationChannel(String channelId) {
+        INotificationManager service = getService();
+        try {
+            return service.getNotificationChannel(mContext.getPackageName(), channelId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all notification channels created by the calling app.
+     */
+    public List<NotificationChannel> getNotificationChannels() {
+        INotificationManager service = getService();
+        try {
+            return service.getNotificationChannels(mContext.getPackageName()).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Updates settings for a given channel.
+     */
+    public void updateNotificationChannel(NotificationChannel channel) {
+        INotificationManager service = getService();
+        try {
+            service.updateNotificationChannel(mContext.getPackageName(), channel);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Deletes the given notification channel.
+     */
+    public void deleteNotificationChannel(String channelId) {
+        INotificationManager service = getService();
+        try {
+            service.deleteNotificationChannel(mContext.getPackageName(), channelId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @hide
      */
     public ComponentName getEffectsSuppressor() {
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index 7f1f385..8ec9622 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -35,19 +35,27 @@
 import java.text.NumberFormat;
 
 /**
- * <p>A dialog showing a progress indicator and an optional text message or view.
- * Only a text message or a view can be used at the same time.</p>
+ * A dialog showing a progress indicator and an optional text message or view.
+ * Only a text message or a view can be used at the same time.
+ *
  * <p>The dialog can be made cancelable on back key press.</p>
- * <p>The progress range is 0..10000.</p>
+ *
+ * <p>The progress range is 0 to {@link #getMax() max}.</p>
+ *
+ * @deprecated Use a progress indicator such as ProgressBar inline inside of
+ * an activity rather than using this modal dialog.
  */
+@Deprecated
 public class ProgressDialog extends AlertDialog {
     
-    /** Creates a ProgressDialog with a circular, spinning progress
+    /**
+     * Creates a ProgressDialog with a circular, spinning progress
      * bar. This is the default.
      */
     public static final int STYLE_SPINNER = 0;
     
-    /** Creates a ProgressDialog with a horizontal progress bar.
+    /**
+     * Creates a ProgressDialog with a horizontal progress bar.
      */
     public static final int STYLE_HORIZONTAL = 1;
     
@@ -72,12 +80,25 @@
     
     private boolean mHasStarted;
     private Handler mViewUpdateHandler;
-    
+
+    /**
+     * Creates a Progress dialog.
+     *
+     * @param context the parent context
+     */
     public ProgressDialog(Context context) {
         super(context);
         initFormats();
     }
 
+    /**
+     * Creates a Progress dialog.
+     *
+     * @param context the parent context
+     * @param theme the resource ID of the theme against which to inflate
+     *              this dialog, or {@code 0} to use the parent
+     *              {@code context}'s default alert dialog theme
+     */
     public ProgressDialog(Context context, int theme) {
         super(context, theme);
         initFormats();
@@ -88,22 +109,66 @@
         mProgressPercentFormat = NumberFormat.getPercentInstance();
         mProgressPercentFormat.setMaximumFractionDigits(0);
     }
-    
+
+    /**
+     * Creates and shows a ProgressDialog.
+     *
+     * @param context the parent context
+     * @param title the title text for the dialog's window
+     * @param message the text to be displayed in the dialog
+     * @return the ProgressDialog
+     */
     public static ProgressDialog show(Context context, CharSequence title,
             CharSequence message) {
         return show(context, title, message, false);
     }
 
+    /**
+     * Creates and shows a ProgressDialog.
+     *
+     * @param context the parent context
+     * @param title the title text for the dialog's window
+     * @param message the text to be displayed in the dialog
+     * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
+     *        indeterminate}, false otherwise
+     * @return the ProgressDialog
+     */
     public static ProgressDialog show(Context context, CharSequence title,
             CharSequence message, boolean indeterminate) {
         return show(context, title, message, indeterminate, false, null);
     }
 
+    /**
+     * Creates and shows a ProgressDialog.
+     *
+     * @param context the parent context
+     * @param title the title text for the dialog's window
+     * @param message the text to be displayed in the dialog
+     * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
+     *        indeterminate}, false otherwise
+     * @param cancelable true if the dialog is {@link #setCancelable(boolean) cancelable},
+     *        false otherwise
+     * @return the ProgressDialog
+     */
     public static ProgressDialog show(Context context, CharSequence title,
             CharSequence message, boolean indeterminate, boolean cancelable) {
         return show(context, title, message, indeterminate, cancelable, null);
     }
 
+    /**
+     * Creates and shows a ProgressDialog.
+     *
+     * @param context the parent context
+     * @param title the title text for the dialog's window
+     * @param message the text to be displayed in the dialog
+     * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
+     *        indeterminate}, false otherwise
+     * @param cancelable true if the dialog is {@link #setCancelable(boolean) cancelable},
+     *        false otherwise
+     * @param cancelListener the {@link #setOnCancelListener(OnCancelListener) listener}
+     *        to be invoked when the dialog is canceled
+     * @return the ProgressDialog
+     */
     public static ProgressDialog show(Context context, CharSequence title,
             CharSequence message, boolean indeterminate,
             boolean cancelable, OnCancelListener cancelListener) {
@@ -210,6 +275,13 @@
         mHasStarted = false;
     }
 
+    /**
+     * Sets the current progress.
+     *
+     * @param value the current progress, a value between 0 and {@link #getMax()}
+     *
+     * @see ProgressBar#setProgress(int)
+     */
     public void setProgress(int value) {
         if (mHasStarted) {
             mProgress.setProgress(value);
@@ -219,6 +291,14 @@
         }
     }
 
+    /**
+     * Sets the secondary progress.
+     *
+     * @param secondaryProgress the current secondary progress, a value between 0 and
+     * {@link #getMax()}
+     *
+     * @see ProgressBar#setSecondaryProgress(int)
+     */
     public void setSecondaryProgress(int secondaryProgress) {
         if (mProgress != null) {
             mProgress.setSecondaryProgress(secondaryProgress);
@@ -228,6 +308,11 @@
         }
     }
 
+    /**
+     * Gets the current progress.
+     *
+     * @return the current progress, a value between 0 and {@link #getMax()}
+     */
     public int getProgress() {
         if (mProgress != null) {
             return mProgress.getProgress();
@@ -235,6 +320,11 @@
         return mProgressVal;
     }
 
+    /**
+     * Gets the current secondary progress.
+     *
+     * @return the current secondary progress, a value between 0 and {@link #getMax()}
+     */
     public int getSecondaryProgress() {
         if (mProgress != null) {
             return mProgress.getSecondaryProgress();
@@ -242,6 +332,11 @@
         return mSecondaryProgressVal;
     }
 
+    /**
+     * Gets the maximum allowed progress value. The default value is 100.
+     *
+     * @return the maximum value
+     */
     public int getMax() {
         if (mProgress != null) {
             return mProgress.getMax();
@@ -249,6 +344,9 @@
         return mMax;
     }
 
+    /**
+     * Sets the maximum allowed progress value.
+     */
     public void setMax(int max) {
         if (mProgress != null) {
             mProgress.setMax(max);
@@ -258,6 +356,12 @@
         }
     }
 
+    /**
+     * Increments the current progress value.
+     *
+     * @param diff the amount by which the current progress will be incremented,
+     * up to {@link #getMax()}
+     */
     public void incrementProgressBy(int diff) {
         if (mProgress != null) {
             mProgress.incrementProgressBy(diff);
@@ -267,6 +371,12 @@
         }
     }
 
+    /**
+     * Increments the current secondary progress value.
+     *
+     * @param diff the amount by which the current secondary progress will be incremented,
+     * up to {@link #getMax()}
+     */
     public void incrementSecondaryProgressBy(int diff) {
         if (mProgress != null) {
             mProgress.incrementSecondaryProgressBy(diff);
@@ -276,6 +386,13 @@
         }
     }
 
+    /**
+     * Sets the drawable to be used to display the progress value.
+     *
+     * @param d the drawable to be used
+     *
+     * @see ProgressBar#setProgressDrawable(Drawable)
+     */
     public void setProgressDrawable(Drawable d) {
         if (mProgress != null) {
             mProgress.setProgressDrawable(d);
@@ -284,6 +401,14 @@
         }
     }
 
+    /**
+     * Sets the drawable to be used to display the indeterminate progress value.
+     *
+     * @param d the drawable to be used
+     *
+     * @see ProgressBar#setProgressDrawable(Drawable)
+     * @see #setIndeterminate(boolean)
+     */
     public void setIndeterminateDrawable(Drawable d) {
         if (mProgress != null) {
             mProgress.setIndeterminateDrawable(d);
@@ -292,6 +417,18 @@
         }
     }
 
+    /**
+     * Change the indeterminate mode for this ProgressDialog. In indeterminate
+     * mode, the progress is ignored and the dialog shows an infinite
+     * animation instead.
+     *
+     * <p><strong>Note:</strong> A ProgressDialog with style {@link #STYLE_SPINNER}
+     * is always indeterminate and will ignore this setting.</p>
+     *
+     * @param indeterminate true to enable indeterminate mode, false otherwise
+     *
+     * @see #setProgressStyle(int)
+     */
     public void setIndeterminate(boolean indeterminate) {
         if (mProgress != null) {
             mProgress.setIndeterminate(indeterminate);
@@ -300,6 +437,11 @@
         }
     }
 
+    /**
+     * Whether this ProgressDialog is in indeterminate mode.
+     *
+     * @return true if the dialog is in indeterminate mode, false otherwise
+     */
     public boolean isIndeterminate() {
         if (mProgress != null) {
             return mProgress.isIndeterminate();
@@ -319,7 +461,18 @@
             mMessage = message;
         }
     }
-    
+
+    /**
+     * Sets the style of this ProgressDialog, either {@link #STYLE_SPINNER} or
+     * {@link #STYLE_HORIZONTAL}. The default is {@link #STYLE_SPINNER}.
+     *
+     * <p><strong>Note:</strong> A ProgressDialog with style {@link #STYLE_SPINNER}
+     * is always indeterminate and will ignore the {@link #setIndeterminate(boolean)
+     * indeterminate} setting.</p>
+     *
+     * @param style the style of this ProgressDialog, either {@link #STYLE_SPINNER} or
+     * {@link #STYLE_HORIZONTAL}
+     */
     public void setProgressStyle(int style) {
         mProgressStyle = style;
     }
diff --git a/core/java/android/app/SynchronousUserSwitchObserver.java b/core/java/android/app/SynchronousUserSwitchObserver.java
index 6d929f9..3a73888 100644
--- a/core/java/android/app/SynchronousUserSwitchObserver.java
+++ b/core/java/android/app/SynchronousUserSwitchObserver.java
@@ -25,7 +25,7 @@
  *
  * @hide
  */
-public abstract class SynchronousUserSwitchObserver extends IUserSwitchObserver.Stub {
+public abstract class SynchronousUserSwitchObserver extends UserSwitchObserver {
     /**
      * Calls {@link #onUserSwitching(int)} and notifies {@code reply} by calling
      * {@link IRemoteCallback#sendResult(Bundle)}.
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/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index aca0763..3f467a0 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
@@ -91,6 +92,12 @@
 
     /**
      * Creates a new time picker dialog with the specified theme.
+     * <p>
+     * The theme is overlaid on top of the theme of the parent {@code context}.
+     * If {@code themeResId} is 0, the dialog will be inflated using the theme
+     * specified by the
+     * {@link android.R.attr#timePickerDialogTheme android:timePickerDialogTheme}
+     * attribute on the parent {@code context}'s theme.
      *
      * @param context the parent context
      * @param themeResId the resource ID of the theme to apply to this dialog
@@ -109,11 +116,6 @@
         mIs24HourView = is24HourView;
 
         final Context themeContext = getContext();
-
-
-        final TypedValue outValue = new TypedValue();
-        context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
-
         final LayoutInflater inflater = LayoutInflater.from(themeContext);
         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
@@ -128,6 +130,15 @@
         mTimePicker.setOnTimeChangedListener(this);
     }
 
+    /**
+     * @return the time picker displayed in the dialog
+     * @hide For testing only.
+     */
+    @TestApi
+    public TimePicker getTimePicker() {
+        return mTimePicker;
+    }
+
     @Override
     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
         /* do nothing */
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 0d4d007..b859418 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -580,37 +580,46 @@
         command.run();
 
         // Acquire the lock and wait for the event.
-        synchronized (mLock) {
-            try {
-                // Wait for the event.
-                final long startTimeMillis = SystemClock.uptimeMillis();
-                while (true) {
-                    // Drain the event queue
-                    while (!mEventQueue.isEmpty()) {
-                        AccessibilityEvent event = mEventQueue.remove(0);
-                        // Ignore events from previous interactions.
-                        if (event.getEventTime() < executionStartTimeMillis) {
-                            continue;
-                        }
-                        if (filter.accept(event)) {
-                            return event;
-                        }
-                        event.recycle();
+        try {
+            // Wait for the event.
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                List<AccessibilityEvent> localEvents = new ArrayList<>();
+                synchronized (mLock) {
+                    localEvents.addAll(mEventQueue);
+                    mEventQueue.clear();
+                }
+                // Drain the event queue
+                while (!localEvents.isEmpty()) {
+                    AccessibilityEvent event = localEvents.remove(0);
+                    // Ignore events from previous interactions.
+                    if (event.getEventTime() < executionStartTimeMillis) {
+                        continue;
                     }
-                    // Check if timed out and if not wait.
-                    final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
-                    final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
-                    if (remainingTimeMillis <= 0) {
-                        throw new TimeoutException("Expected event not received within: "
-                                + timeoutMillis + " ms.");
+                    if (filter.accept(event)) {
+                        return event;
                     }
-                    try {
-                        mLock.wait(remainingTimeMillis);
-                    } catch (InterruptedException ie) {
-                        /* ignore */
+                    event.recycle();
+                }
+                // Check if timed out and if not wait.
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    throw new TimeoutException("Expected event not received within: "
+                            + timeoutMillis + " ms.");
+                }
+                synchronized (mLock) {
+                    if (mEventQueue.isEmpty()) {
+                        try {
+                            mLock.wait(remainingTimeMillis);
+                        } catch (InterruptedException ie) {
+                            /* ignore */
+                        }
                     }
                 }
-            } finally {
+            }
+        } finally {
+            synchronized (mLock) {
                 mWaitingForEventDelivery = false;
                 mEventQueue.clear();
                 mLock.notifyAll();
diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java
new file mode 100644
index 0000000..c0f7a4c
--- /dev/null
+++ b/core/java/android/app/UserSwitchObserver.java
@@ -0,0 +1,41 @@
+/*
+ * 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.app;
+
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+public class UserSwitchObserver extends IUserSwitchObserver.Stub {
+    @Override
+    public void onUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException {
+        if (reply != null) {
+            reply.sendResult(null);
+        }
+    }
+
+    @Override
+    public void onUserSwitchComplete(int newUserId) throws RemoteException {}
+
+    @Override
+    public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {}
+
+    @Override
+    public void onLockedBootComplete(int newUserId) throws RemoteException {}
+}
\ No newline at end of file
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6e44662..aa0eaae 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;
@@ -909,7 +910,7 @@
      * wallpaper.
      */
     public void setResource(@RawRes int resid) throws IOException {
-        setResource(resid, FLAG_SYSTEM);
+        setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
     }
 
     /**
@@ -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;
@@ -1014,7 +1016,7 @@
      */
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM);
+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
     }
 
     /**
@@ -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 {
@@ -1139,7 +1154,7 @@
      */
     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
-        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM);
+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
     }
 
     /**
@@ -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 {
@@ -1378,6 +1393,7 @@
      */
     @SystemApi
     public void clearWallpaper() {
+        clearWallpaper(FLAG_LOCK, mContext.getUserId());
         clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
     }
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6ac7132..a207a52 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -411,6 +411,14 @@
     public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
 
     /**
+     * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
+     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+     *
+     * @hide
+     */
+    public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
+
+    /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
      * allows a mobile device management application or NFC programmer application which starts
      * managed provisioning to pass data to the management application instance after provisioning.
@@ -878,7 +886,7 @@
             = "android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED";
 
     /**
-     * Broadcast action: sent when the device owner is set or changed.
+     * Broadcast action: sent when the device owner is set, changed or cleared.
      *
      * This broadcast is sent only to the primary user.
      * @see #ACTION_PROVISION_MANAGED_DEVICE
@@ -1270,6 +1278,33 @@
     public static final int PASSWORD_QUALITY_MANAGED = 0x80000;
 
     /**
+     * @hide
+     *
+     * adb shell dpm set-{device,profile}-owner will normally not allow installing an owner to
+     * a user with accounts.  {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}
+     * and {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} are the account features
+     * used by authenticator to exempt their accounts from this:
+     *
+     * <ul>
+     *     <li>Non-test-only DO/PO still can't be installed when there are accounts.
+     *     <p>In order to make an apk test-only, add android:testOnly="true" to the
+     *     &lt;application&gt; tag in the manifest.
+     *
+     *     <li>Test-only DO/PO can be installed even when there are accounts, as long as all the
+     *     accounts have the {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} feature.
+     *     Some authenticators claim to have any features, so to detect it, we also check
+     *     {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} and disallow installing
+     *     if any of the accounts have it.
+     * </ul>
+     */
+    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED =
+            "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
+
+    /** @hide See {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} */
+    public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED =
+            "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
+
+    /**
      * Called by an application that is administering the device to set the password restrictions it
      * is imposing. After setting this, the user will not be able to enter a new password that is
      * not at least as restrictive as what has been set. Note that the current password will remain
@@ -2303,6 +2338,78 @@
     }
 
     /**
+     * Called by a device/profile owner to set the timeout after which unlocking with secondary, non
+     * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong
+     * authentication method like password, pin or pattern.
+     *
+     * <p>This timeout is used internally to reset the timer to require strong auth again after
+     * specified timeout each time it has been successfully used.
+     *
+     * <p>Fingerprint can also be disabled altogether using {@link #KEYGUARD_DISABLE_FINGERPRINT}.
+     *
+     * <p>Trust agents can also be disabled altogether using {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
+     *
+     * <p>The calling device admin must be a device or profile owner. If it is not,
+     * a {@link SecurityException} will be thrown.
+     *
+     * <p>This method can be called on the {@link DevicePolicyManager} instance returned by
+     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+     * profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param timeoutMs The new timeout, after which the user will have to unlock with strong
+     *         authentication method. If the timeout is lower than 1 hour (minimum) or higher than
+     *         72 hours (default and maximum) an {@link IllegalArgumentException} is thrown.
+     *
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @throws IllegalArgumentException if the timeout is lower than 1 hour (minimum) or higher than
+     *         72 hours (default and maximum)
+     *
+     * @hide
+     */
+    public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin,
+            long timeoutMs) {
+        if (mService != null) {
+            try {
+                mService.setRequiredStrongAuthTimeout(admin, timeoutMs, mParentInstance);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Determine for how long the user will be able to use secondary, non strong auth for
+     * authentication, since last strong method authentication (password, pin or pattern) was used.
+     * After the returned timeout the user is required to use strong authentication method.
+     *
+     * <p>This method can be called on the {@link DevicePolicyManager} instance
+     * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+     * restrictions on the parent profile.
+     *
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
+     *         accross all participating admins.
+     * @return The timeout or default timeout if not configured
+     *
+     * @hide
+     */
+    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
+        return getRequiredStrongAuthTimeout(admin, myUserId());
+    }
+
+    /** @hide per-user version */
+    public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) {
+        if (mService != null) {
+            try {
+                return mService.getRequiredStrongAuthTimeout(admin, userId, mParentInstance);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+    }
+
+    /**
      * Make the device lock immediately, as if the lock screen timeout has expired at the point of
      * this call.
      * <p>
@@ -2341,8 +2448,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.
@@ -5389,6 +5498,7 @@
 
     /**
      * Called by profile or device owners to set the master volume mute on or off.
+     * This has no effect when set on a managed profile.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param on {@code true} to mute master volume, {@code false} to turn mute off.
@@ -6463,9 +6573,55 @@
         }
     }
 
+    /**
+     * @hide
+     * Force update user setup completed status. This API has no effect on user build.
+     * @throws {@link SecurityException} if the caller has no
+     *         {@link android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS} or the caller is
+     *         not {@link UserHandle.SYSTEM_USER}
+     */
+    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");
         }
     }
+
+    /**
+     * @hide
+     * Enable backup service.
+     * <p>This includes all backup and restore mechanisms.
+     * Setting this to {@code false} will make backup service no-op or return empty results.
+     *
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
+     *
+     * <p>Backup service is off by default when device owner is present.
+     */
+    public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
+        try {
+            mService.setBackupServiceEnabled(admin, enabled);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     * @return {@code true} if backup service is enabled, {@code false} otherwise.
+     */
+    public boolean isBackupServiceEnabled(@NonNull ComponentName admin) {
+        try {
+            return mService.isBackupServiceEnabled(admin);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 1036f04..8c376bb 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -82,6 +82,9 @@
     long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
     long getMaximumTimeToLockForUserAndProfiles(int userHandle);
 
+    void setRequiredStrongAuthTimeout(in ComponentName who, long timeMs, boolean parent);
+    long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
+
     void lockNow(boolean parent);
 
     void wipeData(int flags);
@@ -305,4 +308,9 @@
     boolean isDeviceProvisioned();
     boolean isDeviceProvisioningConfigApplied();
     void setDeviceProvisioningConfigApplied();
+
+    void forceUpdateUserSetupComplete();
+
+    void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
+    boolean isBackupServiceEnabled(in ComponentName admin);
 }
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 7fcca09..80bc136 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -128,6 +128,14 @@
     @SystemApi
     public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
 
+    /**
+     * Intent extra when any subsidiary backup-related UI is launched from Settings:  does
+     * device policy or configuration permit backup operations to run at all?
+     *
+     * @hide
+     */
+    public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
+
     private Context mContext;
     private static IBackupManager sService;
 
diff --git a/core/java/android/app/package.html b/core/java/android/app/package.html
index f37f1dc..b259cad 100644
--- a/core/java/android/app/package.html
+++ b/core/java/android/app/package.html
@@ -34,7 +34,7 @@
 <p>For information about using some the classes in this package, see the following
 documents: <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
 href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, <a
-href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>, <a
+href="{@docRoot}guide/components/fragments.html">Fragments</a>, <a
 href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>, <a
 href="{@docRoot}guide/topics/ui/dialogs.html">Creating Dialogs</a>, and <a
 href="{@docRoot}guide/topics/ui/notifiers/index.html">Notifying the User</a>.</p>
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 073196c..c71dc7c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -90,8 +90,11 @@
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
- * <p>For more information about using Bluetooth, read the
- * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.
+ * <p>
+ *  For more information about using Bluetooth, read the <a href=
+ * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
+ * guide.
+ * </p>
  * </div>
  *
  * {@see BluetoothDevice}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index 444e429..a395aa4 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -66,21 +66,6 @@
         "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
 
     /**
-     * Intent used to broadcast the change in metadata state of playing track on the AVRCP
-     * AG.
-     *
-     * <p>This intent will have the two extras:
-     * <ul>
-     *    <li> {@link #EXTRA_METADATA} - {@link MediaMetadata} containing the current metadata.</li>
-     *    <li> {@link #EXTRA_PLAYBACK} - {@link PlaybackState} containing the current playback
-     *    state. </li>
-     * </ul>
-     */
-    public static final String ACTION_TRACK_EVENT =
-        "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";
-
-
-    /**
      * Intent used to broadcast the change in player application setting state on AVRCP AG.
      *
      * <p>This intent will have the following extras:
@@ -92,35 +77,9 @@
     public static final String ACTION_PLAYER_SETTING =
         "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
 
-    public static final String EXTRA_METADATA =
-            "android.bluetooth.avrcp-controller.profile.extra.METADATA";
-
-    public static final String EXTRA_PLAYBACK =
-            "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";
-
     public static final String EXTRA_PLAYER_SETTING =
             "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
 
-    /*
-     * KeyCoded for Pass Through Commands
-     */
-    public static final int PASS_THRU_CMD_ID_PLAY = 0x44;
-    public static final int PASS_THRU_CMD_ID_PAUSE = 0x46;
-    public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41;
-    public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42;
-    public static final int PASS_THRU_CMD_ID_STOP = 0x45;
-    public static final int PASS_THRU_CMD_ID_FF = 0x49;
-    public static final int PASS_THRU_CMD_ID_REWIND = 0x48;
-    public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B;
-    public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C;
-    /* Key State Variables */
-    public static final int KEY_STATE_PRESSED = 0;
-    public static final int KEY_STATE_RELEASED = 1;
-    /* Group Navigation Key Codes */
-    public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00;
-    public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01;
-
-
     private Context mContext;
     private ServiceListener mServiceListener;
     private IBluetoothAvrcpController mService;
@@ -267,20 +226,6 @@
         return BluetoothProfile.STATE_DISCONNECTED;
     }
 
-    public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
-        if (DBG) Log.d(TAG, "sendPassThroughCmd");
-        if (mService != null && isEnabled()) {
-            try {
-                mService.sendPassThroughCmd(device, keyCode, keyState);
-                return;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
-                return;
-            }
-        }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
-    }
-
     /**
      * Gets the player application settings.
      *
@@ -301,49 +246,6 @@
     }
 
     /**
-     * Gets the metadata for the current track.
-     *
-     * This should be usually called when application UI needs to be updated, eg. when the track
-     * changes or immediately after connecting and getting the current state.
-     * @return the {@link MediaMetadata} or {@link null} if there is an error.
-     */
-    public MediaMetadata getMetadata(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "getMetadata");
-        MediaMetadata metadata = null;
-        if (mService != null && isEnabled()) {
-            try {
-                metadata = mService.getMetadata(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
-                return null;
-            }
-        }
-        return metadata;
-    }
-
-    /**
-     * Gets the playback state for current track.
-     *
-     * When the application is first connecting it can use current track state to get playback info.
-     * For all further updates it should listen to notifications.
-     * @return the {@link PlaybackState} or {@link null} if there is an error.
-     */
-    public PlaybackState getPlaybackState(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "getPlaybackState");
-        PlaybackState playbackState = null;
-        if (mService != null && isEnabled()) {
-            try {
-                playbackState = mService.getPlaybackState(device);
-            } catch (RemoteException e) {
-                Log.e(TAG,
-                    "Error talking to BT service in getPlaybackState() " + e);
-                return null;
-            }
-        }
-        return playbackState;
-    }
-
-    /**
      * Sets the player app setting for current player.
      * returns true in case setting is supported by remote, false otherwise
      */
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fa70c3f..cd5eff2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -59,8 +59,11 @@
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
- * <p>For more information about using Bluetooth, read the
- * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
+ * <p>
+ * For more information about using Bluetooth, read the <a href=
+ * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
+ * guide.
+ * </p>
  * </div>
  *
  * {@see BluetoothAdapter}
@@ -1164,12 +1167,12 @@
 
     /**
      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
      *
      * @return true confirmation has been sent out
      *         false for error
      */
-    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
     public boolean setPairingConfirmation(boolean confirm) {
         if (sService == null) {
             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
@@ -1593,7 +1596,7 @@
                 // BLE is not supported
                 return null;
             }
-            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
+            BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport);
             gatt.connect(autoConnect, callback);
             return gatt;
         } catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 17145f2..2bb9012 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -41,7 +41,6 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    private final Context mContext;
     private IBluetoothGatt mService;
     private BluetoothGattCallback mCallback;
     private int mClientIf;
@@ -492,9 +491,8 @@
             }
         };
 
-    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+    /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
                                 int transport) {
-        mContext = context;
         mService = iGatt;
         mDevice = device;
         mTransport = transport;
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index 17e533a..da81569 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -83,11 +83,6 @@
     }
 
     @Override
-    public void onMultiAdvertiseCallback(int status, boolean isStart,
-            AdvertiseSettings advertiseSettings) throws RemoteException {
-    }
-
-    @Override
     public void onConfigureMTU(String address, int mtu, int status) throws RemoteException {
     }
 
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index c2bcbb2..5ffceba 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -44,7 +44,6 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    private final Context mContext;
     private BluetoothAdapter mAdapter;
     private IBluetoothGatt mService;
     private BluetoothGattServerCallback mCallback;
@@ -298,8 +297,7 @@
     /**
      * Create a BluetoothGattServer proxy object.
      */
-    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
-        mContext = context;
+    /*package*/ BluetoothGattServer(IBluetoothGatt iGatt, int transport) {
         mService = iGatt;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
         mCallback = null;
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 15a9101..1717a1e 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -68,7 +68,9 @@
     public boolean equals(Object o) {
         if (o instanceof BluetoothHealthAppConfiguration) {
             BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-            // config.getName() can never be NULL
+
+            if (mName == null) return false;
+
             return mName.equals(config.getName()) &&
                     mDataType == config.getDataType() &&
                     mRole == config.getRole() &&
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 35437a1..29283e7 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -38,8 +38,11 @@
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
- * <p>For more information about using BLUETOOTH, read the
- * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
+ * <p>
+ * For more information about using BLUETOOTH, read the <a href=
+ * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
+ * guide.
+ * </p>
  * </div>
  *
  * @see Context#getSystemService
@@ -233,7 +236,7 @@
                 Log.e(TAG, "Fail to get GATT Server connection");
                 return null;
             }
-            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
+            BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt,transport);
             Boolean regStatus = mGattServer.registerCallback(callback);
             return regStatus? mGattServer : null;
         } catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index f1288d0..cfa11ca 100644
--- a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -30,10 +30,7 @@
     List<BluetoothDevice> getConnectedDevices();
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
     int getConnectionState(in BluetoothDevice device);
-    void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
     BluetoothAvrcpPlayerSettings getPlayerSettings(in BluetoothDevice device);
-    MediaMetadata getMetadata(in BluetoothDevice device);
-    PlaybackState getPlaybackState(in BluetoothDevice device);
     boolean setPlayerApplicationSetting(in BluetoothAvrcpPlayerSettings plAppSetting);
     void sendGroupNavigationCmd(in BluetoothDevice device, int keyCode, int keyState);
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 7498038..f4ebcaf 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -28,6 +28,7 @@
 
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothGattServerCallback;
+import android.bluetooth.le.IAdvertiserCallback;
 
 /**
  * API for interacting with BLE / GATT
@@ -41,11 +42,15 @@
                    in String callingPackage);
     void stopScan(in int appIf, in boolean isServer);
     void flushPendingBatchResults(in int appIf, in boolean isServer);
-    void startMultiAdvertising(in int appIf,
+
+    void registerAdvertiser(in IAdvertiserCallback callback);
+    void unregisterAdvertiser(in int advertiserId);
+    void startMultiAdvertising(in int advertiserId,
                                in AdvertiseData advertiseData,
                                in AdvertiseData scanResponse,
                                in AdvertiseSettings settings);
-    void stopMultiAdvertising(in int appIf);
+    void stopMultiAdvertising(in int advertiserId);
+
     void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
     void unregisterClient(in int clientIf);
     void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 7163c37..efda08e 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -38,8 +38,6 @@
     void onDescriptorWrite(in String address, in int status, in int handle);
     void onNotify(in String address, in int handle, in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
-    void onMultiAdvertiseCallback(in int status, boolean isStart,
-                                  in AdvertiseSettings advertiseSettings);
     void onScanManagerErrorCallback(in int errorCode);
     void onConfigureMTU(in String address, in int mtu, in int status);
     void onFoundOrLost(in boolean onFound, in ScanResult scanResult);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index d468bd4..048f791 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -22,6 +22,7 @@
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManager;
+import android.bluetooth.le.IAdvertiserCallback;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
@@ -162,7 +163,7 @@
     }
 
     /**
-     * Cleans up advertise clients. Should be called when bluetooth is down.
+     * Cleans up advertisers. Should be called when bluetooth is down.
      *
      * @hide
      */
@@ -228,7 +229,7 @@
     /**
      * Bluetooth GATT interface callbacks for advertising.
      */
-    private class AdvertiseCallbackWrapper extends BluetoothGattCallbackWrapper {
+    private class AdvertiseCallbackWrapper extends IAdvertiserCallback.Stub {
         private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
         private final AdvertiseCallback mAdvertiseCallback;
         private final AdvertiseData mAdvertisement;
@@ -236,10 +237,10 @@
         private final AdvertiseSettings mSettings;
         private final IBluetoothGatt mBluetoothGatt;
 
-        // mClientIf 0: not registered
+        // mAdvertiserId 0: not registered
         // -1: advertise stopped or registration timeout
         // >0: registered and advertising started
-        private int mClientIf;
+        private int mAdvertiserId;
         private boolean mIsAdvertising = false;
 
         public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
@@ -251,35 +252,34 @@
             mScanResponse = scanResponse;
             mSettings = settings;
             mBluetoothGatt = bluetoothGatt;
-            mClientIf = 0;
+            mAdvertiserId = 0;
         }
 
         public void startRegisteration() {
             synchronized (this) {
-                if (mClientIf == -1) return;
+                if (mAdvertiserId == -1) return;
 
                 try {
-                    UUID uuid = UUID.randomUUID();
-                    mBluetoothGatt.registerClient(new ParcelUuid(uuid), this);
+                    mBluetoothGatt.registerAdvertiser(this);
                     wait(LE_CALLBACK_TIMEOUT_MILLIS);
                 } catch (InterruptedException | RemoteException e) {
                     Log.e(TAG, "Failed to start registeration", e);
                 }
-                if (mClientIf > 0 && mIsAdvertising) {
+                if (mAdvertiserId > 0 && mIsAdvertising) {
                     mLeAdvertisers.put(mAdvertiseCallback, this);
-                } else if (mClientIf <= 0) {
+                } else if (mAdvertiserId <= 0) {
 
                     // Registration timeout, reset mClientIf to -1 so no subsequent operations can
                     // proceed.
-                    if (mClientIf == 0) mClientIf = -1;
+                    if (mAdvertiserId == 0) mAdvertiserId = -1;
                     // Post internal error if registration failed.
                     postStartFailure(mAdvertiseCallback,
                             AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
                 } else {
                     // Unregister application if it's already registered but advertise failed.
                     try {
-                        mBluetoothGatt.unregisterClient(mClientIf);
-                        mClientIf = -1;
+                        mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
+                        mAdvertiserId = -1;
                     } catch (RemoteException e) {
                         Log.e(TAG, "remote exception when unregistering", e);
                     }
@@ -290,7 +290,7 @@
         public void stopAdvertising() {
             synchronized (this) {
                 try {
-                    mBluetoothGatt.stopMultiAdvertising(mClientIf);
+                    mBluetoothGatt.stopMultiAdvertising(mAdvertiserId);
                     wait(LE_CALLBACK_TIMEOUT_MILLIS);
                 } catch (InterruptedException | RemoteException e) {
                     Log.e(TAG, "Failed to stop advertising", e);
@@ -305,20 +305,20 @@
         }
 
         /**
-         * Application interface registered - app is ready to go
+         * Advertiser interface registered - app is ready to go
          */
         @Override
-        public void onClientRegistered(int status, int clientIf) {
-            Log.d(TAG, "onClientRegistered() - status=" + status + " clientIf=" + clientIf);
+        public void onAdvertiserRegistered(int status, int advertiserId) {
+            Log.d(TAG, "onAdvertiserRegistered() - status=" + status + " advertiserId=" + advertiserId);
             synchronized (this) {
                 if (status == BluetoothGatt.GATT_SUCCESS) {
                     try {
-                        if (mClientIf == -1) {
-                            // Registration succeeds after timeout, unregister client.
-                            mBluetoothGatt.unregisterClient(clientIf);
+                        if (mAdvertiserId == -1) {
+                            // Registration succeeds after timeout, unregister advertiser.
+                            mBluetoothGatt.unregisterAdvertiser(advertiserId);
                         } else {
-                            mClientIf = clientIf;
-                            mBluetoothGatt.startMultiAdvertising(mClientIf, mAdvertisement,
+                            mAdvertiserId = advertiserId;
+                            mBluetoothGatt.startMultiAdvertising(mAdvertiserId, mAdvertisement,
                                     mScanResponse, mSettings);
                         }
                         return;
@@ -327,7 +327,7 @@
                     }
                 }
                 // Registration failed.
-                mClientIf = -1;
+                mAdvertiserId = -1;
                 notifyAll();
             }
         }
@@ -346,10 +346,10 @@
                         postStartFailure(mAdvertiseCallback, status);
                     }
                 } else {
-                    // unregister client for stop.
+                    // unregister advertiser for stop.
                     try {
-                        mBluetoothGatt.unregisterClient(mClientIf);
-                        mClientIf = -1;
+                        mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
+                        mAdvertiserId = -1;
                         mIsAdvertising = false;
                         mLeAdvertisers.remove(mAdvertiseCallback);
                     } catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/le/IAdvertiserCallback.aidl b/core/java/android/bluetooth/le/IAdvertiserCallback.aidl
new file mode 100644
index 0000000..c58b1df
--- /dev/null
+++ b/core/java/android/bluetooth/le/IAdvertiserCallback.aidl
@@ -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 android.bluetooth.le;
+
+import android.bluetooth.le.AdvertiseSettings;
+
+/**
+ * Callback definitions for interacting with Advertiser
+ * @hide
+ */
+oneway interface IAdvertiserCallback {
+    void onAdvertiserRegistered(in int status, in int advertiserId);
+
+    void onMultiAdvertiseCallback(in int status, boolean isStart,
+                                  in AdvertiseSettings advertiseSettings);
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b3320d6..daa1b93 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,6 +1877,7 @@
         if (extras != null) {
             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
             if (!TextUtils.isEmpty(accountName)) {
+                // TODO: No references to Google in AOSP
                 account = new Account(accountName, "com.google");
             }
             extras.remove(SYNC_EXTRAS_ACCOUNT);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 467eb89..2f2ffc9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1130,7 +1130,9 @@
      * <strong>Note: you should not <em>rely</em> on the system deleting these
      * files for you; you should always have a reasonable maximum, such as 1 MB,
      * for the amount of space you consume with cache files, and prune those
-     * files when exceeding that space.</strong>
+     * files when exceeding that space.</strong> If your app requires a larger
+     * cache (larger than 1 MB), you should use {@link #getExternalCacheDir()}
+     * instead.
      * <p>
      * The returned path may change over time if the calling app is moved to an
      * adopted storage device, so only relative paths should be persisted.
@@ -1142,6 +1144,7 @@
      * @see #openFileOutput
      * @see #getFileStreamPath
      * @see #getDir
+     * @see #getExternalCacheDir
      */
     public abstract File getCacheDir();
 
@@ -1190,7 +1193,7 @@
      * </ul>
      * <p>
      * If a shared storage device is emulated (as determined by
-     * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+     * {@link Environment#isExternalStorageEmulated(File)}), its contents are
      * backed by a private user data partition, which means there is little
      * benefit to storing data here instead of the private directory returned by
      * {@link #getCacheDir()}.
@@ -2740,6 +2743,7 @@
             //@hide: SOUND_TRIGGER_SERVICE,
             SHORTCUT_SERVICE,
             //@hide: CONTEXTHUB_SERVICE,
+            SYSTEM_HEALTH_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2782,8 +2786,10 @@
      *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
      *  handling management of network connections.
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
-     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
-     * Wi-Fi connectivity.
+     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
+     *  connectivity.  On releases before NYC, it should only be obtained from an application
+     *  context, and not from any other derived context to avoid memory leaks within the calling
+     *  process.
      *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
      *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
      * Wi-Fi Direct connectivity.
@@ -3156,7 +3162,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
@@ -3672,6 +3678,12 @@
     public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";
 
     /**
+     * Service defining the policy for access to device identifiers.
+     * @hide
+     */
+    public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d537739..02c8f0c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -128,7 +128,7 @@
  *     a list of people, which the user can browse through.  This example is a
  *     typical top-level entry into the Contacts application, showing you the
  *     list of people. Selecting a particular person to view would result in a
- *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/N</i></b> }
+ *     new intent { <b>{@link #ACTION_VIEW} <i>content://contacts/people/N</i></b> }
  *     being used to start an activity to display that person.</p>
  *   </li>
  * </ul>
@@ -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
@@ -3037,6 +3037,18 @@
             "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
 
     /**
+     * Broadcast sent to the system user when the 'device locked' state changes for any user.
+     * Carries an extra {@link #EXTRA_USER_HANDLE} that specifies the ID of the user for which
+     * the device was locked or unlocked.
+     *
+     * This is only sent to registered receivers.
+     *
+     * @hide
+     */
+    public static final String ACTION_DEVICE_LOCKED_CHANGED =
+            "android.intent.action.DEVICE_LOCKED_CHANGED";
+
+    /**
      * Sent when the user taps on the clock widget in the system's "quick settings" area.
      */
     public static final String ACTION_QUICK_CLOCK =
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 22ab43b..f5a79c8 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -124,7 +124,7 @@
  * <em>Note that authority matching here is <b>case sensitive</b>, unlike
  * formal RFC host names!</em>  You should thus always use lower case letters
  * for your authority.
- * 
+ *
  * <p><strong>Data Path</strong> matches if any of the given values match the
  * Intent's data path <em>and</em> both a scheme and authority in the filter
  * has matched against the Intent, <em>or</em> no paths were supplied in the
@@ -265,6 +265,7 @@
     public static final String SCHEME_HTTPS = "https";
 
     private int mPriority;
+    private int mOrder;
     private final ArrayList<String> mActions;
     private ArrayList<String> mCategories = null;
     private ArrayList<String> mDataSchemes = null;
@@ -358,8 +359,8 @@
      * the {@link MalformedMimeTypeException} exception that the constructor
      * can call and turns it into a runtime exception.
      *
-     * @param action The action to match, i.e. Intent.ACTION_VIEW.
-     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
+     * @param action The action to match, such as Intent.ACTION_VIEW.
+     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
      *
      * @return A new IntentFilter for the given action and type.
      *
@@ -386,7 +387,7 @@
      * no data characteristics are subsequently specified, then the
      * filter will only match intents that contain no data.
      *
-     * @param action The action to match, i.e. Intent.ACTION_MAIN.
+     * @param action The action to match, such as Intent.ACTION_MAIN.
      */
     public IntentFilter(String action) {
         mPriority = 0;
@@ -406,8 +407,8 @@
      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
      * not syntactically correct.
      *
-     * @param action The action to match, i.e. Intent.ACTION_VIEW.
-     * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
+     * @param action The action to match, such as Intent.ACTION_VIEW.
+     * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
      *
      */
     public IntentFilter(String action, String dataType)
@@ -425,6 +426,7 @@
      */
     public IntentFilter(IntentFilter o) {
         mPriority = o.mPriority;
+        mOrder = o.mOrder;
         mActions = new ArrayList<String>(o.mActions);
         if (o.mCategories != null) {
             mCategories = new ArrayList<String>(o.mCategories);
@@ -477,6 +479,16 @@
         return mPriority;
     }
 
+    /** @hide */
+    public final void setOrder(int order) {
+        mOrder = order;
+    }
+
+    /** @hide */
+    public final int getOrder() {
+        return mOrder;
+    }
+
     /**
      * Set whether this filter will needs to be automatically verified against its data URIs or not.
      * The default is false.
@@ -640,7 +652,7 @@
      * in the filter, then an Intent's action must be one of those values for
      * it to match.  If no actions are included, the Intent action is ignored.
      *
-     * @param action Name of the action to match, i.e. Intent.ACTION_VIEW.
+     * @param action Name of the action to match, such as Intent.ACTION_VIEW.
      */
     public final void addAction(String action) {
         if (!mActions.contains(action)) {
@@ -709,7 +721,7 @@
      * <p>Throws {@link MalformedMimeTypeException} if the given MIME type is
      * not syntactically correct.
      *
-     * @param type Name of the data type to match, i.e. "vnd.android.cursor.dir/person".
+     * @param type Name of the data type to match, such as "vnd.android.cursor.dir/person".
      *
      * @see #matchData
      */
@@ -786,7 +798,7 @@
      * and any schemes you receive from outside of Android should be
      * converted to lower case before supplying them here.</em></p>
      *
-     * @param scheme Name of the scheme to match, i.e. "http".
+     * @param scheme Name of the scheme to match, such as "http".
      *
      * @see #matchData
      */
@@ -897,7 +909,7 @@
          * Determine whether this AuthorityEntry matches the given data Uri.
          * <em>Note that this comparison is case-sensitive, unlike formal
          * RFC host names.  You thus should always normalize to lower-case.</em>
-         * 
+         *
          * @param data The Uri to match.
          * @return Returns either {@link IntentFilter#NO_MATCH_DATA},
          * {@link IntentFilter#MATCH_CATEGORY_PORT}, or
@@ -1352,7 +1364,7 @@
      * filter has no impact on matching unless that category is specified in
      * the intent.
      *
-     * @param category Name of category to match, i.e. Intent.CATEGORY_EMBED.
+     * @param category Name of category to match, such as Intent.CATEGORY_EMBED.
      */
     public final void addCategory(String category) {
         if (mCategories == null) mCategories = new ArrayList<String>();
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index c5e0ea7..3faf13b 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -44,7 +44,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using loaders, read the
- * <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/loaders.html">Loaders</a> developer guide.</p>
  * </div>
  *
  * @param <D> The result returned when the load is complete
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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 94c406a..5d2c6cd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -377,6 +377,7 @@
 
     /** @hide */
     @IntDef({
+            SCREEN_ORIENTATION_UNSET,
             SCREEN_ORIENTATION_UNSPECIFIED,
             SCREEN_ORIENTATION_LANDSCAPE,
             SCREEN_ORIENTATION_PORTRAIT,
@@ -398,6 +399,15 @@
     public @interface ScreenOrientation {}
 
     /**
+     * Internal constant used to indicate that the app didn't set a specific orientation value.
+     * Different from {@link #SCREEN_ORIENTATION_UNSPECIFIED} below as the app can set its
+     * orientation to {@link #SCREEN_ORIENTATION_UNSPECIFIED} while this means that the app didn't
+     * set anything. The system will mostly treat this similar to
+     * {@link #SCREEN_ORIENTATION_UNSPECIFIED}.
+     * @hide
+     */
+    public static final int SCREEN_ORIENTATION_UNSET = -2;
+    /**
      * Constant corresponding to <code>unspecified</code> in
      * the {@link android.R.attr#screenOrientation} attribute.
      */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e8f0845..26e0346 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
      */
@@ -5429,7 +5428,7 @@
      * {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
      * {@link #COMPONENT_ENABLED_STATE_DEFAULT}.  The last one means the
      * application's enabled state is based on the original information in
-     * the manifest as found in {@link ComponentInfo}.
+     * the manifest as found in {@link ApplicationInfo}.
      * @throws IllegalArgumentException if the named package does not exist.
      */
     public abstract int getApplicationEnabledSetting(String packageName);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index d208fe7..f5bcf64 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -160,4 +160,12 @@
      * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
      */
     public abstract boolean isPackageDataProtected(int userId, String packageName);
+
+    /**
+     * Gets whether the package was ever launched.
+     * @param packageName The package name.
+     * @param userId The user for which to check.
+     * @return Whether was launched.
+     */
+    public abstract boolean wasPackageEverLaunched(String packageName, int userId);
 }
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/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 6162d1a..aea843a 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -30,6 +30,7 @@
 import android.os.UserManager;
 import android.util.AtomicFile;
 import android.util.AttributeSet;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -54,6 +55,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -344,18 +346,61 @@
         }
     }
 
+    public void updateServices(int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "updateServices u" + userId);
+        }
+        List<ServiceInfo<V>> allServices;
+        synchronized (mServicesLock) {
+            final UserServices<V> user = findOrCreateUserLocked(userId);
+            // If services haven't been initialized yet - no updates required
+            if (user.services == null) {
+                return;
+            }
+            allServices = new ArrayList<>(user.services.values());
+        }
+        IntArray updatedUids = null;
+        for (ServiceInfo<V> service : allServices) {
+            int versionCode = service.componentInfo.applicationInfo.versionCode;
+            String pkg = service.componentInfo.packageName;
+            ApplicationInfo newAppInfo = null;
+            try {
+                newAppInfo = mContext.getPackageManager().getApplicationInfoAsUser(pkg, 0, userId);
+            } catch (NameNotFoundException e) {
+                // Package uninstalled - treat as null app info
+            }
+            // If package updated or removed
+            if ((newAppInfo == null) || (newAppInfo.versionCode != versionCode)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Package " + pkg + " uid=" + service.uid
+                            + " updated. New appInfo: " + newAppInfo);
+                }
+                if (updatedUids == null) {
+                    updatedUids = new IntArray();
+                }
+                updatedUids.add(service.uid);
+            }
+        }
+        if (updatedUids != null && updatedUids.size() > 0) {
+            int[] updatedUidsArray = updatedUids.toArray();
+            generateServicesMap(updatedUidsArray, userId);
+        }
+    }
+
     @VisibleForTesting
     protected boolean inSystemImage(int callerUid) {
         String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
-        for (String name : packages) {
-            try {
-                PackageInfo packageInfo =
-                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
-                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                    return true;
+        if (packages != null) {
+            for (String name : packages) {
+                try {
+                    PackageInfo packageInfo =
+                            mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
+                    if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        return true;
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                    return false;
                 }
-            } catch (PackageManager.NameNotFoundException e) {
-                return false;
             }
         }
         return false;
@@ -379,10 +424,11 @@
      */
     private void generateServicesMap(int[] changedUids, int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
+            Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = "
+                    + Arrays.toString(changedUids));
         }
 
-        final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
+        final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>();
         final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
         for (ResolveInfo resolveInfo : resolveInfos) {
             try {
diff --git a/core/java/android/content/pm/Signature.aidl b/core/java/android/content/pm/Signature.aidl
index 3a0d775..36c127a 100644
--- a/core/java/android/content/pm/Signature.aidl
+++ b/core/java/android/content/pm/Signature.aidl
@@ -2,19 +2,31 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 package android.content.pm;
 
-parcelable Signature;
+/* For the key attestation application id provider service we needed a native implementation
+ * of the Signature parcelable because the service is used by the native keystore.
+ * The native implementation is now located at
+ * system/security/keystore/Signature.cpp
+ * and
+ * system/security/keystore/include/keystore/Signature.h.
+ * and can be used by linking against libkeystore_binder.
+ *
+ * This is not the best arrangement. If you, dear reader, happen to implement native implementations
+ * for the package manager's parcelables, consider moving Signature.cpp/.h to your library and
+ * adjust keystore's dependencies accordingly. Thank you.
+ */
+parcelable Signature cpp_header "keystore/Signature.h";
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 35d3dc3..ee1f190 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1139,78 +1139,88 @@
      * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}.
      */
     public int diff(Configuration delta) {
+        return diff(delta, false /* compareUndefined */);
+    }
+
+    /**
+     * Variation of {@link #diff(Configuration)} with an option to skip checks for undefined values.
+     *
+     * @hide
+     */
+    public int diff(Configuration delta, boolean compareUndefined) {
         int changed = 0;
-        if (delta.fontScale > 0 && fontScale != delta.fontScale) {
+        if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) {
             changed |= ActivityInfo.CONFIG_FONT_SCALE;
         }
-        if (delta.mcc != 0 && mcc != delta.mcc) {
+        if ((compareUndefined || delta.mcc != 0) && mcc != delta.mcc) {
             changed |= ActivityInfo.CONFIG_MCC;
         }
-        if (delta.mnc != 0 && mnc != delta.mnc) {
+        if ((compareUndefined || delta.mnc != 0) && mnc != delta.mnc) {
             changed |= ActivityInfo.CONFIG_MNC;
         }
         fixUpLocaleList();
         delta.fixUpLocaleList();
-        if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
+        if ((compareUndefined || !delta.mLocaleList.isEmpty())
+                && !mLocaleList.equals(delta.mLocaleList)) {
             changed |= ActivityInfo.CONFIG_LOCALE;
             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
-        if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
-                deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
+        if ((compareUndefined || deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED)
+                && deltaScreenLayoutDir != (screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) {
             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
-        if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
+        if ((compareUndefined || delta.touchscreen != TOUCHSCREEN_UNDEFINED)
                 && touchscreen != delta.touchscreen) {
             changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
         }
-        if (delta.keyboard != KEYBOARD_UNDEFINED
+        if ((compareUndefined || delta.keyboard != KEYBOARD_UNDEFINED)
                 && keyboard != delta.keyboard) {
             changed |= ActivityInfo.CONFIG_KEYBOARD;
         }
-        if (delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED
+        if ((compareUndefined || delta.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED)
                 && keyboardHidden != delta.keyboardHidden) {
             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
         }
-        if (delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED
+        if ((compareUndefined || delta.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED)
                 && hardKeyboardHidden != delta.hardKeyboardHidden) {
             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
         }
-        if (delta.navigation != NAVIGATION_UNDEFINED
+        if ((compareUndefined || delta.navigation != NAVIGATION_UNDEFINED)
                 && navigation != delta.navigation) {
             changed |= ActivityInfo.CONFIG_NAVIGATION;
         }
-        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
+        if ((compareUndefined || delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED)
                 && navigationHidden != delta.navigationHidden) {
             changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
         }
-        if (delta.orientation != ORIENTATION_UNDEFINED
+        if ((compareUndefined || delta.orientation != ORIENTATION_UNDEFINED)
                 && orientation != delta.orientation) {
             changed |= ActivityInfo.CONFIG_ORIENTATION;
         }
-        if (getScreenLayoutNoDirection(delta.screenLayout) !=
-                    (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED)
+        if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
+                (SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
                 && getScreenLayoutNoDirection(screenLayout) !=
-                    getScreenLayoutNoDirection(delta.screenLayout)) {
+                getScreenLayoutNoDirection(delta.screenLayout)) {
             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
         }
-        if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
+        if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED))
                 && uiMode != delta.uiMode) {
             changed |= ActivityInfo.CONFIG_UI_MODE;
         }
-        if (delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED
+        if ((compareUndefined || delta.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED)
                 && screenWidthDp != delta.screenWidthDp) {
             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
         }
-        if (delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED
+        if ((compareUndefined || delta.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED)
                 && screenHeightDp != delta.screenHeightDp) {
             changed |= ActivityInfo.CONFIG_SCREEN_SIZE;
         }
-        if (delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+        if ((compareUndefined || delta.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED)
                 && smallestScreenWidthDp != delta.smallestScreenWidthDp) {
             changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
         }
-        if (delta.densityDpi != DENSITY_DPI_UNDEFINED
+        if ((compareUndefined || delta.densityDpi != DENSITY_DPI_UNDEFINED)
                 && densityDpi != delta.densityDpi) {
             changed |= ActivityInfo.CONFIG_DENSITY;
         }
diff --git a/core/java/android/database/CursorJoiner.java b/core/java/android/database/CursorJoiner.java
index e3c2988..a95263b 100644
--- a/core/java/android/database/CursorJoiner.java
+++ b/core/java/android/database/CursorJoiner.java
@@ -27,7 +27,7 @@
  *
  * <pre>
  * CursorJoiner joiner = new CursorJoiner(cursorA, keyColumnsofA, cursorB, keyColumnsofB);
- * for (CursorJointer.Result joinerResult : joiner) {
+ * for (CursorJoiner.Result joinerResult : joiner) {
  *     switch (joinerResult) {
  *         case LEFT:
  *             // handle case where a row in cursorA is unique
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0f64b92..8e17832 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1371,6 +1371,7 @@
 
     /**
      * Convenience method for replacing a row in the database.
+     * Inserts a new row if a row does not already exist.
      *
      * @param table the table in which to replace the row
      * @param nullColumnHack optional; may be <code>null</code>.
@@ -1381,7 +1382,7 @@
      *            provides the name of nullable column name to explicitly insert a NULL into
      *            in the case where your <code>initialValues</code> is empty.
      * @param initialValues this map contains the initial column values for
-     *   the row.
+     *   the row. The keys should be the column names and the values the column values.
      * @return the row ID of the newly inserted row, or -1 if an error occurred
      */
     public long replace(String table, String nullColumnHack, ContentValues initialValues) {
@@ -1396,6 +1397,7 @@
 
     /**
      * Convenience method for replacing a row in the database.
+     * Inserts a new row if a row does not already exist.
      *
      * @param table the table in which to replace the row
      * @param nullColumnHack optional; may be <code>null</code>.
@@ -1406,7 +1408,7 @@
      *            provides the name of nullable column name to explicitly insert a NULL into
      *            in the case where your <code>initialValues</code> is empty.
      * @param initialValues this map contains the initial column values for
-     *   the row. The key
+     *   the row. The keys should be the column names and the values the column values.
      * @throws SQLException
      * @return the row ID of the newly inserted row, or -1 if an error occurred
      */
@@ -1740,7 +1742,7 @@
      * Returns true if the new version code is greater than the current database version.
      *
      * @param newVersion The new version code.
-     * @return True if the new version code is greater than the current database version. 
+     * @return True if the new version code is greater than the current database version.
      */
     public boolean needUpgrade(int newVersion) {
         return newVersion > getVersion();
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index ceed171..864a9bb 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -6,15 +6,44 @@
 Applications use these classes to manage private databases. If creating a
 content provider, you will probably have to use these classes to create and
 manage your own database to store content. See <a
-href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> to learn
-the conventions for implementing a content provider. See the
-NotePadProvider class in the NotePad sample application in the SDK for an
-example of a content provider. Android ships with SQLite version 3.4.0
-<p>If you are working with data sent to you by a provider, you will not use
-these SQLite classes, but instead use the generic {@link android.database}
-classes.
-<p>Android ships with the sqlite3 database tool in the <code>tools/</code>
-folder. You can use this tool to browse or run SQL commands on the device. Run by
-typing <code>sqlite3</code> in a shell window.
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
+to learn the conventions for implementing a content provider. If you are working
+with data sent to you by a provider, you do not use these SQLite classes, but
+instead use the generic {@link android.database} classes.
+
+<p>The Android SDK and Android emulators both include the
+<a href="{@docRoot}studio/command-line/sqlite3.html">sqlite3</a> command-line
+database tool. On your development machine, run the tool from the
+<code>platform-tools/</code> folder of your SDK. On the emulator, run the tool
+with adb shell, for example, <code>adb -e shell sqlite3</code>.
+
+<p>The version of SQLite depends on the version of Android. See the following table:
+<table style="width:auto;">
+  <tr><th>Android API</th><th>SQLite Version</th></tr>
+  <tr><td>API 24</td><td>3.9</td></tr>
+  <tr><td>API 21</td><td>3.8</td></tr>
+  <tr><td>API 11</td><td>3.7</td></tr>
+  <tr><td>API 8</td><td>3.6</td></tr>
+  <tr><td>API 3</td><td>3.5</td></tr>
+  <tr><td>API 1</td><td>3.4</td></tr>
+</table>
+
+<p>Some device manufacturers include different versions of SQLite on their devices.
+  There are two ways to programmatically determine the version number.
+
+<ul>
+  <li>If available, use the sqlite3 tool, for example:
+    <code>adb -e shell sqlite3 --version</code>.</li>
+  <li>Create and query an in-memory database as shown in the following code sample:
+    <pre>
+    String query = "select sqlite_version() AS sqlite_version";
+    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
+    Cursor cursor = db.rawQuery(query, null);
+    String sqliteVersion = "";
+    if (cursor.moveToNext()) {
+        sqliteVersion = cursor.getString(0);
+    }</pre>
+  </li>
+</ul>
 </BODY>
 </HTML>
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 4b21187..1d85493 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -221,34 +221,32 @@
     public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
 
     /**
-     * <p>
-     * Finish the deferred output configurations where the output Surface was not configured before.
-     * </p>
-     * <p>
-     * For camera use cases where a preview and other output configurations need to be configured,
-     * it can take some time for the preview Surface to be ready (e.g., if the preview Surface is
-     * obtained from {@link android.view.SurfaceView}, the SurfaceView is ready after the UI layout
-     * is done, then it takes some time to get the preview Surface).
-     * </p>
-     * <p>
-     * To speed up camera startup time, the application can configure the
-     * {@link CameraCaptureSession} with the desired preview size, and defer the preview output
-     * configuration until the Surface is ready. After the {@link CameraCaptureSession} is created
-     * successfully with this deferred configuration and other normal configurations, the
-     * application can submit requests that don't include deferred output Surfaces. Once the
-     * deferred Surface is ready, the application can set the Surface to the same deferred output
-     * configuration with the {@link OutputConfiguration#setDeferredSurface} method, and then finish
-     * the deferred output configuration via this method, before it can submit requests with this
-     * output target.
-     * </p>
-     * <p>
-     * The output Surfaces included by this list of deferred {@link OutputConfiguration
-     * OutputConfigurations} can be used as {@link CaptureRequest} targets as soon as this call
-     * returns;
-     * </p>
-     * <p>
-     * This method is not supported by Legacy devices.
-     * </p>
+     * <p>Finish the deferred output configurations where the output Surface was not configured
+     * before.</p>
+     *
+     * <p>For camera use cases where a preview and other output configurations need to be
+     * configured, it can take some time for the preview Surface to be ready. For example, if the
+     * preview Surface is obtained from {@link android.view.SurfaceView}, the SurfaceView will only
+     * be ready after the UI layout is done, potentially delaying camera startup.</p>
+     *
+     * <p>To speed up camera startup time, the application can configure the
+     * {@link CameraCaptureSession} with the eventual preview size (via
+     * {@link OutputConfiguration#OutputConfiguration(Size,Class) a deferred OutputConfiguration}),
+     * and defer the preview output configuration until the Surface is ready. After the
+     * {@link CameraCaptureSession} is created successfully with this deferred output and other
+     * normal outputs, the application can start submitting requests as long as they do not include
+     * deferred output Surfaces. Once a deferred Surface is ready, the application can set the
+     * Surface on the deferred output configuration with the
+     * {@link OutputConfiguration#setDeferredSurface} method, and then finish the deferred output
+     * configuration via this method, before it can submit capture requests with this output
+     * target.</p>
+     *
+     * <p>The output Surfaces included by this list of deferred
+     * {@link OutputConfiguration OutputConfigurations} can be used as {@link CaptureRequest}
+     * targets as soon as this call returns.</p>
+     *
+     * <p>This method is not supported by
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}-level devices.</p>
      *
      * @param deferredOutputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
      *            have had {@link OutputConfiguration#setDeferredSurface setDeferredSurface} invoked
@@ -256,13 +254,12 @@
      * @throws CameraAccessException if the camera device is no longer connected or has encountered
      *             a fatal error.
      * @throws IllegalStateException if this session is no longer active, either because the session
-     *             was explicitly closed, a new session has been created or the camera device has
-     *             been closed. Or if this output configuration was already finished with the
-     *             included surface before.
+     *             was explicitly closed, a new session has been created, or the camera device has
+     *             been closed.
      * @throws IllegalArgumentException for invalid output configurations, including ones where the
      *             source of the Surface is no longer valid or the Surface is from a unsupported
-     *             source.
-     * @hide
+     *             source. Or if one of the output configuration was already finished with an
+     *             included surface in a prior call.
      */
     public abstract void finishDeferredConfiguration(
             List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException;
@@ -764,13 +761,6 @@
     }
 
     /**
-     * Temporary for migrating to Callback naming
-     * @hide
-     */
-    public static abstract class StateListener extends StateCallback {
-    }
-
-    /**
      * <p>A callback object for tracking the progress of a {@link CaptureRequest} submitted to the
      * camera device.</p>
      *
@@ -835,16 +825,6 @@
          */
         public void onCaptureStarted(@NonNull CameraCaptureSession session,
                 @NonNull CaptureRequest request, long timestamp, long frameNumber) {
-            // Temporary trampoline for API change transition
-            onCaptureStarted(session, request, timestamp);
-        }
-
-        /**
-         * Temporary for API change transition
-         * @hide
-         */
-        public void onCaptureStarted(CameraCaptureSession session,
-                CaptureRequest request, long timestamp) {
             // default empty implementation
         }
 
@@ -1064,11 +1044,4 @@
         }
     }
 
-    /**
-     * Temporary for migrating to Callback naming
-     * @hide
-     */
-    public static abstract class CaptureListener extends CaptureCallback {
-    }
-
 }
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index c54d1e1..9e00b65 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -239,9 +239,9 @@
      * <p>If a prior CameraCaptureSession already exists when this method is called, the previous
      * session will no longer be able to accept new capture requests and will be closed. Any
      * in-progress capture requests made on the prior session will be completed before it's closed.
-     * {@link CameraCaptureSession.StateListener#onConfigured} for the new session may be invoked
-     * before {@link CameraCaptureSession.StateListener#onClosed} is invoked for the prior
-     * session. Once the new session is {@link CameraCaptureSession.StateListener#onConfigured
+     * {@link CameraCaptureSession.StateCallback#onConfigured} for the new session may be invoked
+     * before {@link CameraCaptureSession.StateCallback#onClosed} is invoked for the prior
+     * session. Once the new session is {@link CameraCaptureSession.StateCallback#onConfigured
      * configured}, it is able to start capturing its own requests. To minimize the transition time,
      * the {@link CameraCaptureSession#abortCaptures} call can be used to discard the remaining
      * requests for the prior capture session before a new one is created. Note that once the new
@@ -265,7 +265,7 @@
      * but the camera device won't meet the frame rate guarantees as described in
      * {@link StreamConfigurationMap#getOutputMinFrameDuration}. Or third, if the output set
      * cannot be used at all, session creation will fail entirely, with
-     * {@link CameraCaptureSession.StateListener#onConfigureFailed} being invoked.</p>
+     * {@link CameraCaptureSession.StateCallback#onConfigureFailed} being invoked.</p>
      *
      * <p>For the type column, {@code PRIV} refers to any target whose available sizes are found
      * using {@link StreamConfigurationMap#getOutputSizes(Class)} with no direct application-visible
@@ -984,13 +984,6 @@
     }
 
     /**
-     * Temporary for migrating to Callback naming
-     * @hide
-     */
-    public static abstract class StateListener extends StateCallback {
-    }
-
-    /**
      * To be inherited by android.hardware.camera2.* code only.
      * @hide
      */
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 9478dc0..1a51acd 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -27,6 +27,7 @@
 import android.media.ExifInterface;
 import android.media.Image;
 import android.os.SystemClock;
+import android.util.Log;
 import android.util.Size;
 
 import java.io.IOException;
@@ -89,21 +90,43 @@
             throw new IllegalArgumentException("Null argument to DngCreator constructor");
         }
 
-        // Find current time
+        // Find current time in milliseconds since 1970
         long currentTime = System.currentTimeMillis();
+        // Assume that sensor timestamp has that timebase to start
+        long timeOffset = 0;
 
-        // Find boot time
-        long bootTimeMillis = currentTime - SystemClock.elapsedRealtime();
+        int timestampSource = characteristics.get(
+                CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
+
+        if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
+            // This means the same timebase as SystemClock.elapsedRealtime(),
+            // which is CLOCK_BOOTTIME
+            timeOffset = currentTime - SystemClock.elapsedRealtime();
+        } else if (timestampSource == CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN) {
+            // This means the same timebase as System.currentTimeMillis(),
+            // which is CLOCK_MONOTONIC
+            timeOffset = currentTime - SystemClock.uptimeMillis();
+        } else {
+            // Unexpected time source - treat as CLOCK_MONOTONIC
+            Log.w(TAG, "Sensor timestamp source is unexpected: " + timestampSource);
+            timeOffset = currentTime - SystemClock.uptimeMillis();
+        }
 
         // Find capture time (nanos since boot)
         Long timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP);
         long captureTime = currentTime;
         if (timestamp != null) {
-            captureTime = timestamp / 1000000 + bootTimeMillis;
+            captureTime = timestamp / 1000000 + timeOffset;
         }
 
+        // Create this fresh each time since the time zone may change while a long-running application
+        // is active.
+        final DateFormat dateTimeStampFormat =
+            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
+        dateTimeStampFormat.setTimeZone(TimeZone.getDefault());
+
         // Format for metadata
-        String formattedCaptureTime = sDateTimeStampFormat.format(captureTime);
+        String formattedCaptureTime = dateTimeStampFormat.format(captureTime);
 
         nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(),
                 formattedCaptureTime);
@@ -450,13 +473,10 @@
     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
     private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
     private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
-    private static final DateFormat sDateTimeStampFormat =
-            new SimpleDateFormat(TIFF_DATETIME_FORMAT);
     private final Calendar mGPSTimeStampCalendar = Calendar
             .getInstance(TimeZone.getTimeZone("UTC"));
 
     static {
-        sDateTimeStampFormat.setTimeZone(TimeZone.getDefault());
         sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC"));
     }
 
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 69c00e9..f897d85 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -229,7 +229,6 @@
      * @param klass a non-{@code null} {@link Class} object reference that indicates the source of
      *            this surface. Only {@link android.view.SurfaceHolder SurfaceHolder.class} and
      *            {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
-     * @hide
      */
     public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass) {
         checkNotNull(klass, "surfaceSize must not be null");
@@ -283,7 +282,6 @@
      * @throws IllegalArgumentException if the Surface is invalid.
      * @throws IllegalStateException if a Surface was already set to this deferred
      *         OutputConfiguration.
-     * @hide
      */
     public void setDeferredSurface(@NonNull Surface surface) {
         checkNotNull(surface, "Surface must not be null");
diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
index 7c46e50..ed30ff3 100644
--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
@@ -29,8 +29,9 @@
  * (and new ones won't begin).
  *
  * <p>The initial state is to allow all tasks to be started and finished. A task may only be started
- * once, after which it must be finished before starting again. Likewise, finishing a task
- * that hasn't been started is also not allowed.</p>
+ * once, after which it must be finished before starting again. Likewise, a task may only be
+ * finished once, after which it must be started before finishing again. It is okay to finish a
+ * task before starting it due to different threads handling starting and finishing.</p>
  *
  * <p>When draining begins, no more new tasks can be started. This guarantees that at some
  * point when all the tasks are finished there will be no more collective new tasks,
@@ -60,6 +61,11 @@
 
     /** Set of tasks which have been started but not yet finished with #taskFinished */
     private final Set<T> mTaskSet = new HashSet<T>();
+    /**
+     * Set of tasks which have been finished but not yet started with #taskStarted. This may happen
+     * if taskStarted and taskFinished are called from two different threads.
+     */
+    private final Set<T> mEarlyFinishedTaskSet = new HashSet<T>();
     private final Object mLock = new Object();
 
     private boolean mDraining = false;
@@ -118,8 +124,12 @@
                 throw new IllegalStateException("Can't start more tasks after draining has begun");
             }
 
-            if (!mTaskSet.add(task)) {
-                throw new IllegalStateException("Task " + task + " was already started");
+            // Try to remove the task from the early finished set.
+            if (!mEarlyFinishedTaskSet.remove(task)) {
+                // The task is not finished early. Add it to the started set.
+                if (!mTaskSet.add(task)) {
+                    throw new IllegalStateException("Task " + task + " was already started");
+                }
             }
         }
     }
@@ -128,8 +138,7 @@
     /**
      * Mark an asynchronous task as having finished.
      *
-     * <p>A task cannot be finished if it hasn't started. Once finished, a task
-     * cannot be finished again (unless it's started again).</p>
+     * <p>A task cannot be finished more than once without first having started.</p>
      *
      * @param task a key to identify a task
      *
@@ -137,7 +146,7 @@
      * @see #beginDrain
      *
      * @throws IllegalStateException
-     *          If attempting to start a task which is already finished (and not re-started),
+     *          If attempting to finish a task which is already finished (and not started),
      */
     public void taskFinished(T task) {
         synchronized (mLock) {
@@ -145,8 +154,12 @@
                 Log.v(TAG + "[" + mName + "]", "taskFinished " + task);
             }
 
+            // Try to remove the task from started set.
             if (!mTaskSet.remove(task)) {
-                throw new IllegalStateException("Task " + task + " was already finished");
+                // Task is not started yet. Add it to the early finished set.
+                if (!mEarlyFinishedTaskSet.add(task)) {
+                    throw new IllegalStateException("Task " + task + " was already finished");
+                }
             }
 
             // If this is the last finished task and draining has already begun, fire #onDrained
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 2aed53c..0b919c7 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -118,10 +118,18 @@
     /**
      * Load a nano app on a specified context hub.
      *
+     * Note that loading is asynchronous.  When we return from this method,
+     * the nano app (probably) hasn't loaded yet.  Assuming a return of 0
+     * from this method, then the final success/failure for the load, along
+     * with the "handle" for the nanoapp, is all delivered in a byte
+     * string via a call to Callback.onMessageReceipt.
+     *
+     * TODO(b/30784270): Provide a better success/failure and "handle" delivery.
+     *
      * @param hubHandle handle of context hub to load the app on.
      * @param app the nanoApp to load on the hub
      *
-     * @return int nanoAppInstance of the loaded nanoApp on success,
+     * @return 0 if the command for loading was sent to the context hub;
      *         -1 otherwise
      *
      * @see NanoApp
@@ -137,9 +145,17 @@
     /**
      * Unload a specified nanoApp
      *
-     * @param nanoAppHandle handle of the nanoApp to load
+     * Note that unloading is asynchronous.  When we return from this method,
+     * the nano app (probably) hasn't unloaded yet.  Assuming a return of 0
+     * from this method, then the final success/failure for the unload is
+     * delivered in a byte string via a call to Callback.onMessageReceipt.
      *
-     * @return int  0 on success, -1 otherwise
+     * TODO(b/30784270): Provide a better success/failure delivery.
+     *
+     * @param nanoAppHandle handle of the nanoApp to unload
+     *
+     * @return 0 if the command for unloading was sent to the context hub;
+     *         -1 otherwise
      */
     public int unloadNanoApp(int nanoAppHandle) {
         try {
@@ -152,6 +168,24 @@
     /**
      * get information about the nano app instance
      *
+     * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct
+     * information for several fields, specifically:
+     * - getName()
+     * - getPublisher()
+     * - getNeededExecMemBytes()
+     * - getNeededReadMemBytes()
+     * - getNeededWriteMemBytes()
+     *
+     * For example, say you call loadNanoApp() with a NanoApp that has
+     * getName() returning "My Name".  Later, if you call getNanoAppInstanceInfo
+     * for that nanoapp, the returned NanoAppInstanceInfo's getName()
+     * method will claim "Preloaded app, unknown", even though you would
+     * have expected "My Name".  For now, as the user, you'll need to
+     * separately track the above fields if they are of interest to you.
+     *
+     * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
+     *     correct information.
+     *
      * @param nanoAppHandle handle of the nanoAppInstance
      * @return NanoAppInstanceInfo Information about the nano app instance.
      *
@@ -186,6 +220,14 @@
     /**
      * Send a message to a specific nano app instance on a context hub.
      *
+     * Note that the return value of this method only speaks of success
+     * up to the point of sending this to the Context Hub.  It is not
+     * an assurance that the Context Hub successfully sent this message
+     * on to the nanoapp.  If assurance is desired, a protocol should be
+     * established between your code and the nanoapp, with the nanoapp
+     * sending a confirmation message (which will be reported via
+     * Callback.onMessageReceipt).
+     *
      * @param hubHandle handle of the hub to send the message to
      * @param nanoAppHandle  handle of the nano app to send to
      * @param message Message to be sent
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 893ed3f..35df015 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -18,6 +18,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -146,6 +148,36 @@
         return mContextHubInfo[contextHubHandle];
     }
 
+    // TODO(b/30808791): Remove this when NanoApp's API is correctly treating
+    // app IDs as 64-bits.
+    private static long parseAppId(NanoApp app) {
+        // NOTE: If this shifting seems odd (since it's actually "ONAN"), note
+        //     that it matches how this is defined in context_hub.h.
+        final int HEADER_MAGIC =
+            (((int)'N' <<  0) |
+             ((int)'A' <<  8) |
+             ((int)'N' << 16) |
+             ((int)'O' << 24));
+        final int HEADER_MAGIC_OFFSET = 4;
+        final int HEADER_APP_ID_OFFSET = 8;
+
+        ByteBuffer header = ByteBuffer.wrap(app.getAppBinary())
+            .order(ByteOrder.LITTLE_ENDIAN);
+
+        try {
+            if (header.getInt(HEADER_MAGIC_OFFSET) == HEADER_MAGIC) {
+                // This is a legitimate nanoapp header.  Let's grab the app ID.
+                return header.getLong(HEADER_APP_ID_OFFSET);
+            }
+        } catch (IndexOutOfBoundsException e) {
+            // The header is undersized.  We'll fall through to our code
+            // path below, which handles being unable to parse the header.
+        }
+        // We failed to parse the header.  Even through it's probably wrong,
+        // let's give NanoApp's idea of our ID.  This is at least consistent.
+        return app.getAppId();
+    }
+
     @Override
     public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
         checkPermissions();
@@ -165,6 +197,15 @@
         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
 
         long appId = app.getAppId();
+        // TODO(b/30808791): Remove this hack when the NanoApp API is fixed,
+        //     and getAppId() returns a 'long' instead of an 'int'.
+        if ((appId >> 32) != 0) {
+            // We're unlikely to notice this warning, but at least
+            // we can avoid running our hack logic.
+            Log.w(TAG, "Code has not been updated since API fix.");
+        } else {
+            appId = parseAppId(app);
+        }
 
         msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
         msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
@@ -330,9 +371,16 @@
         appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
         appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
 
+        String action;
+        if (mNanoAppHash.containsKey(appInstanceHandle)) {
+            action = "Updated";
+        } else {
+            action = "Added";
+        }
+
         mNanoAppHash.put(appInstanceHandle, appInfo);
-        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
-              + " version " + appVersion);
+        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
+              + appId + " version " + appVersion);
 
         return 0;
     }
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 8db70e9..bf35a3d 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -43,7 +43,8 @@
     private long mAppIdVendorMask;
 
     // Id of the context hub this instance is expected on
-    private int mContextHubId;
+    // TODO: Provide an API which will let us change this HubId.
+    private int mContextHubId = HUB_ANY;
 
     /**
      * Flag indicating any version. With this flag set, all versions shall match provided version.
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index 71a5a88..ac6d83f 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -113,7 +113,12 @@
     }
 
     /**
-     * Set the application version
+     * Get the application version
+     *
+     * NOTE: There is a race condition where shortly after loading, this
+     * may return -1 instead of the correct version.
+     *
+     * TODO(b/30970527): Fix this race condition.
      *
      * @return int - version of the app
      */
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 6e4c9de..fafe116 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -17,6 +17,7 @@
 package android.hardware.usb;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbPort;
@@ -116,4 +117,7 @@
 
     /* Sets the port's current role. */
     void setPortRoles(in String portId, int powerRole, int dataRole);
+
+   /* Sets USB device connection handler. */
+   void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
 }
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index c062b3a..160e261 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -16,10 +16,15 @@
 
 package android.hardware.usb;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
 import android.os.ParcelFileDescriptor;
+import dalvik.system.CloseGuard;
 
 import java.io.FileDescriptor;
-
+import java.nio.ByteBuffer;
 
 /**
  * This class is used for sending and receiving data and control messages to a USB device.
@@ -31,9 +36,13 @@
 
     private final UsbDevice mDevice;
 
+    private Context mContext;
+
     // used by the JNI code
     private long mNativeContext;
 
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     /**
      * UsbDevice should only be instantiated by UsbService implementation
      * @hide
@@ -42,8 +51,24 @@
         mDevice = device;
     }
 
-    /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
-        return native_open(name, pfd.getFileDescriptor());
+    /* package */ boolean open(String name, ParcelFileDescriptor pfd, @NonNull Context context) {
+        mContext = context.getApplicationContext();
+        boolean wasOpened = native_open(name, pfd.getFileDescriptor());
+
+        if (wasOpened) {
+            mCloseGuard.open("close");
+        }
+
+        return wasOpened;
+    }
+
+    /**
+     * @return The application context the connection was created for.
+     *
+     * @hide
+     */
+    public @Nullable Context getContext() {
+        return mContext;
     }
 
     /**
@@ -53,7 +78,10 @@
      * to retrieve a new instance to reestablish communication with the device.
      */
     public void close() {
-        native_close();
+        if (mNativeContext != 0) {
+            native_close();
+            mCloseGuard.close();
+        }
     }
 
     /**
@@ -185,9 +213,10 @@
      * </p>
      *
      * @param endpoint the endpoint for this transaction
-     * @param buffer buffer for data to send or receive
+     * @param buffer buffer for data to send or receive; can be {@code null} to wait for next
+     *               transaction without reading data
      * @param length the length of the data to send or receive
-     * @param timeout in milliseconds
+     * @param timeout in milliseconds, 0 is infinite
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
@@ -204,7 +233,7 @@
      * @param buffer buffer for data to send or receive
      * @param offset the index of the first byte in the buffer to send or receive
      * @param length the length of the data to send or receive
-     * @param timeout in milliseconds
+     * @param timeout in milliseconds, 0 is infinite
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
@@ -215,14 +244,33 @@
     }
 
     /**
+     * Reset USB port for the connected device.
+     *
+     * @return true if reset succeeds.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean resetDevice() {
+        return native_reset_device();
+    }
+
+    /**
      * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
-     * Note that this may return requests queued on multiple 
-     * {@link android.hardware.usb.UsbEndpoint}s.
-     * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
-     * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
-     * how to process the result of this function.
+     * <p>Note that this may return requests queued on multiple
+     * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use,
+     * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link
+     * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process
+     * the result of this function.</p>
+     * <p>Position and array offset of the request's buffer are ignored and assumed to be 0. The
+     * position will be set to the number of bytes read/written.</p>
      *
      * @return a completed USB request, or null if an error occurred
+     *
+     * @throws IllegalArgumentException if the number of bytes read or written is more than the
+     *                                  limit of the request's buffer. The number of bytes is
+     *                                  determined by the {@code length} parameter of
+     *                                  {@link UsbRequest#queue(ByteBuffer, int)}
      */
     public UsbRequest requestWait() {
         UsbRequest request = native_request_wait();
@@ -244,11 +292,20 @@
 
     private static void checkBounds(byte[] buffer, int start, int length) {
         final int bufferLength = (buffer != null ? buffer.length : 0);
-        if (start < 0 || start + length > bufferLength) {
+        if (length < 0 || start < 0 || start + length > bufferLength) {
             throw new IllegalArgumentException("Buffer start or length out of bounds.");
         }
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+        } finally {
+            super.finalize();
+        }
+    }
+
     private native boolean native_open(String deviceName, FileDescriptor pfd);
     private native void native_close();
     private native int native_get_fd();
@@ -263,4 +320,5 @@
             int offset, int length, int timeout);
     private native UsbRequest native_request_wait();
     private native String native_get_serial();
+    private native boolean native_reset_device();
 }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 629db06..1d20c78 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -19,7 +19,9 @@
 
 import com.android.internal.util.Preconditions;
 
+import android.annotation.Nullable;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
@@ -330,7 +332,7 @@
             ParcelFileDescriptor pfd = mService.openDevice(deviceName);
             if (pfd != null) {
                 UsbDeviceConnection connection = new UsbDeviceConnection(device);
-                boolean result = connection.open(deviceName, pfd);
+                boolean result = connection.open(deviceName, pfd, mContext);
                 pfd.close();
                 if (result) {
                     return connection;
@@ -469,8 +471,20 @@
      * {@hide}
      */
     public void grantPermission(UsbDevice device) {
+        grantPermission(device, Process.myUid());
+    }
+
+    /**
+     * Grants permission for USB device to given uid without showing system dialog.
+     * Only system components can call this function.
+     * @param device to request permissions for
+     * @uid uid to give permission
+     *
+     * {@hide}
+     */
+    public void grantPermission(UsbDevice device, int uid) {
         try {
-            mService.grantDevicePermission(device, Process.myUid());
+            mService.grantDevicePermission(device, uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -488,11 +502,9 @@
         try {
             int uid = mContext.getPackageManager()
                 .getPackageUidAsUser(packageName, mContext.getUserId());
-            mService.grantDevicePermission(device, uid);
+            grantPermission(device, uid);
         } catch (NameNotFoundException e) {
             Log.e(TAG, "Package " + packageName + " not found.", e);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -631,6 +643,26 @@
         }
     }
 
+    /**
+     * Sets the component that will handle USB device connection.
+     * <p>
+     * Setting component allows to specify external USB host manager to handle use cases, where
+     * selection dialog for an activity that will handle USB device is undesirable.
+     * Only system components can call this function, as it requires the MANAGE_USB permission.
+     *
+     * @param usbDeviceConnectionHandler The component to handle usb connections,
+     * {@code null} to unset.
+     *
+     * {@hide}
+     */
+    public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
+        try {
+            mService.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public static String addFunction(String functions, String function) {
         if (USB_FUNCTION_NONE.equals(functions)) {
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index ce66084..9f7592f 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -17,6 +17,8 @@
 package android.hardware.usb;
 
 import android.util.Log;
+import com.android.internal.util.Preconditions;
+import dalvik.system.CloseGuard;
 
 import java.nio.ByteBuffer;
 
@@ -48,6 +50,11 @@
     // for client use
     private Object mClientData;
 
+    // Prevent the connection from being finalized
+    private UsbDeviceConnection mConnection;
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     public UsbRequest() {
     }
 
@@ -60,25 +67,35 @@
      */
     public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
         mEndpoint = endpoint;
-        return native_init(connection, endpoint.getAddress(), endpoint.getAttributes(),
-                endpoint.getMaxPacketSize(), endpoint.getInterval());
+        mConnection = Preconditions.checkNotNull(connection);
+
+        boolean wasInitialized = native_init(connection, endpoint.getAddress(),
+                endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval());
+
+        if (wasInitialized) {
+            mCloseGuard.open("close");
+        }
+
+        return wasInitialized;
     }
 
     /**
      * Releases all resources related to this request.
      */
     public void close() {
-        mEndpoint = null;
-        native_close();
+        if (mNativeContext != 0) {
+            mEndpoint = null;
+            mConnection = null;
+            native_close();
+            mCloseGuard.close();
+        }
     }
 
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mEndpoint != null) {
-                Log.v(TAG, "endpoint still open in finalize(): " + this);
-                close();
-            }
+            mCloseGuard.warnIfOpen();
+            close();
         } finally {
             super.finalize();
         }
@@ -121,19 +138,28 @@
 
     /**
      * Queues the request to send or receive data on its endpoint.
-     * For OUT endpoints, the given buffer data will be sent on the endpoint.
-     * For IN endpoints, the endpoint will attempt to read the given number of bytes
-     * into the specified buffer.
-     * If the queueing operation is successful, we return true and the result will be
-     * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait}
+     * <p>For OUT endpoints, the given buffer data will be sent on the endpoint. For IN endpoints,
+     * the endpoint will attempt to read the given number of bytes into the specified buffer. If the
+     * queueing operation is successful, we return true and the result will be returned via {@link
+     * android.hardware.usb.UsbDeviceConnection#requestWait}</p>
      *
-     * @param buffer the buffer containing the bytes to write, or location to store
-     * the results of a read
-     * @param length number of bytes to read or write
+     * @param buffer the buffer containing the bytes to write, or location to store the results of a
+     *               read. Position and array offset will be ignored and assumed to be 0. Limit and
+     *               capacity will be ignored.
+     * @param length number of bytes to read or write.
+     *
      * @return true if the queueing operation succeeded
      */
     public boolean queue(ByteBuffer buffer, int length) {
         boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
+
+        // save our buffer for when the request has completed
+        mBuffer = buffer;
+        mLength = length;
+
+        // Note: On a buffer slice we lost the capacity information about the underlying buffer,
+        // hence we cannot check if the access would be a data leak/memory corruption.
+
         boolean result;
         if (buffer.isDirect()) {
             result = native_queue_direct(buffer, length, out);
@@ -142,10 +168,9 @@
         } else {
             throw new IllegalArgumentException("buffer is not direct and has no array");
         }
-        if (result) {
-            // save our buffer for when the request has completed
-            mBuffer = buffer;
-            mLength = length;
+        if (!result) {
+            mBuffer = null;
+            mLength = 0;
         }
         return result;
     }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ad3f4d2..c6338cb 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -266,7 +266,6 @@
     InputMethodManager mImm;
     
     int mTheme = 0;
-    boolean mHardwareAccelerated = false;
     
     LayoutInflater mInflater;
     TypedArray mThemeAttrs;
@@ -752,27 +751,27 @@
     }
 
     /**
-     * You can call this to try to enable hardware accelerated drawing for
-     * your IME. This must be set before {@link #onCreate}, so you
-     * will typically call it in your constructor.  It is not always possible
-     * to use hardware accelerated drawing in an IME (for example on low-end
-     * devices that do not have the resources to support this), so the call
-     * returns true if it succeeds otherwise false if you will need to draw
-     * in software.  You must be able to handle either case.
+     * You can call this to try to enable accelerated drawing for your IME. This must be set before
+     * {@link #onCreate()}, so you will typically call it in your constructor.  It is not always
+     * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
+     * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
+     * {@code false} if you will need to draw in software.  You must be able to handle either case.
      *
-     * @deprecated Starting in API 21, hardware acceleration is always enabled
-     *             on capable devices.
+     * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
+     * IME on capable devices even if this method is not explicitly called. Make sure that your IME
+     * is able to handle either case.</p>
+     *
+     * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
+     *         On API 21 and later devices the return value is basically just a hint and your IME
+     *         does not need to change the behavior based on the it
+     * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
      */
     @Deprecated
     public boolean enableHardwareAcceleration() {
         if (mWindow != null) {
             throw new IllegalStateException("Must be called before onCreate()");
         }
-        if (ActivityManager.isHighEndGfx()) {
-            mHardwareAccelerated = true;
-            return true;
-        }
-        return false;
+        return ActivityManager.isHighEndGfx();
     }
 
     @Override public void onCreate() {
@@ -793,9 +792,6 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
-        if (mHardwareAccelerated) {
-            mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
-        }
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
     }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8f62d3f..9e5aaf5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -343,6 +343,15 @@
     public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
 
     /**
+     * Action used to display a dialog that asks the user whether to avoid a network that is no
+     * longer validated. This intent is used to start the dialog in settings via startActivity.
+     *
+     * @hide
+     */
+    public static final String ACTION_PROMPT_LOST_VALIDATION =
+            "android.net.conn.PROMPT_LOST_VALIDATION";
+
+    /**
      * Invalid tethering type.
      * @see #startTethering(int, OnStartTetheringCallback, boolean)
      * @hide
@@ -1831,6 +1840,16 @@
         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
+    /* TODO: These permissions checks don't belong in client-side code. Move them to
+     * services.jar, possibly in com.android.server.net. */
+
+    /** {@hide} */
+    public static final boolean checkChangePermission(Context context) {
+        int uid = Binder.getCallingUid();
+        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
+                .getPackageNameForUid(context, uid), false /* throwException */);
+    }
+
     /** {@hide} */
     public static final void enforceChangePermission(Context context) {
         int uid = Binder.getCallingUid();
@@ -2595,7 +2614,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 +2688,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 +2874,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 +2890,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);
@@ -3211,6 +3251,27 @@
     }
 
     /**
+     * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
+     * only meaningful if the system is configured not to penalize such networks, e.g., if the
+     * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code
+     * NETWORK_AVOID_BAD_WIFI setting is unset}.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+     *
+     * @param network The network to accept.
+     *
+     * @hide
+     */
+    public void setAvoidUnvalidated(Network network) {
+        try {
+            mService.setAvoidUnvalidated(network);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Resets all connectivity manager settings back to factory defaults.
      * @hide
      */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d48c155..4aabda9 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -161,6 +161,7 @@
     void releaseNetworkRequest(in NetworkRequest networkRequest);
 
     void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
+    void setAvoidUnvalidated(in Network network);
 
     int getRestoreDefaultNetworkDelay(int networkType);
 
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
new file mode 100644
index 0000000..8f634bb
--- /dev/null
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -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 android.net;
+
+import android.os.Parcelable;
+import android.net.ConnectivityMetricsEvent;
+
+/** {@hide} */
+interface IIpConnectivityMetrics {
+
+    /**
+     * @return number of remaining available slots in buffer.
+     */
+    int logEvent(in ConnectivityMetricsEvent event);
+}
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index 93463b4..005dd6e 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -22,7 +22,6 @@
     void onUidRulesChanged(int uid, int uidRules);
     void onMeteredIfacesChanged(in String[] meteredIfaces);
     void onRestrictBackgroundChanged(boolean restrictBackground);
-    void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted);
-    void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted);
+    void onUidPoliciesChanged(int uid, int uidPolicies);
 
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 224ff5b..495340d 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -58,10 +58,6 @@
     /** Callback used to change internal state on tethering */
     void onTetheringChanged(String iface, boolean tethering);
 
-    /** Control which applications can be exempt from background data restrictions */
-    void addRestrictBackgroundWhitelistedUid(int uid);
-    void removeRestrictBackgroundWhitelistedUid(int uid);
-    int[] getRestrictBackgroundWhitelistedUids();
     /** Gets the restrict background status based on the caller's UID:
         1 - disabled
         2 - whitelisted
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 8cdd153..ea53a71 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -80,6 +80,14 @@
         mFlags.add(FLAG_DOWN);
     }
 
+    /**
+     * Set flags so that no changes will be made to the up/down status.
+     */
+    public void ignoreInterfaceUpDownStatus() {
+        mFlags.remove(FLAG_UP);
+        mFlags.remove(FLAG_DOWN);
+    }
+
     public LinkAddress getLinkAddress() {
         return mAddr;
     }
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index b83fb26..0f0e9c4 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -516,13 +516,11 @@
                     Os.setsockoptLinger(fd, OsConstants.SOL_SOCKET, OsConstants.SO_LINGER, linger);
                     break;
                 case SocketOptions.SO_TIMEOUT:
-                    /*
-                     * SO_TIMEOUT from the core library gets converted to
-                     * SO_SNDTIMEO, but the option is supposed to set both
-                     * send and receive timeouts. Note: The incoming timeout
-                     * value is in milliseconds.
-                     */
+                    // The option must set both send and receive timeouts.
+                    // Note: The incoming timeout value is in milliseconds.
                     StructTimeval timeval = StructTimeval.fromMillis(intValue);
+                    Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
+                            timeval);
                     Os.setsockoptTimeval(fd, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
                             timeval);
                     break;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ebb9601..6196400 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -182,8 +182,15 @@
      */
     public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
 
+    /**
+     * Indicates that this network is available for use by apps, and not a network that is being
+     * kept up in the background to facilitate fast network switching.
+     * @hide
+     */
+    public static final int NET_CAPABILITY_FOREGROUND = 18;
+
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
-    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
 
     /**
      * Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -194,7 +201,8 @@
             // http://b/18206275
             (1 << NET_CAPABILITY_TRUSTED) |
             (1 << NET_CAPABILITY_VALIDATED) |
-            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
+            (1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
+            (1 << NET_CAPABILITY_FOREGROUND);
 
     /**
      * Network specifier for factories which want to match any network specifier
@@ -217,8 +225,7 @@
      * get immediately torn down because they do not have the requested capability.
      */
     private static final long NON_REQUESTABLE_CAPABILITIES =
-            (1 << NET_CAPABILITY_VALIDATED) |
-            (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
+            MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
 
     /**
      * Capabilities that are set by default when the object is constructed.
@@ -325,6 +332,7 @@
     public String describeFirstNonRequestableCapability() {
         if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED";
         if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL";
+        if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND";
         // This cannot happen unless the preceding checks are incomplete.
         if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) {
             return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities);
@@ -352,6 +360,11 @@
                 (that.mNetworkCapabilities & ~MUTABLE_CAPABILITIES));
     }
 
+    private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
+        return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
+                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
+    }
+
     /**
      * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
      * typically provided by restricted networks.
@@ -756,6 +769,19 @@
                 equalsSpecifier(nc));
     }
 
+    /**
+     * Checks that our requestable capabilities are the same as those of the given
+     * {@code NetworkCapabilities}.
+     *
+     * @hide
+     */
+    public boolean equalRequestableCapabilities(NetworkCapabilities nc) {
+        if (nc == null) return false;
+        return (equalsNetCapabilitiesRequestable(nc) &&
+                equalsTransportTypes(nc) &&
+                equalsSpecifier(nc));
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
@@ -840,6 +866,7 @@
                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
                 case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
                 case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
+                case NET_CAPABILITY_FOREGROUND:     capabilities += "FOREGROUND"; break;
             }
             if (++i < types.length) capabilities += "&";
         }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 9cd563e..d570e66 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -175,7 +175,11 @@
 
         if (isNetworkTypeMobile(type)) {
             if (state.subscriberId == null) {
-                Slog.w(TAG, "Active mobile network without subscriber!");
+                if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
+                        state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
+                    Slog.w(TAG, "Active mobile network without subscriber! ni = "
+                            + state.networkInfo);
+                }
             }
 
             subscriberId = state.subscriberId;
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/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 4501f7b..ae72470 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -49,7 +49,7 @@
     public final int legacyType;
 
     /**
-     * A NetworkRequest as used by the system can be one of three types:
+     * A NetworkRequest as used by the system can be one of the following types:
      *
      *     - LISTEN, for which the framework will issue callbacks about any
      *       and all networks that match the specified NetworkCapabilities,
@@ -64,7 +64,20 @@
      *       current network (if any) that matches the capabilities of the
      *       default Internet request (mDefaultRequest), but which cannot cause
      *       the framework to either create or retain the existence of any
-     *       specific network.
+     *       specific network. Note that from the point of view of the request
+     *       matching code, TRACK_DEFAULT is identical to REQUEST: its special
+     *       behaviour is not due to different semantics, but to the fact that
+     *       the system will only ever create a TRACK_DEFAULT with capabilities
+     *       that are identical to the default request's capabilities, thus
+     *       causing it to share fate in every way with the default request.
+     *
+     *     - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
+     *       to retain the NET_CAPABILITY_FOREGROUND capability. A network with
+     *       no foreground requests is in the background. A network that has
+     *       one or more background requests and loses its last foreground
+     *       request to a higher-scoring network will not go into the
+     *       background immediately, but will linger and go into the background
+     *       after the linger timeout.
      *
      *     - The value NONE is used only by applications. When an application
      *       creates a NetworkRequest, it does not have a type; the type is set
@@ -77,7 +90,8 @@
         NONE,
         LISTEN,
         TRACK_DEFAULT,
-        REQUEST
+        REQUEST,
+        BACKGROUND_REQUEST,
     };
 
     /**
@@ -140,7 +154,7 @@
          * Add the given capability requirement to this builder.  These represent
          * the requested network's required capabilities.  Note that when searching
          * for a network to satisfy a request, all capabilities requested must be
-         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
+         * satisfied.  See {@link NetworkCapabilities} for {@code NET_CAPABILITY_*}
          * definitions.
          *
          * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
@@ -284,7 +298,7 @@
         };
 
     /**
-     * Returns true iff. the contained NetworkRequest is of type LISTEN.
+     * Returns true iff. this NetworkRequest is of type LISTEN.
      *
      * @hide
      */
@@ -298,8 +312,9 @@
      *     - should be associated with at most one satisfying network
      *       at a time;
      *
-     *     - should cause a network to be kept up if it is the best network
-     *       which can satisfy the NetworkRequest.
+     *     - should cause a network to be kept up, but not necessarily in
+     *       the foreground, if it is the best network which can satisfy the
+     *       NetworkRequest.
      *
      * For full detail of how isRequest() is used for pairing Networks with
      * NetworkRequests read rematchNetworkAndRequests().
@@ -307,9 +322,36 @@
      * @hide
      */
     public boolean isRequest() {
+        return isForegroundRequest() || isBackgroundRequest();
+    }
+
+    /**
+     * Returns true iff. the contained NetworkRequest is one that:
+     *
+     *     - should be associated with at most one satisfying network
+     *       at a time;
+     *
+     *     - should cause a network to be kept up and in the foreground if
+     *       it is the best network which can satisfy the NetworkRequest.
+     *
+     * For full detail of how isRequest() is used for pairing Networks with
+     * NetworkRequests read rematchNetworkAndRequests().
+     *
+     * @hide
+     */
+    public boolean isForegroundRequest() {
         return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
     }
 
+    /**
+     * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
+     *
+     * @hide
+     */
+    public boolean isBackgroundRequest() {
+        return type == Type.BACKGROUND_REQUEST;
+    }
+
     public String toString() {
         return "NetworkRequest [ " + type + " id=" + requestId +
                 (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
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/net/PskKeyManager.java b/core/java/android/net/PskKeyManager.java
index 667abb4..f5167ea 100644
--- a/core/java/android/net/PskKeyManager.java
+++ b/core/java/android/net/PskKeyManager.java
@@ -104,6 +104,8 @@
  *
  * SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(...);
  * }</pre>
+ *
+ * @removed This class is removed because it does not work with TLS 1.3.
  */
 public abstract class PskKeyManager implements PSKKeyManager {
     // IMPLEMENTATION DETAILS: This class exists only because the default implemenetation of the
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 27096b1..b56437e 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -18,6 +18,8 @@
 
 import android.os.SystemProperties;
 import android.util.Log;
+
+import com.android.internal.os.RoSystemProperties;
 import com.android.org.conscrypt.OpenSSLContextImpl;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 import com.android.org.conscrypt.SSLClientSessionCache;
@@ -221,8 +223,8 @@
     }
 
     private static boolean isSslCheckRelaxed() {
-        return "1".equals(SystemProperties.get("ro.debuggable")) &&
-            "yes".equals(SystemProperties.get("socket.relaxsslcheck"));
+        return RoSystemProperties.DEBUGGABLE &&
+            SystemProperties.getBoolean("socket.relaxsslcheck", false);
     }
 
     private synchronized SSLSocketFactory getDelegate() {
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 4fc6b7a..6176b2c 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -21,7 +21,7 @@
 import android.os.Parcelable;
 
 /**
- * An event recorded by DnsEventListenerService.
+ * A DNS event recorded by NetdEventListenerService.
  * {@hide}
  */
 @SystemApi
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index dd7bd1b..173e5fd 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -17,63 +17,65 @@
 package android.net.metrics;
 
 import android.net.ConnectivityMetricsEvent;
-import android.net.ConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLogger;
+import android.net.IIpConnectivityMetrics;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
-
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
- * Specialization of the ConnectivityMetricsLogger class for recording IP connectivity events.
+ * Class for logging IpConnectvity events with IpConnectivityMetrics
  * {@hide}
  */
-public class IpConnectivityLog extends ConnectivityMetricsLogger {
-    private static String TAG = "IpConnectivityMetricsLogger";
-    private static final boolean DBG = true;
+public class IpConnectivityLog {
+    private static final String TAG = IpConnectivityLog.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    public static final String SERVICE_NAME = "connmetrics";
+
+    private IIpConnectivityMetrics mService;
 
     public IpConnectivityLog() {
-        // mService initialized in super constructor.
     }
 
     @VisibleForTesting
-    public IpConnectivityLog(IConnectivityMetricsLogger service) {
-        super(service);
+    public IpConnectivityLog(IIpConnectivityMetrics service) {
+        mService = service;
+    }
+
+    private boolean checkLoggerService() {
+        if (mService != null) {
+            return true;
+        }
+        final IIpConnectivityMetrics service =
+                IIpConnectivityMetrics.Stub.asInterface(ServiceManager.getService(SERVICE_NAME));
+        if (service == null) {
+            return false;
+        }
+        // Two threads racing here will write the same pointer because getService
+        // is idempotent once MetricsLoggerService is initialized.
+        mService = service;
+        return true;
     }
 
     /**
-     * Log an IpConnectivity event. Contrary to logEvent(), this method does not
-     * keep track of skipped events and is thread-safe for callers.
-     *
+     * Log an IpConnectivity event.
      * @param timestamp is the epoch timestamp of the event in ms.
      * @param data is a Parcelable instance representing the event.
-     *
      * @return true if the event was successfully logged.
      */
     public boolean log(long timestamp, Parcelable data) {
         if (!checkLoggerService()) {
             if (DBG) {
-                Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service was not ready");
-            }
-            return false;
-        }
-
-        if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
-            if (DBG) {
-                Log.d(TAG, "skipping logging due to throttling for IpConnectivity component");
+                Log.d(TAG, SERVICE_NAME + " service was not ready");
             }
             return false;
         }
 
         try {
-            final ConnectivityMetricsEvent event =
-                new ConnectivityMetricsEvent(timestamp, COMPONENT_TAG_CONNECTIVITY, 0, data);
-            final long result = mService.logEvent(event);
-            if (result >= 0) {
-                mServiceUnblockedTimestampMillis = result;
-            }
-            return (result == 0);
+            int left = mService.logEvent(new ConnectivityMetricsEvent(timestamp, 0, 0, data));
+            return left >= 0;
         } catch (RemoteException e) {
             Log.e(TAG, "Error logging event", e);
             return false;
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 331cf0c..1a31b56 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -34,10 +34,12 @@
 @SystemApi
 public final class ValidationProbeEvent implements Parcelable {
 
-    public static final int PROBE_DNS   = 0;
-    public static final int PROBE_HTTP  = 1;
-    public static final int PROBE_HTTPS = 2;
-    public static final int PROBE_PAC   = 3;
+    public static final int PROBE_DNS       = 0;
+    public static final int PROBE_HTTP      = 1;
+    public static final int PROBE_HTTPS     = 2;
+    public static final int PROBE_PAC       = 3;
+    /** {@hide} */
+    public static final int PROBE_FALLBACK  = 4;
 
     public static final int DNS_FAILURE = 0;
     public static final int DNS_SUCCESS = 1;
@@ -57,7 +59,7 @@
     public final @ProbeType int probeType;
     public final @ReturnCode int returnCode;
 
-    /** @hide */
+    /** {@hide} */
     public ValidationProbeEvent(
             int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
         this.netId = netId;
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 63f39c5..fea64ec 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -35,8 +35,8 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to
- * perform background operations and publish results on the UI thread without
+ * <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
+ * to perform background operations and publish results on the UI thread without
  * having to manipulate threads and/or handlers.</p>
  *
  * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
@@ -55,7 +55,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using tasks and threads, read the
- * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
+ * <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and
  * Threads</a> developer guide.</p>
  * </div>
  *
@@ -298,12 +298,19 @@
         mWorker = new WorkerRunnable<Params, Result>() {
             public Result call() throws Exception {
                 mTaskInvoked.set(true);
-
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                //noinspection unchecked
-                Result result = doInBackground(mParams);
-                Binder.flushPendingCommands();
-                return postResult(result);
+                Result result = null;
+                try {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    //noinspection unchecked
+                    result = doInBackground(mParams);
+                    Binder.flushPendingCommands();
+                } catch (Throwable tr) {
+                    mCancelled.set(true);
+                    throw tr;
+                } finally {
+                    postResult(result);
+                }
+                return result;
             }
         };
 
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea8ba2f..cf77567 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -23,7 +23,6 @@
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Modifier;
@@ -361,13 +360,14 @@
             ParcelFileDescriptor out = data.readFileDescriptor();
             ParcelFileDescriptor err = data.readFileDescriptor();
             String[] args = data.readStringArray();
+            ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data);
             ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
             try {
                 if (out != null) {
                     shellCommand(in != null ? in.getFileDescriptor() : null,
                             out.getFileDescriptor(),
                             err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
-                            args, resultReceiver);
+                            args, shellCallback, resultReceiver);
                 }
             } finally {
                 IoUtils.closeQuietly(in);
@@ -459,13 +459,15 @@
      * @param out The raw file descriptor that normal command messages should be written to.
      * @param err The raw file descriptor that command error messages should be written to.
      * @param args Command-line arguments.
+     * @param callback Callback through which to interact with the invoking shell.
      * @param resultReceiver Called when the command has finished executing, with the result code.
      * @throws RemoteException
      * @hide
      */
     public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
-        onShellCommand(in, out, err, args, resultReceiver);
+            String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) throws RemoteException {
+        onShellCommand(in, out, err, args, callback, resultReceiver);
     }
 
     /**
@@ -477,7 +479,7 @@
      * @hide
      */
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) throws RemoteException {
         FileOutputStream fout = new FileOutputStream(err != null ? err : out);
         PrintWriter pw = new FastPrintWriter(fout);
         pw.println("No shell command implementation.");
@@ -650,13 +652,15 @@
     }
 
     public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeFileDescriptor(in);
         data.writeFileDescriptor(out);
         data.writeFileDescriptor(err);
         data.writeStringArray(args);
+        ShellCallback.writeToParcel(callback, data);
         resultReceiver.writeToParcel(data, 0);
         try {
             transact(SHELL_COMMAND_TRANSACTION, data, reply, 0);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index c180c7f..312a098 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -98,8 +101,35 @@
      */
     public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
 
-    /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */
-    public static final String SERIAL = getString("ro.serialno");
+    /**
+     * A hardware serial number, if available. Alphanumeric only, case-insensitive.
+     * For apps targeting SDK higher than {@link Build.VERSION_CODES#N_MR1} this
+     * field is set to {@link Build#UNKNOWN}.
+     *
+     * @deprecated Use {@link #getSerial()} instead.
+     **/
+    @Deprecated
+    // IMPORTANT: This field should be initialized via a function call to
+    // prevent its value being inlined in the app during compilation because
+    // we will later set it to the value based on the app's target SDK.
+    public static final String SERIAL = getString("no.such.thing");
+
+    /**
+     * Gets the hardware serial, if available. Requires holding the {@link
+     * android.Manifest.permission#READ_PHONE_STATE} permission.
+     * @return The serial if specified.
+     */
+    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+    public static String getSerial() {
+        IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
+                .asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
+        try {
+            return service.getSerial();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return UNKNOWN;
+    }
 
     /**
      * An ordered list of ABIs supported by this device. The most preferred ABI is the first
@@ -709,6 +739,14 @@
          * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} to
          * {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams}).</li>
          * <li>Your application processes will not be killed when the device density changes.</li>
+         * <li>Drag and drop. After a view receives the
+         * {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, when the drag shadow moves into
+         * a descendant view that can accept the data, the view receives the
+         * {@link android.view.DragEvent#ACTION_DRAG_EXITED} event and won’t receive
+         * {@link android.view.DragEvent#ACTION_DRAG_LOCATION} and
+         * {@link android.view.DragEvent#ACTION_DROP} events while the drag shadow is within that
+         * descendant view, even if the descendant view returns <code>false</code> from its handler
+         * for these events.</li>
          * </ul>
          */
         public static final int N = 24;
@@ -847,6 +885,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/FactoryTest.java b/core/java/android/os/FactoryTest.java
index 7a252f9..b59227c 100644
--- a/core/java/android/os/FactoryTest.java
+++ b/core/java/android/os/FactoryTest.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import com.android.internal.os.RoSystemProperties;
+
 /**
  * Provides support for in-place factory test functions.
  *
@@ -36,7 +38,7 @@
      * or {@link #FACTORY_TEST_HIGH_LEVEL}.
      */
     public static int getMode() {
-        return SystemProperties.getInt("ro.factorytest", FACTORY_TEST_OFF);
+        return RoSystemProperties.FACTORYTEST;
     }
 
     /**
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/FileUtils.java b/core/java/android/os/FileUtils.java
index 0d9b91b..44ae6ee 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -605,6 +605,22 @@
         return null;
     }
 
+    private static File buildUniqueFileWithExtension(File parent, String name, String ext)
+            throws FileNotFoundException {
+        File file = buildFile(parent, name, ext);
+
+        // If conflicting file, try adding counter suffix
+        int n = 0;
+        while (file.exists()) {
+            if (n++ >= 32) {
+                throw new FileNotFoundException("Failed to create unique file");
+            }
+            file = buildFile(parent, name + " (" + n + ")", ext);
+        }
+
+        return file;
+    }
+
     /**
      * Generates a unique file name under the given parent directory. If the display name doesn't
      * have an extension that matches the requested MIME type, the default extension for that MIME
@@ -619,20 +635,29 @@
     public static File buildUniqueFile(File parent, String mimeType, String displayName)
             throws FileNotFoundException {
         final String[] parts = splitFileName(mimeType, displayName);
-        final String name = parts[0];
-        final String ext = parts[1];
-        File file = buildFile(parent, name, ext);
+        return buildUniqueFileWithExtension(parent, parts[0], parts[1]);
+    }
 
-        // If conflicting file, try adding counter suffix
-        int n = 0;
-        while (file.exists()) {
-            if (n++ >= 32) {
-                throw new FileNotFoundException("Failed to create unique file");
-            }
-            file = buildFile(parent, name + " (" + n + ")", ext);
+    /**
+     * Generates a unique file name under the given parent directory, keeping
+     * any extension intact.
+     */
+    public static File buildUniqueFile(File parent, String displayName)
+            throws FileNotFoundException {
+        final String name;
+        final String ext;
+
+        // Extract requested extension from display name
+        final int lastDot = displayName.lastIndexOf('.');
+        if (lastDot >= 0) {
+            name = displayName.substring(0, lastDot);
+            ext = displayName.substring(lastDot + 1);
+        } else {
+            name = displayName;
+            ext = null;
         }
 
-        return file;
+        return buildUniqueFileWithExtension(parent, name, ext);
     }
 
     /**
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
new file mode 100644
index 0000000..88226f0
--- /dev/null
+++ b/core/java/android/os/HwBlob.java
@@ -0,0 +1,139 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+
+import libcore.util.NativeAllocationRegistry;
+
+/** @hide */
+public class HwBlob {
+    private static final String TAG = "HwBlob";
+
+    private static final NativeAllocationRegistry sNativeRegistry;
+
+    public HwBlob(int size) {
+        native_setup(size);
+
+        sNativeRegistry.registerNativeAllocation(
+                this,
+                mNativeContext);
+    }
+
+    public native final boolean getBool(long offset);
+    public native final byte getInt8(long offset);
+    public native final short getInt16(long offset);
+    public native final int getInt32(long offset);
+    public native final long getInt64(long offset);
+    public native final float getFloat(long offset);
+    public native final double getDouble(long offset);
+    public native final String getString(long offset);
+
+    public native final void putBool(long offset, boolean x);
+    public native final void putInt8(long offset, byte x);
+    public native final void putInt16(long offset, short x);
+    public native final void putInt32(long offset, int x);
+    public native final void putInt64(long offset, long x);
+    public native final void putFloat(long offset, float x);
+    public native final void putDouble(long offset, double x);
+    public native final void putString(long offset, String x);
+
+    public native final void putBlob(long offset, HwBlob blob);
+
+    public native final long handle();
+
+    public static Boolean[] wrapArray(@NonNull boolean[] array) {
+        final int n = array.length;
+        Boolean[] wrappedArray = new Boolean[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Long[] wrapArray(@NonNull long[] array) {
+        final int n = array.length;
+        Long[] wrappedArray = new Long[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Byte[] wrapArray(@NonNull byte[] array) {
+        final int n = array.length;
+        Byte[] wrappedArray = new Byte[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Short[] wrapArray(@NonNull short[] array) {
+        final int n = array.length;
+        Short[] wrappedArray = new Short[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Integer[] wrapArray(@NonNull int[] array) {
+        final int n = array.length;
+        Integer[] wrappedArray = new Integer[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Float[] wrapArray(@NonNull float[] array) {
+        final int n = array.length;
+        Float[] wrappedArray = new Float[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    public static Double[] wrapArray(@NonNull double[] array) {
+        final int n = array.length;
+        Double[] wrappedArray = new Double[n];
+        for (int i = 0; i < n; ++i) {
+          wrappedArray[i] = array[i];
+        }
+        return wrappedArray;
+    }
+
+    // Returns address of the "freeFunction".
+    private static native final long native_init();
+
+    private native final void native_setup(int size);
+
+    static {
+        long freeFunction = native_init();
+
+        sNativeRegistry = new NativeAllocationRegistry(
+                HwBlob.class.getClassLoader(),
+                freeFunction,
+                128 /* size */);
+    }
+
+    private long mNativeContext;
+}
+
+
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index fe7cdcc..180e8f4 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -44,6 +44,7 @@
     }
 
     public native final void writeInterfaceToken(String interfaceName);
+    public native final void writeBool(boolean val);
     public native final void writeInt8(byte val);
     public native final void writeInt16(short val);
     public native final void writeInt32(int val);
@@ -52,24 +53,19 @@
     public native final void writeDouble(double val);
     public native final void writeString(String val);
 
-    public native final void writeInt8Array(int size, byte[] val);
+    public native final void writeBoolVector(boolean[] val);
     public native final void writeInt8Vector(byte[] val);
-    public native final void writeInt16Array(int size, short[] val);
     public native final void writeInt16Vector(short[] val);
-    public native final void writeInt32Array(int size, int[] val);
     public native final void writeInt32Vector(int[] val);
-    public native final void writeInt64Array(int size, long[] val);
     public native final void writeInt64Vector(long[] val);
-    public native final void writeFloatArray(int size, float[] val);
     public native final void writeFloatVector(float[] val);
-    public native final void writeDoubleArray(int size, double[] val);
     public native final void writeDoubleVector(double[] val);
-    public native final void writeStringArray(int size, String[] val);
     public native final void writeStringVector(String[] val);
 
     public native final void writeStrongBinder(IHwBinder binder);
 
     public native final void enforceInterface(String interfaceName);
+    public native final boolean readBool();
     public native final byte readInt8();
     public native final short readInt16();
     public native final int readInt32();
@@ -78,23 +74,25 @@
     public native final double readDouble();
     public native final String readString();
 
-    public native final byte[] readInt8Array(int size);
+    public native final boolean[] readBoolVector();
     public native final byte[] readInt8Vector();
-    public native final short[] readInt16Array(int size);
     public native final short[] readInt16Vector();
-    public native final int[] readInt32Array(int size);
     public native final int[] readInt32Vector();
-    public native final long[] readInt64Array(int size);
     public native final long[] readInt64Vector();
-    public native final float[] readFloatArray(int size);
     public native final float[] readFloatVector();
-    public native final double[] readDoubleArray(int size);
     public native final double[] readDoubleVector();
-    public native final String[] readStringArray(int size);
     public native final String[] readStringVector();
 
     public native final IHwBinder readStrongBinder();
 
+    // Handle is stored as part of the blob.
+    public native final HwBlob readBuffer();
+
+    public native final HwBlob readEmbeddedBuffer(
+            long parentHandle, long offset);
+
+    public native final void writeBuffer(HwBlob blob);
+
     public native final void writeStatus(int status);
     public native final void verifySuccess();
     public native final void releaseTemporaryStorage();
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 0fa8750..f762a05 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -220,11 +220,13 @@
      * @param out The raw file descriptor that normal command messages should be written to.
      * @param err The raw file descriptor that command error messages should be written to.
      * @param args Command-line arguments.
+     * @param shellCallback Optional callback to the caller's shell to perform operations in it.
      * @param resultReceiver Called when the command has finished executing, with the result code.
      * @hide
      */
     public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException;
+            String[] args, ShellCallback shellCallback,
+            ResultReceiver resultReceiver) throws RemoteException;
 
     /**
      * Perform a generic operation with the object.
diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
new file mode 100644
index 0000000..ac19f2b
--- /dev/null
+++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.os;
+
+/**
+ * @hide
+ */
+interface IDeviceIdentifiersPolicyService {
+    String getSerial();
+}
\ No newline at end of file
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/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 12830a4..c5ceecd 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,4 +25,5 @@
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
+    void rebootRecoveryWithCommand(in String command);
 }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f6e6ad6..85f999b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -46,6 +46,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import dalvik.annotation.optimization.FastNative;
 import dalvik.system.VMRuntime;
 
 /**
@@ -254,22 +255,35 @@
     // see libbinder's binder/Status.h
     private static final int EX_TRANSACTION_FAILED = -129;
 
+    @FastNative
     private static native int nativeDataSize(long nativePtr);
+    @FastNative
     private static native int nativeDataAvail(long nativePtr);
+    @FastNative
     private static native int nativeDataPosition(long nativePtr);
+    @FastNative
     private static native int nativeDataCapacity(long nativePtr);
+    @FastNative
     private static native long nativeSetDataSize(long nativePtr, int size);
+    @FastNative
     private static native void nativeSetDataPosition(long nativePtr, int pos);
+    @FastNative
     private static native void nativeSetDataCapacity(long nativePtr, int size);
 
+    @FastNative
     private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
+    @FastNative
     private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
 
     private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
     private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
+    @FastNative
     private static native void nativeWriteInt(long nativePtr, int val);
+    @FastNative
     private static native void nativeWriteLong(long nativePtr, long val);
+    @FastNative
     private static native void nativeWriteFloat(long nativePtr, float val);
+    @FastNative
     private static native void nativeWriteDouble(long nativePtr, double val);
     private static native void nativeWriteString(long nativePtr, String val);
     private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
@@ -277,9 +291,13 @@
 
     private static native byte[] nativeCreateByteArray(long nativePtr);
     private static native byte[] nativeReadBlob(long nativePtr);
+    @FastNative
     private static native int nativeReadInt(long nativePtr);
+    @FastNative
     private static native long nativeReadLong(long nativePtr);
+    @FastNative
     private static native float nativeReadFloat(long nativePtr);
+    @FastNative
     private static native double nativeReadDouble(long nativePtr);
     private static native String nativeReadString(long nativePtr);
     private static native IBinder nativeReadStrongBinder(long nativePtr);
@@ -294,6 +312,7 @@
             long nativePtr, byte[] data, int offset, int length);
     private static native long nativeAppendFrom(
             long thisNativePtr, long otherNativePtr, int offset, int length);
+    @FastNative
     private static native boolean nativeHasFileDescriptors(long nativePtr);
     private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
     private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
index 56dc837..3890fbf 100644
--- a/core/java/android/os/PatternMatcher.java
+++ b/core/java/android/os/PatternMatcher.java
@@ -16,6 +16,10 @@
 
 package android.os;
 
+import android.util.Log;
+
+import java.util.Arrays;
+
 /**
  * A simple pattern matcher, which is safe to use on untrusted data: it does
  * not provide full reg-exp support, only simple globbing that can not be
@@ -44,13 +48,59 @@
      * wildcard part of a normal regexp. 
      */
     public static final int PATTERN_SIMPLE_GLOB = 2;
-    
+
+    /**
+     * Pattern type: the given pattern is interpreted with a regular
+     * expression-like syntax for matching against the string it is tested
+     * against. Supported tokens include dot ({@code .}) and sets ({@code [...]})
+     * with full support for character ranges and the not ({@code ^}) modifier.
+     * Supported modifiers include star ({@code *}) for zero-or-more, plus ({@code +})
+     * for one-or-more and full range ({@code {...}}) support. This is a simple
+     * evaulation implementation in which matching is done against the pattern in
+     * realtime with no backtracking support.
+     *
+     * {@hide} Pending approval for public API
+     */
+    public static final int PATTERN_ADVANCED_GLOB = 3;
+
+    // token types for advanced matching
+    private static final int TOKEN_TYPE_LITERAL = 0;
+    private static final int TOKEN_TYPE_ANY = 1;
+    private static final int TOKEN_TYPE_SET = 2;
+    private static final int TOKEN_TYPE_INVERSE_SET = 3;
+
+    // Return for no match
+    private static final int NO_MATCH = -1;
+
+    private static final String TAG = "PatternMatcher";
+
+    // Parsed placeholders for advanced patterns
+    private static final int PARSED_TOKEN_CHAR_SET_START = -1;
+    private static final int PARSED_TOKEN_CHAR_SET_INVERSE_START = -2;
+    private static final int PARSED_TOKEN_CHAR_SET_STOP = -3;
+    private static final int PARSED_TOKEN_CHAR_ANY = -4;
+    private static final int PARSED_MODIFIER_RANGE_START = -5;
+    private static final int PARSED_MODIFIER_RANGE_STOP = -6;
+    private static final int PARSED_MODIFIER_ZERO_OR_MORE = -7;
+    private static final int PARSED_MODIFIER_ONE_OR_MORE = -8;
+
     private final String mPattern;
     private final int mType;
-    
+    private final int[] mParsedPattern;
+
+
+    private static final int MAX_PATTERN_STORAGE = 2048;
+    // workspace to use for building a parsed advanced pattern;
+    private static final int[] sParsedPatternScratch = new int[MAX_PATTERN_STORAGE];
+
     public PatternMatcher(String pattern, int type) {
         mPattern = pattern;
         mType = type;
+        if (mType == PATTERN_ADVANCED_GLOB) {
+            mParsedPattern = parseAndVerifyAdvancedPattern(pattern);
+        } else {
+            mParsedPattern = null;
+        }
     }
 
     public final String getPath() {
@@ -62,7 +112,7 @@
     }
     
     public boolean match(String str) {
-        return matchPattern(mPattern, str, mType);
+        return matchPattern(str, mPattern, mParsedPattern, mType);
     }
 
     public String toString() {
@@ -77,6 +127,9 @@
             case PATTERN_SIMPLE_GLOB:
                 type = "GLOB: ";
                 break;
+            case PATTERN_ADVANCED_GLOB:
+                type = "ADVANCED: ";
+                break;
         }
         return "PatternMatcher{" + type + mPattern + "}";
     }
@@ -88,11 +141,13 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mPattern);
         dest.writeInt(mType);
+        dest.writeIntArray(mParsedPattern);
     }
     
     public PatternMatcher(Parcel src) {
         mPattern = src.readString();
         mType = src.readInt();
+        mParsedPattern = src.createIntArray();
     }
     
     public static final Parcelable.Creator<PatternMatcher> CREATOR
@@ -106,16 +161,21 @@
         }
     };
     
-    static boolean matchPattern(String pattern, String match, int type) {
+    static boolean matchPattern(String match, String pattern, int[] parsedPattern, int type) {
         if (match == null) return false;
         if (type == PATTERN_LITERAL) {
             return pattern.equals(match);
         } if (type == PATTERN_PREFIX) {
             return match.startsWith(pattern);
-        } else if (type != PATTERN_SIMPLE_GLOB) {
-            return false;
+        } else if (type == PATTERN_SIMPLE_GLOB) {
+            return matchGlobPattern(pattern, match);
+        } else if (type == PATTERN_ADVANCED_GLOB) {
+            return matchAdvancedPattern(parsedPattern, match);
         }
-        
+        return false;
+    }
+
+    static boolean matchGlobPattern(String pattern, String match) {
         final int NP = pattern.length();
         if (NP <= 0) {
             return match.length() <= 0;
@@ -194,4 +254,310 @@
         
         return false;
     }
-}
+
+    /**
+     * Parses the advanced pattern and returns an integer array representation of it. The integer
+     * array treats each field as a character if positive and a unique token placeholder if
+     * negative. This method will throw on any pattern structure violations.
+     */
+    synchronized static int[] parseAndVerifyAdvancedPattern(String pattern) {
+        int ip = 0;
+        final int LP = pattern.length();
+
+        int it = 0;
+
+        boolean inSet = false;
+        boolean inRange = false;
+        boolean inCharClass = false;
+
+        boolean addToParsedPattern;
+
+        while (ip < LP) {
+            if (it > MAX_PATTERN_STORAGE - 3) {
+                throw new IllegalArgumentException("Pattern is too large!");
+            }
+
+            char c = pattern.charAt(ip);
+            addToParsedPattern = false;
+
+            switch (c) {
+                case '[':
+                    if (inSet) {
+                        addToParsedPattern = true; // treat as literal or char class in set
+                    } else {
+                        if (pattern.charAt(ip + 1) == '^') {
+                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_INVERSE_START;
+                            ip++; // skip over the '^'
+                        } else {
+                            sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_START;
+                        }
+                        ip++; // move to the next pattern char
+                        inSet = true;
+                        continue;
+                    }
+                    break;
+                case ']':
+                    if (!inSet) {
+                        addToParsedPattern = true; // treat as literal outside of set
+                    } else {
+                        int parsedToken = sParsedPatternScratch[it - 1];
+                        if (parsedToken == PARSED_TOKEN_CHAR_SET_START ||
+                            parsedToken == PARSED_TOKEN_CHAR_SET_INVERSE_START) {
+                            throw new IllegalArgumentException(
+                                    "You must define characters in a set.");
+                        }
+                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_SET_STOP;
+                        inSet = false;
+                        inCharClass = false;
+                    }
+                    break;
+                case '{':
+                    if (!inSet) {
+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
+                            throw new IllegalArgumentException("Modifier must follow a token.");
+                        }
+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_START;
+                        ip++;
+                        inRange = true;
+                    }
+                    break;
+                case '}':
+                    if (inRange) { // only terminate the range if we're currently in one
+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_RANGE_STOP;
+                        inRange = false;
+                    }
+                    break;
+                case '*':
+                    if (!inSet) {
+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
+                            throw new IllegalArgumentException("Modifier must follow a token.");
+                        }
+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ZERO_OR_MORE;
+                    }
+                    break;
+                case '+':
+                    if (!inSet) {
+                        if (it == 0 || isParsedModifier(sParsedPatternScratch[it - 1])) {
+                            throw new IllegalArgumentException("Modifier must follow a token.");
+                        }
+                        sParsedPatternScratch[it++] = PARSED_MODIFIER_ONE_OR_MORE;
+                    }
+                    break;
+                case '.':
+                    if (!inSet) {
+                        sParsedPatternScratch[it++] = PARSED_TOKEN_CHAR_ANY;
+                    }
+                    break;
+                case '\\': // escape
+                    if (ip + 1 >= LP) {
+                        throw new IllegalArgumentException("Escape found at end of pattern!");
+                    }
+                    c = pattern.charAt(++ip);
+                    addToParsedPattern = true;
+                    break;
+                default:
+                    addToParsedPattern = true;
+                    break;
+            }
+            if (inSet) {
+                if (inCharClass) {
+                    sParsedPatternScratch[it++] = c;
+                    inCharClass = false;
+                } else {
+                    // look forward for character class
+                    if (ip + 2 < LP
+                            && pattern.charAt(ip + 1) == '-'
+                            && pattern.charAt(ip + 2) != ']') {
+                        inCharClass = true;
+                        sParsedPatternScratch[it++] = c; // set first token as lower end of range
+                        ip++; // advance past dash
+                    } else { // literal
+                        sParsedPatternScratch[it++] = c; // set first token as literal
+                        sParsedPatternScratch[it++] = c; // set second set as literal
+                    }
+                }
+            } else if (inRange) {
+                int endOfSet = pattern.indexOf('}', ip);
+                if (endOfSet < 0) {
+                    throw new IllegalArgumentException("Range not ended with '}'");
+                }
+                String rangeString = pattern.substring(ip, endOfSet);
+                int commaIndex = rangeString.indexOf(',');
+                try {
+                    final int rangeMin;
+                    final int rangeMax;
+                    if (commaIndex < 0) {
+                        int parsedRange = Integer.parseInt(rangeString);
+                        rangeMin = rangeMax = parsedRange;
+                    } else {
+                        rangeMin = Integer.parseInt(rangeString.substring(0, commaIndex));
+                        if (commaIndex == rangeString.length() - 1) { // e.g. {n,} (n or more)
+                            rangeMax = Integer.MAX_VALUE;
+                        } else {
+                            rangeMax = Integer.parseInt(rangeString.substring(commaIndex + 1));
+                        }
+                    }
+                    if (rangeMin > rangeMax) {
+                        throw new IllegalArgumentException(
+                            "Range quantifier minimum is greater than maximum");
+                    }
+                    sParsedPatternScratch[it++] = rangeMin;
+                    sParsedPatternScratch[it++] = rangeMax;
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Range number format incorrect", e);
+                }
+                ip = endOfSet;
+                continue; // don't increment ip
+            } else if (addToParsedPattern) {
+                sParsedPatternScratch[it++] = c;
+            }
+            ip++;
+        }
+        if (inSet) {
+            throw new IllegalArgumentException("Set was not terminated!");
+        }
+        return Arrays.copyOf(sParsedPatternScratch, it);
+    }
+
+    private static boolean isParsedModifier(int parsedChar) {
+        return parsedChar == PARSED_MODIFIER_ONE_OR_MORE ||
+                parsedChar == PARSED_MODIFIER_ZERO_OR_MORE ||
+                parsedChar == PARSED_MODIFIER_RANGE_STOP ||
+                parsedChar == PARSED_MODIFIER_RANGE_START;
+    }
+
+    static boolean matchAdvancedPattern(int[] parsedPattern, String match) {
+
+        // create indexes
+        int ip = 0, im = 0;
+
+        // one-time length check
+        final int LP = parsedPattern.length, LM = match.length();
+
+        // The current character being analyzed in the pattern
+        int patternChar;
+
+        int tokenType;
+
+        int charSetStart = 0, charSetEnd = 0;
+
+        while (ip < LP) { // we still have content in the pattern
+
+            patternChar = parsedPattern[ip];
+            // get the match type of the next verb
+
+            switch (patternChar) {
+                case PARSED_TOKEN_CHAR_ANY:
+                    tokenType = TOKEN_TYPE_ANY;
+                    ip++;
+                    break;
+                case PARSED_TOKEN_CHAR_SET_START:
+                case PARSED_TOKEN_CHAR_SET_INVERSE_START:
+                    tokenType = patternChar == PARSED_TOKEN_CHAR_SET_START
+                            ? TOKEN_TYPE_SET
+                            : TOKEN_TYPE_INVERSE_SET;
+                    charSetStart = ip + 1; // start from the char after the set start
+                    while (++ip < LP && parsedPattern[ip] != PARSED_TOKEN_CHAR_SET_STOP);
+                    charSetEnd = ip - 1; // we're on the set stop, end is the previous
+                    ip++; // move the pointer to the next pattern entry
+                    break;
+                default:
+                    charSetStart = ip;
+                    tokenType = TOKEN_TYPE_LITERAL;
+                    ip++;
+                    break;
+            }
+
+            final int minRepetition;
+            final int maxRepetition;
+
+            // look for a match length modifier
+            if (ip >= LP) {
+                minRepetition = maxRepetition = 1;
+            } else {
+                patternChar = parsedPattern[ip];
+                switch (patternChar) {
+                    case PARSED_MODIFIER_ZERO_OR_MORE:
+                        minRepetition = 0;
+                        maxRepetition = Integer.MAX_VALUE;
+                        ip++;
+                        break;
+                    case PARSED_MODIFIER_ONE_OR_MORE:
+                        minRepetition = 1;
+                        maxRepetition = Integer.MAX_VALUE;
+                        ip++;
+                        break;
+                    case PARSED_MODIFIER_RANGE_START:
+                        minRepetition = parsedPattern[++ip];
+                        maxRepetition = parsedPattern[++ip];
+                        ip += 2; // step over PARSED_MODIFIER_RANGE_STOP and on to the next token
+                        break;
+                    default:
+                        minRepetition = maxRepetition = 1; // implied literal
+                        break;
+                }
+            }
+            if (minRepetition > maxRepetition) {
+                return false;
+            }
+
+            // attempt to match as many characters as possible
+            int matched = matchChars(match, im, LM, tokenType, minRepetition, maxRepetition,
+                    parsedPattern, charSetStart, charSetEnd);
+
+            // if we found a conflict, return false immediately
+            if (matched == NO_MATCH) {
+                return false;
+            }
+
+            // move the match pointer the number of characters matched
+            im += matched;
+        }
+        return ip >= LP && im >= LM; // have parsed entire string and regex
+    }
+
+    private static int matchChars(String match, int im, final int lm, int tokenType,
+            int minRepetition, int maxRepetition, int[] parsedPattern,
+            int tokenStart, int tokenEnd) {
+        int matched = 0;
+
+        while(matched < maxRepetition
+                && matchChar(match, im + matched, lm, tokenType, parsedPattern, tokenStart,
+                    tokenEnd)) {
+            matched++;
+        }
+
+        return matched < minRepetition ? NO_MATCH : matched;
+    }
+
+    private static boolean matchChar(String match, int im, final int lm, int tokenType,
+            int[] parsedPattern, int tokenStart, int tokenEnd) {
+        if (im >= lm) { // we've overrun the string, no match
+            return false;
+        }
+        switch (tokenType) {
+            case TOKEN_TYPE_ANY:
+                return true;
+            case TOKEN_TYPE_SET:
+                for (int i = tokenStart; i < tokenEnd; i += 2) {
+                    char matchChar = match.charAt(im);
+                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
+                        return true;
+                    }
+                }
+                return false;
+            case TOKEN_TYPE_INVERSE_SET:
+                for (int i = tokenStart; i < tokenEnd; i += 2) {
+                    char matchChar = match.charAt(im);
+                    if (matchChar >= parsedPattern[i] && matchChar <= parsedPattern[i + 1]) {
+                        return false;
+                    }
+                }
+                return true;
+            case TOKEN_TYPE_LITERAL:
+                return match.charAt(im) == parsedPattern[tokenStart];
+            default:
+                return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index ce7a124..8d4d0a5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1340,6 +1340,11 @@
         }
 
         /** @hide */
+        public String getTag() {
+            return mTag;
+        }
+
+        /** @hide */
         public void setHistoryTag(String tag) {
             mHistoryTag = tag;
         }
@@ -1358,5 +1363,34 @@
                     + " held=" + mHeld + ", refCount=" + mCount + "}";
             }
         }
+
+        /**
+         * Wraps a Runnable such that this method immediately acquires the wake lock and then
+         * once the Runnable is done the wake lock is released.
+         *
+         * <p>Example:
+         *
+         * <pre>
+         * mHandler.post(mWakeLock.wrap(() -> {
+         *     // do things on handler, lock is held while we're waiting for this
+         *     // to get scheduled and until the runnable is done executing.
+         * });
+         * </pre>
+         *
+         * <p>Note: you must make sure that the Runnable eventually gets executed, otherwise you'll
+         *    leak the wakelock!
+         *
+         * @hide
+         */
+        public Runnable wrap(Runnable r) {
+            acquire();
+            return () -> {
+                try {
+                    r.run();
+                } finally {
+                    release();
+                }
+            };
+        }
     }
 }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 507379b..d48431a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -93,6 +93,14 @@
      */
     public static final File UNCRYPT_PACKAGE_FILE = new File(RECOVERY_DIR, "uncrypt_file");
 
+    /**
+     * UNCRYPT_STATUS_FILE stores the time cost (and error code in the case of a failure)
+     * of uncrypt.
+     *
+     * @hide
+     */
+    public static final File UNCRYPT_STATUS_FILE = new File(RECOVERY_DIR, "uncrypt_status");
+
     // Length limits for reading files.
     private static final int LOG_FILE_MAX_LENGTH = 64 * 1024;
 
@@ -692,28 +700,22 @@
      * @throws IOException if something goes wrong.
      */
     private static void bootCommand(Context context, String... args) throws IOException {
-        synchronized (sRequestLock) {
-            LOG_FILE.delete();
+        LOG_FILE.delete();
 
-            StringBuilder command = new StringBuilder();
-            for (String arg : args) {
-                if (!TextUtils.isEmpty(arg)) {
-                    command.append(arg);
-                    command.append("\n");
-                }
+        StringBuilder command = new StringBuilder();
+        for (String arg : args) {
+            if (!TextUtils.isEmpty(arg)) {
+                command.append(arg);
+                command.append("\n");
             }
-
-            // Write the command into BCB (bootloader control block).
-            RecoverySystem rs = (RecoverySystem) context.getSystemService(
-                    Context.RECOVERY_SERVICE);
-            rs.setupBcb(command.toString());
-
-            // Having set up the BCB, go ahead and reboot.
-            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-            pm.reboot(PowerManager.REBOOT_RECOVERY);
-
-            throw new IOException("Reboot failed (no permissions?)");
         }
+
+        // Write the command into BCB (bootloader control block) and boot from
+        // there. Will not return unless failed.
+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+        rs.rebootRecoveryWithCommand(command.toString());
+
+        throw new IOException("Reboot failed (no permissions?)");
     }
 
     // Read last_install; then report time (in seconds) and I/O (in MiB) for
@@ -724,6 +726,7 @@
             String line = null;
             int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
             int timeTotal = -1;
+            int uncryptTime = -1;
             int sourceVersion = -1;
             while ((line = in.readLine()) != null) {
                 // Here is an example of lines in last_install:
@@ -759,6 +762,8 @@
 
                 if (line.startsWith("time")) {
                     timeTotal = scaled;
+                } else if (line.startsWith("uncrypt_time")) {
+                    uncryptTime = scaled;
                 } else if (line.startsWith("source_build")) {
                     sourceVersion = scaled;
                 } else if (line.startsWith("bytes_written")) {
@@ -774,6 +779,9 @@
             if (timeTotal != -1) {
                 MetricsLogger.histogram(context, "ota_time_total", timeTotal);
             }
+            if (uncryptTime != -1) {
+                MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
+            }
             if (sourceVersion != -1) {
                 MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
             }
@@ -902,6 +910,17 @@
     }
 
     /**
+     * Talks to RecoverySystemService via Binder to set up the BCB command and
+     * reboot into recovery accordingly.
+     */
+    private void rebootRecoveryWithCommand(String command) {
+        try {
+            mService.rebootRecoveryWithCommand(command);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
      * Internally, recovery treats each line of the command file as a separate
      * argv, so we only need to protect against newlines and nulls.
      */
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 5849350..3546e17 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -288,20 +288,22 @@
      * @see #beginBroadcast
      */
     public void finishBroadcast() {
-        if (mBroadcastCount < 0) {
-            throw new IllegalStateException(
-                    "finishBroadcast() called outside of a broadcast");
-        }
-        
-        Object[] active = mActiveBroadcast;
-        if (active != null) {
-            final int N = mBroadcastCount;
-            for (int i=0; i<N; i++) {
-                active[i] = null;
+        synchronized (mCallbacks) {
+            if (mBroadcastCount < 0) {
+                throw new IllegalStateException(
+                        "finishBroadcast() called outside of a broadcast");
             }
+
+            Object[] active = mActiveBroadcast;
+            if (active != null) {
+                final int N = mBroadcastCount;
+                for (int i=0; i<N; i++) {
+                    active[i] = null;
+                }
+            }
+
+            mBroadcastCount = -1;
         }
-        
-        mBroadcastCount = -1;
     }
 
     /**
diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java
new file mode 100644
index 0000000..e7fe697
--- /dev/null
+++ b/core/java/android/os/ShellCallback.java
@@ -0,0 +1,114 @@
+/*
+ * 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.os;
+
+import android.util.Log;
+
+import com.android.internal.os.IShellCallback;
+
+/**
+ * Special-purpose API for use with {@link IBinder#shellCommand IBinder.shellCommand} for
+ * performing operations back on the invoking shell.
+ * @hide
+ */
+public class ShellCallback implements Parcelable {
+    final static String TAG = "ShellCallback";
+
+    final static boolean DEBUG = false;
+
+    final boolean mLocal;
+
+    IShellCallback mShellCallback;
+
+    class MyShellCallback extends IShellCallback.Stub {
+        public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) {
+            return onOpenOutputFile(path, seLinuxContext);
+        }
+    }
+
+    /**
+     * Create a new ShellCallback to receive requests.
+     */
+    public ShellCallback() {
+        mLocal = true;
+    }
+
+    /**
+     * Ask the shell to open a file for writing.  This will truncate the file if it
+     * already exists.  It will create the file if it doesn't exist.
+     * @param path Path of the file to be opened/created.
+     * @param seLinuxContext Optional SELinux context that must be allowed to have
+     * access to the file; if null, nothing is required.
+     */
+    public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) {
+        if (DEBUG) Log.d(TAG, "openOutputFile " + this + ": mLocal=" + mLocal
+                + " mShellCallback=" + mShellCallback);
+
+        if (mLocal) {
+            return onOpenOutputFile(path, seLinuxContext);
+        }
+
+        if (mShellCallback != null) {
+            try {
+                return mShellCallback.openOutputFile(path, seLinuxContext);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failure opening " + path, e);
+            }
+        }
+        return null;
+    }
+
+    public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+        return null;
+    }
+
+    public static void writeToParcel(ShellCallback callback, Parcel out) {
+        if (callback == null) {
+            out.writeStrongBinder(null);
+        } else {
+            callback.writeToParcel(out, 0);
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        synchronized (this) {
+            if (mShellCallback == null) {
+                mShellCallback = new MyShellCallback();
+            }
+            out.writeStrongBinder(mShellCallback.asBinder());
+        }
+    }
+
+    ShellCallback(Parcel in) {
+        mLocal = false;
+        mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder());
+    }
+
+    public static final Parcelable.Creator<ShellCallback> CREATOR
+            = new Parcelable.Creator<ShellCallback>() {
+        public ShellCallback createFromParcel(Parcel in) {
+            return new ShellCallback(in);
+        }
+        public ShellCallback[] newArray(int size) {
+            return new ShellCallback[size];
+        }
+    };
+}
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index fc804e5..831c9b2 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -40,6 +40,7 @@
     private FileDescriptor mOut;
     private FileDescriptor mErr;
     private String[] mArgs;
+    private ShellCallback mShellCallback;
     private ResultReceiver mResultReceiver;
 
     private String mCmd;
@@ -55,12 +56,13 @@
     private InputStream mInputStream;
 
     public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, int firstArgPos) {
+            String[] args, ShellCallback callback, int firstArgPos) {
         mTarget = target;
         mIn = in;
         mOut = out;
         mErr = err;
         mArgs = args;
+        mShellCallback = callback;
         mResultReceiver = null;
         mCmd = null;
         mArgPos = firstArgPos;
@@ -74,7 +76,7 @@
     }
 
     public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
         String cmd;
         int start;
         if (args != null && args.length > 0) {
@@ -84,7 +86,7 @@
             cmd = null;
             start = 0;
         }
-        init(target, in, out, err, args, start);
+        init(target, in, out, err, args, callback, start);
         mCmd = cmd;
         mResultReceiver = resultReceiver;
 
@@ -105,7 +107,7 @@
             // go.
             PrintWriter eout = getErrPrintWriter();
             eout.println();
-            eout.println("Exception occurred while dumping:");
+            eout.println("Exception occurred while executing:");
             e.printStackTrace(eout);
         } finally {
             if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
@@ -257,6 +259,13 @@
         return arg;
     }
 
+    /**
+     * Return the {@link ShellCallback} for communicating back with the calling shell.
+     */
+    public ShellCallback getShellCallback() {
+        return mShellCallback;
+    }
+
     public int handleDefaultCommands(String cmd) {
         if ("dump".equals(cmd)) {
             String[] newArgs = new String[mArgs.length-1];
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 672df6d..b3d76d7 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.util.Slog;
 
+import dalvik.annotation.optimization.CriticalNative;
+
 /**
  * Core timekeeping facilities.
  *
@@ -124,7 +126,7 @@
             }
             duration = start + ms - uptimeMillis();
         } while (duration > 0);
-        
+
         if (interrupted) {
             // Important: we don't want to quietly eat an interrupt() event,
             // so we make sure to re-interrupt the thread so that the next
@@ -132,7 +134,7 @@
             Thread.currentThread().interrupt();
         }
     }
-    
+
     /**
      * Sets the current wall time, in milliseconds.  Requires the calling
      * process to have appropriate permissions.
@@ -162,6 +164,7 @@
      *
      * @return milliseconds of non-sleep uptime since boot.
      */
+    @CriticalNative
     native public static long uptimeMillis();
 
     /**
@@ -169,6 +172,7 @@
      *
      * @return elapsed milliseconds since boot.
      */
+    @CriticalNative
     native public static long elapsedRealtime();
 
     /**
@@ -176,30 +180,34 @@
      *
      * @return elapsed nanoseconds since boot.
      */
+    @CriticalNative
     public static native long elapsedRealtimeNanos();
 
     /**
      * Returns milliseconds running in the current thread.
-     * 
+     *
      * @return elapsed milliseconds in the thread
      */
+    @CriticalNative
     public static native long currentThreadTimeMillis();
 
     /**
      * Returns microseconds running in the current thread.
-     * 
+     *
      * @return elapsed microseconds in the thread
-     * 
+     *
      * @hide
      */
+    @CriticalNative
     public static native long currentThreadTimeMicro();
 
     /**
      * Returns current wall time in  microseconds.
-     * 
+     *
      * @return elapsed microseconds in wall time
-     * 
+     *
      * @hide
      */
+    @CriticalNative
     public static native long currentTimeMicro();
 }
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 1479035..d31036c 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -16,7 +16,13 @@
 
 package android.os;
 
+import android.util.Log;
+import android.util.MutableInt;
+
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
+import java.util.HashMap;
 
 
 /**
@@ -25,13 +31,45 @@
  *
  * {@hide}
  */
-public class SystemProperties
-{
+public class SystemProperties {
+    private static final String TAG = "SystemProperties";
+    private static final boolean TRACK_KEY_ACCESS = false;
+
     public static final int PROP_NAME_MAX = 31;
     public static final int PROP_VALUE_MAX = 91;
 
     private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
 
+    @GuardedBy("sRoReads")
+    private static final HashMap<String, MutableInt> sRoReads;
+    static {
+        if (TRACK_KEY_ACCESS) {
+            sRoReads = new HashMap<>();
+        } else {
+            sRoReads = null;
+        }
+    }
+
+    private static void onKeyAccess(String key) {
+        if (!TRACK_KEY_ACCESS) return;
+
+        if (key != null && key.startsWith("ro.")) {
+            synchronized (sRoReads) {
+                MutableInt numReads = sRoReads.getOrDefault(key, null);
+                if (numReads == null) {
+                    numReads = new MutableInt(0);
+                    sRoReads.put(key, numReads);
+                }
+                numReads.value++;
+                if (numReads.value > 3) {
+                    Log.d(TAG, "Repeated read (count=" + numReads.value
+                            + ") of a read-only system property '" + key + "'",
+                            new Exception());
+                }
+            }
+        }
+    }
+
     private static native String native_get(String key);
     private static native String native_get(String key, String def);
     private static native int native_get_int(String key, int def);
@@ -49,6 +87,7 @@
         if (key.length() > PROP_NAME_MAX) {
             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get(key);
     }
 
@@ -61,6 +100,7 @@
         if (key.length() > PROP_NAME_MAX) {
             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get(key, def);
     }
 
@@ -76,6 +116,7 @@
         if (key.length() > PROP_NAME_MAX) {
             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_int(key, def);
     }
 
@@ -91,6 +132,7 @@
         if (key.length() > PROP_NAME_MAX) {
             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_long(key, def);
     }
 
@@ -111,6 +153,7 @@
         if (key.length() > PROP_NAME_MAX) {
             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_boolean(key, def);
     }
 
@@ -127,6 +170,7 @@
             throw new IllegalArgumentException("val.length > " +
                 PROP_VALUE_MAX);
         }
+        if (TRACK_KEY_ACCESS) onKeyAccess(key);
         native_set(key, val);
     }
 
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 9e8103a..7e8cc0b 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Writes trace events to the system trace buffer.  These trace events can be
  * collected and visualized using the Systrace tool.
@@ -81,6 +83,8 @@
     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
     /** @hide */
     public static final long TRACE_TAG_DATABASE = 1L << 20;
+    /** @hide */
+    public static final long TRACE_TAG_NETWORK = 1L << 21;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
@@ -89,14 +93,20 @@
     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
 
     private static native long nativeGetEnabledTags();
-    private static native void nativeTraceCounter(long tag, String name, int value);
-    private static native void nativeTraceBegin(long tag, String name);
-    private static native void nativeTraceEnd(long tag);
-    private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
-    private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
     private static native void nativeSetAppTracingAllowed(boolean allowed);
     private static native void nativeSetTracingEnabled(boolean allowed);
 
+    @FastNative
+    private static native void nativeTraceCounter(long tag, String name, int value);
+    @FastNative
+    private static native void nativeTraceBegin(long tag, String name);
+    @FastNative
+    private static native void nativeTraceEnd(long tag);
+    @FastNative
+    private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
+    @FastNative
+    private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
+
     static {
         // We configure two separate change callbacks, one in Trace.cpp and one here.  The
         // native callback reads the tags from the system property, and this callback
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 06e2931..5dc18fb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -43,6 +43,7 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
+import com.android.internal.os.RoSystemProperties;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -746,7 +747,7 @@
      * a single owner user.  see @link {android.os.UserHandle#USER_OWNER}
      */
     public static boolean isSplitSystemUser() {
-        return SystemProperties.getBoolean("ro.fw.system_user_split", false);
+        return RoSystemProperties.FW_SYSTEM_USER_SPLIT;
     }
 
     /**
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/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cee7553..1a78fe7 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -44,6 +44,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.os.RoSystemProperties;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 
@@ -1149,8 +1150,7 @@
      *         false not encrypted and not encryptable
      */
     public static boolean isEncryptable() {
-        final String state = SystemProperties.get("ro.crypto.state", "unsupported");
-        return !"unsupported".equalsIgnoreCase(state);
+        return RoSystemProperties.CRYPTO_ENCRYPTABLE;
     }
 
     /** {@hide}
@@ -1159,8 +1159,7 @@
      *         false not encrypted
      */
     public static boolean isEncrypted() {
-        final String state = SystemProperties.get("ro.crypto.state", "");
-        return "encrypted".equalsIgnoreCase(state);
+        return RoSystemProperties.CRYPTO_ENCRYPTED;
     }
 
     /** {@hide}
@@ -1172,9 +1171,7 @@
         if (!isEncrypted()) {
             return false;
         }
-
-        final String status = SystemProperties.get("ro.crypto.type", "");
-        return "file".equalsIgnoreCase(status);
+        return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
     }
 
     /** {@hide}
@@ -1186,8 +1183,7 @@
         if (!isEncrypted()) {
             return false;
         }
-        final String status = SystemProperties.get("ro.crypto.type", "");
-        return "block".equalsIgnoreCase(status);
+        return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
     }
 
     /** {@hide}
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/preference/Preference.java b/core/java/android/preference/Preference.java
index b1cad05..2bfe33b 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -58,14 +58,14 @@
  * This class contains a {@code key} that will be used as the key into the
  * {@link SharedPreferences}. It is up to the subclass to decide how to store
  * the value.
- * 
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For information about building a settings UI with Preferences,
  * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
  * guide.</p>
  * </div>
- * 
+ *
  * @attr ref android.R.styleable#Preference_icon
  * @attr ref android.R.styleable#Preference_key
  * @attr ref android.R.styleable#Preference_title
@@ -89,13 +89,13 @@
 
     private Context mContext;
     private PreferenceManager mPreferenceManager;
-    
+
     /**
      * Set when added to hierarchy since we need a unique ID within that
      * hierarchy.
      */
     private long mId;
-    
+
     private OnPreferenceChangeListener mOnChangeListener;
     private OnPreferenceClickListener mOnClickListener;
 
@@ -120,22 +120,22 @@
     private Object mDefaultValue;
     private boolean mDependencyMet = true;
     private boolean mParentDependencyMet = true;
-    
+
     /**
      * @see #setShouldDisableView(boolean)
      */
     private boolean mShouldDisableView = true;
-    
+
     private int mLayoutResId = com.android.internal.R.layout.preference;
     private int mWidgetLayoutResId;
     private boolean mCanRecycleLayout = true;
-    
+
     private OnPreferenceChangeInternalListener mListener;
-    
+
     private List<Preference> mDependents;
-    
+
     private boolean mBaseMethodCalled;
-    
+
     /**
      * Interface definition for a callback to be invoked when the value of this
      * {@link Preference} has been changed by the user and is
@@ -147,7 +147,7 @@
          * Called when a Preference has been changed by the user. This is
          * called before the state of the Preference is about to be updated and
          * before the state is persisted.
-         * 
+         *
          * @param preference The changed Preference.
          * @param newValue The new value of the Preference.
          * @return True to update the state of the Preference with the new value.
@@ -177,14 +177,14 @@
     interface OnPreferenceChangeInternalListener {
         /**
          * Called when this Preference has changed.
-         * 
+         *
          * @param preference This preference.
          */
         void onPreferenceChange(Preference preference);
-        
+
         /**
          * Called when this group has added/removed {@link Preference}(s).
-         * 
+         *
          * @param preference This Preference.
          */
         void onPreferenceHierarchyChange(Preference preference);
@@ -220,7 +220,7 @@
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.Preference, defStyleAttr, defStyleRes);
         for (int i = a.getIndexCount() - 1; i >= 0; i--) {
-            int attr = a.getIndex(i); 
+            int attr = a.getIndex(i);
             switch (attr) {
                 case com.android.internal.R.styleable.Preference_icon:
                     mIconResId = a.getResourceId(attr, 0);
@@ -229,16 +229,16 @@
                 case com.android.internal.R.styleable.Preference_key:
                     mKey = a.getString(attr);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_title:
                     mTitleRes = a.getResourceId(attr, 0);
-                    mTitle = a.getString(attr);
+                    mTitle = a.getText(attr);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_summary:
-                    mSummary = a.getString(attr);
+                    mSummary = a.getText(attr);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_order:
                     mOrder = a.getInt(attr, mOrder);
                     break;
@@ -254,27 +254,27 @@
                 case com.android.internal.R.styleable.Preference_widgetLayout:
                     mWidgetLayoutResId = a.getResourceId(attr, mWidgetLayoutResId);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_enabled:
                     mEnabled = a.getBoolean(attr, true);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_selectable:
                     mSelectable = a.getBoolean(attr, true);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_persistent:
                     mPersistent = a.getBoolean(attr, mPersistent);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_dependency:
                     mDependencyKey = a.getString(attr);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_defaultValue:
                     mDefaultValue = onGetDefaultValue(a, attr);
                     break;
-                    
+
                 case com.android.internal.R.styleable.Preference_shouldDisableView:
                     mShouldDisableView = a.getBoolean(attr, mShouldDisableView);
                     break;
@@ -312,14 +312,14 @@
     public Preference(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
-    
+
     /**
      * Constructor that is called when inflating a Preference from XML. This is
      * called when a Preference is being constructed from an XML file, supplying
      * attributes that were specified in the XML file. This version uses a
      * default style of 0, so the only attribute values applied are those in the
      * Context's Theme and the given AttributeSet.
-     * 
+     *
      * @param context The Context this is associated with, through which it can
      *            access the current theme, resources, {@link SharedPreferences},
      *            etc.
@@ -333,7 +333,7 @@
 
     /**
      * Constructor to create a Preference.
-     * 
+     *
      * @param context The Context in which to store Preference values.
      */
     public Preference(Context context) {
@@ -348,7 +348,7 @@
      * <p>
      * For example, if the value type is String, the body of the method would
      * proxy to {@link TypedArray#getString(int)}.
-     * 
+     *
      * @param a The set of attributes.
      * @param index The index of the default value attribute.
      * @return The default value of this preference type.
@@ -356,20 +356,20 @@
     protected Object onGetDefaultValue(TypedArray a, int index) {
         return null;
     }
-    
+
     /**
      * Sets an {@link Intent} to be used for
      * {@link Context#startActivity(Intent)} when this Preference is clicked.
-     * 
+     *
      * @param intent The intent associated with this Preference.
      */
     public void setIntent(Intent intent) {
         mIntent = intent;
     }
-    
+
     /**
      * Return the {@link Intent} associated with this Preference.
-     * 
+     *
      * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. 
      */
     public Intent getIntent() {
@@ -423,7 +423,7 @@
      * {@link android.R.id#widget_frame} to be the parent of the specific widget
      * for this Preference. It should similarly contain
      * {@link android.R.id#title} and {@link android.R.id#summary}.
-     * 
+     *
      * @param layoutResId The layout resource ID to be inflated and returned as
      *            a {@link View}.
      * @see #setWidgetLayoutResource(int)
@@ -436,23 +436,23 @@
 
         mLayoutResId = layoutResId;
     }
-    
+
     /**
      * Gets the layout resource that will be shown as the {@link View} for this Preference.
-     * 
+     *
      * @return The layout resource ID.
      */
     @LayoutRes
     public int getLayoutResource() {
         return mLayoutResId;
     }
-    
+
     /**
      * Sets the layout for the controllable widget portion of this Preference. This
      * is inflated into the main layout. For example, a {@link CheckBoxPreference}
      * would specify a custom layout (consisting of just the CheckBox) here,
      * instead of creating its own main layout.
-     * 
+     *
      * @param widgetLayoutResId The layout resource ID to be inflated into the
      *            main layout.
      * @see #setLayoutResource(int)
@@ -467,17 +467,17 @@
 
     /**
      * Gets the layout resource for the controllable widget portion of this Preference.
-     * 
+     *
      * @return The layout resource ID.
      */
     @LayoutRes
     public int getWidgetLayoutResource() {
         return mWidgetLayoutResId;
     }
-    
+
     /**
      * Gets the View that will be shown in the {@link PreferenceActivity}.
-     * 
+     *
      * @param convertView The old View to reuse, if possible. Note: You should
      *            check that this View is non-null and of an appropriate type
      *            before using. If it is not possible to convert this View to
@@ -495,7 +495,7 @@
         onBindView(convertView);
         return convertView;
     }
-    
+
     /**
      * Creates the View to be shown for this Preference in the
      * {@link PreferenceActivity}. The default behavior is to inflate the main
@@ -504,7 +504,7 @@
      * {@link android.R.id#widget_frame}.
      * <p>
      * Make sure to call through to the superclass's implementation.
-     * 
+     *
      * @param parent The parent that this View will eventually be attached to.
      * @return The View that displays this Preference.
      * @see #onBindView(View)
@@ -512,10 +512,10 @@
     @CallSuper
     protected View onCreateView(ViewGroup parent) {
         final LayoutInflater layoutInflater =
-            (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        
-        final View layout = layoutInflater.inflate(mLayoutResId, parent, false); 
-        
+                (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        final View layout = layoutInflater.inflate(mLayoutResId, parent, false);
+
         final ViewGroup widgetFrame = (ViewGroup) layout
                 .findViewById(com.android.internal.R.id.widget_frame);
         if (widgetFrame != null) {
@@ -527,7 +527,7 @@
         }
         return layout;
     }
-    
+
     /**
      * Binds the created View to the data for this Preference.
      * <p>
@@ -535,7 +535,7 @@
      * set properties on them.
      * <p>
      * Make sure to call through to the superclass's implementation.
-     * 
+     *
      * @param view The View that shows this Preference.
      * @see #onCreateView(ViewGroup)
      */
@@ -592,7 +592,7 @@
      */
     private void setEnabledStateOnViews(View v, boolean enabled) {
         v.setEnabled(enabled);
-        
+
         if (v instanceof ViewGroup) {
             final ViewGroup vg = (ViewGroup) v;
             for (int i = vg.getChildCount() - 1; i >= 0; i--) {
@@ -600,14 +600,14 @@
             }
         }
     }
-    
+
     /**
      * Sets the order of this Preference with respect to other
      * Preference objects on the same level. If this is not specified, the
      * default behavior is to sort alphabetically. The
      * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
      * Preference objects based on the order they appear in the XML.
-     * 
+     *
      * @param order The order for this Preference. A lower value will be shown
      *            first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
      *            allow ordering from XML.
@@ -622,11 +622,11 @@
             notifyHierarchyChanged();
         }
     }
-    
+
     /**
      * Gets the order of this Preference with respect to other Preference objects
      * on the same level.
-     * 
+     *
      * @return The order of this Preference.
      * @see #setOrder(int)
      */
@@ -639,7 +639,7 @@
      * This title will be placed into the ID
      * {@link android.R.id#title} within the View created by
      * {@link #onCreateView(ViewGroup)}.
-     * 
+     *
      * @param title The title for this Preference.
      */
     public void setTitle(CharSequence title) {
@@ -649,10 +649,10 @@
             notifyChanged();
         }
     }
-    
+
     /**
      * Sets the title for this Preference with a resource ID. 
-     * 
+     *
      * @see #setTitle(CharSequence)
      * @param titleResId The title as a resource ID.
      */
@@ -660,7 +660,7 @@
         setTitle(mContext.getString(titleResId));
         mTitleRes = titleResId;
     }
-    
+
     /**
      * Returns the title resource ID of this Preference.  If the title did
      * not come from a resource, 0 is returned.
@@ -675,7 +675,7 @@
 
     /**
      * Returns the title of this Preference.
-     * 
+     *
      * @return The title.
      * @see #setTitle(CharSequence)
      */
@@ -688,7 +688,7 @@
      * This icon will be placed into the ID
      * {@link android.R.id#icon} within the View created by
      * {@link #onCreateView(ViewGroup)}.
-     * 
+     *
      * @param icon The optional icon for this Preference.
      */
     public void setIcon(Drawable icon) {
@@ -701,7 +701,7 @@
 
     /**
      * Sets the icon for this Preference with a resource ID. 
-     * 
+     *
      * @see #setIcon(Drawable)
      * @param iconResId The icon as a resource ID.
      */
@@ -714,17 +714,20 @@
 
     /**
      * Returns the icon of this Preference.
-     * 
+     *
      * @return The icon.
      * @see #setIcon(Drawable)
      */
     public Drawable getIcon() {
+        if (mIcon == null && mIconResId != 0) {
+            mIcon = getContext().getDrawable(mIconResId);
+        }
         return mIcon;
     }
 
     /**
      * Returns the summary of this Preference.
-     * 
+     *
      * @return The summary.
      * @see #setSummary(CharSequence)
      */
@@ -734,7 +737,7 @@
 
     /**
      * Sets the summary for this Preference with a CharSequence. 
-     * 
+     *
      * @param summary The summary for the preference.
      */
     public void setSummary(CharSequence summary) {
@@ -746,18 +749,18 @@
 
     /**
      * Sets the summary for this Preference with a resource ID. 
-     * 
+     *
      * @see #setSummary(CharSequence)
      * @param summaryResId The summary as a resource.
      */
     public void setSummary(@StringRes int summaryResId) {
         setSummary(mContext.getString(summaryResId));
     }
-    
+
     /**
      * Sets whether this Preference is enabled. If disabled, it will
      * not handle clicks.
-     * 
+     *
      * @param enabled Set true to enable it.
      */
     public void setEnabled(boolean enabled) {
@@ -770,10 +773,10 @@
             notifyChanged();
         }
     }
-    
+
     /**
      * Checks whether this Preference should be enabled in the list.
-     * 
+     *
      * @return True if this Preference is enabled, false otherwise.
      */
     public boolean isEnabled() {
@@ -782,7 +785,7 @@
 
     /**
      * Sets whether this Preference is selectable.
-     * 
+     *
      * @param selectable Set true to make it selectable.
      */
     public void setSelectable(boolean selectable) {
@@ -791,10 +794,10 @@
             notifyChanged();
         }
     }
-    
+
     /**
      * Checks whether this Preference should be selectable in the list.
-     * 
+     *
      * @return True if it is selectable, false otherwise.
      */
     public boolean isSelectable() {
@@ -808,7 +811,7 @@
      * For example, set this and {@link #setEnabled(boolean)} to false for
      * preferences that are only displaying information and 1) should not be
      * clickable 2) should not have the view set to the disabled state.
-     * 
+     *
      * @param shouldDisableView Set true if this preference should disable its view
      *            when the preference is disabled.
      */
@@ -816,7 +819,7 @@
         mShouldDisableView = shouldDisableView;
         notifyChanged();
     }
-    
+
     /**
      * Checks whether this Preference should disable its view when it's action is disabled.
      * @see #setShouldDisableView(boolean)
@@ -829,13 +832,13 @@
     /**
      * Returns a unique ID for this Preference.  This ID should be unique across all
      * Preference objects in a hierarchy.
-     * 
+     *
      * @return A unique ID for this Preference.
      */
     long getId() {
         return mId;
     }
-    
+
     /**
      * Processes a click on the preference. This includes saving the value to
      * the {@link SharedPreferences}. However, the overridden method should
@@ -844,93 +847,93 @@
      */
     protected void onClick() {
     }
-    
+
     /**
      * Sets the key for this Preference, which is used as a key to the
      * {@link SharedPreferences}. This should be unique for the package.
-     * 
+     *
      * @param key The key for the preference.
      */
     public void setKey(String key) {
         mKey = key;
-        
+
         if (mRequiresKey && !hasKey()) {
             requireKey();
         }
     }
-    
+
     /**
      * Gets the key for this Preference, which is also the key used for storing
      * values into SharedPreferences.
-     * 
+     *
      * @return The key.
      */
     public String getKey() {
         return mKey;
     }
-    
+
     /**
      * Checks whether the key is present, and if it isn't throws an
      * exception. This should be called by subclasses that store preferences in
      * the {@link SharedPreferences}.
-     * 
+     *
      * @throws IllegalStateException If there is no key assigned.
      */
     void requireKey() {
         if (mKey == null) {
             throw new IllegalStateException("Preference does not have a key assigned.");
         }
-        
+
         mRequiresKey = true;
     }
-    
+
     /**
      * Checks whether this Preference has a valid key.
-     * 
+     *
      * @return True if the key exists and is not a blank string, false otherwise.
      */
     public boolean hasKey() {
         return !TextUtils.isEmpty(mKey);
     }
-    
+
     /**
      * Checks whether this Preference is persistent. If it is, it stores its value(s) into
      * the persistent {@link SharedPreferences} storage.
-     * 
+     *
      * @return True if it is persistent.
      */
     public boolean isPersistent() {
         return mPersistent;
     }
-    
+
     /**
      * Checks whether, at the given time this method is called,
      * this Preference should store/restore its value(s) into the
      * {@link SharedPreferences}. This, at minimum, checks whether this
      * Preference is persistent and it currently has a key. Before you
      * save/restore from the {@link SharedPreferences}, check this first.
-     * 
+     *
      * @return True if it should persist the value.
      */
     protected boolean shouldPersist() {
         return mPreferenceManager != null && isPersistent() && hasKey();
     }
-    
+
     /**
      * Sets whether this Preference is persistent. When persistent,
      * it stores its value(s) into the persistent {@link SharedPreferences}
      * storage.
-     * 
+     *
      * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}.
      */
     public void setPersistent(boolean persistent) {
         mPersistent = persistent;
     }
-    
+
     /**
      * Call this method after the user changes the preference, but before the
      * internal state is set. This allows the client to ignore the user value.
-     * 
+     *
      * @param newValue The new value of this Preference.
      * @return True if the user value should be set as the preference
      *         value (and persisted).
@@ -938,11 +941,11 @@
     protected boolean callChangeListener(Object newValue) {
         return mOnChangeListener == null ? true : mOnChangeListener.onPreferenceChange(this, newValue);
     }
-    
+
     /**
      * Sets the callback to be invoked when this Preference is changed by the
      * user (but before the internal state has been updated).
-     * 
+     *
      * @param onPreferenceChangeListener The callback to be invoked.
      */
     public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
@@ -952,7 +955,7 @@
     /**
      * Returns the callback to be invoked when this Preference is changed by the
      * user (but before the internal state has been updated).
-     * 
+     *
      * @return The callback to be invoked.
      */
     public OnPreferenceChangeListener getOnPreferenceChangeListener() {
@@ -961,7 +964,7 @@
 
     /**
      * Sets the callback to be invoked when this Preference is clicked.
-     * 
+     *
      * @param onPreferenceClickListener The callback to be invoked.
      */
     public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
@@ -970,7 +973,7 @@
 
     /**
      * Returns the callback to be invoked when this Preference is clicked.
-     * 
+     *
      * @return The callback to be invoked.
      */
     public OnPreferenceClickListener getOnPreferenceClickListener() {
@@ -979,24 +982,24 @@
 
     /**
      * Called when a click should be performed.
-     * 
+     *
      * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click
      *            listener should be called in the proper order (between other
      *            processing). May be null.
      * @hide
      */
     public void performClick(PreferenceScreen preferenceScreen) {
-        
+
         if (!isEnabled()) {
             return;
         }
-        
+
         onClick();
-        
+
         if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
             return;
         }
-        
+
         PreferenceManager preferenceManager = getPreferenceManager();
         if (preferenceManager != null) {
             PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
@@ -1006,7 +1009,7 @@
                 return;
             }
         }
-        
+
         if (mIntent != null) {
             Context context = getContext();
             context.startActivity(mIntent);
@@ -1023,19 +1026,19 @@
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         return false;
     }
-    
+
     /**
      * Returns the {@link android.content.Context} of this Preference. 
      * Each Preference in a Preference hierarchy can be
      * from different Context (for example, if multiple activities provide preferences into a single
      * {@link PreferenceActivity}). This Context will be used to save the Preference values.
-     * 
+     *
      * @return The Context of this Preference.
      */
     public Context getContext() {
         return mContext;
     }
-    
+
     /**
      * Returns the {@link SharedPreferences} where this Preference can read its
      * value(s). Usually, it's easier to use one of the helper read methods:
@@ -1048,7 +1051,7 @@
      * right away and hence not show up in the returned
      * {@link SharedPreferences}, this is intended behavior to improve
      * performance.
-     * 
+     *
      * @return The {@link SharedPreferences} where this Preference reads its
      *         value(s), or null if it isn't attached to a Preference hierarchy.
      * @see #getEditor()
@@ -1057,10 +1060,10 @@
         if (mPreferenceManager == null) {
             return null;
         }
-        
+
         return mPreferenceManager.getSharedPreferences();
     }
-    
+
     /**
      * Returns an {@link SharedPreferences.Editor} where this Preference can
      * save its value(s). Usually it's easier to use one of the helper save
@@ -1073,7 +1076,7 @@
      * In some cases, writes to this will not be committed right away and hence
      * not show up in the SharedPreferences, this is intended behavior to
      * improve performance.
-     * 
+     *
      * @return A {@link SharedPreferences.Editor} where this preference saves
      *         its value(s), or null if it isn't attached to a Preference
      *         hierarchy.
@@ -1084,15 +1087,15 @@
         if (mPreferenceManager == null) {
             return null;
         }
-        
+
         return mPreferenceManager.getEditor();
     }
-    
+
     /**
      * Returns whether the {@link Preference} should commit its saved value(s) in
      * {@link #getEditor()}. This may return false in situations where batch
      * committing is being done (by the manager) to improve performance.
-     * 
+     *
      * @return Whether the Preference should commit its saved value(s).
      * @see #getEditor()
      */
@@ -1100,13 +1103,13 @@
         if (mPreferenceManager == null) {
             return false;
         }
-        
+
         return mPreferenceManager.shouldCommit();
     }
-    
+
     /**
      * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
-     * 
+     *
      * @param another The Preference to compare to this one.
      * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
      *          greater than 0 if this Preference sorts after <var>another</var>.
@@ -1128,10 +1131,10 @@
             return CharSequences.compareToIgnoreCase(mTitle, another.mTitle);
         }
     }
-    
+
     /**
      * Sets the internal change listener.
-     * 
+     *
      * @param listener The listener.
      * @see #notifyChanged()
      */
@@ -1147,7 +1150,7 @@
             mListener.onPreferenceChange(this);
         }
     }
-    
+
     /**
      * Should be called when a Preference has been
      * added/removed from this group, or the ordering should be
@@ -1161,27 +1164,27 @@
 
     /**
      * Gets the {@link PreferenceManager} that manages this Preference object's tree.
-     * 
+     *
      * @return The {@link PreferenceManager}.
      */
     public PreferenceManager getPreferenceManager() {
         return mPreferenceManager;
     }
-    
+
     /**
      * Called when this Preference has been attached to a Preference hierarchy.
      * Make sure to call the super implementation.
-     * 
+     *
      * @param preferenceManager The PreferenceManager of the hierarchy.
      */
     protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
         mPreferenceManager = preferenceManager;
-        
+
         mId = preferenceManager.getNextId();
-        
+
         dispatchSetInitialValue();
     }
-    
+
     /**
      * Called when the Preference hierarchy has been attached to the
      * {@link PreferenceActivity}. This can also be called when this
@@ -1195,9 +1198,9 @@
     }
 
     private void registerDependency() {
-        
+
         if (TextUtils.isEmpty(mDependencyKey)) return;
-        
+
         Preference preference = findPreferenceInHierarchy(mDependencyKey);
         if (preference != null) {
             preference.registerDependent(this);
@@ -1215,14 +1218,14 @@
             }
         }
     }
-    
+
     /**
      * Finds a Preference in this hierarchy (the whole thing,
      * even above/below your {@link PreferenceScreen} screen break) with the given
      * key.
      * <p>
      * This only functions after we have been attached to a hierarchy.
-     * 
+     *
      * @param key The key of the Preference to find.
      * @return The Preference that uses the given key.
      */
@@ -1230,16 +1233,16 @@
         if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
             return null;
         }
-        
+
         return mPreferenceManager.findPreference(key);
     }
-    
+
     /**
      * Adds a dependent Preference on this Preference so we can notify it.
      * Usually, the dependent Preference registers itself (it's good for it to
      * know it depends on something), so please use
      * {@link Preference#setDependency(String)} on the dependent Preference.
-     * 
+     *
      * @param dependent The dependent Preference that will be enabled/disabled
      *            according to the state of this Preference.
      */
@@ -1247,15 +1250,15 @@
         if (mDependents == null) {
             mDependents = new ArrayList<Preference>();
         }
-        
+
         mDependents.add(dependent);
-        
+
         dependent.onDependencyChanged(this, shouldDisableDependents());
     }
-    
+
     /**
      * Removes a dependent Preference on this Preference.
-     * 
+     *
      * @param dependent The dependent Preference that will be enabled/disabled
      *            according to the state of this Preference.
      * @return Returns the same Preference object, for chaining multiple calls
@@ -1266,21 +1269,21 @@
             mDependents.remove(dependent);
         }
     }
-    
+
     /**
      * Notifies any listening dependents of a change that affects the
      * dependency.
-     * 
+     *
      * @param disableDependents Whether this Preference should disable
      *            its dependents.
      */
     public void notifyDependencyChange(boolean disableDependents) {
         final List<Preference> dependents = mDependents;
-        
+
         if (dependents == null) {
             return;
         }
-        
+
         final int dependentsCount = dependents.size();
         for (int i = 0; i < dependentsCount; i++) {
             dependents.get(i).onDependencyChanged(this, disableDependents);
@@ -1289,7 +1292,7 @@
 
     /**
      * Called when the dependency changes.
-     * 
+     *
      * @param dependency The Preference that this Preference depends on.
      * @param disableDependent Set true to disable this Preference.
      */
@@ -1324,38 +1327,38 @@
     /**
      * Checks whether this preference's dependents should currently be
      * disabled.
-     * 
+     *
      * @return True if the dependents should be disabled, otherwise false.
      */
     public boolean shouldDisableDependents() {
         return !isEnabled();
     }
-    
+
     /**
      * Sets the key of a Preference that this Preference will depend on. If that
      * Preference is not set or is off, this Preference will be disabled.
-     * 
+     *
      * @param dependencyKey The key of the Preference that this depends on.
      */
     public void setDependency(String dependencyKey) {
         // Unregister the old dependency, if we had one
         unregisterDependency();
-        
+
         // Register the new
         mDependencyKey = dependencyKey;
         registerDependency();
     }
-    
+
     /**
      * Returns the key of the dependency on this Preference.
-     * 
+     *
      * @return The key of the dependency.
      * @see #setDependency(String)
      */
     public String getDependency() {
         return mDependencyKey;
     }
-    
+
     /**
      * Called when this Preference is being removed from the hierarchy. You
      * should remove any references to this Preference that you know about. Make
@@ -1365,18 +1368,18 @@
     protected void onPrepareForRemoval() {
         unregisterDependency();
     }
-    
+
     /**
      * Sets the default value for this Preference, which will be set either if
      * persistence is off or persistence is on and the preference is not found
      * in the persistent storage.
-     * 
+     *
      * @param defaultValue The default value.
      */
     public void setDefaultValue(Object defaultValue) {
         mDefaultValue = defaultValue;
     }
-    
+
     private void dispatchSetInitialValue() {
         // By now, we know if we are persistent.
         final boolean shouldPersist = shouldPersist();
@@ -1388,7 +1391,7 @@
             onSetInitialValue(true, null);
         }
     }
-    
+
     /**
      * Implement this to set the initial value of the Preference. 
      * <p>
@@ -1400,7 +1403,7 @@
      * <p>
      * This may not always be called. One example is if it should not persist
      * but there is no default value given.
-     * 
+     *
      * @param restorePersistedValue True to restore the persisted value;
      *            false to use the given <var>defaultValue</var>.
      * @param defaultValue The default value for this Preference. Only use this
@@ -1421,14 +1424,14 @@
             }
         }
     }
-    
+
     /**
      * Attempts to persist a String to the {@link android.content.SharedPreferences}.
      * <p>
      * This will check if this Preference is persistent, get an editor from
      * the {@link PreferenceManager}, put in the string, and check if we should commit (and
      * commit if so).
-     * 
+     *
      * @param value The value to persist.
      * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1442,7 +1445,7 @@
                 // It's already there, so the same as persisting
                 return true;
             }
-            
+
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putString(mKey, value);
             tryCommit(editor);
@@ -1450,13 +1453,13 @@
         }
         return false;
     }
-    
+
     /**
      * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
      * <p>
      * This will check if this Preference is persistent, get the SharedPreferences
      * from the {@link PreferenceManager}, and get the value.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either the
      *            Preference is not persistent or the Preference is not in the
      *            shared preferences.
@@ -1468,17 +1471,17 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
     }
-    
+
     /**
      * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
      * <p>
      * This will check if this Preference is persistent, get an editor from
      * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
      * commit if so).
-     * 
+     *
      * @param values The values to persist.
      * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1492,7 +1495,7 @@
                 // It's already there, so the same as persisting
                 return true;
             }
-            
+
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putStringSet(mKey, values);
             tryCommit(editor);
@@ -1507,7 +1510,7 @@
      * <p>
      * This will check if this Preference is persistent, get the SharedPreferences
      * from the {@link PreferenceManager}, and get the value.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either the
      *            Preference is not persistent or the Preference is not in the
      *            shared preferences.
@@ -1519,13 +1522,13 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
     }
-    
+
     /**
      * Attempts to persist an int to the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param value The value to persist.
      * @return True if the Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1539,7 +1542,7 @@
                 // It's already there, so the same as persisting
                 return true;
             }
-            
+
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putInt(mKey, value);
             tryCommit(editor);
@@ -1547,10 +1550,10 @@
         }
         return false;
     }
-    
+
     /**
      * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either this
      *            Preference is not persistent or this Preference is not in the
      *            SharedPreferences.
@@ -1563,13 +1566,13 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
     }
-    
+
     /**
      * Attempts to persist a float to the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1591,10 +1594,10 @@
         }
         return false;
     }
-    
+
     /**
      * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either this
      *            Preference is not persistent or this Preference is not in the
      *            SharedPreferences.
@@ -1607,13 +1610,13 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
     }
-    
+
     /**
      * Attempts to persist a long to the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1627,7 +1630,7 @@
                 // It's already there, so the same as persisting
                 return true;
             }
-            
+
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putLong(mKey, value);
             tryCommit(editor);
@@ -1635,10 +1638,10 @@
         }
         return false;
     }
-    
+
     /**
      * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either this
      *            Preference is not persistent or this Preference is not in the
      *            SharedPreferences.
@@ -1651,13 +1654,13 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
     }
-    
+
     /**
      * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param value The value to persist.
      * @return True if this Preference is persistent. (This is not whether the
      *         value was persisted, since we may not necessarily commit if there
@@ -1671,7 +1674,7 @@
                 // It's already there, so the same as persisting
                 return true;
             }
-            
+
             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
             editor.putBoolean(mKey, value);
             tryCommit(editor);
@@ -1679,10 +1682,10 @@
         }
         return false;
     }
-    
+
     /**
      * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
-     * 
+     *
      * @param defaultReturnValue The default value to return if either this
      *            Preference is not persistent or this Preference is not in the
      *            SharedPreferences.
@@ -1695,26 +1698,26 @@
         if (!shouldPersist()) {
             return defaultReturnValue;
         }
-        
+
         return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
     }
-    
+
     boolean canRecycleLayout() {
         return mCanRecycleLayout;
     }
-    
+
     @Override
     public String toString() {
         return getFilterableStringBuilder().toString();
     }
-        
+
     /**
      * Returns the text that will be used to filter this Preference depending on
      * user input.
      * <p>
      * If overridding and calling through to the superclass, make sure to prepend
      * your additions with a space.
-     * 
+     *
      * @return Text as a {@link StringBuilder} that will be used to filter this
      *         preference. By default, this is the title and summary
      *         (concatenated with a space).
@@ -1738,9 +1741,9 @@
 
     /**
      * Store this Preference hierarchy's frozen state into the given container.
-     * 
+     *
      * @param container The Bundle in which to save the instance of this Preference.
-     * 
+     *
      * @see #restoreHierarchyState
      * @see #onSaveInstanceState
      */
@@ -1752,9 +1755,9 @@
      * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
      * May be overridden to modify how the save happens for children. For example, some
      * Preference objects may want to not store an instance for their children.
-     * 
+     *
      * @param container The Bundle in which to save the instance of this Preference.
-     * 
+     *
      * @see #saveHierarchyState
      * @see #onSaveInstanceState
      */
@@ -1777,7 +1780,7 @@
      * state that can later be used to create a new instance with that same
      * state. This state should only contain information that is not persistent
      * or can be reconstructed later.
-     * 
+     *
      * @return A Parcelable object containing the current dynamic state of
      *         this Preference, or null if there is nothing interesting to save.
      *         The default implementation returns null.
@@ -1791,9 +1794,9 @@
 
     /**
      * Restore this Preference hierarchy's previously saved state from the given container.
-     * 
+     *
      * @param container The Bundle that holds the previously saved state.
-     * 
+     *
      * @see #saveHierarchyState
      * @see #onRestoreInstanceState
      */
@@ -1806,7 +1809,7 @@
      * Preference and its children. May be overridden to modify how restoring
      * happens to the children of a Preference. For example, some Preference objects may
      * not want to save state for their children.
-     * 
+     *
      * @param container The Bundle that holds the previously saved state.
      * @see #restoreHierarchyState
      * @see #onRestoreInstanceState
@@ -1829,7 +1832,7 @@
      * Hook allowing a Preference to re-apply a representation of its internal
      * state that had previously been generated by {@link #onSaveInstanceState}.
      * This function will never be called with a null state.
-     * 
+     *
      * @param state The saved state that had previously been returned by
      *            {@link #onSaveInstanceState}.
      * @see #onSaveInstanceState
@@ -1853,17 +1856,17 @@
         public BaseSavedState(Parcelable superState) {
             super(superState);
         }
-        
+
         public static final Parcelable.Creator<BaseSavedState> CREATOR =
                 new Parcelable.Creator<BaseSavedState>() {
-            public BaseSavedState createFromParcel(Parcel in) {
-                return new BaseSavedState(in);
-            }
+                    public BaseSavedState createFromParcel(Parcel in) {
+                        return new BaseSavedState(in);
+                    }
 
-            public BaseSavedState[] newArray(int size) {
-                return new BaseSavedState[size];
-            }
-        };
+                    public BaseSavedState[] newArray(int size) {
+                        return new BaseSavedState[size];
+                    }
+                };
     }
 
 }
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 1ec00db..11b9606 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -142,13 +142,13 @@
         final boolean zenMuted = isZenMuted();
         mSeekBar.setEnabled(!zenMuted);
         if (zenMuted) {
-            mSeekBar.setProgress(mLastAudibleStreamVolume);
+            mSeekBar.setProgress(mLastAudibleStreamVolume, true);
         } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
-            mSeekBar.setProgress(0);
+            mSeekBar.setProgress(0, true);
         } else if (mMuted) {
-            mSeekBar.setProgress(0);
+            mSeekBar.setProgress(0, true);
         } else {
-            mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume);
+            mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume, true);
         }
     }
 
@@ -313,13 +313,13 @@
 
     public void muteVolume() {
         if (mVolumeBeforeMute != -1) {
-            mSeekBar.setProgress(mVolumeBeforeMute);
+            mSeekBar.setProgress(mVolumeBeforeMute, true);
             postSetVolume(mVolumeBeforeMute);
             postStartSample();
             mVolumeBeforeMute = -1;
         } else {
             mVolumeBeforeMute = mSeekBar.getProgress();
-            mSeekBar.setProgress(0);
+            mSeekBar.setProgress(0, true);
             postStopSample();
             postSetVolume(0);
         }
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index f134943..3d094f7 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -586,8 +586,6 @@
      *
      * @param key The option key.
      * @return Whether the option is present.
-     *
-     * @hide
      */
     public boolean hasAdvancedOption(String key) {
         return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
@@ -598,8 +596,6 @@
      *
      * @param key The option key.
      * @return The option value.
-     *
-     * @hide
      */
     public String getAdvancedStringOption(String key) {
         if (mAdvancedOptions != null) {
@@ -613,8 +609,6 @@
      *
      * @param key The option key.
      * @return The option value.
-     *
-     * @hide
      */
     public int getAdvancedIntOption(String key) {
         if (mAdvancedOptions != null) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index fbd61cf..c7c6ceb 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -284,8 +284,10 @@
 
         /**
          * The cached name associated with the phone number, if it exists.
-         * This value is not guaranteed to be current, if the contact information
-         * associated with this number has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_NAME = "name";
@@ -293,8 +295,10 @@
         /**
          * The cached number type (Home, Work, etc) associated with the
          * phone number, if it exists.
-         * This value is not guaranteed to be current, if the contact information
-         * associated with this number has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: INTEGER</P>
          */
         public static final String CACHED_NUMBER_TYPE = "numbertype";
@@ -302,8 +306,10 @@
         /**
          * The cached number label, for a custom number type, associated with the
          * phone number, if it exists.
-         * This value is not guaranteed to be current, if the contact information
-         * associated with this number has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_NUMBER_LABEL = "numberlabel";
@@ -339,40 +345,50 @@
 
         /**
          * The cached URI to look up the contact associated with the phone number, if it exists.
-         * This value may not be current if the contact information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_LOOKUP_URI = "lookup_uri";
 
         /**
          * The cached phone number of the contact which matches this entry, if it exists.
-         * This value may not be current if the contact information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_MATCHED_NUMBER = "matched_number";
 
         /**
          * The cached normalized(E164) version of the phone number, if it exists.
-         * This value may not be current if the contact information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
 
         /**
          * The cached photo id of the picture associated with the phone number, if it exists.
-         * This value may not be current if the contact information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: INTEGER (long)</P>
          */
         public static final String CACHED_PHOTO_ID = "photo_id";
 
         /**
          * The cached photo URI of the picture associated with the phone number, if it exists.
-         * This value may not be current if the contact information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT (URI)</P>
          */
         public static final String CACHED_PHOTO_URI = "photo_uri";
@@ -380,9 +396,10 @@
         /**
          * The cached phone number, formatted with formatting rules based on the country the
          * user was in when the call was made or received.
-         * This value is not guaranteed to be present, and may not be current if the contact
-         * information associated with this number
-         * has changed.
+         *
+         * <p>This value is typically filled in by the dialer app for the caching purpose,
+         * so it's not guaranteed to be present, and may not be current if the contact
+         * information associated with this number has changed.
          * <P>Type: TEXT</P>
          */
         public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c70304e..a1763c0 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -35,6 +35,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.database.CursorWrapper;
 import android.database.DatabaseUtils;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -138,8 +139,20 @@
     public static final String DIRECTORY_PARAM_KEY = "directory";
 
     /**
-     * A query parameter that limits the number of results returned. The
+     * A query parameter that limits the number of results returned for supported URIs. The
      * parameter value should be an integer.
+     *
+     * <p>This parameter is not supported by all URIs.  Supported URIs include, but not limited to,
+     * {@link Contacts#CONTENT_URI},
+     * {@link RawContacts#CONTENT_URI},
+     * {@link Data#CONTENT_URI},
+     * {@link CommonDataKinds.Phone#CONTENT_URI},
+     * {@link CommonDataKinds.Callable#CONTENT_URI},
+     * {@link CommonDataKinds.Email#CONTENT_URI},
+     * {@link CommonDataKinds.Contactables#CONTENT_URI},
+     *
+     * <p>In order to limit the number of rows returned by a non-supported URI, you can implement a
+     * {@link CursorWrapper} and override the {@link CursorWrapper#getCount()} methods.
      */
     public static final String LIMIT_PARAM_KEY = "limit";
 
@@ -437,6 +450,9 @@
 
         /**
          * _ID of the default directory, which represents locally stored contacts.
+         * <b>This is only supported by {@link ContactsContract.Contacts#CONTENT_URI} and
+         * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}.
+         * Other URLs do not support the concept of "visible" or "invisible" contacts.
          */
         public static final long DEFAULT = 0;
 
@@ -5150,7 +5166,7 @@
      * </table>
      */
     public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
-            ContactsColumns, ContactOptionsColumns {
+            ContactsColumns, ContactOptionsColumns, ContactNameColumns {
         /**
          * This utility class cannot be instantiated
          */
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..bf73089 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -44,7 +44,6 @@
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.DropBoxManager;
 import android.os.IBinder;
@@ -1284,6 +1283,19 @@
             = "android.settings.VR_LISTENER_SETTINGS";
 
     /**
+     * Activity Action: Show Storage Manager settings.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_STORAGE_MANAGER_SETTINGS
+            = "android.settings.STORAGE_MANAGER_SETTINGS";
+
+    /**
      * Activity Action: Allows user to select current webview implementation.
      * <p>
      * Input: Nothing.
@@ -1658,6 +1670,9 @@
                                                     + cr.getPackageName() + " and user:"
                                                     + userHandle + " with index:" + index);
                                         }
+                                        if (mGenerationTracker != null) {
+                                            mGenerationTracker.destroy();
+                                        }
                                         mGenerationTracker = new GenerationTracker(array, index,
                                                 generation, () -> {
                                             synchronized (NameValueCache.this) {
@@ -3817,6 +3832,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 +5881,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";
@@ -5922,6 +5959,36 @@
                 INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF;
 
         /**
+         * What happens when the user presses the Back button while in-call
+         * and the screen is on.<br/>
+         * <b>Values:</b><br/>
+         * 0 - The Back buttons does nothing different.<br/>
+         * 1 - The Back button hangs up the current call.<br/>
+         *
+         * @hide
+         */
+        public static final String INCALL_BACK_BUTTON_BEHAVIOR = "incall_back_button_behavior";
+
+        /**
+         * INCALL_BACK_BUTTON_BEHAVIOR value for no action.
+         * @hide
+         */
+        public static final int INCALL_BACK_BUTTON_BEHAVIOR_NONE = 0x0;
+
+        /**
+         * INCALL_BACK_BUTTON_BEHAVIOR value for "hang up".
+         * @hide
+         */
+        public static final int INCALL_BACK_BUTTON_BEHAVIOR_HANGUP = 0x1;
+
+        /**
+         * INCALL_POWER_BUTTON_BEHAVIOR default value.
+         * @hide
+         */
+        public static final int INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT =
+                INCALL_BACK_BUTTON_BEHAVIOR_NONE;
+
+        /**
          * Whether the device should wake when the wake gesture sensor detects motion.
          * @hide
          */
@@ -5934,6 +6001,18 @@
         public static final String DOZE_ENABLED = "doze_enabled";
 
         /**
+         * Whether the device should pulse on pick up gesture.
+         * @hide
+         */
+        public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
+
+        /**
+         * Whether the device should pulse on double tap gesture.
+         * @hide
+         */
+        public static final String DOZE_PULSE_ON_DOUBLE_TAP = "doze_pulse_on_double_tap";
+
+        /**
          * The current night mode that has been selected by the user.  Owned
          * and controlled by UiModeManagerService.  Constants are as per
          * UiModeManager.
@@ -6061,6 +6140,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";
 
@@ -6350,6 +6440,12 @@
                 "automatic_storage_manager_downloads_days_to_retain";
 
         /**
+         * Holds comma separated list of ordering of QS tiles.
+         * @hide
+         */
+        public static final String QS_TILES = "sysui_qs_tiles";
+
+        /**
          * Whether preloaded APKs have been installed for the user.
          * @hide
          */
@@ -6357,6 +6453,13 @@
                 = "demo_user_setup_complete";
 
         /**
+         * Specifies whether the web action API is enabled.
+         *
+         * @hide
+         */
+        public static final String WEB_ACTION_ENABLED = "web_action_enabled";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -6432,7 +6535,15 @@
             NIGHT_DISPLAY_CUSTOM_START_TIME,
             NIGHT_DISPLAY_CUSTOM_END_TIME,
             NIGHT_DISPLAY_AUTO_MODE,
-            NIGHT_DISPLAY_ACTIVATED
+            NIGHT_DISPLAY_ACTIVATED,
+            SYNC_PARENT_SOUNDS,
+            CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+            CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
+            SYSTEM_NAVIGATION_KEYS_ENABLED,
+            QS_TILES,
+            DOZE_ENABLED,
+            DOZE_PULSE_ON_PICK_UP,
+            DOZE_PULSE_ON_DOUBLE_TAP
         };
 
         /**
@@ -7437,27 +7548,54 @@
         public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
                 "webview_data_reduction_proxy_key";
 
-        /**
-         * Whether or not the WebView fallback mechanism should be enabled.
-         * 0=disabled, 1=enabled.
-         * @hide
-         */
-        public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
-                "webview_fallback_logic_enabled";
+       /**
+        * Whether or not the WebView fallback mechanism should be enabled.
+        * 0=disabled, 1=enabled.
+        * @hide
+        */
+       public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
+               "webview_fallback_logic_enabled";
 
-        /**
-         * Name of the package used as WebView provider (if unset the provider is instead determined
-         * by the system).
-         * @hide
-         */
-        public static final String WEBVIEW_PROVIDER = "webview_provider";
+       /**
+        * Name of the package used as WebView provider (if unset the provider is instead determined
+        * by the system).
+        * @hide
+        */
+       public static final String WEBVIEW_PROVIDER = "webview_provider";
 
-        /**
-         * Developer setting to enable WebView multiprocess rendering.
-         * @hide
-         */
-        @SystemApi
-        public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+       /**
+        * Developer setting to enable WebView multiprocess rendering.
+        * @hide
+        */
+       @SystemApi
+       public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+
+       /**
+        * The maximum number of notifications shown in 24 hours when switching networks.
+        * @hide
+        */
+       public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+              "network_switch_notification_daily_limit";
+
+       /**
+        * The minimum time in milliseconds between notifications when switching networks.
+        * @hide
+        */
+       public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+              "network_switch_notification_rate_limit_millis";
+
+       /**
+        * Whether to automatically switch away from wifi networks that lose Internet access.
+        * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+        * avoids such networks. Valid values are:
+        *
+        * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+        * null: Ask the user whether to switch away from bad wifi.
+        * 1: Avoid bad wifi.
+        *
+        * @hide
+        */
+       public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
 
        /**
         * Whether Wifi display is enabled/disabled
@@ -7929,12 +8067,37 @@
         /**
          * The server used for captive portal detection upon a new conection. A
          * 204 response code from the server is used for validation.
+         * TODO: remove this deprecated symbol.
          *
          * @hide
          */
         public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
 
         /**
+         * The URL used for HTTPS captive portal detection upon a new connection.
+         * A 204 response code from the server is used for validation.
+         *
+         * @hide
+         */
+        public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
+
+        /**
+         * The URL used for HTTP captive portal detection upon a new connection.
+         * A 204 response code from the server is used for validation.
+         *
+         * @hide
+         */
+        public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+        /**
+         * The URL used for fallback HTTP captive portal detection when previous HTTP
+         * and HTTPS captive portal detection attemps did not return a conclusive answer.
+         *
+         * @hide
+         */
+        public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
+
+        /**
          * Whether to use HTTPS for network validation. This is enabled by default and the setting
          * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
          * don't actually use HTTPS, but it's consistent with the other settings.
@@ -7944,6 +8107,14 @@
         public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
 
         /**
+         * Which User-Agent string to use in the header of the captive portal detection probes.
+         * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
+         *
+         * @hide
+         */
+        public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+
+        /**
          * Whether network service discovery is enabled.
          *
          * @hide
@@ -8316,6 +8487,13 @@
         public static final String CALL_AUTO_RETRY = "call_auto_retry";
 
         /**
+         * A setting that can be read whether the emergency affordance is currently needed.
+         * The value is a boolean (1 or 0).
+         * @hide
+         */
+        public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
+
+        /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
@@ -8647,7 +8825,7 @@
         public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
 
         /**
-         * WFC Mode.
+         * WFC mode on home/non-roaming network.
          * <p>
          * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
          *
@@ -8656,6 +8834,15 @@
         public static final String WFC_IMS_MODE = "wfc_ims_mode";
 
         /**
+         * WFC mode on roaming network.
+         * <p>
+         * Type: int - see {@link WFC_IMS_MODE} for values
+         *
+         * @hide
+         */
+        public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+        /**
          * Whether WFC roaming is enabled
          * <p>
          * Type: int (0 for false, 1 for true)
@@ -8683,6 +8870,16 @@
                 "ephemeral_cookie_max_size_bytes";
 
         /**
+         * Toggle to enable/disable the entire ephemeral feature. By default, ephemeral is
+         * enabled. Set to zero to disable.
+         * <p>
+         * Type: int (0 for false, 1 for true)
+         *
+         * @hide
+         */
+        public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
+
+        /**
          * A mask applied to the ephemeral hash to generate the hash prefix.
          * <p>
          * Type: int
@@ -8761,6 +8958,24 @@
         public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants";
 
         /**
+         * The reason for the settings database being downgraded. This is only for
+         * troubleshooting purposes and its value should not be interpreted in any way.
+         *
+         * Type: string
+         *
+         * @hide
+         */
+        public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
+
+        /**
+         * Flag to toggle journal mode WAL on or off for the contacts database. WAL is enabled by
+         * default. Set to 0 to disable.
+         *
+         * @hide
+         */
+        public static final String CONTACTS_DATABASE_WAL_ENABLED = "contacts_database_wal_enabled";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
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/security/keymaster/IKeyAttestationApplicationIdProvider.aidl b/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
new file mode 100644
index 0000000..dbffd5f
--- /dev/null
+++ b/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
@@ -0,0 +1,32 @@
+/**
+ * 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.security.keymaster;
+
+import android.security.keymaster.KeyAttestationApplicationId;
+import android.security.keymaster.KeyAttestationPackageInfo;
+import android.content.pm.Signature;
+
+/**
+ * This must be kept manually in sync with system/security/keystore until AIDL
+ * can generate both Java and C++ bindings.
+ *
+ * @hide
+ */
+interface IKeyAttestationApplicationIdProvider {
+    /* keep in sync with /system/security/keystore/keystore_attestation_id.cpp */
+    KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
+}
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl b/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
new file mode 100644
index 0000000..9f6ff58
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.security.keymaster;
+
+/* The cpp_header is relative to system/security/keystore/include
+ * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
+ */
+parcelable KeyAttestationApplicationId cpp_header "keystore/KeyAttestationApplicationId.h";
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.java b/core/java/android/security/keymaster/KeyAttestationApplicationId.java
new file mode 100644
index 0000000..8e585f4b
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyAttestationApplicationId.java
@@ -0,0 +1,74 @@
+/*
+ * 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.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ * The information aggregated by this class is used by keystore to identify a caller of the
+ * keystore API toward a remote party. It aggregates multiple PackageInfos because keystore
+ * can only determine a caller by uid granularity, and a uid can be shared by multiple packages.
+ * The remote party must decide if it trusts all of the packages enough to consider the
+ * confidentiality of the key material in question intact.
+ */
+public class KeyAttestationApplicationId implements Parcelable {
+    private final KeyAttestationPackageInfo[] mAttestationPackageInfos;
+
+    /**
+     * @param mAttestationPackageInfos
+     */
+    public KeyAttestationApplicationId(KeyAttestationPackageInfo[] mAttestationPackageInfos) {
+        super();
+        this.mAttestationPackageInfos = mAttestationPackageInfos;
+    }
+
+    /**
+     * @return the mAttestationPackageInfos
+     */
+    public KeyAttestationPackageInfo[] getAttestationPackageInfos() {
+        return mAttestationPackageInfos;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedArray(mAttestationPackageInfos, flags);
+    }
+
+    public static final Parcelable.Creator<KeyAttestationApplicationId> CREATOR
+            = new Parcelable.Creator<KeyAttestationApplicationId>() {
+        @Override
+        public KeyAttestationApplicationId createFromParcel(Parcel source) {
+            return new KeyAttestationApplicationId(source);
+        }
+
+        @Override
+        public KeyAttestationApplicationId[] newArray(int size) {
+            return new KeyAttestationApplicationId[size];
+        }
+    };
+
+    KeyAttestationApplicationId(Parcel source) {
+        mAttestationPackageInfos = source.createTypedArray(KeyAttestationPackageInfo.CREATOR);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
new file mode 100644
index 0000000..f8b843b
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.security.keymaster;
+
+/* The cpp_header is relative to system/security/keystore/include
+ * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
+ */
+parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
new file mode 100644
index 0000000..5a3f390
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
@@ -0,0 +1,95 @@
+/*
+ * 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.security.keymaster;
+
+import android.content.pm.Signature;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ * This class constitutes and excerpt from the PackageManager's PackageInfo for the purpose of
+ * key attestation. It is part of the KeyAttestationApplicationId, which is used by
+ * keystore to identify the caller of the keystore API towards a remote party.
+ */
+public class KeyAttestationPackageInfo implements Parcelable {
+    private final String mPackageName;
+    private final int mPackageVersionCode;
+    private final Signature[] mPackageSignatures;
+
+    /**
+     * @param mPackageName
+     * @param mPackageVersionCode
+     * @param mPackageSignatures
+     */
+    public KeyAttestationPackageInfo(
+            String mPackageName, int mPackageVersionCode, Signature[] mPackageSignatures) {
+        super();
+        this.mPackageName = mPackageName;
+        this.mPackageVersionCode = mPackageVersionCode;
+        this.mPackageSignatures = mPackageSignatures;
+    }
+    /**
+     * @return the mPackageName
+     */
+    public String getPackageName() {
+        return mPackageName;
+    }
+    /**
+     * @return the mPackageVersionCode
+     */
+    public int getPackageVersionCode() {
+        return mPackageVersionCode;
+    }
+    /**
+     * @return the mPackageSignatures
+     */
+    public Signature[] getPackageSignatures() {
+        return mPackageSignatures;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mPackageName);
+        dest.writeInt(mPackageVersionCode);
+        dest.writeTypedArray(mPackageSignatures, flags);
+    }
+
+    public static final Parcelable.Creator<KeyAttestationPackageInfo> CREATOR
+            = new Parcelable.Creator<KeyAttestationPackageInfo>() {
+        @Override
+        public KeyAttestationPackageInfo createFromParcel(Parcel source) {
+            return new KeyAttestationPackageInfo(source);
+        }
+
+        @Override
+        public KeyAttestationPackageInfo[] newArray(int size) {
+            return new KeyAttestationPackageInfo[size];
+        }
+    };
+
+    private KeyAttestationPackageInfo(Parcel source) {
+        mPackageName = source.readString();
+        mPackageVersionCode = source.readInt();
+        mPackageSignatures = source.createTypedArray(Signature.CREATOR);
+    }
+}
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index e3c9d65..119f5d0 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -19,6 +19,7 @@
 import android.os.Environment;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Pair;
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -44,6 +45,7 @@
  * @hide
  */
 abstract class DirectoryCertificateSource implements CertificateSource {
+    private static final String LOG_TAG = "DirectoryCertificateSrc";
     private final File mDir;
     private final Object mLock = new Object();
     private final CertificateFactory mCertFactory;
@@ -149,6 +151,9 @@
                 continue;
             }
             X509Certificate cert = readCertificate(fileName);
+            if (cert == null) {
+                continue;
+            }
             if (!subj.equals(cert.getSubjectX500Principal())) {
                 continue;
             }
@@ -173,6 +178,9 @@
                 continue;
             }
             X509Certificate cert = readCertificate(fileName);
+            if (cert == null) {
+                continue;
+            }
             if (!subj.equals(cert.getSubjectX500Principal())) {
                 continue;
             }
@@ -194,6 +202,7 @@
             is = new BufferedInputStream(new FileInputStream(new File(mDir, file)));
             return (X509Certificate) mCertFactory.generateCertificate(is);
         } catch (CertificateException | IOException e) {
+            Log.e(LOG_TAG, "Failed to read certificate from " + file, e);
             return null;
         } finally {
             IoUtils.closeQuietly(is);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 0557d13..94505d3 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -27,6 +27,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -942,8 +943,9 @@
      * Must run on mHandler.
      *
      * @param windowToken A window token that will allow a window to be created in the correct layer.
+     * @param started A callback that will be invoked once onDreamingStarted has completed.
      */
-    private final void attach(IBinder windowToken, boolean canDoze) {
+    private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
         if (mWindowToken != null) {
             Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
             return;
@@ -1017,7 +1019,15 @@
                 if (mWindow != null || mWindowless) {
                     if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
                     mStarted = true;
-                    onDreamingStarted();
+                    try {
+                        onDreamingStarted();
+                    } finally {
+                        try {
+                            started.sendResult(null);
+                        } catch (RemoteException e) {
+                            throw e.rethrowFromSystemServer();
+                        }
+                    }
                 }
             }
         });
@@ -1092,11 +1102,12 @@
 
     private final class DreamServiceWrapper extends IDreamService.Stub {
         @Override
-        public void attach(final IBinder windowToken, final boolean canDoze) {
+        public void attach(final IBinder windowToken, final boolean canDoze,
+                IRemoteCallback started) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    DreamService.this.attach(windowToken, canDoze);
+                    DreamService.this.attach(windowToken, canDoze, started);
                 }
             });
         }
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 9bb1804..ce04354 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -16,11 +16,13 @@
 
 package android.service.dreams;
 
+import android.os.IRemoteCallback;
+
 /**
  * @hide
  */
 oneway interface IDreamService {
-    void attach(IBinder windowToken, boolean canDoze);
+    void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started);
     void detach();
     void wakeUp();
 }
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 9d4b0a4..c8358a6 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
@@ -126,6 +127,42 @@
     }
 
     /**
+     * Request that the provider be rebound, after a previous call to (@link requestUnbind).
+     *
+     * <p>This method will fail for providers that have not been granted the permission by the user.
+     */
+    public static final void requestRebind(ComponentName componentName) {
+        INotificationManager noMan = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        try {
+            noMan.requestBindProvider(componentName);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request that the provider service be unbound.
+     *
+     * <p>This will no longer receive subscription updates and will not be able to update the
+     * state of conditions until {@link #requestRebind(ComponentName)} is called.
+     * The service will likely be killed by the system after this call.
+     *
+     * <p>The service should wait for the {@link #onConnected()} event before performing this
+     * operation.
+     */
+    public final void requestUnbind() {
+        INotificationManager noMan = getNotificationInterface();
+        try {
+            noMan.requestUnbindProvider(mProvider);
+            // Disable future messages.
+            mProvider = null;
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Informs the notification manager that the state of a Condition has changed. Use this method
      * to put the system into Do Not Disturb mode or request that it exits Do Not Disturb mode. This
      * call will be ignored unless there is an enabled {@link android.app.AutomaticZenRule} owned by
@@ -193,6 +230,9 @@
         @Override
         public void handleMessage(Message msg) {
             String name = null;
+            if (!isBound()) {
+                return;
+            }
             try {
                 switch(msg.what) {
                     case ON_CONNECTED:
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
index ee5361a..261d82d 100644
--- a/core/java/android/service/notification/NotificationRankerService.java
+++ b/core/java/android/service/notification/NotificationRankerService.java
@@ -99,6 +99,9 @@
     /** Autobundled summary notification was canceled because its group was unbundled */
     public static final int REASON_UNAUTOBUNDLED = 16;
 
+    /** Notification was canceled by the user banning the channel. */
+    public static final int REASON_CHANNEL_BANNED = 17;
+
     private Handler mHandler;
 
     /** @hide */
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 474a9b6..b225018 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1,7 +1,7 @@
 /**
  * Copyright (c) 2014, The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License,  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
  *
@@ -398,18 +398,13 @@
         }
     }
 
-    public static ZenModeConfig readXml(XmlPullParser parser, Migration migration)
+    public static ZenModeConfig readXml(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type != XmlPullParser.START_TAG) return null;
         String tag = parser.getName();
         if (!ZEN_TAG.equals(tag)) return null;
         final ZenModeConfig rt = new ZenModeConfig();
-        final int version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
-        if (version == 1) {
-            final XmlV1 v1 = XmlV1.readXml(parser);
-            return migration.migrate(v1);
-        }
         rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
             tag = parser.getName();
@@ -1241,122 +1236,6 @@
         };
     }
 
-    // Legacy config
-    public static final class XmlV1 {
-        public static final String SLEEP_MODE_NIGHTS = "nights";
-        public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
-        public static final String SLEEP_MODE_DAYS_PREFIX = "days:";
-
-        private static final String EXIT_CONDITION_TAG = "exitCondition";
-        private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
-        private static final String SLEEP_TAG = "sleep";
-        private static final String SLEEP_ATT_MODE = "mode";
-        private static final String SLEEP_ATT_NONE = "none";
-
-        private static final String SLEEP_ATT_START_HR = "startHour";
-        private static final String SLEEP_ATT_START_MIN = "startMin";
-        private static final String SLEEP_ATT_END_HR = "endHour";
-        private static final String SLEEP_ATT_END_MIN = "endMin";
-
-        public boolean allowCalls;
-        public boolean allowMessages;
-        public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
-        public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
-        public int allowFrom = SOURCE_ANYONE;
-
-        public String sleepMode;     // nights, weeknights, days:1,2,3  Calendar.days
-        public int sleepStartHour;   // 0-23
-        public int sleepStartMinute; // 0-59
-        public int sleepEndHour;
-        public int sleepEndMinute;
-        public boolean sleepNone;    // false = priority, true = none
-        public ComponentName[] conditionComponents;
-        public Uri[] conditionIds;
-        public Condition exitCondition;  // manual exit condition
-        public ComponentName exitConditionComponent;  // manual exit condition component
-
-        private static boolean isValidSleepMode(String sleepMode) {
-            return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
-                    || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null;
-        }
-
-        public static int[] tryParseDays(String sleepMode) {
-            if (sleepMode == null) return null;
-            sleepMode = sleepMode.trim();
-            if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS;
-            if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS;
-            if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null;
-            if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null;
-            return tryParseDayList(sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()), ",");
-        }
-
-        public static XmlV1 readXml(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            int type;
-            String tag;
-            XmlV1 rt = new XmlV1();
-            final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
-            final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
-                tag = parser.getName();
-                if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
-                    if (!conditionComponents.isEmpty()) {
-                        rt.conditionComponents = conditionComponents
-                                .toArray(new ComponentName[conditionComponents.size()]);
-                        rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
-                    }
-                    return rt;
-                }
-                if (type == XmlPullParser.START_TAG) {
-                    if (ALLOW_TAG.equals(tag)) {
-                        rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
-                        rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
-                        rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
-                                DEFAULT_ALLOW_REMINDERS);
-                        rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS,
-                                DEFAULT_ALLOW_EVENTS);
-                        rt.allowFrom = safeInt(parser, ALLOW_ATT_FROM, SOURCE_ANYONE);
-                        if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) {
-                            throw new IndexOutOfBoundsException("bad source in config:"
-                                    + rt.allowFrom);
-                        }
-                    } else if (SLEEP_TAG.equals(tag)) {
-                        final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
-                        rt.sleepMode = isValidSleepMode(mode)? mode : null;
-                        rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
-                        final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
-                        final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
-                        final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
-                        final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
-                        rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
-                        rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
-                        rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
-                        rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
-                    } else if (CONDITION_TAG.equals(tag)) {
-                        final ComponentName component =
-                                safeComponentName(parser, CONDITION_ATT_COMPONENT);
-                        final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
-                        if (component != null && conditionId != null) {
-                            conditionComponents.add(component);
-                            conditionIds.add(conditionId);
-                        }
-                    } else if (EXIT_CONDITION_TAG.equals(tag)) {
-                        rt.exitCondition = readConditionXml(parser);
-                        if (rt.exitCondition != null) {
-                            rt.exitConditionComponent =
-                                    safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
-                        }
-                    }
-                }
-            }
-            throw new IllegalStateException("Failed to reach END_DOCUMENT");
-        }
-    }
-
-    public interface Migration {
-        ZenModeConfig migrate(XmlV1 v1);
-    }
-
     public static class Diff {
         private final ArrayList<String> lines = new ArrayList<>();
 
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 3c7741d..9ac8996 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -17,8 +17,11 @@
 package android.text;
 
 import android.graphics.Paint;
+import android.graphics.Rect;
+import android.text.style.ReplacementSpan;
 import android.text.style.UpdateLayout;
 import android.text.style.WrapTogetherSpan;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -300,7 +303,6 @@
                 .setHyphenationFrequency(mHyphenationFrequency);
         reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
-
         // If the new layout has a blank line at the end, but it is not
         // the very end of the buffer, then we already have a line that
         // starts there, so disregard the blank line.
@@ -345,9 +347,10 @@
         Directions[] objects = new Directions[1];
 
         for (int i = 0; i < n; i++) {
-            ints[START] = reflowed.getLineStart(i) |
-                          (reflowed.getParagraphDirection(i) << DIR_SHIFT) |
-                          (reflowed.getLineContainsTab(i) ? TAB_MASK : 0);
+            final int start = reflowed.getLineStart(i);
+            ints[START] = start;
+            ints[DIR] |= reflowed.getParagraphDirection(i) << DIR_SHIFT;
+            ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;
 
             int top = reflowed.getLineTop(i) + startv;
             if (i > 0)
@@ -361,7 +364,11 @@
             ints[DESCENT] = desc;
             objects[0] = reflowed.getLineDirections(i);
 
-            ints[HYPHEN] = reflowed.getHyphen(i);
+            final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
+            ints[HYPHEN] = reflowed.getHyphen(i) & HYPHEN_MASK;
+            ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |=
+                    contentMayProtrudeFromLineTopOrBottom(text, start, end) ?
+                            MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;
 
             if (mEllipsize) {
                 ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
@@ -381,6 +388,21 @@
         }
     }
 
+    private boolean contentMayProtrudeFromLineTopOrBottom(CharSequence text, int start, int end) {
+        if (text instanceof Spanned) {
+            final Spanned spanned = (Spanned) text;
+            if (spanned.getSpans(start, end, ReplacementSpan.class).length > 0) {
+                return true;
+            }
+        }
+        // Spans other than ReplacementSpan can be ignored because line top and bottom are
+        // disjunction of all tops and bottoms, although it's not optimal.
+        final Paint paint = getPaint();
+        paint.getTextBounds(text, start, end, mTempRect);
+        final Paint.FontMetricsInt fm = paint.getFontMetricsInt();
+        return mTempRect.top < fm.top || mTempRect.bottom > fm.bottom;
+    }
+
     /**
      * Create the initial block structure, cutting the text into blocks of at least
      * BLOCK_MINIMUM_CHARACTER_SIZE characters, aligned on the ends of paragraphs.
@@ -409,17 +431,41 @@
     }
 
     /**
+     * @hide
+     */
+    public ArraySet<Integer> getBlocksAlwaysNeedToBeRedrawn() {
+        return mBlocksAlwaysNeedToBeRedrawn;
+    }
+
+    private void updateAlwaysNeedsToBeRedrawn(int blockIndex) {
+        int startLine = blockIndex == 0 ? 0 : (mBlockEndLines[blockIndex - 1] + 1);
+        int endLine = mBlockEndLines[blockIndex];
+        for (int i = startLine; i <= endLine; i++) {
+            if (getContentMayProtrudeFromTopOrBottom(i)) {
+                if (mBlocksAlwaysNeedToBeRedrawn == null) {
+                    mBlocksAlwaysNeedToBeRedrawn = new ArraySet<>();
+                }
+                mBlocksAlwaysNeedToBeRedrawn.add(blockIndex);
+                return;
+            }
+        }
+        if (mBlocksAlwaysNeedToBeRedrawn != null) {
+            mBlocksAlwaysNeedToBeRedrawn.remove(blockIndex);
+        }
+    }
+
+    /**
      * Create a new block, ending at the specified character offset.
      * A block will actually be created only if has at least one line, i.e. this offset is
      * not on the end line of the previous block.
      */
     private void addBlockAtOffset(int offset) {
         final int line = getLineForOffset(offset);
-
         if (mBlockEndLines == null) {
             // Initial creation of the array, no test on previous block ending line
             mBlockEndLines = ArrayUtils.newUnpaddedIntArray(1);
             mBlockEndLines[mNumberOfBlocks] = line;
+            updateAlwaysNeedsToBeRedrawn(mNumberOfBlocks);
             mNumberOfBlocks++;
             return;
         }
@@ -427,6 +473,7 @@
         final int previousBlockEndLine = mBlockEndLines[mNumberOfBlocks - 1];
         if (line > previousBlockEndLine) {
             mBlockEndLines = GrowingArrayUtils.append(mBlockEndLines, mNumberOfBlocks, line);
+            updateAlwaysNeedsToBeRedrawn(mNumberOfBlocks);
             mNumberOfBlocks++;
         }
     }
@@ -506,13 +553,25 @@
                     blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
             mBlockEndLines = blockEndLines;
             mBlockIndices = blockIndices;
-        } else {
+        } else if (numAddedBlocks + numRemovedBlocks != 0) {
             System.arraycopy(mBlockEndLines, lastBlock + 1,
                     mBlockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
             System.arraycopy(mBlockIndices, lastBlock + 1,
                     mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
         }
 
+        if (numAddedBlocks + numRemovedBlocks != 0 && mBlocksAlwaysNeedToBeRedrawn != null) {
+            final ArraySet<Integer> set = new ArraySet<>();
+            for (int i = 0; i < mBlocksAlwaysNeedToBeRedrawn.size(); i++) {
+                Integer block = mBlocksAlwaysNeedToBeRedrawn.valueAt(i);
+                if (block > firstBlock) {
+                    block += numAddedBlocks - numRemovedBlocks;
+                }
+                set.add(block);
+            }
+            mBlocksAlwaysNeedToBeRedrawn = set;
+        }
+
         mNumberOfBlocks = newNumberOfBlocks;
         int newFirstChangedBlock;
         final int deltaLines = newLineCount - (endLine - startLine + 1);
@@ -531,18 +590,21 @@
         int blockIndex = firstBlock;
         if (createBlockBefore) {
             mBlockEndLines[blockIndex] = startLine - 1;
+            updateAlwaysNeedsToBeRedrawn(blockIndex);
             mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
             blockIndex++;
         }
 
         if (createBlock) {
             mBlockEndLines[blockIndex] = startLine + newLineCount - 1;
+            updateAlwaysNeedsToBeRedrawn(blockIndex);
             mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
             blockIndex++;
         }
 
         if (createBlockAfter) {
             mBlockEndLines[blockIndex] = lastBlockEndLine + deltaLines;
+            updateAlwaysNeedsToBeRedrawn(blockIndex);
             mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
         }
     }
@@ -577,6 +639,21 @@
     /**
      * @hide
      */
+    public int getBlockIndex(int index) {
+        return mBlockIndices[index];
+    }
+
+    /**
+     * @hide
+     * @param index
+     */
+    public void setBlockIndex(int index, int blockIndex) {
+        mBlockIndices[index] = blockIndex;
+    }
+
+    /**
+     * @hide
+     */
     public int getNumberOfBlocks() {
         return mNumberOfBlocks;
     }
@@ -645,7 +722,12 @@
      */
     @Override
     public int getHyphen(int line) {
-        return mInts.getValue(line, HYPHEN);
+        return mInts.getValue(line, HYPHEN) & HYPHEN_MASK;
+    }
+
+    private boolean getContentMayProtrudeFromTopOrBottom(int line) {
+        return (mInts.getValue(line, MAY_PROTRUDE_FROM_TOP_OR_BOTTOM)
+                & MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK) != 0;
     }
 
     @Override
@@ -741,6 +823,8 @@
     // The indices of this block's display list in TextView's internal display list array or
     // INVALID_BLOCK_INDEX if this block has been invalidated during an edition
     private int[] mBlockIndices;
+    // Set of blocks that always need to be redrawn.
+    private ArraySet<Integer> mBlocksAlwaysNeedToBeRedrawn;
     // Number of items actually currently being used in the above 2 arrays
     private int mNumberOfBlocks;
     // The first index of the blocks whose locations are changed
@@ -748,17 +832,22 @@
 
     private int mTopPadding, mBottomPadding;
 
+    private Rect mTempRect = new Rect();
+
     private static StaticLayout sStaticLayout = null;
     private static StaticLayout.Builder sBuilder = null;
 
     private static final Object[] sLock = new Object[0];
 
+    // START, DIR, and TAB share the same entry.
     private static final int START = 0;
     private static final int DIR = START;
     private static final int TAB = START;
     private static final int TOP = 1;
     private static final int DESCENT = 2;
+    // HYPHEN and MAY_PROTRUDE_FROM_TOP_OR_BOTTOM share the same entry.
     private static final int HYPHEN = 3;
+    private static final int MAY_PROTRUDE_FROM_TOP_OR_BOTTOM = HYPHEN;
     private static final int COLUMNS_NORMAL = 4;
 
     private static final int ELLIPSIS_START = 4;
@@ -768,6 +857,8 @@
     private static final int START_MASK = 0x1FFFFFFF;
     private static final int DIR_SHIFT  = 30;
     private static final int TAB_MASK   = 0x20000000;
+    private static final int HYPHEN_MASK = 0xFF;
+    private static final int MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK = 0x100;
 
     private static final int ELLIPSIS_UNDEFINED = 0x80000000;
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 55df206..ce3e282 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -279,7 +279,9 @@
                 if (width < 0.0f) break;
                 i--;
             }
-            while (i < limit - 1 && mChars[i + 1] == ' ') i++;
+            while (i < limit - 1 && (mChars[i + 1] == ' ' || w[i + 1] == 0.0f)) {
+                i++;
+            }
             return limit - i - 1;
         }
     }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index bb131a0..bdbe8b0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1029,8 +1029,10 @@
 
                 for (i = len; i > 0; i--) {
                     float w = widths[i - 1 + lineStart - widthStart];
-
                     if (w + sum + ellipsisWidth > avail) {
+                        while (i < len && widths[i + lineStart - widthStart] == 0.0f) {
+                            i++;
+                        }
                         break;
                     }
 
@@ -1076,9 +1078,11 @@
                     float w = widths[right - 1 + lineStart - widthStart];
 
                     if (w + rsum > ravail) {
+                        while (right < len && widths[right + lineStart - widthStart] == 0.0f) {
+                            right++;
+                        }
                         break;
                     }
-
                     rsum += w;
                 }
 
@@ -1181,7 +1185,7 @@
      */
     @Override
     public int getHyphen(int line) {
-        return mLines[mColumns * line + HYPHEN] & 0xff;
+        return mLines[mColumns * line + HYPHEN] & HYPHEN_MASK;
     }
 
     /**
@@ -1295,6 +1299,7 @@
     private static final int START_MASK = 0x1FFFFFFF;
     private static final int DIR_SHIFT  = 30;
     private static final int TAB_MASK   = 0x20000000;
+    private static final int HYPHEN_MASK = 0xFF;
 
     private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
 
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 16f3bc0..479f493 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -185,25 +185,25 @@
 
         final ViewGroup sceneRoot = scene.getSceneRoot();
         if (!sPendingTransitions.contains(sceneRoot)) {
-            sPendingTransitions.add(sceneRoot);
+            if (transition == null) {
+                scene.enter();
+            } else {
+                sPendingTransitions.add(sceneRoot);
 
-            Transition transitionClone = null;
-            if (transition != null) {
-                transitionClone = transition.clone();
+                Transition transitionClone = transition.clone();
                 transitionClone.setSceneRoot(sceneRoot);
+
+                Scene oldScene = Scene.getCurrentScene(sceneRoot);
+                if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
+                    transitionClone.setCanRemoveViews(true);
+                }
+
+                sceneChangeSetup(sceneRoot, transitionClone);
+
+                scene.enter();
+
+                sceneChangeRunTransition(sceneRoot, transitionClone);
             }
-
-            Scene oldScene = Scene.getCurrentScene(sceneRoot);
-            if (oldScene != null && transitionClone != null &&
-                    oldScene.isCreatedFromLayoutResource()) {
-                transitionClone.setCanRemoveViews(true);
-            }
-
-            sceneChangeSetup(sceneRoot, transitionClone);
-
-            scene.enter();
-
-            sceneChangeRunTransition(sceneRoot, transitionClone);
         }
     }
 
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 1e765b6..2eea7df 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,32 +152,54 @@
     }
 
     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;
-                    mArray = array;
-                    mTwiceBaseCache = (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");
+                if (sTwiceBaseCache != null) {
+                    final Object[] array = sTwiceBaseCache;
+                    try {
+                        mArray = array;
+                        sTwiceBaseCache = (Object[]) array[0];
+                        mHashes = (int[]) array[1];
+                        array[0] = array[1] = null;
+                        sTwiceBaseCacheSize--;
+                        if (DEBUG) {
+                            Log.d(TAG, "Retrieving 2x cache " + mHashes + " now have "
+                                    + sTwiceBaseCacheSize + " entries");
+                    }
                     return;
+                    } catch (ClassCastException e) {
+                    }
+                    // Whoops!  Someone trampled the array (probably due to not protecting
+                    // their access with a lock).  Our cache is corrupt; report and give up.
+                    Slog.wtf(TAG, "Found corrupt ArraySet cache: [0]=" + array[0]
+                            + " [1]=" + array[1]);
+                    sTwiceBaseCache = null;
+                    sTwiceBaseCacheSize = 0;
                 }
             }
         } else if (size == BASE_SIZE) {
             synchronized (ArraySet.class) {
-                if (mBaseCache != null) {
-                    final Object[] array = mBaseCache;
-                    mArray = array;
-                    mBaseCache = (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");
-                    return;
+                if (sBaseCache != null) {
+                    final Object[] array = sBaseCache;
+                    try {
+                        mArray = array;
+                        sBaseCache = (Object[]) array[0];
+                        mHashes = (int[]) array[1];
+                        array[0] = array[1] = null;
+                        sBaseCacheSize--;
+                        if (DEBUG) {
+                            Log.d(TAG, "Retrieving 1x cache " + mHashes + " now have " + sBaseCacheSize
+                                    + " entries");
+                        }
+                        return;
+                    } catch (ClassCastException e) {
+                    }
+                    // Whoops!  Someone trampled the array (probably due to not protecting
+                    // their access with a lock).  Our cache is corrupt; report and give up.
+                    Slog.wtf(TAG, "Found corrupt ArraySet cache: [0]=" + array[0]
+                            + " [1]=" + array[1]);
+                    sBaseCache = null;
+                    sBaseCacheSize = 0;
                 }
             }
         }
@@ -187,32 +209,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 +347,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 +384,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 +403,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 +459,7 @@
                 mSize = N;
             }
         } else {
-            for (int i=0; i<N; i++) {
+            for (int i = 0; i < N; i++) {
                 add(array.valueAt(i));
             }
         }
@@ -469,11 +496,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 +515,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 +575,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 +607,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 +651,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 +789,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/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 8f9b36e..ccaf204 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -20,7 +20,9 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.os.Process;
+
 import libcore.io.IoUtils;
+import dalvik.system.CloseGuard;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -51,10 +53,12 @@
 
     private static final int MAX_SIZE = 1024;
 
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     private final int mOwnerPid;
     private final boolean mClientWritable;
     private final long mMemoryAddr;
-    private ParcelFileDescriptor mFd;
+    private int mFd;
 
     /**
      * Creates a new instance.
@@ -71,23 +75,26 @@
         mOwnerPid = Process.myPid();
         mClientWritable = clientWritable;
         final String name = UUID.randomUUID().toString();
-        mFd = ParcelFileDescriptor.fromFd(nativeCreate(name, size));
-        mMemoryAddr = nativeOpen(mFd.getFd(), true, clientWritable);
+        mFd = nativeCreate(name, size);
+        mMemoryAddr = nativeOpen(mFd, true, clientWritable);
+        mCloseGuard.open("close");
     }
 
     private MemoryIntArray(Parcel parcel) throws IOException {
         mOwnerPid = parcel.readInt();
         mClientWritable = (parcel.readInt() == 1);
-        mFd = parcel.readParcelable(null);
-        if (mFd == null) {
+        ParcelFileDescriptor pfd = parcel.readParcelable(null);
+        if (pfd == null) {
             throw new IOException("No backing file descriptor");
         }
+        mFd = pfd.detachFd();
         final long memoryAddress = parcel.readLong();
         if (isOwner()) {
             mMemoryAddr = memoryAddress;
         } else {
-            mMemoryAddr = nativeOpen(mFd.getFd(), false, mClientWritable);
+            mMemoryAddr = nativeOpen(mFd, false, mClientWritable);
         }
+        mCloseGuard.open("close");
     }
 
     /**
@@ -108,7 +115,7 @@
     public int get(int index) throws IOException {
         enforceNotClosed();
         enforceValidIndex(index);
-        return nativeGet(mFd.getFd(), mMemoryAddr, index, isOwner());
+        return nativeGet(mFd, mMemoryAddr, index, isOwner());
     }
 
     /**
@@ -124,7 +131,7 @@
         enforceNotClosed();
         enforceWritable();
         enforceValidIndex(index);
-        nativeSet(mFd.getFd(), mMemoryAddr, index, value, isOwner());
+        nativeSet(mFd, mMemoryAddr, index, value, isOwner());
     }
 
     /**
@@ -134,7 +141,7 @@
      */
     public int size() throws IOException {
         enforceNotClosed();
-        return nativeSize(mFd.getFd());
+        return nativeSize(mFd);
     }
 
     /**
@@ -145,9 +152,9 @@
     @Override
     public void close() throws IOException {
         if (!isClosed()) {
-            ParcelFileDescriptor pfd = mFd;
-            mFd = null;
-            nativeClose(pfd.getFd(), mMemoryAddr, isOwner());
+            nativeClose(mFd, mMemoryAddr, isOwner());
+            mFd = -1;
+            mCloseGuard.close();
         }
     }
 
@@ -155,13 +162,17 @@
      * @return Whether this array is closed and shouldn't be used.
      */
     public boolean isClosed() {
-        return mFd == null;
+        return mFd == -1;
     }
 
     @Override
     protected void finalize() throws Throwable {
-        IoUtils.closeQuietly(this);
-        super.finalize();
+        try {
+            mCloseGuard.warnIfOpen();
+            IoUtils.closeQuietly(this);
+        } finally {
+            super.finalize();
+        }
     }
 
     @Override
@@ -171,10 +182,16 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeInt(mOwnerPid);
-        parcel.writeInt(mClientWritable ? 1 : 0);
-        parcel.writeParcelable(mFd, 0);
-        parcel.writeLong(mMemoryAddr);
+        ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(mFd);
+        try {
+            parcel.writeInt(mOwnerPid);
+            parcel.writeInt(mClientWritable ? 1 : 0);
+            // Don't let writing to a parcel to close our fd - plz
+            parcel.writeParcelable(pfd, flags & ~Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            parcel.writeLong(mMemoryAddr);
+        } finally {
+            pfd.detachFd();
+        }
     }
 
     @Override
@@ -189,19 +206,12 @@
             return false;
         }
         MemoryIntArray other = (MemoryIntArray) obj;
-        if (mFd == null) {
-            if (other.mFd != null) {
-                return false;
-            }
-        } else if (mFd.getFd() != other.mFd.getFd()) {
-            return false;
-        }
-        return true;
+        return mFd == other.mFd;
     }
 
     @Override
     public int hashCode() {
-        return mFd != null ? mFd.hashCode() : 1;
+        return mFd;
     }
 
     private boolean isOwner() {
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
new file mode 100644
index 0000000..6531aef
--- /dev/null
+++ b/core/java/android/util/PackageUtils.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Helper functions applicable to packages.
+ * @hide
+ */
+public final class PackageUtils {
+    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+    private PackageUtils() {
+        /* hide constructor */
+    }
+
+    /**
+     * Computes the SHA256 digest of the signing cert for a package.
+     * @param packageManager The package manager.
+     * @param packageName The package for which to generate the digest.
+     * @param userId The user for which to generate the digest.
+     * @return The digest or null if the package does not exist for this user.
+     */
+    public static @Nullable String computePackageCertSha256Digest(
+            @NonNull PackageManager packageManager,
+            @NonNull String packageName, int userId) {
+        final PackageInfo packageInfo;
+        try {
+            packageInfo = packageManager.getPackageInfoAsUser(packageName,
+                    PackageManager.GET_SIGNATURES, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+        return computeCertSha256Digest(packageInfo.signatures[0]);
+    }
+
+    /**
+     * Computes the SHA256 digest of a cert.
+     * @param signature The signature.
+     * @return The digest or null if an error occurs.
+     */
+    public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
+        return computeSha256Digest(signature.toByteArray());
+    }
+
+    /**
+     * Computes the SHA256 digest of some data.
+     * @param data The data.
+     * @return The digest or null if an error occurs.
+     */
+    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance("SHA256");
+        } catch (NoSuchAlgorithmException e) {
+            /* can't happen */
+            return null;
+        }
+
+        messageDigest.update(data);
+
+        final byte[] digest = messageDigest.digest();
+        final int digestLength = digest.length;
+        final int charCount = 2 * digestLength;
+
+        final char[] chars = new char[charCount];
+        for (int i = 0; i < digestLength; i++) {
+            final int byteHex = digest[i] & 0xFF;
+            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
+            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
+        }
+        return new String(chars);
+    }
+}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5a9a1ea..4393992 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import dalvik.annotation.optimization.FastNative;
 import dalvik.system.CloseGuard;
 
 import android.os.Looper;
@@ -47,6 +48,7 @@
     private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
             MessageQueue messageQueue);
     private static native void nativeDispose(long receiverPtr);
+    @FastNative
     private static native void nativeScheduleVsync(long receiverPtr);
 
     /**
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index b0f15b5..2baa0b4 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -134,6 +134,7 @@
 
     Object mLocalState;
     boolean mDragResult;
+    boolean mEventHandlerWasCalled;
 
     private DragEvent mNext;
     private RuntimeException mRecycledLocation;
@@ -152,12 +153,16 @@
      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
      * from {@link #getClipDescription()} to determine if they can accept the data contained in
      * this drag. For an operation that doesn't represent data transfer, these methods may
-     * perform other actions to determine whether or not the View should accept the drag.
+     * perform other actions to determine whether or not the View should accept the data.
      * If the View wants to indicate that it is a valid drop target, it can also react by
      * changing its appearance.
      * <p>
-     * A View only receives further drag events if it returns {@code true} in response to
-     * ACTION_DRAG_STARTED.
+     *  Views added or becoming visible for the first time during a drag operation receive this
+     *  event when they are added or becoming visible.
+     * </p>
+     * <p>
+     *  A View only receives further drag events if it returns {@code true} in response to
+     *  ACTION_DRAG_STARTED.
      * </p>
      * @see #ACTION_DRAG_ENDED
      * @see #getX()
@@ -176,9 +181,10 @@
      * </p>
      * <p>
      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
-     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
-     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
-     * receiving any more ACTION_DRAG_LOCATION events.
+     * drag shadow out of the View object's bounding box or into a descendant view that can accept
+     * the data. If the user moves the drag shadow back into the View object's bounding box or out
+     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
+     * before receiving any more ACTION_DRAG_LOCATION events.
      * </p>
      * @see #ACTION_DRAG_ENTERED
      * @see #getX()
@@ -188,7 +194,8 @@
 
     /**
      * Action constant returned by {@link #getAction()}: Signals to a View that the user
-     * has released the drag shadow, and the drag point is within the bounding box of the View.
+     * has released the drag shadow, and the drag point is within the bounding box of the View and
+     * not within a descendant view that can accept the data.
      * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
      * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
      * within the View object's bounding box.
@@ -211,8 +218,10 @@
      * operation has concluded.  A View that changed its appearance during the operation should
      * return to its usual drawing state in response to this event.
      * <p>
-     * All views that received an ACTION_DRAG_STARTED event will receive the
-     * ACTION_DRAG_ENDED event even if they are not currently visible when the drag ends.
+     *  All views with listeners that returned boolean <code>true</code> for the ACTION_DRAG_STARTED
+     *  event will receive the ACTION_DRAG_ENDED event even if they are not currently visible when
+     *  the drag ends. Views removed during the drag operation won't receive the ACTION_DRAG_ENDED
+     *  event.
      * </p>
      * <p>
      *  The View object can call {@link #getResult()} to see the result of the operation.
@@ -233,9 +242,10 @@
      *  drop target.
      * </p>
      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
-     * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
-     * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
-     * receiving any more ACTION_DRAG_LOCATION events.
+     * drag shadow out of the View object's bounding box or into a descendant view that can accept
+     * the data. If the user moves the drag shadow back into the View object's bounding box or out
+     * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
+     * before receiving any more ACTION_DRAG_LOCATION events.
      * </p>
      * @see #ACTION_DRAG_ENTERED
      * @see #ACTION_DRAG_LOCATION
@@ -244,7 +254,8 @@
 
     /**
      * Action constant returned by {@link #getAction()}: Signals that the user has moved the
-     * drag shadow outside the bounding box of the View.
+     * drag shadow out of the bounding box of the View or into a descendant view that can accept
+     * the data.
      * The View can react by changing its appearance in a way that tells the user that
      * View is no longer the immediate drop target.
      * <p>
@@ -377,6 +388,10 @@
      * The object is intended to provide local information about the drag and drop operation. For
      * example, it can indicate whether the drag and drop operation is a copy or a move.
      * <p>
+     * The local state is available only to views in the activity which has started the drag
+     * operation. In all other activities this method will return null
+     * </p>
+     * <p>
      *  This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
      * </p>
      * @return The local state object sent to the system by startDrag().
@@ -435,6 +450,7 @@
         mClipData = null;
         mClipDescription = null;
         mLocalState = null;
+        mEventHandlerWasCalled = false;
 
         synchronized (gRecyclerLock) {
             if (gRecyclerUsed < MAX_RECYCLED) {
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/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7de7d8a..897e29b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IRemoteCallback;
+import android.os.ParcelFileDescriptor;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
@@ -73,8 +74,8 @@
     void clearForcedDisplaySize(int displayId);
     int getInitialDisplayDensity(int displayId);
     int getBaseDisplayDensity(int displayId);
-    void setForcedDisplayDensity(int displayId, int density);
-    void clearForcedDisplayDensity(int displayId);
+    void setForcedDisplayDensityForUser(int displayId, int density, int userId);
+    void clearForcedDisplayDensityForUser(int displayId, int userId);
     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
 
     void setOverscan(int displayId, int left, int top, int right, int bottom);
@@ -101,7 +102,7 @@
      * @param launchTaskBehind True if the token is been launched from behind.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @param configuration Configuration that is being used with this task.
+     * @param overrideConfig Override configuration that is being used with this task.
      * @param taskResizeMode The resize mode of the task.
      * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
      *                        they are in.
@@ -112,7 +113,7 @@
     void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds, in Configuration configuration, int taskResizeMode,
+            in Rect taskBounds, in Configuration overrideConfig, int taskResizeMode,
             boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
             int rotationAnimationHint, boolean isOnTopLauncher);
     /**
@@ -123,13 +124,14 @@
      *                if the task doesn't exist yet.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @param config Configuration that is being used with this task.
+     * @param overrideConfig Override configuration that is being used with this task.
      * @param taskResizeMode The resize mode of the task.
      * @param homeTask True if this is the task.
      * @param isOnTopLauncher True if this task is an on-top launcher.
      */
     void setAppTask(IBinder token, int taskId, int stackId, in Rect taskBounds,
-            in Configuration config, int taskResizeMode, boolean homeTask, boolean isOnTopLauncher);
+            in Configuration overrideConfig, int taskResizeMode, boolean homeTask,
+            boolean isOnTopLauncher);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
@@ -176,7 +178,7 @@
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppVisibility(IBinder token, boolean visible);
-    void notifyAppResumed(IBinder token, boolean wasStopped);
+    void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface);
     void notifyAppStopped(IBinder token);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
@@ -255,6 +257,13 @@
     void setScreenCaptureDisabled(int userId, boolean disabled);
 
     /**
+     * Testing and debugging infrastructure for writing surface events
+     * to given FD. See RemoteSurfaceTrace.java or Wm.java for format.
+     */
+    void enableSurfaceTrace(in ParcelFileDescriptor fd);
+    void disableSurfaceTrace();
+
+    /**
      * Cancels the window transitions for the given task.
      */
     void cancelTaskWindowTransition(int taskId);
@@ -347,6 +356,16 @@
     oneway void statusBarVisibilityChanged(int visibility);
 
     /**
+     * Called by System UI to notify of changes to the visibility of Recents.
+     */
+    oneway void setRecentsVisibility(boolean visible);
+
+    /**
+     * Called by System UI to notify of changes to the visibility of PIP.
+     */
+    oneway void setTvPipVisibility(boolean visible);
+
+    /**
      * Device has a software navigation bar (separate from the status bar).
      */
     boolean hasNavigationBar();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 990d553..b73acda 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1289,8 +1289,9 @@
         boolean onKeyUp(int keyCode, KeyEvent event);
 
         /**
-         * Called when multiple down/up pairs of the same key have occurred
-         * in a row.
+         * Called when a user's interaction with an analog control, such as
+         * flinging a trackball, generates simulated down/up events for the same
+         * key multiple times in quick succession.
          *
          * @param keyCode The value in event.getKeyCode().
          * @param count Number of pairs as returned by event.getRepeatCount().
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 3e72192..3e8d577 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -16,12 +16,16 @@
 
 package android.view;
 
+import android.annotation.TestApi;
 import android.graphics.Matrix;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.SparseArray;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Object used to report movement (mouse, pen, finger, trackball) events.
  * Motion events may hold either absolute or relative movements and other data,
@@ -1444,60 +1448,98 @@
             float xOffset, float yOffset, float xPrecision, float yPrecision,
             long downTimeNanos, long eventTimeNanos,
             int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords);
-    private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
-            boolean keepHistory);
     private static native void nativeDispose(long nativePtr);
     private static native void nativeAddBatch(long nativePtr, long eventTimeNanos,
             PointerCoords[] pointerCoords, int metaState);
-
-    private static native int nativeGetDeviceId(long nativePtr);
-    private static native int nativeGetSource(long nativePtr);
-    private static native int nativeSetSource(long nativePtr, int source);
-    private static native int nativeGetAction(long nativePtr);
-    private static native void nativeSetAction(long nativePtr, int action);
-    private static native boolean nativeIsTouchEvent(long nativePtr);
-    private static native int nativeGetFlags(long nativePtr);
-    private static native void nativeSetFlags(long nativePtr, int flags);
-    private static native int nativeGetEdgeFlags(long nativePtr);
-    private static native void nativeSetEdgeFlags(long nativePtr, int action);
-    private static native int nativeGetMetaState(long nativePtr);
-    private static native int nativeGetButtonState(long nativePtr);
-    private static native void nativeSetButtonState(long nativePtr, int buttonState);
-    private static native int nativeGetActionButton(long nativePtr);
-    private static native void nativeSetActionButton(long nativePtr, int actionButton);
-    private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
-    private static native float nativeGetXOffset(long nativePtr);
-    private static native float nativeGetYOffset(long nativePtr);
-    private static native float nativeGetXPrecision(long nativePtr);
-    private static native float nativeGetYPrecision(long nativePtr);
-    private static native long nativeGetDownTimeNanos(long nativePtr);
-    private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
-
-    private static native int nativeGetPointerCount(long nativePtr);
-    private static native int nativeGetPointerId(long nativePtr, int pointerIndex);
-    private static native int nativeGetToolType(long nativePtr, int pointerIndex);
-    private static native int nativeFindPointerIndex(long nativePtr, int pointerId);
-
-    private static native int nativeGetHistorySize(long nativePtr);
-    private static native long nativeGetEventTimeNanos(long nativePtr, int historyPos);
-    private static native float nativeGetRawAxisValue(long nativePtr,
-            int axis, int pointerIndex, int historyPos);
-    private static native float nativeGetAxisValue(long nativePtr,
-            int axis, int pointerIndex, int historyPos);
     private static native void nativeGetPointerCoords(long nativePtr,
             int pointerIndex, int historyPos, PointerCoords outPointerCoords);
     private static native void nativeGetPointerProperties(long nativePtr,
             int pointerIndex, PointerProperties outPointerProperties);
 
-    private static native void nativeScale(long nativePtr, float scale);
-    private static native void nativeTransform(long nativePtr, Matrix matrix);
-
     private static native long nativeReadFromParcel(long nativePtr, Parcel parcel);
     private static native void nativeWriteToParcel(long nativePtr, Parcel parcel);
 
     private static native String nativeAxisToString(int axis);
     private static native int nativeAxisFromString(String label);
 
+    // -------------- @FastNative -------------------------
+
+    @FastNative
+    private static native int nativeGetPointerId(long nativePtr, int pointerIndex);
+    @FastNative
+    private static native int nativeGetToolType(long nativePtr, int pointerIndex);
+    @FastNative
+    private static native long nativeGetEventTimeNanos(long nativePtr, int historyPos);
+    @FastNative
+    private static native float nativeGetRawAxisValue(long nativePtr,
+            int axis, int pointerIndex, int historyPos);
+    @FastNative
+    private static native float nativeGetAxisValue(long nativePtr,
+            int axis, int pointerIndex, int historyPos);
+
+    // -------------- @CriticalNative ----------------------
+
+    @CriticalNative
+    private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
+            boolean keepHistory);
+    @CriticalNative
+    private static native int nativeGetDeviceId(long nativePtr);
+    @CriticalNative
+    private static native int nativeGetSource(long nativePtr);
+    @CriticalNative
+    private static native int nativeSetSource(long nativePtr, int source);
+    @CriticalNative
+    private static native int nativeGetAction(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetAction(long nativePtr, int action);
+    @CriticalNative
+    private static native boolean nativeIsTouchEvent(long nativePtr);
+    @CriticalNative
+    private static native int nativeGetFlags(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetFlags(long nativePtr, int flags);
+    @CriticalNative
+    private static native int nativeGetEdgeFlags(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetEdgeFlags(long nativePtr, int action);
+    @CriticalNative
+    private static native int nativeGetMetaState(long nativePtr);
+    @CriticalNative
+    private static native int nativeGetButtonState(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetButtonState(long nativePtr, int buttonState);
+    @CriticalNative
+    private static native int nativeGetActionButton(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetActionButton(long nativePtr, int actionButton);
+    @CriticalNative
+    private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
+    @CriticalNative
+    private static native float nativeGetXOffset(long nativePtr);
+    @CriticalNative
+    private static native float nativeGetYOffset(long nativePtr);
+    @CriticalNative
+    private static native float nativeGetXPrecision(long nativePtr);
+    @CriticalNative
+    private static native float nativeGetYPrecision(long nativePtr);
+    @CriticalNative
+    private static native long nativeGetDownTimeNanos(long nativePtr);
+    @CriticalNative
+    private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
+
+    @CriticalNative
+    private static native int nativeGetPointerCount(long nativePtr);
+    @CriticalNative
+    private static native int nativeFindPointerIndex(long nativePtr, int pointerId);
+
+    @CriticalNative
+    private static native int nativeGetHistorySize(long nativePtr);
+
+    @CriticalNative
+    private static native void nativeScale(long nativePtr, float scale);
+    @CriticalNative
+    private static native void nativeTransform(long nativePtr, long matrix);
+
     private MotionEvent() {
     }
 
@@ -2064,7 +2106,7 @@
     public final int getPointerCount() {
         return nativeGetPointerCount(mNativePtr);
     }
-    
+
     /**
      * Return the pointer identifier associated with a particular pointer
      * data index in this event.  The identifier tells you the actual pointer
@@ -2333,6 +2375,7 @@
      * @see #getButtonState()
      * @hide
      */
+    @TestApi
     public final void setButtonState(int buttonState) {
         nativeSetButtonState(mNativePtr, buttonState);
     }
@@ -2355,6 +2398,7 @@
      * @see #getActionButton()
      * @hide
      */
+    @TestApi
     public final void setActionButton(int button) {
         nativeSetActionButton(mNativePtr, button);
     }
@@ -2888,7 +2932,7 @@
             throw new IllegalArgumentException("matrix must not be null");
         }
 
-        nativeTransform(mNativePtr, matrix);
+        nativeTransform(mNativePtr, matrix.native_instance);
     }
 
     /**
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index bce5ec1..51d818b 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -24,6 +24,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
 
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
 /**
  * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
@@ -128,6 +132,12 @@
  */
 public class RenderNode {
 
+ // Use a Holder to allow static initialization in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+            RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
+    }
+
     private boolean mValid;
     // Do not access directly unless you are ThreadedRenderer
     final long mNativeRenderNode;
@@ -135,6 +145,7 @@
 
     private RenderNode(String name, View owningView) {
         mNativeRenderNode = nCreate(name);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
         mOwningView = owningView;
         if (mOwningView instanceof SurfaceView) {
             nRequestPositionUpdates(mNativeRenderNode, (SurfaceView) mOwningView);
@@ -145,6 +156,7 @@
      * @see RenderNode#adopt(long)
      */
     private RenderNode(long nativePtr) {
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, nativePtr);
         mNativeRenderNode = nativePtr;
         mOwningView = null;
     }
@@ -812,99 +824,143 @@
     // Intentionally not static because it acquires a reference to 'this'
     private native long nCreate(String name);
 
-    private static native void nDestroyRenderNode(long renderNode);
+    private static native long nGetNativeFinalizer();
     private static native void nSetDisplayList(long renderNode, long newData);
-
-    // Matrix
-
-    private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
-    private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
-    private static native boolean nHasIdentityMatrix(long renderNode);
-
-    // Properties
-
-    private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
-    private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
-    private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
-            int right, int bottom);
-    private static native boolean nSetBottom(long renderNode, int bottom);
-    private static native boolean nSetRight(long renderNode, int right);
-    private static native boolean nSetTop(long renderNode, int top);
-    private static native boolean nSetLeft(long renderNode, int left);
-    private static native boolean nSetCameraDistance(long renderNode, float distance);
-    private static native boolean nSetPivotY(long renderNode, float pivotY);
-    private static native boolean nSetPivotX(long renderNode, float pivotX);
-    private static native boolean nSetLayerType(long renderNode, int layerType);
-    private static native boolean nSetLayerPaint(long renderNode, long paint);
-    private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
-    private static native boolean nSetClipBounds(long renderNode, int left, int top,
-            int right, int bottom);
-    private static native boolean nSetClipBoundsEmpty(long renderNode);
-    private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
-    private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
-    private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
-            int right, int bottom, float radius, float alpha);
-    private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
-            float alpha);
-    private static native boolean nSetOutlineEmpty(long renderNode);
-    private static native boolean nSetOutlineNone(long renderNode);
-    private static native boolean nHasShadow(long renderNode);
-    private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
-    private static native boolean nSetRevealClip(long renderNode,
-            boolean shouldClip, float x, float y, float radius);
-    private static native boolean nSetAlpha(long renderNode, float alpha);
-    private static native boolean nSetHasOverlappingRendering(long renderNode,
-            boolean hasOverlappingRendering);
-    private static native boolean nSetElevation(long renderNode, float lift);
-    private static native boolean nSetTranslationX(long renderNode, float translationX);
-    private static native boolean nSetTranslationY(long renderNode, float translationY);
-    private static native boolean nSetTranslationZ(long renderNode, float translationZ);
-    private static native boolean nSetRotation(long renderNode, float rotation);
-    private static native boolean nSetRotationX(long renderNode, float rotationX);
-    private static native boolean nSetRotationY(long renderNode, float rotationY);
-    private static native boolean nSetScaleX(long renderNode, float scaleX);
-    private static native boolean nSetScaleY(long renderNode, float scaleY);
-    private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
-    private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
-
-    private static native boolean nHasOverlappingRendering(long renderNode);
-    private static native boolean nGetClipToOutline(long renderNode);
-    private static native float nGetAlpha(long renderNode);
-    private static native float nGetCameraDistance(long renderNode);
-    private static native float nGetScaleX(long renderNode);
-    private static native float nGetScaleY(long renderNode);
-    private static native float nGetElevation(long renderNode);
-    private static native float nGetTranslationX(long renderNode);
-    private static native float nGetTranslationY(long renderNode);
-    private static native float nGetTranslationZ(long renderNode);
-    private static native float nGetRotation(long renderNode);
-    private static native float nGetRotationX(long renderNode);
-    private static native float nGetRotationY(long renderNode);
-    private static native boolean nIsPivotExplicitlySet(long renderNode);
-    private static native float nGetPivotX(long renderNode);
-    private static native float nGetPivotY(long renderNode);
     private static native void nOutput(long renderNode);
     private static native int nGetDebugSize(long renderNode);
-
     private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
 
-    ///////////////////////////////////////////////////////////////////////////
     // Animations
-    ///////////////////////////////////////////////////////////////////////////
 
     private static native void nAddAnimator(long renderNode, long animatorPtr);
     private static native void nEndAllAnimators(long renderNode);
 
     ///////////////////////////////////////////////////////////////////////////
-    // Finalization
+    // Fast native methods
     ///////////////////////////////////////////////////////////////////////////
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            nDestroyRenderNode(mNativeRenderNode);
-        } finally {
-            super.finalize();
-        }
-    }
+    // Matrix
+
+    @FastNative
+    private static native void nGetTransformMatrix(long renderNode, long nativeMatrix);
+    @FastNative
+    private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix);
+    @FastNative
+    private static native boolean nHasIdentityMatrix(long renderNode);
+
+    // Properties
+
+    @FastNative
+    private static native boolean nOffsetTopAndBottom(long renderNode, int offset);
+    @FastNative
+    private static native boolean nOffsetLeftAndRight(long renderNode, int offset);
+    @FastNative
+    private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
+            int right, int bottom);
+    @FastNative
+    private static native boolean nSetBottom(long renderNode, int bottom);
+    @FastNative
+    private static native boolean nSetRight(long renderNode, int right);
+    @FastNative
+    private static native boolean nSetTop(long renderNode, int top);
+    @FastNative
+    private static native boolean nSetLeft(long renderNode, int left);
+    @FastNative
+    private static native boolean nSetCameraDistance(long renderNode, float distance);
+    @FastNative
+    private static native boolean nSetPivotY(long renderNode, float pivotY);
+    @FastNative
+    private static native boolean nSetPivotX(long renderNode, float pivotX);
+    @FastNative
+    private static native boolean nSetLayerType(long renderNode, int layerType);
+    @FastNative
+    private static native boolean nSetLayerPaint(long renderNode, long paint);
+    @FastNative
+    private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
+    @FastNative
+    private static native boolean nSetClipBounds(long renderNode, int left, int top,
+            int right, int bottom);
+    @FastNative
+    private static native boolean nSetClipBoundsEmpty(long renderNode);
+    @FastNative
+    private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
+    @FastNative
+    private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
+    @FastNative
+    private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
+            int right, int bottom, float radius, float alpha);
+    @FastNative
+    private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
+            float alpha);
+    @FastNative
+    private static native boolean nSetOutlineEmpty(long renderNode);
+    @FastNative
+    private static native boolean nSetOutlineNone(long renderNode);
+    @FastNative
+    private static native boolean nHasShadow(long renderNode);
+    @FastNative
+    private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
+    @FastNative
+    private static native boolean nSetRevealClip(long renderNode,
+            boolean shouldClip, float x, float y, float radius);
+    @FastNative
+    private static native boolean nSetAlpha(long renderNode, float alpha);
+    @FastNative
+    private static native boolean nSetHasOverlappingRendering(long renderNode,
+            boolean hasOverlappingRendering);
+    @FastNative
+    private static native boolean nSetElevation(long renderNode, float lift);
+    @FastNative
+    private static native boolean nSetTranslationX(long renderNode, float translationX);
+    @FastNative
+    private static native boolean nSetTranslationY(long renderNode, float translationY);
+    @FastNative
+    private static native boolean nSetTranslationZ(long renderNode, float translationZ);
+    @FastNative
+    private static native boolean nSetRotation(long renderNode, float rotation);
+    @FastNative
+    private static native boolean nSetRotationX(long renderNode, float rotationX);
+    @FastNative
+    private static native boolean nSetRotationY(long renderNode, float rotationY);
+    @FastNative
+    private static native boolean nSetScaleX(long renderNode, float scaleX);
+    @FastNative
+    private static native boolean nSetScaleY(long renderNode, float scaleY);
+    @FastNative
+    private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
+    @FastNative
+    private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
+
+    @FastNative
+    private static native boolean nHasOverlappingRendering(long renderNode);
+    @FastNative
+    private static native boolean nGetClipToOutline(long renderNode);
+    @FastNative
+    private static native float nGetAlpha(long renderNode);
+    @FastNative
+    private static native float nGetCameraDistance(long renderNode);
+    @FastNative
+    private static native float nGetScaleX(long renderNode);
+    @FastNative
+    private static native float nGetScaleY(long renderNode);
+    @FastNative
+    private static native float nGetElevation(long renderNode);
+    @FastNative
+    private static native float nGetTranslationX(long renderNode);
+    @FastNative
+    private static native float nGetTranslationY(long renderNode);
+    @FastNative
+    private static native float nGetTranslationZ(long renderNode);
+    @FastNative
+    private static native float nGetRotation(long renderNode);
+    @FastNative
+    private static native float nGetRotationX(long renderNode);
+    @FastNative
+    private static native float nGetRotationY(long renderNode);
+    @FastNative
+    private static native boolean nIsPivotExplicitlySet(long renderNode);
+    @FastNative
+    private static native float nGetPivotX(long renderNode);
+    @FastNative
+    private static native float nGetPivotY(long renderNode);
 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 286e097..22e68a3 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -33,6 +33,18 @@
 
 /**
  * Handle onto a raw buffer that is being managed by the screen compositor.
+ *
+ * <p>A Surface is generally created by or from a consumer of image buffers (such as a
+ * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
+ * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
+ * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
+ * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
+ * into.</p>
+ *
+ * <p><strong>Note:</strong> A Surface acts like a
+ * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
+ * itself it will not keep its parent consumer from being reclaimed.</p>
  */
 public class Surface implements Parcelable {
     private static final String TAG = "Surface";
@@ -59,6 +71,7 @@
     private static native long nativeGetNextFrameNumber(long nativeObject);
     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
     private static native void nativeSetBuffersTransform(long nativeObject, long transform);
+    private static native int nativeForceScopedDisconnect(long nativeObject);
 
     public static final Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
@@ -96,6 +109,8 @@
 
     private HwuiContext mHwuiContext;
 
+    private boolean mIsSingleBuffered;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
@@ -158,7 +173,7 @@
         if (surfaceTexture == null) {
             throw new IllegalArgumentException("surfaceTexture must not be null");
         }
-
+        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
         synchronized (mLock) {
             mName = surfaceTexture.toString();
             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
@@ -457,7 +472,10 @@
             // create a new native Surface and return it after reducing
             // the reference count on mNativeObject.  Either way, it is
             // not necessary to call nativeRelease() here.
+            // NOTE: This must be kept synchronized with the native parceling code
+            // in frameworks/native/libs/Surface.cpp
             mName = source.readString();
+            mIsSingleBuffered = source.readInt() != 0;
             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
         }
     }
@@ -468,7 +486,10 @@
             throw new IllegalArgumentException("dest must not be null");
         }
         synchronized (mLock) {
+            // NOTE: This must be kept synchronized with the native parceling code
+            // in frameworks/native/libs/Surface.cpp
             dest.writeString(mName);
+            dest.writeInt(mIsSingleBuffered ? 1 : 0);
             nativeWriteToParcel(mNativeObject, dest);
         }
         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
@@ -530,6 +551,24 @@
         }
     }
 
+    void forceScopedDisconnect() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            int err = nativeForceScopedDisconnect(mNativeObject);
+            if (err != 0) {
+                throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
+            }
+        }
+    }
+
+    /**
+     * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
+     * @hide
+     */
+    public boolean isSingleBuffered() {
+        return mIsSingleBuffered;
+    }
+
     /**
      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
      * when a SurfaceTexture could not successfully be allocated.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e778a7f..6456826 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -308,6 +308,17 @@
         mCloseGuard.open("release");
     }
 
+    // This is a transfer constructor, useful for transferring a live SurfaceControl native
+    // object to another Java wrapper which could have some different behavior, e.g.
+    // event logging.
+    public SurfaceControl(SurfaceControl other) {
+        mName = other.mName;
+        mNativeObject = other.mNativeObject;
+        other.mCloseGuard.close();
+        other.mNativeObject = 0;
+        mCloseGuard.open("release");
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 292e3f5..816bcf0 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -115,6 +115,7 @@
     final Rect mStableInsets = new Rect();
     final Rect mOutsets = new Rect();
     final Rect mBackdropFrame = new Rect();
+    final Rect mTmpRect = new Rect();
     final Configuration mConfiguration = new Configuration();
 
     static final int KEEP_SCREEN_ON_MSG = 1;
@@ -193,26 +194,20 @@
     private boolean mGlobalListenersAdded;
 
     public SurfaceView(Context context) {
-        super(context);
-        init();
+        this(context, null);
     }
 
     public SurfaceView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
+        this(context, attrs, 0);
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        init();
+        this(context, attrs, defStyleAttr, 0);
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        init();
-    }
 
-    private void init() {
         setWillNotDraw(true);
     }
 
@@ -233,6 +228,7 @@
         mSession = getWindowSession();
         mLayout.token = getWindowToken();
         mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
+        mLayout.packageName = mContext.getOpPackageName();
         mViewVisibility = getVisibility() == VISIBLE;
 
         if (!mGlobalListenersAdded) {
@@ -593,6 +589,20 @@
                             for (SurfaceHolder.Callback c : callbacks) {
                                 c.surfaceDestroyed(mSurfaceHolder);
                             }
+                            // Since Android N the same surface may be reused and given to us
+                            // again by the system server at a later point. However
+                            // as we didn't do this in previous releases, clients weren't
+                            // necessarily required to clean up properly in
+                            // surfaceDestroyed. This leads to problems for example when
+                            // clients don't destroy their EGL context, and try
+                            // and create a new one on the same surface following reuse.
+                            // Since there is no valid use of the surface in-between
+                            // surfaceDestroyed and surfaceCreated, we force a disconnect,
+                            // so the next connect will always work if we end up reusing
+                            // the surface.
+                            if (mSurface.isValid()) {
+                                mSurface.forceScopedDisconnect();
+                            }
                         }
                     }
 
@@ -668,21 +678,21 @@
 
                 transformFromViewToWindowSpace(mLocation);
 
-                mWinFrame.set(mWindowSpaceLeft, mWindowSpaceTop,
+                mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
                         mLocation[0], mLocation[1]);
 
                 if (mTranslator != null) {
-                    mTranslator.translateRectInAppWindowToScreen(mWinFrame);
+                    mTranslator.translateRectInAppWindowToScreen(mTmpRect);
                 }
 
                 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
                     try {
                         if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
                                 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                                mWinFrame.left, mWinFrame.top,
-                                mWinFrame.right, mWinFrame.bottom));
-                        mSession.repositionChild(mWindow, mWinFrame.left, mWinFrame.top,
-                                mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
+                                mTmpRect.left, mTmpRect.top,
+                                mTmpRect.right, mTmpRect.bottom));
+                        mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
+                                mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
                     } catch (RemoteException ex) {
                         Log.e(TAG, "Exception from relayout", ex);
                     }
@@ -694,10 +704,10 @@
     private Rect mRTLastReportedPosition = new Rect();
 
     /**
-     * Called by native on RenderThread to update the window position
+     * Called by native by a Rendering Worker thread to update the window position
      * @hide
      */
-    public final void updateWindowPositionRT(long frameNumber,
+    public final void updateWindowPosition_renderWorker(long frameNumber,
             int left, int top, int right, int bottom) {
         IWindowSession session = mSession;
         MyWindow window = mWindow;
@@ -722,7 +732,7 @@
         }
         try {
             if (DEBUG) {
-                Log.d(TAG, String.format("%d updateWindowPosition RT, frameNr = %d, " +
+                Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
                         "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
                         frameNumber, left, top, right, bottom));
             }
@@ -739,12 +749,12 @@
 
     /**
      * Called by native on RenderThread to notify that the window is no longer in the
-     * draw tree
+     * draw tree. UI thread is blocked at this point.
      * @hide
      */
-    public final void windowPositionLostRT(long frameNumber) {
+    public final void windowPositionLost_uiRtSync(long frameNumber) {
         if (DEBUG) {
-            Log.d(TAG, String.format("%d windowPositionLostRT RT, frameNr = %d",
+            Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
                     System.identityHashCode(this), frameNumber));
         }
         IWindowSession session = mSession;
@@ -759,14 +769,18 @@
             // safely access other member variables at this time.
             // So do what the UI thread would have done if RT wasn't handling position
             // updates.
-            if (!mWinFrame.isEmpty() && !mWinFrame.equals(mRTLastReportedPosition)) {
+            mTmpRect.set(mLayout.x, mLayout.y,
+                    mLayout.x + mLayout.width,
+                    mLayout.y + mLayout.height);
+
+            if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
                 try {
                     if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
                             "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                            mWinFrame.left, mWinFrame.top,
-                            mWinFrame.right, mWinFrame.bottom));
-                    session.repositionChild(window, mWinFrame.left, mWinFrame.top,
-                            mWinFrame.right, mWinFrame.bottom, frameNumber, mWinFrame);
+                            mTmpRect.left, mTmpRect.top,
+                            mTmpRect.right, mTmpRect.bottom));
+                    session.repositionChild(window, mTmpRect.left, mTmpRect.top,
+                            mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Exception from relayout", ex);
                 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index bb77100..25dce99 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -228,6 +228,7 @@
      */
     @Override
     protected void destroyHardwareResources() {
+        super.destroyHardwareResources();
         destroyHardwareLayer();
     }
 
@@ -379,9 +380,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);
 
@@ -719,7 +720,7 @@
     /**
      * Set the {@link SurfaceTexture} for this view to use. If a {@link
      * SurfaceTexture} is already being used by this view, it is immediately
-     * released and not be usable any more.  The {@link
+     * released and not usable any more.  The {@link
      * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
      * called for the previous {@link SurfaceTexture}.  Similarly, the {@link
      * SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b>
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1034275..ce390a2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -883,8 +883,14 @@
         nSerializeDisplayListTree(mNativeProxy);
     }
 
-    public static int copySurfaceInto(Surface surface, Bitmap bitmap) {
-        return nCopySurfaceInto(surface, bitmap);
+    public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
+        if (srcRect == null) {
+            // Empty rect means entire surface
+            return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
+        } else {
+            return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
+                    srcRect.right, srcRect.bottom, bitmap);
+        }
     }
 
     @Override
@@ -1036,5 +1042,6 @@
     private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
     private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
 
-    private static native int nCopySurfaceInto(Surface surface, Bitmap bitmap);
+    private static native int nCopySurfaceInto(Surface surface,
+            int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5a7f0ff..deb3f90 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
@@ -830,6 +829,16 @@
      */
     protected static boolean sPreserveMarginParamsInLayoutParamConversion;
 
+    /**
+     * Prior to N, when drag enters into child of a view that has already received an
+     * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event.
+     * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned
+     * false from its event handler for these events.
+     * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its
+     * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent.
+     * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation.
+     */
+    static boolean sCascadedDragDrop;
 
     /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
@@ -2319,7 +2328,7 @@
     static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO;
 
     /**
-     * Mask for obtainig the bits which specify how to determine
+     * Mask for obtaining the bits which specify how to determine
      * whether a view is important for accessibility.
      */
     static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO
@@ -2441,9 +2450,7 @@
      *                     1             PFLAG3_SCROLL_INDICATOR_START
      *                    1              PFLAG3_SCROLL_INDICATOR_END
      *                   1               PFLAG3_ASSIST_BLOCKED
-     *                  1                PFLAG3_POINTER_ICON_NULL
-     *                 1                 PFLAG3_POINTER_ICON_VALUE_START
-     *           11111111                PFLAG3_POINTER_ICON_MASK
+     *           xxxxxxxx                * NO LONGER NEEDED, SHOULD BE REUSED *
      *          1                        PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
      *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
      *        1                          PFLAG3_TEMPORARY_DETACH
@@ -2642,31 +2649,6 @@
     static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
 
     /**
-     * The mask for use with private flags indicating bits used for pointer icon shapes.
-     */
-    static final int PFLAG3_POINTER_ICON_MASK = 0x7f8000;
-
-    /**
-     * Left-shift used for pointer icon shape values in private flags.
-     */
-    static final int PFLAG3_POINTER_ICON_LSHIFT = 15;
-
-    /**
-     * Value indicating no specific pointer icons.
-     */
-    private static final int PFLAG3_POINTER_ICON_NOT_SPECIFIED = 0 << PFLAG3_POINTER_ICON_LSHIFT;
-
-    /**
-     * Value indicating {@link PointerIcon.TYPE_NULL}.
-     */
-    private static final int PFLAG3_POINTER_ICON_NULL = 1 << PFLAG3_POINTER_ICON_LSHIFT;
-
-    /**
-     * The base value for other pointer icon shapes.
-     */
-    private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT;
-
-    /**
      * Whether this view has rendered elements that overlap (see {@link
      * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and
      * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when
@@ -3089,20 +3071,6 @@
     /**
      * @hide
      *
-     * Whether Recents is visible or not.
-     */
-    public static final int RECENT_APPS_VISIBLE = 0x00004000;
-
-    /**
-     * @hide
-     *
-     * Whether the TV's picture-in-picture is visible or not.
-     */
-    public static final int TV_PICTURE_IN_PICTURE_VISIBLE = 0x00010000;
-
-    /**
-     * @hide
-     *
      * Makes navigation bar transparent (but not the status bar).
      */
     public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
@@ -4069,6 +4037,8 @@
             // in apps so we target check it to avoid breaking existing apps.
             sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
 
+            sCascadedDragDrop = targetSdkVersion < N;
+
             sCompatibilityDone = true;
         }
     }
@@ -6929,13 +6899,7 @@
 
         info.setVisibleToUser(isVisibleToUser());
 
-        if ((mAttachInfo != null) && ((mAttachInfo.mAccessibilityFetchFlags
-                & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0)) {
-            info.setImportantForAccessibility(isImportantForAccessibility());
-        } else {
-            info.setImportantForAccessibility(true);
-        }
-
+        info.setImportantForAccessibility(isImportantForAccessibility());
         info.setPackageName(mContext.getPackageName());
         info.setClassName(getAccessibilityClassName());
         info.setContentDescription(getContentDescription());
@@ -8066,7 +8030,7 @@
     }
 
     /**
-     * Set the enabled state of this view.
+     * Set the visibility state of this view.
      *
      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
      * @attr ref android.R.styleable#View_visibility
@@ -9178,11 +9142,14 @@
     }
 
     /**
-     * Gets the mode for determining whether this View is important for accessibility
-     * which is if it fires accessibility events and if it is reported to
-     * accessibility services that query the screen.
+     * Gets the mode for determining whether this View is important for accessibility.
+     * A view is important for accessibility if it fires accessibility events and if it
+     * is reported to accessibility services that query the screen.
      *
-     * @return The mode for determining whether a View is important for accessibility.
+     * @return The mode for determining whether a view is important for accessibility, one
+     * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES},
+     * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or
+     * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}.
      *
      * @attr ref android.R.styleable#View_importantForAccessibility
      *
@@ -9856,6 +9823,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 +9869,8 @@
      */
     @CallSuper
     public void dispatchFinishTemporaryDetach() {
-        onFinishTemporaryDetach();
         mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
+        onFinishTemporaryDetach();
         if (hasWindowFocus() && hasFocus()) {
             InputMethodManager.getInstance().focusIn(this);
         }
@@ -10377,7 +10356,7 @@
      *                  ancestors or by window visibility
      * @return true if this view is visible to the user, not counting clipping or overlapping
      */
-    @Visibility boolean dispatchVisibilityAggregated(boolean isVisible) {
+    boolean dispatchVisibilityAggregated(boolean isVisible) {
         final boolean thisVisible = getVisibility() == VISIBLE;
         // If we're not visible but something is telling us we are, ignore it.
         if (thisVisible || !isVisible) {
@@ -14459,7 +14438,7 @@
      *
      * Returns the scrollbar fade duration.
      *
-     * @return the scrollbar fade duration
+     * @return the scrollbar fade duration, in milliseconds
      *
      * @attr ref android.R.styleable#View_scrollbarFadeDuration
      */
@@ -14471,7 +14450,7 @@
     /**
      * Define the scrollbar fade duration.
      *
-     * @param scrollBarFadeDuration - the scrollbar fade duration
+     * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds
      *
      * @attr ref android.R.styleable#View_scrollbarFadeDuration
      */
@@ -15520,7 +15499,7 @@
         if (vis != GONE) {
             onWindowVisibilityChanged(vis);
             if (isShown()) {
-                // Calling onVisibilityChanged directly here since the subtree will also
+                // Calling onVisibilityAggregated directly here since the subtree will also
                 // receive dispatchAttachedToWindow and this same call
                 onVisibilityAggregated(vis == VISIBLE);
             }
@@ -19094,7 +19073,7 @@
             return mAttachInfo.mTreeObserver;
         }
         if (mFloatingTreeObserver == null) {
-            mFloatingTreeObserver = new ViewTreeObserver();
+            mFloatingTreeObserver = new ViewTreeObserver(mContext);
         }
         return mFloatingTreeObserver;
     }
@@ -20090,7 +20069,7 @@
     /**
      * Returns the minimum height of the view.
      *
-     * @return the minimum height the view will try to be.
+     * @return the minimum height the view will try to be, in pixels
      *
      * @see #setMinimumHeight(int)
      *
@@ -20105,7 +20084,7 @@
      * be able to achieve this minimum height (for example, if its parent layout
      * constrains it with less available height).
      *
-     * @param minHeight The minimum height the view will try to be.
+     * @param minHeight The minimum height the view will try to be, in pixels
      *
      * @see #getMinimumHeight()
      *
@@ -20120,7 +20099,7 @@
     /**
      * Returns the minimum width of the view.
      *
-     * @return the minimum width the view will try to be.
+     * @return the minimum width the view will try to be, in pixels
      *
      * @see #setMinimumWidth(int)
      *
@@ -20135,7 +20114,7 @@
      * be able to achieve this minimum width (for example, if its parent layout
      * constrains it with less available width).
      *
-     * @param minWidth The minimum width the view will try to be.
+     * @param minWidth The minimum width the view will try to be, in pixels
      *
      * @see #getMinimumWidth()
      *
@@ -20273,8 +20252,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
@@ -20643,8 +20628,10 @@
      * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
      * drag shadow.
      * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
-     * drop operation. This Object is put into every DragEvent object sent by the system during the
-     * current drag.
+     * drop operation. When dispatching drag events to views in the same activity this object
+     * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other
+     * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}
+     * will return null).
      * <p>
      * myLocalState is a lightweight mechanism for the sending information from the dragged View
      * to the target Views. For example, it can contain flags that differentiate between a
@@ -20674,7 +20661,9 @@
             return false;
         }
 
-        data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
+        if (data != null) {
+            data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
+        }
 
         boolean okay = false;
 
@@ -20848,6 +20837,11 @@
         return false;
     }
 
+    // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps.
+    boolean dispatchDragEnterExitInPreN(DragEvent event) {
+        return callDragEventHandler(event);
+    }
+
     /**
      * Detects if this View is enabled and has a drag event listener.
      * If both are true, then it calls the drag event listener with the
@@ -20865,13 +20859,44 @@
      * </p>
      */
     public boolean dispatchDragEvent(DragEvent event) {
+        event.mEventHandlerWasCalled = true;
+        if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
+            event.mAction == DragEvent.ACTION_DROP) {
+            // About to deliver an event with coordinates to this view. Notify that now this view
+            // has drag focus. This will send exit/enter events as needed.
+            getViewRootImpl().setDragFocus(this, event);
+        }
+        return callDragEventHandler(event);
+    }
+
+    final boolean callDragEventHandler(DragEvent event) {
+        final boolean result;
+
         ListenerInfo li = mListenerInfo;
         //noinspection SimplifiableIfStatement
         if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                 && li.mOnDragListener.onDrag(this, event)) {
-            return true;
+            result = true;
+        } else {
+            result = onDragEvent(event);
         }
-        return onDragEvent(event);
+
+        switch (event.mAction) {
+            case DragEvent.ACTION_DRAG_ENTERED: {
+                mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
+                refreshDrawableState();
+            } break;
+            case DragEvent.ACTION_DRAG_EXITED: {
+                mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
+                refreshDrawableState();
+            } break;
+            case DragEvent.ACTION_DRAG_ENDED: {
+                mPrivateFlags2 &= ~View.DRAG_MASK;
+                refreshDrawableState();
+            } break;
+        }
+
+        return result;
     }
 
     boolean canAcceptDrag() {
@@ -23037,7 +23062,7 @@
          * The view tree observer used to dispatch global events like
          * layout, pre-draw, touch mode change, etc.
          */
-        final ViewTreeObserver mTreeObserver = new ViewTreeObserver();
+        final ViewTreeObserver mTreeObserver;
 
         /**
          * A Canvas used by the view hierarchy to perform bitmap caching.
@@ -23159,7 +23184,8 @@
          * @param handler the events handler the view must use
          */
         AttachInfo(IWindowSession session, IWindow window, Display display,
-                ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
+                ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer,
+                Context context) {
             mSession = session;
             mWindow = window;
             mWindowToken = window.asBinder();
@@ -23167,6 +23193,7 @@
             mViewRootImpl = viewRootImpl;
             mHandler = handler;
             mRootCallbacks = effectPlayer;
+            mTreeObserver = new ViewTreeObserver(context);
         }
     }
 
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/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 6f9768f..e1ff0d6 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -846,6 +846,8 @@
         view.post(new Runnable() {
             @Override
             public void run() {
+                encoder.addProperty("window:left", view.mAttachInfo.mWindowLeft);
+                encoder.addProperty("window:top", view.mAttachInfo.mWindowTop);
                 view.encode(encoder);
                 latch.countDown();
             }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c682d09..2e428a7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -20,6 +20,7 @@
 import android.annotation.IdRes;
 import android.annotation.NonNull;
 import android.annotation.UiThread;
+import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -45,6 +46,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -153,8 +155,9 @@
      */
     Transformation mInvalidationTransformation;
 
-    // View currently under an ongoing drag. Can be null, a child or this window.
-    private View mCurrentDragView;
+    // Current frontmost child that can accept drag and lies under the drag location.
+    // Used only to generate ENTER/EXIT events for pre-Nougat aps.
+    private View mCurrentDragChild;
 
     // Metadata about the ongoing drag
     private DragEvent mCurrentDragStartEvent;
@@ -1358,22 +1361,35 @@
         return mLocalPoint;
     }
 
+    @Override
+    boolean dispatchDragEnterExitInPreN(DragEvent event) {
+        if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
+            // The drag exited a sub-tree of views; notify of the exit all descendants that are in
+            // entered state.
+            // We don't need this recursive delivery for ENTERED events because they get generated
+            // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
+            // recursion.
+            mCurrentDragChild.dispatchDragEnterExitInPreN(event);
+            mCurrentDragChild = null;
+        }
+        return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
+    }
+
     // TODO: Write real docs
     @Override
     public boolean dispatchDragEvent(DragEvent event) {
         boolean retval = false;
         final float tx = event.mX;
         final float ty = event.mY;
-
-        ViewRootImpl root = getViewRootImpl();
+        final ClipData td = event.mClipData;
 
         // Dispatch down the view hierarchy
         final PointF localPoint = getLocalPoint();
 
         switch (event.mAction) {
         case DragEvent.ACTION_DRAG_STARTED: {
-            // clear state to recalculate which views we drag over
-            mCurrentDragView = null;
+            // Clear the state to recalculate which views we drag over.
+            mCurrentDragChild = null;
 
             // Set up our tracking of drag-started notifications
             mCurrentDragStartEvent = DragEvent.obtain(event);
@@ -1419,8 +1435,6 @@
                     if (child.dispatchDragEvent(event)) {
                         retval = true;
                     }
-                    child.mPrivateFlags2 &= ~View.DRAG_MASK;
-                    child.refreshDrawableState();
                 }
                 childrenInterestedInDrag.clear();
             }
@@ -1437,60 +1451,47 @@
             }
         } break;
 
-        case DragEvent.ACTION_DRAG_LOCATION: {
+        case DragEvent.ACTION_DRAG_LOCATION:
+        case DragEvent.ACTION_DROP: {
             // Find the [possibly new] drag target
             View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
+
+            if (target != mCurrentDragChild) {
+                if (sCascadedDragDrop) {
+                    // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
+                    // the drag location is kept in the state between ENTERED and EXITED events.
+                    // (Starting with N, only the innermost view will be in that state).
+
+                    final int action = event.mAction;
+                    // Position should not be available for ACTION_DRAG_ENTERED and
+                    // ACTION_DRAG_EXITED.
+                    event.mX = 0;
+                    event.mY = 0;
+                    event.mClipData = null;
+
+                    if (mCurrentDragChild != null) {
+                        event.mAction = DragEvent.ACTION_DRAG_EXITED;
+                        mCurrentDragChild.dispatchDragEnterExitInPreN(event);
+                    }
+
+                    if (target != null) {
+                        event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+                        target.dispatchDragEnterExitInPreN(event);
+                    }
+
+                    event.mAction = action;
+                    event.mX = tx;
+                    event.mY = ty;
+                    event.mClipData = td;
+                }
+                mCurrentDragChild = target;
+            }
+
             if (target == null && mIsInterestedInDrag) {
                 target = this;
             }
 
-            // If we've changed apparent drag target, tell the view root which view
-            // we're over now [for purposes of the eventual drag-recipient-changed
-            // notifications to the framework] and tell the new target that the drag
-            // has entered its bounds.  The root will see setDragFocus() calls all
-            // the way down to the final leaf view that is handling the LOCATION event
-            // before reporting the new potential recipient to the framework.
-            if (mCurrentDragView != target) {
-                root.setDragFocus(target);
-
-                final int action = event.mAction;
-                // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
-                event.mX = 0;
-                event.mY = 0;
-
-                // If we've dragged off of a child view or this window, send it the EXITED message
-                if (mCurrentDragView != null) {
-                    final View view = mCurrentDragView;
-                    event.mAction = DragEvent.ACTION_DRAG_EXITED;
-                    if (view != this) {
-                        view.dispatchDragEvent(event);
-                        view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
-                        view.refreshDrawableState();
-                    } else {
-                        super.dispatchDragEvent(event);
-                    }
-                }
-
-                mCurrentDragView = target;
-
-                // If we've dragged over a new child view, send it the ENTERED message, otherwise
-                // send it to this window.
-                if (target != null) {
-                    event.mAction = DragEvent.ACTION_DRAG_ENTERED;
-                    if (target != this) {
-                        target.dispatchDragEvent(event);
-                        target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
-                        target.refreshDrawableState();
-                    } else {
-                        super.dispatchDragEvent(event);
-                    }
-                }
-                event.mAction = action;  // restore the event's original state
-                event.mX = tx;
-                event.mY = ty;
-            }
-
-            // Dispatch the actual drag location notice, localized into its coordinates
+            // Dispatch the actual drag notice, localized into the target coordinates.
             if (target != null) {
                 if (target != this) {
                     event.mX = localPoint.x;
@@ -1500,58 +1501,24 @@
 
                     event.mX = tx;
                     event.mY = ty;
+
+                    if (mIsInterestedInDrag) {
+                        final boolean eventWasConsumed;
+                        if (sCascadedDragDrop) {
+                            eventWasConsumed = retval;
+                        } else {
+                            eventWasConsumed = event.mEventHandlerWasCalled;
+                        }
+
+                        if (!eventWasConsumed) {
+                            retval = super.dispatchDragEvent(event);
+                        }
+                    }
                 } else {
                     retval = super.dispatchDragEvent(event);
                 }
             }
         } break;
-
-        /* Entered / exited dispatch
-         *
-         * DRAG_ENTERED is not dispatched downwards from ViewGroup.  The reason for this is
-         * that we're about to get the corresponding LOCATION event, which we will use to
-         * determine which of our children is the new target; at that point we will
-         * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
-         * If no suitable child is detected, dispatch to this window.
-         *
-         * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
-         * drag has left this ViewGroup, we know by definition that every contained subview
-         * is also no longer under the drag point.
-         */
-
-        case DragEvent.ACTION_DRAG_EXITED: {
-            if (mCurrentDragView != null) {
-                final View view = mCurrentDragView;
-                if (view != this) {
-                    view.dispatchDragEvent(event);
-                    view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
-                    view.refreshDrawableState();
-                } else {
-                    super.dispatchDragEvent(event);
-                }
-
-                mCurrentDragView = null;
-            }
-        } break;
-
-        case DragEvent.ACTION_DROP: {
-            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
-            View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
-            if (target != null) {
-                if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
-                event.mX = localPoint.x;
-                event.mY = localPoint.y;
-                retval = target.dispatchDragEvent(event);
-                event.mX = tx;
-                event.mY = ty;
-            } else if (mIsInterestedInDrag) {
-                retval = super.dispatchDragEvent(event);
-            } else {
-                if (ViewDebug.DEBUG_DRAG) {
-                    Log.d(View.VIEW_LOG_TAG, "   not dropped on an accepting view");
-                }
-            }
-        } break;
         }
 
         return retval;
@@ -1595,6 +1562,7 @@
         final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
         mCurrentDragStartEvent.mX = tx;
         mCurrentDragStartEvent.mY = ty;
+        mCurrentDragStartEvent.mEventHandlerWasCalled = false;
         if (canAccept) {
             mChildrenInterestedInDrag.add(child);
             if (!child.canAcceptDrag()) {
@@ -3144,6 +3112,25 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public void notifySubtreeAccessibilityStateChangedIfNeeded() {
+        if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
+            return;
+        }
+        // If something important for a11y is happening in this subtree, make sure it's dispatched
+        // from a view that is important for a11y so it doesn't get lost.
+        if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
+                && !isImportantForAccessibility() && (getChildCount() > 0)) {
+            ViewParent a11yParent = getParentForAccessibility();
+            if (a11yParent instanceof View) {
+                ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
+                return;
+            }
+        }
+        super.notifySubtreeAccessibilityStateChangedIfNeeded();
+    }
+
     @Override
     void resetSubtreeAccessibilityStateChanged() {
         super.resetSubtreeAccessibilityStateChanged();
@@ -6415,16 +6402,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..87b330d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -29,6 +29,7 @@
 import android.annotation.NonNull;
 import android.app.ActivityManagerNative;
 import android.app.ResourcesManager;
+import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ComponentCallbacks;
 import android.content.Context;
@@ -429,7 +430,8 @@
         mPreviousTransparentRegion = new Region();
         mFirst = true; // true for the first time the view is added
         mAdded = false;
-        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
+        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
+                context);
         mAccessibilityManager = AccessibilityManager.getInstance(context);
         mAccessibilityInteractionConnectionManager =
             new AccessibilityInteractionConnectionManager();
@@ -1467,6 +1469,8 @@
         final int viewVisibility = getHostVisibility();
         final boolean viewVisibilityChanged = !mFirst
                 && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
+        final boolean viewUserVisibilityChanged = !mFirst &&
+                ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
 
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
@@ -1540,7 +1544,9 @@
         if (viewVisibilityChanged) {
             mAttachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
-            host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+            if (viewUserVisibilityChanged) {
+                host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+            }
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                 endDragResizing();
                 destroyHardwareResources();
@@ -2163,7 +2169,12 @@
         }
 
         if (changedVisibility || regainedFocus) {
-            host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            // Toasts are presented as notifications - don't present them as windows as well
+            boolean isToast = (mWindowAttributes == null) ? false
+                    : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
+            if (!isToast) {
+                host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            }
         }
 
         mFirst = false;
@@ -5517,9 +5528,11 @@
             if (what == DragEvent.ACTION_DRAG_EXITED) {
                 // A direct EXITED event means that the window manager knows we've just crossed
                 // a window boundary, so the current drag target within this one must have
-                // just been exited.  Send it the usual notifications and then we're done
-                // for now.
-                mView.dispatchDragEvent(event);
+                // just been exited. Send the EXITED notification to the current drag view, if any.
+                if (View.sCascadedDragDrop) {
+                    mView.dispatchDragEnterExitInPreN(event);
+                }
+                setDragFocus(null, event);
             } else {
                 // For events with a [screen] location, translate into window coordinates
                 if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
@@ -5539,13 +5552,19 @@
                 // Remember who the current drag target is pre-dispatch
                 final View prevDragView = mCurrentDragView;
 
-                if (what == DragEvent.ACTION_DROP) {
-                    event.getClipData().prepareToEnterProcess();
+                if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
+                    event.mClipData.prepareToEnterProcess();
                 }
 
                 // Now dispatch the drag/drop event
                 boolean result = mView.dispatchDragEvent(event);
 
+                if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
+                    // If the LOCATION event wasn't delivered to any handler, no view now has a drag
+                    // focus.
+                    setDragFocus(null, event);
+                }
+
                 // If we changed apparent drag target, tell the OS about it
                 if (prevDragView != mCurrentDragView) {
                     try {
@@ -5572,6 +5591,7 @@
 
                 // When the drag operation ends, reset drag-related state
                 if (what == DragEvent.ACTION_DRAG_ENDED) {
+                    mCurrentDragView = null;
                     setLocalDragState(null);
                     mAttachInfo.mDragToken = null;
                     if (mAttachInfo.mDragSurface != null) {
@@ -5631,10 +5651,36 @@
         return mLastTouchSource;
     }
 
-    public void setDragFocus(View newDragTarget) {
-        if (mCurrentDragView != newDragTarget) {
-            mCurrentDragView = newDragTarget;
+    public void setDragFocus(View newDragTarget, DragEvent event) {
+        if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) {
+            // Send EXITED and ENTERED notifications to the old and new drag focus views.
+
+            final float tx = event.mX;
+            final float ty = event.mY;
+            final int action = event.mAction;
+            final ClipData td = event.mClipData;
+            // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
+            event.mX = 0;
+            event.mY = 0;
+            event.mClipData = null;
+
+            if (mCurrentDragView != null) {
+                event.mAction = DragEvent.ACTION_DRAG_EXITED;
+                mCurrentDragView.callDragEventHandler(event);
+            }
+
+            if (newDragTarget != null) {
+                event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+                newDragTarget.callDragEventHandler(event);
+            }
+
+            event.mAction = action;
+            event.mX = tx;
+            event.mY = ty;
+            event.mClipData = td;
         }
+
+        mCurrentDragView = newDragTarget;
     }
 
     private AudioManager getAudioManager() {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 521fd31..7dd2fc2 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -16,8 +16,11 @@
 
 package android.view;
 
+import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.Build;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,7 +52,9 @@
     private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
 
     // These listeners cannot be mutated during dispatch
+    private boolean mInDispatchOnDraw;
     private ArrayList<OnDrawListener> mOnDrawListeners;
+    private static boolean sIllegalOnDrawModificationIsFatal;
 
     /** Remains false until #dispatchOnWindowShown() is called. If a listener registers after
      * that the listener will be immediately called. */
@@ -327,7 +332,9 @@
     /**
      * Creates a new ViewTreeObserver. This constructor should not be called
      */
-    ViewTreeObserver() {
+    ViewTreeObserver(Context context) {
+        sIllegalOnDrawModificationIsFatal =
+                context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1;
     }
 
     /**
@@ -657,6 +664,15 @@
             mOnDrawListeners = new ArrayList<OnDrawListener>();
         }
 
+        if (mInDispatchOnDraw) {
+            IllegalStateException ex = new IllegalStateException(
+                    "Cannot call addOnDrawListener inside of onDraw");
+            if (sIllegalOnDrawModificationIsFatal) {
+                throw ex;
+            } else {
+                Log.e("ViewTreeObserver", ex.getMessage(), ex);
+            }
+        }
         mOnDrawListeners.add(listener);
     }
 
@@ -676,6 +692,15 @@
         if (mOnDrawListeners == null) {
             return;
         }
+        if (mInDispatchOnDraw) {
+            IllegalStateException ex = new IllegalStateException(
+                    "Cannot call removeOnDrawListener inside of onDraw");
+            if (sIllegalOnDrawModificationIsFatal) {
+                throw ex;
+            } else {
+                Log.e("ViewTreeObserver", ex.getMessage(), ex);
+            }
+        }
         mOnDrawListeners.remove(victim);
     }
 
@@ -976,11 +1001,13 @@
      */
     public final void dispatchOnDraw() {
         if (mOnDrawListeners != null) {
+            mInDispatchOnDraw = true;
             final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
             int numListeners = listeners.size();
             for (int i = 0; i < numListeners; ++i) {
                 listeners.get(i).onDraw();
             }
+            mInDispatchOnDraw = false;
         }
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index eb6b17e..395f738 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;
@@ -1743,14 +1752,18 @@
         public CharSequence accessibilityTitle;
 
         /**
-         * Sets a timeout in milliseconds before which the window will be removed
+         * Sets a timeout in milliseconds before which the window will be hidden
          * by the window manager. Useful for transient notifications like toasts
          * so we don't have to rely on client cooperation to ensure the window
-         * is removed. Must be specified at window creation time.
+         * is hidden. Must be specified at window creation time. Note that apps
+         * are not prepared to handle their windows being removed without their
+         * explicit request and may try to interact with the removed window
+         * resulting in undefined behavior and crashes. Therefore, we do hide
+         * such windows to prevent them from overlaying other apps.
          *
          * @hide
          */
-        public long removeTimeoutMilliseconds = -1;
+        public long hideTimeoutMilliseconds = -1;
 
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
@@ -1886,7 +1899,7 @@
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
-            out.writeLong(removeTimeoutMilliseconds);
+            out.writeLong(hideTimeoutMilliseconds);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1940,7 +1953,7 @@
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            removeTimeoutMilliseconds = in.readLong();
+            hideTimeoutMilliseconds = in.readLong();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2162,7 +2175,7 @@
             }
 
             // This can't change, it's only set at window creation time.
-            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
 
             return changes;
         }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 080bc32..83fc362 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -335,20 +335,17 @@
             mViews.add(view);
             mRoots.add(root);
             mParams.add(wparams);
-        }
 
-        // do this last because it fires off messages to start doing things
-        try {
-            root.setView(view, wparams, panelParentView);
-        } catch (RuntimeException e) {
-            // BadTokenException or InvalidDisplayException, clean up.
-            synchronized (mLock) {
-                final int index = findViewLocked(view, false);
+            // do this last because it fires off messages to start doing things
+            try {
+                root.setView(view, wparams, panelParentView);
+            } catch (RuntimeException e) {
+                // BadTokenException or InvalidDisplayException, clean up.
                 if (index >= 0) {
                     removeViewLocked(index, true);
                 }
+                throw e;
             }
-            throw e;
         }
     }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 0b9f9d0..da361c1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -507,6 +507,11 @@
          * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
          */
         void getStackBounds(int stackId, Rect outBounds);
+
+        /**
+         * Overrides all currently playing app animations with {@param a}.
+         */
+        void overridePlayingAppAnimationsLw(Animation a);
     }
 
     public interface PointerEventListener {
@@ -1306,6 +1311,16 @@
     public int adjustSystemUiVisibilityLw(int visibility);
 
     /**
+     * Called by System UI to notify of changes to the visibility of Recents.
+     */
+    public void setRecentsVisibilityLw(boolean visible);
+
+    /**
+     * Called by System UI to notify of changes to the visibility of PIP.
+     */
+    public void setTvPipVisibilityLw(boolean visible);
+
+    /**
      * Specifies whether there is an on-screen navigation bar separate from the status bar.
      */
     public boolean hasNavigationBar();
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 28e31c4..ee5bbe8 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -23,14 +23,18 @@
 import android.util.LongSparseArray;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Cache for AccessibilityWindowInfos and AccessibilityNodeInfos.
  * It is updated when windows change or nodes change.
+ * @hide
  */
-final class AccessibilityCache {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class AccessibilityCache {
 
     private static final String LOG_TAG = "AccessibilityCache";
 
@@ -40,6 +44,8 @@
 
     private final Object mLock = new Object();
 
+    private final AccessibilityNodeRefresher mAccessibilityNodeRefresher;
+
     private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
     private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
@@ -54,6 +60,10 @@
     private final SparseArray<AccessibilityWindowInfo> mTempWindowArray =
             new SparseArray<>();
 
+    public AccessibilityCache(AccessibilityNodeRefresher nodeRefresher) {
+        mAccessibilityNodeRefresher = nodeRefresher;
+    }
+
     public void setWindows(List<AccessibilityWindowInfo> windows) {
         synchronized (mLock) {
             if (DEBUG) {
@@ -170,7 +180,7 @@
             return;
         }
         // The node changed so we will just refresh it right now.
-        if (cachedInfo.refresh(true)) {
+        if (mAccessibilityNodeRefresher.refreshNode(cachedInfo, true)) {
             return;
         }
         // Weird, we could not refresh. Just evict the entire sub-tree.
@@ -285,10 +295,12 @@
 
                 // Also be careful if the parent has changed since the new
                 // parent may be a predecessor of the old parent which will
-                // add cyclse to the cache.
+                // add cycles to the cache.
                 final long oldParentId = oldInfo.getParentNodeId();
                 if (info.getParentNodeId() != oldParentId) {
                     clearSubTreeLocked(windowId, oldParentId);
+                } else {
+                    oldInfo.recycle();
                 }
            }
 
@@ -296,6 +308,12 @@
             // will wipe the data of the cached info.
             AccessibilityNodeInfo clone = AccessibilityNodeInfo.obtain(info);
             nodes.put(sourceId, clone);
+            if (clone.isAccessibilityFocused()) {
+                mAccessibilityFocus = sourceId;
+            }
+            if (clone.isFocused()) {
+                mInputFocus = sourceId;
+            }
         }
     }
 
@@ -383,6 +401,7 @@
             final long childNodeId = current.getChildId(i);
             clearSubTreeRecursiveLocked(nodes, childNodeId);
         }
+        current.recycle();
     }
 
     /**
@@ -505,4 +524,11 @@
             }
         }
     }
+
+    // Layer of indirection included to break dependency chain for testing
+    public static class AccessibilityNodeRefresher {
+        public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
+            return info.refresh(bypassCache);
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 1406fbd..1543597 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -104,7 +104,7 @@
         new SparseArray<>();
 
     private static final AccessibilityCache sAccessibilityCache =
-        new AccessibilityCache();
+        new AccessibilityCache(new AccessibilityCache.AccessibilityNodeRefresher());
 
     /**
      * @return The client for the current thread.
@@ -293,6 +293,9 @@
                             interactionId);
                     finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
                     if (infos != null && !infos.isEmpty()) {
+                        for (int i = 1; i < infos.size(); i++) {
+                            infos.get(i).recycle();
+                        }
                         return infos.get(0);
                     }
                 }
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/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 7880b1a..9127861 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -19,6 +19,7 @@
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -35,6 +36,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class represents a node of the window content as well as actions that
@@ -553,6 +555,8 @@
      */
     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
 
+    private static AtomicInteger sNumInstancesInUse;
+
     /**
      * Gets the accessibility view id which identifies a View in the view three.
      *
@@ -2230,7 +2234,7 @@
      */
     public void setText(CharSequence text) {
         enforceNotSealed();
-        mText = text;
+        mText = (text == null) ? null : text.subSequence(0, text.length());
     }
 
     /**
@@ -2247,7 +2251,7 @@
      */
     public void setError(CharSequence error) {
         enforceNotSealed();
-        mError = error;
+        mError = (error == null) ? null : error.subSequence(0, error.length());
     }
 
     /**
@@ -2282,7 +2286,8 @@
      */
     public void setContentDescription(CharSequence contentDescription) {
         enforceNotSealed();
-        mContentDescription = contentDescription;
+        mContentDescription = (contentDescription == null) ? null
+                : contentDescription.subSequence(0, contentDescription.length());
     }
 
     /**
@@ -2688,6 +2693,9 @@
      */
     public static AccessibilityNodeInfo obtain() {
         AccessibilityNodeInfo info = sPool.acquire();
+        if (sNumInstancesInUse != null) {
+            sNumInstancesInUse.incrementAndGet();
+        }
         return (info != null) ? info : new AccessibilityNodeInfo();
     }
 
@@ -2715,6 +2723,19 @@
     public void recycle() {
         clear();
         sPool.release(this);
+        if (sNumInstancesInUse != null) {
+            sNumInstancesInUse.decrementAndGet();
+        }
+    }
+
+    /**
+     * Specify a counter that will be incremented on obtain() and decremented on recycle()
+     *
+     * @hide
+     */
+    @TestApi
+    public static void setNumInstancesInUseCounter(AtomicInteger counter) {
+        sNumInstancesInUse = counter;
     }
 
     /**
@@ -3282,6 +3303,7 @@
         builder.append("; enabled: ").append(isEnabled());
         builder.append("; password: ").append(isPassword());
         builder.append("; scrollable: ").append(isScrollable());
+        builder.append("; importantForAccessibility: ").append(isImportantForAccessibility());
         builder.append("; actions: ").append(mActions);
 
         return builder.toString();
@@ -3734,7 +3756,7 @@
          * how to override the standard click action by adding a custom label:
          * <pre>
          *   AccessibilityAction action = new AccessibilityAction(
-         *           AccessibilityAction.ACTION_ACTION_CLICK, getLocalizedLabel());
+         *           AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel());
          *   node.addAction(action);
          * </pre>
          *
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f99690a..f2979bb 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -572,7 +572,8 @@
      */
     public void setBeforeText(CharSequence beforeText) {
         enforceNotSealed();
-        mBeforeText = beforeText;
+        mBeforeText = (beforeText == null) ? null
+                : beforeText.subSequence(0, beforeText.length());
     }
 
     /**
@@ -593,7 +594,8 @@
      */
     public void setContentDescription(CharSequence contentDescription) {
         enforceNotSealed();
-        mContentDescription = contentDescription;
+        mContentDescription = (contentDescription == null) ? null
+                : contentDescription.subSequence(0, contentDescription.length());
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 52f35de..3287298 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -17,12 +17,15 @@
 package android.view.accessibility;
 
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * This class represents a state snapshot of a window for accessibility
  * purposes. The screen content contains one or more windows where some
@@ -81,6 +84,7 @@
     private static final int MAX_POOL_SIZE = 10;
     private static final SynchronizedPool<AccessibilityWindowInfo> sPool =
             new SynchronizedPool<AccessibilityWindowInfo>(MAX_POOL_SIZE);
+    private static AtomicInteger sNumInstancesInUse;
 
     // Data.
     private int mType = UNDEFINED;
@@ -400,6 +404,9 @@
         if (info == null) {
             info = new AccessibilityWindowInfo();
         }
+        if (sNumInstancesInUse != null) {
+            sNumInstancesInUse.incrementAndGet();
+        }
         return info;
     }
 
@@ -437,6 +444,18 @@
     }
 
     /**
+     * Specify a counter that will be incremented on obtain() and decremented on recycle()
+     *
+     * @hide
+     */
+    @TestApi
+    public static void setNumInstancesInUseCounter(AtomicInteger counter) {
+        if (sNumInstancesInUse != null) {
+            sNumInstancesInUse = counter;
+        }
+    }
+
+    /**
      * Return an instance back to be reused.
      * <p>
      * <strong>Note:</strong> You must not touch the object after calling this function.
@@ -447,6 +466,9 @@
     public void recycle() {
         clear();
         sPool.release(this);
+        if (sNumInstancesInUse != null) {
+            sNumInstancesInUse.decrementAndGet();
+        }
     }
 
     @Override
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionCallback.aidl
deleted file mode 100644
index eeab4f2..0000000
--- a/core/java/android/view/accessibility/IAccessibilityInteractionCallback.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 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.view.accessibility;
-
-import android.view.accessibility.AccessibilityNodeInfo;
-import java.util.List;
-
-/**
- * Callback for specifying the result for an asynchronous request made
- * via calling a method on IAccessibilityInteractionCallback.
- *
- * @hide
- */
-oneway interface IAccessibilityInteractionCallback {
-
-    /**
-     * Sets the result of an async request that returns an {@link AccessibilityNodeInfo}.
-     *
-     * @param infos The result {@link AccessibilityNodeInfo}.
-     * @param interactionId The interaction id to match the result with the request.
-     */
-    void setFindAccessibilityNodeInfoResult(in AccessibilityNodeInfo info, int interactionId);
-
-    /**
-     * Sets the result of an async request that returns {@link AccessibilityNodeInfo}s.
-     *
-     * @param infos The result {@link AccessibilityNodeInfo}s.
-     * @param interactionId The interaction id to match the result with the request.
-     */
-    void setFindAccessibilityNodeInfosResult(in List<AccessibilityNodeInfo> infos,
-        int interactionId);
-
-    /**
-     * Sets the result of a request to perform an accessibility action.
-     *
-     * @param Whether the action was performed.
-     * @param interactionId The interaction id to match the result with the request.
-     */
-    void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
-}
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index 42ae1b3..c1a3ab7 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -16,7 +16,6 @@
 
 package android.view.accessibility;
 
-import android.graphics.Point;
 import android.view.accessibility.AccessibilityNodeInfo;
 import java.util.List;
 
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/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 07910b6..8023201 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -43,12 +43,14 @@
  *     in {@link android.os.Build.VERSION_CODES#HONEYCOMB}.</li>
  *     <li>{@link #requestCursorUpdates(int)}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#LOLLIPOP}.</li>
- *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}}, which
+ *     <li>{@link #deleteSurroundingTextInCodePoints(int, int)}, which
  *     was introduced in {@link android.os.Build.VERSION_CODES#N}.</li>
- *     <li>{@link #getHandler()}}, which was introduced in
+ *     <li>{@link #getHandler()}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#N}.</li>
- *     <li>{@link #closeConnection()}}, which was introduced in
+ *     <li>{@link #closeConnection()}, which was introduced in
  *     {@link android.os.Build.VERSION_CODES#N}.</li>
+ *     <li>{@link #commitContent(InputContentInfo, int, Bundle)}, which was
+ *     introduced in {@link android.os.Build.VERSION_CODES#N_MR1}.</li>
  * </ul>
  *
  * <h3>Implementing an IME or an editor</h3>
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e37cf96..ca370dc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2065,12 +2065,10 @@
      * have any input method subtype.
      */
     public InputMethodSubtype getCurrentInputMethodSubtype() {
-        synchronized (mH) {
-            try {
-                return mService.getCurrentInputMethodSubtype();
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+        try {
+            return mService.getCurrentInputMethodSubtype();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6f3fa36..8c725cf 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -188,7 +188,7 @@
  * <p>By default, requests by the HTML to open new windows are
  * ignored. This is true whether they be opened by JavaScript or by
  * the target attribute on a link. You can customize your
- * {@link WebChromeClient} to provide your own behaviour for opening multiple windows,
+ * {@link WebChromeClient} to provide your own behavior for opening multiple windows,
  * and render them in whatever manner you want.</p>
  *
  * <p>The standard behavior for an Activity is to be destroyed and
@@ -281,7 +281,7 @@
  * <ul>
  * <li>The HTML body layout height is set to a fixed value. This means that elements with a height
  * relative to the HTML body may not be sized correctly. </li>
- * <li>For applications targetting {@link android.os.Build.VERSION_CODES#KITKAT} and earlier SDKs the
+ * <li>For applications targeting {@link android.os.Build.VERSION_CODES#KITKAT} and earlier SDKs the
  * HTML viewport meta tag will be ignored in order to preserve backwards compatibility. </li>
  * </ul>
  * </p>
@@ -596,7 +596,7 @@
 
     /**
      * Constructs a new WebView with layout parameters, a default style and a set
-     * of custom Javscript interfaces to be added to this WebView at initialization
+     * of custom JavaScript interfaces to be added to this WebView at initialization
      * time. This guarantees that these interfaces will be available when the JS
      * context is initialized.
      *
@@ -610,7 +610,7 @@
      *                             values
      * @param privateBrowsing whether this WebView will be initialized in
      *                        private mode
-     * @hide This is used internally by dumprendertree, as it requires the javaScript interfaces to
+     * @hide This is used internally by dumprendertree, as it requires the JavaScript interfaces to
      *       be added synchronously, before a subsequent loadUrl call takes effect.
      */
     protected WebView(Context context, AttributeSet attrs, int defStyleAttr,
@@ -723,7 +723,7 @@
 
     /**
      * Sets a username and password pair for the specified host. This data is
-     * used by the Webview to autocomplete username and password fields in web
+     * used by the WebView to autocomplete username and password fields in web
      * forms. Note that this is unrelated to the credentials used for HTTP
      * authentication.
      *
@@ -741,18 +741,16 @@
     }
 
     /**
-     * Stores HTTP authentication credentials for a given host and realm. This
-     * method is intended to be used with
-     * {@link WebViewClient#onReceivedHttpAuthRequest}.
+     * Stores HTTP authentication credentials for a given host and realm to the {@link WebViewDatabase}
+     * instance.
      *
      * @param host the host to which the credentials apply
      * @param realm the realm to which the credentials apply
      * @param username the username
      * @param password the password
-     * @see #getHttpAuthUsernamePassword
-     * @see WebViewDatabase#hasHttpAuthUsernamePassword
-     * @see WebViewDatabase#clearHttpAuthUsernamePassword
+     * @deprecated Use {@link WebViewDatabase#setHttpAuthUsernamePassword} instead
      */
+    @Deprecated
     public void setHttpAuthUsernamePassword(String host, String realm,
             String username, String password) {
         checkThread();
@@ -760,19 +758,16 @@
     }
 
     /**
-     * Retrieves HTTP authentication credentials for a given host and realm.
-     * This method is intended to be used with
-     * {@link WebViewClient#onReceivedHttpAuthRequest}.
-     *
+     * Retrieves HTTP authentication credentials for a given host and realm from the {@link
+     * WebViewDatabase} instance.
      * @param host the host to which the credentials apply
      * @param realm the realm to which the credentials apply
      * @return the credentials as a String array, if found. The first element
      *         is the username and the second element is the password. Null if
      *         no credentials are found.
-     * @see #setHttpAuthUsernamePassword
-     * @see WebViewDatabase#hasHttpAuthUsernamePassword
-     * @see WebViewDatabase#clearHttpAuthUsernamePassword
+     * @deprecated Use {@link WebViewDatabase#getHttpAuthUsernamePassword} instead
      */
+    @Deprecated
     public String[] getHttpAuthUsernamePassword(String host, String realm) {
         checkThread();
         return mProvider.getHttpAuthUsernamePassword(host, realm);
@@ -910,7 +905,7 @@
      *            value. Note that if this map contains any of the headers
      *            that are set by default by this WebView, such as those
      *            controlling caching, accept types or the User-Agent, their
-     *            values may be overriden by this WebView's defaults.
+     *            values may be overridden by this WebView's defaults.
      */
     public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
         checkThread();
@@ -1031,7 +1026,7 @@
      * @param script the JavaScript to execute.
      * @param resultCallback A callback to be invoked when the script execution
      *                       completes with the result of the execution (if any).
-     *                       May be null if no notificaion of the result is required.
+     *                       May be null if no notification of the result is required.
      */
     public void evaluateJavascript(String script, ValueCallback<String> resultCallback) {
         checkThread();
@@ -1102,7 +1097,7 @@
     /**
      * Gets whether this WebView has a forward history item.
      *
-     * @return true iff this Webview has a forward history item
+     * @return true iff this WebView has a forward history item
      */
     public boolean canGoForward() {
         checkThread();
@@ -1176,14 +1171,14 @@
      * Posts a {@link VisualStateCallback}, which will be called when
      * the current state of the WebView is ready to be drawn.
      *
-     * <p>Because updates to the the DOM are processed asynchronously, updates to the DOM may not
+     * <p>Because updates to the DOM are processed asynchronously, updates to the DOM may not
      * immediately be reflected visually by subsequent {@link WebView#onDraw} invocations. The
      * {@link VisualStateCallback} provides a mechanism to notify the caller when the contents of
      * the DOM at the current time are ready to be drawn the next time the {@link WebView}
      * draws.</p>
      *
      * <p>The next draw after the callback completes is guaranteed to reflect all the updates to the
-     * DOM up to the the point at which the {@link VisualStateCallback} was posted, but it may also
+     * DOM up to the point at which the {@link VisualStateCallback} was posted, but it may also
      * contain updates applied after the callback was posted.</p>
      *
      * <p>The state of the DOM covered by this API includes the following:
@@ -1216,7 +1211,7 @@
      * </ul></p>
      *
      * <p>When using this API it is also recommended to enable pre-rasterization if the {@link
-     * WebView} is offscreen to avoid flickering. See {@link WebSettings#setOffscreenPreRaster} for
+     * WebView} is off screen to avoid flickering. See {@link WebSettings#setOffscreenPreRaster} for
      * more details and do consider its caveats.</p>
      *
      * @param requestId An id that will be returned in the callback to allow callers to match
@@ -1281,11 +1276,11 @@
     }
 
     /**
-     * Creates a PrintDocumentAdapter that provides the content of this Webview for printing.
+     * Creates a PrintDocumentAdapter that provides the content of this WebView for printing.
      *
-     * The adapter works by converting the Webview contents to a PDF stream. The Webview cannot
+     * The adapter works by converting the WebView contents to a PDF stream. The WebView cannot
      * be drawn during the conversion process - any such draws are undefined. It is recommended
-     * to use a dedicated off screen Webview for the printing. If necessary, an application may
+     * to use a dedicated off screen WebView for the printing. If necessary, an application may
      * temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance
      * wrapped around the object returned and observing the onStart and onFinish methods. See
      * {@link android.print.PrintDocumentAdapter} for more information.
@@ -1320,7 +1315,7 @@
      * {@link WebSettings#getUseWideViewPort()} and
      * {@link WebSettings#getLoadWithOverviewMode()}.
      * If the content fits into the WebView control by width, then
-     * the zoom is set to 100%. For wide content, the behavor
+     * the zoom is set to 100%. For wide content, the behavior
      * depends on the state of {@link WebSettings#getLoadWithOverviewMode()}.
      * If its value is true, the content will be zoomed out to be fit
      * by width into the WebView control, otherwise not.
@@ -1597,10 +1592,10 @@
 
     /**
      * Clears the client certificate preferences stored in response
-     * to proceeding/cancelling client cert requests. Note that Webview
+     * to proceeding/cancelling client cert requests. Note that WebView
      * automatically clears these preferences when it receives a
      * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
-     * shared by all the webviews that are created by the embedder application.
+     * shared by all the WebViews that are created by the embedder application.
      *
      * @param onCleared  A runnable to be invoked when client certs are cleared.
      *                   The embedder can pass null if not interested in the
@@ -1656,7 +1651,7 @@
      * Notifies any registered {@link FindListener}.
      *
      * @param find the string to find
-     * @return the number of occurances of the String "find" that were found
+     * @return the number of occurrences of the String "find" that were found
      * @deprecated {@link #findAllAsync} is preferred.
      * @see #setFindListener
      */
@@ -1773,6 +1768,7 @@
      * requests. This will replace the current handler.
      *
      * @param client an implementation of WebViewClient
+     * @see #getWebViewClient
      */
     public void setWebViewClient(WebViewClient client) {
         checkThread();
@@ -1780,6 +1776,17 @@
     }
 
     /**
+     * Gets the WebViewClient.
+     *
+     * @return the WebViewClient, or a default client if not yet set
+     * @see #setWebViewClient
+     */
+    public WebViewClient getWebViewClient() {
+        checkThread();
+        return mProvider.getWebViewClient();
+    }
+
+    /**
      * Registers the interface to be used when content can not be handled by
      * the rendering engine, and should be downloaded instead. This will replace
      * the current handler.
@@ -1797,6 +1804,7 @@
      * This will replace the current handler.
      *
      * @param client an implementation of WebChromeClient
+     * @see #getWebChromeClient
      */
     public void setWebChromeClient(WebChromeClient client) {
         checkThread();
@@ -1804,6 +1812,17 @@
     }
 
     /**
+     * Gets the chrome handler.
+     *
+     * @return the WebChromeClient, or null if not yet set
+     * @see #setWebChromeClient
+     */
+    public WebChromeClient getWebChromeClient() {
+        checkThread();
+        return mProvider.getWebChromeClient();
+    }
+
+    /**
      * Sets the Picture listener. This is an interface used to receive
      * notifications of a new Picture.
      *
@@ -2071,7 +2090,7 @@
     /**
      * Performs a zoom operation in this WebView.
      *
-     * @param zoomFactor the zoom factor to apply. The zoom factor will be clamped to the Webview's
+     * @param zoomFactor the zoom factor to apply. The zoom factor will be clamped to the WebView's
      * zoom limits. This value must be in the range 0.01 to 100.0 inclusive.
      */
     public void zoomBy(float zoomFactor) {
@@ -2136,7 +2155,7 @@
 
     /**
      * Gets the WebViewProvider. Used by providers to obtain the underlying
-     * implementation, e.g. when the appliction responds to
+     * implementation, e.g. when the application responds to
      * WebViewClient.onCreateWindow() request.
      *
      * @hide WebViewProvider is not public API.
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index cdff416..87d3c7b 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -44,7 +44,7 @@
      *
      * @return true if there are any saved username/password pairs
      * @see WebView#savePassword
-     * @see #clearUsernamePassworda
+     * @see #clearUsernamePassword
      * @deprecated Saving passwords in WebView will not be supported in future versions.
      */
     @Deprecated
@@ -65,22 +65,79 @@
      * Gets whether there are any saved credentials for HTTP authentication.
      *
      * @return whether there are any saved credentials
-     * @see WebView#getHttpAuthUsernamePassword
-     * @see WebView#setHttpAuthUsernamePassword
+     * @see #getHttpAuthUsernamePassword
+     * @see #setHttpAuthUsernamePassword
      * @see #clearHttpAuthUsernamePassword
      */
     public abstract boolean hasHttpAuthUsernamePassword();
 
     /**
-     * Clears any saved credentials for HTTP authentication.
+     * Clears any saved credentials for HTTP authentication. This method only clears the username
+     * and password stored in WebViewDatabase instance. The username and password are not read from
+     * the {@link WebViewDatabase} during {@link WebViewClient#onReceivedHttpAuthRequest}. It is up
+     * to the app to do this or not.
+     * <p>
+     * The username and password used for http authentication might be cached in the network stack
+     * itself, and are not cleared when this method is called.  WebView does not provide a special
+     * mechanism to clear HTTP authentication for implementing client logout. The client logout
+     * mechanism should be implemented by the Web site designer (such as server sending a HTTP 401
+     * for invalidating credentials).
      *
-     * @see WebView#getHttpAuthUsernamePassword
-     * @see WebView#setHttpAuthUsernamePassword
+     * @see #getHttpAuthUsernamePassword
+     * @see #setHttpAuthUsernamePassword
      * @see #hasHttpAuthUsernamePassword
      */
     public abstract void clearHttpAuthUsernamePassword();
 
     /**
+     * Stores HTTP authentication credentials for a given host and realm to the {@link WebViewDatabase}
+     * instance.
+     * <p>
+     * To use HTTP authentication, the embedder application has to implement
+     * {@link WebViewClient#onReceivedHttpAuthRequest}, and call {@link HttpAuthHandler#proceed}
+     * with the correct username and password.
+     * <p>
+     * The embedder app can get the username and password any way it chooses, and does not have to
+     * use {@link WebViewDatabase}.
+     * <p>
+     * Notes:
+     * <li>
+     * {@link WebViewDatabase} is provided only as a convenience to store and retrieve http
+     * authentication credentials. WebView does not read from it during HTTP authentication.
+     * </li>
+     * <li>
+     * WebView does not provide a special mechanism to clear HTTP authentication credentials for
+     * implementing client logout. The client logout mechanism should be implemented by the Web site
+     * designer (such as server sending a HTTP 401 for invalidating credentials).
+     * </li>
+     *
+     * @param host the host to which the credentials apply
+     * @param realm the realm to which the credentials apply
+     * @param username the username
+     * @param password the password
+     * @see #getHttpAuthUsernamePassword
+     * @see #hasHttpAuthUsernamePassword
+     * @see #clearHttpAuthUsernamePassword
+     */
+    public abstract void setHttpAuthUsernamePassword(String host, String realm,
+            String username, String password);
+
+   /**
+     * Retrieves HTTP authentication credentials for a given host and realm from the {@link
+     * WebViewDatabase} instance.
+     *
+     * @param host the host to which the credentials apply
+     * @param realm the realm to which the credentials apply
+     * @return the credentials as a String array, if found. The first element
+     *         is the username and the second element is the password. Null if
+     *         no credentials are found.
+     * @see #setHttpAuthUsernamePassword
+     * @see #hasHttpAuthUsernamePassword
+     * @see #clearHttpAuthUsernamePassword
+     */
+    public abstract String[] getHttpAuthUsernamePassword(String host, String realm);
+
+    /**
      * Gets whether there is any saved data for web forms.
      *
      * @return whether there is any saved data for web forms
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/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index e5b65e7..95ec179 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -229,10 +229,14 @@
 
     public void setWebViewClient(WebViewClient client);
 
+    public WebViewClient getWebViewClient();
+
     public void setDownloadListener(DownloadListener listener);
 
     public void setWebChromeClient(WebChromeClient client);
 
+    public WebChromeClient getWebChromeClient();
+
     public void setPictureListener(PictureListener listener);
 
     public void addJavascriptInterface(Object obj, String interfaceName);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5ed6638..184453b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -616,6 +617,8 @@
     private int mTouchSlop;
     private float mDensityScale;
 
+    private float mScrollFactor;
+
     private InputConnection mDefInputConnection;
     private InputConnectionWrapper mPublicInputConnection;
 
@@ -857,6 +860,10 @@
                 R.styleable.AbsListView_fastScrollAlwaysVisible, false));
 
         a.recycle();
+
+        if (context.getResources().getConfiguration().uiMode == Configuration.UI_MODE_TYPE_WATCH) {
+            setRevealOnFocusHint(false);
+        }
     }
 
     private void initAbsListView() {
@@ -869,6 +876,7 @@
 
         final ViewConfiguration configuration = ViewConfiguration.get(mContext);
         mTouchSlop = configuration.getScaledTouchSlop();
+        mScrollFactor = configuration.getScaledScrollFactor();
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mOverscrollDistance = configuration.getScaledOverscrollDistance();
@@ -4202,21 +4210,26 @@
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_SCROLL:
-                    if (mTouchMode == TOUCH_MODE_REST) {
-                        final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                        if (vscroll != 0) {
-                            final int delta = (int) (vscroll * getVerticalScrollFactor());
-                            if (!trackMotionScroll(delta, delta)) {
-                                return true;
-                            }
-                        }
-                    }
-                    break;
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_SCROLL:
+                final float axisValue;
+                if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+                    axisValue = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                } else if (event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)) {
+                    axisValue = event.getAxisValue(MotionEvent.AXIS_SCROLL);
+                } else {
+                    axisValue = 0;
+                }
 
-                case MotionEvent.ACTION_BUTTON_PRESS:
+                final int delta = Math.round(axisValue * mScrollFactor);
+                if (delta != 0) {
+                    if (!trackMotionScroll(delta, delta)) {
+                        return true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_BUTTON_PRESS:
+                if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
                     int actionButton = event.getActionButton();
                     if ((actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY
                             || actionButton == MotionEvent.BUTTON_SECONDARY)
@@ -4226,8 +4239,8 @@
                             removeCallbacks(mPendingCheckForTap);
                         }
                     }
-                    break;
-            }
+                }
+                break;
         }
 
         return super.onGenericMotionEvent(event);
@@ -7600,15 +7613,27 @@
                 final int position = mTargetPos;
                 final int lastPos = firstPos + childCount - 1;
 
-                int viewTravelCount = 0;
+                // Account for the visible "portion" of the first / last child when we estimate
+                // how many screens we should travel to reach our target
+                final View firstChild = getChildAt(0);
+                final int firstChildHeight = firstChild.getHeight();
+                final View lastChild = getChildAt(childCount - 1);
+                final int lastChildHeight = lastChild.getHeight();
+                final float firstPositionVisiblePart = (firstChildHeight == 0.0f) ? 1.0f
+                        : (float) (firstChildHeight + firstChild.getTop()) / firstChildHeight;
+                final float lastPositionVisiblePart = (lastChildHeight == 0.0f) ? 1.0f
+                        : (float) (lastChildHeight + getHeight() - lastChild.getBottom())
+                                / lastChildHeight;
+
+                float viewTravelCount = 0;
                 if (position < firstPos) {
-                    viewTravelCount = firstPos - position + 1;
+                    viewTravelCount = firstPos - position + (1.0f - firstPositionVisiblePart) + 1;
                 } else if (position > lastPos) {
-                    viewTravelCount = position - lastPos;
+                    viewTravelCount = position - lastPos + (1.0f - lastPositionVisiblePart);
                 }
 
                 // Estimate how many screens we should travel
-                final float screenTravelCount = (float) viewTravelCount / childCount;
+                final float screenTravelCount = viewTravelCount / childCount;
 
                 final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
                 if (position < firstPos) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 878a9eb..01a95a4 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -36,6 +36,10 @@
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+
+/**
+ * AbsSeekBar extends the capabilities of ProgressBar by adding a draggable thumb.
+ */
 public abstract class AbsSeekBar extends ProgressBar {
     private final Rect mTempRect = new Rect();
 
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 154cc33..09e09b7 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.widget.RemoteViews.RemoteView;
 
 
@@ -113,4 +115,12 @@
     public CharSequence getAccessibilityClassName() {
         return Button.class.getName();
     }
+
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (getPointerIcon() == null && isClickable() && isEnabled()) {
+            return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
 }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index e196cf0..80f25d4 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -18,7 +18,9 @@
 
 import com.android.internal.R;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -33,6 +35,8 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
 
 /**
@@ -76,11 +80,36 @@
  */
 @Widget
 public class DatePicker extends FrameLayout {
-    private static final int MODE_SPINNER = 1;
-    private static final int MODE_CALENDAR = 2;
+    /**
+     * Presentation mode for the Holo-style date picker that uses a set of
+     * {@link android.widget.NumberPicker}s.
+     *
+     * @see #getMode()
+     * @hide Visible for testing only.
+     */
+    @TestApi
+    public static final int MODE_SPINNER = 1;
+
+    /**
+     * Presentation mode for the Material-style date picker that uses a
+     * calendar.
+     *
+     * @see #getMode()
+     * @hide Visible for testing only.
+     */
+    @TestApi
+    public static final int MODE_CALENDAR = 2;
+
+    /** @hide */
+    @IntDef({MODE_SPINNER, MODE_CALENDAR})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DatePickerMode {}
 
     private final DatePickerDelegate mDelegate;
 
+    @DatePickerMode
+    private final int mMode;
+
     /**
      * The callback used to indicate the user changed the date.
      */
@@ -115,11 +144,20 @@
 
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
                 defStyleAttr, defStyleRes);
-        final int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
+        final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
+        final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
         final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
         a.recycle();
 
-        switch (mode) {
+        if (requestedMode == MODE_CALENDAR && isDialogMode) {
+            // You want MODE_CALENDAR? YOU CAN'T HANDLE MODE_CALENDAR! Well,
+            // maybe you can depending on your screen size. Let's check...
+            mMode = context.getResources().getInteger(R.integer.date_picker_mode);
+        } else {
+            mMode = requestedMode;
+        }
+
+        switch (mMode) {
             case MODE_CALENDAR:
                 mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
                 break;
@@ -146,6 +184,18 @@
     }
 
     /**
+     * @return the picker's presentation mode, one of {@link #MODE_CALENDAR} or
+     *         {@link #MODE_SPINNER}
+     * @attr ref android.R.styleable#DatePicker_datePickerMode
+     * @hide Visible for testing only.
+     */
+    @DatePickerMode
+    @TestApi
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
      * Initialize the state. If the provided values designate an inconsistent
      * date the values are normalized before updating the spinners.
      *
diff --git a/core/java/android/widget/DialerFilter.java b/core/java/android/widget/DialerFilter.java
index 78786e1..e37e3ba7 100644
--- a/core/java/android/widget/DialerFilter.java
+++ b/core/java/android/widget/DialerFilter.java
@@ -31,8 +31,13 @@
 import android.view.View;
 import android.graphics.Rect;
 
-
-
+/**
+ * This widget is a layout that contains several specifically-named child views that
+ * handle keyboard entry interpreted as standard phone dialpad digits.
+ *
+ * @deprecated Use a custom view or layout to handle this functionality instead
+ */
+@Deprecated
 public class DialerFilter extends RelativeLayout
 {
     public DialerFilter(Context context) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index a0447a6..bf49048 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -70,6 +70,7 @@
 import android.text.style.SuggestionSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.URLSpan;
+import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
@@ -176,11 +177,21 @@
     InputMethodState mInputMethodState;
 
     private static class TextRenderNode {
+        // Render node has 3 recording states:
+        // 1. Recorded operations are valid.
+        // #needsRecord() returns false, but needsToBeShifted is false.
+        // 2. Recorded operations are not valid, but just the position needed to be updated.
+        // #needsRecord() returns false, but needsToBeShifted is true.
+        // 3. Recorded operations are not valid. Need to record operations. #needsRecord() returns
+        // true.
         RenderNode renderNode;
         boolean isDirty;
+        // Becomes true when recorded operations can be reused, but the position has to be updated.
+        boolean needsToBeShifted;
         public TextRenderNode(String name) {
-            isDirty = true;
             renderNode = RenderNode.create(name, null);
+            isDirty = true;
+            needsToBeShifted = true;
         }
         boolean needsRecord() {
             return isDirty || !renderNode.isValid();
@@ -1686,85 +1697,138 @@
             final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
             final int indexFirstChangedBlock = dynamicLayout.getIndexFirstChangedBlock();
 
-            int endOfPreviousBlock = -1;
-            int searchStartIndex = 0;
-            for (int i = 0; i < numberOfBlocks; i++) {
-                int blockEndLine = blockEndLines[i];
-                int blockIndex = blockIndices[i];
-
-                final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
-                if (blockIsInvalid) {
-                    blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks,
-                            searchStartIndex);
-                    // Note how dynamic layout's internal block indices get updated from Editor
-                    blockIndices[i] = blockIndex;
-                    if (mTextRenderNodes[blockIndex] != null) {
-                        mTextRenderNodes[blockIndex].isDirty = true;
+            final ArraySet<Integer> blockSet = dynamicLayout.getBlocksAlwaysNeedToBeRedrawn();
+            if (blockSet != null) {
+                for (int i = 0; i < blockSet.size(); i++) {
+                    final int blockIndex = dynamicLayout.getBlockIndex(blockSet.valueAt(i));
+                    if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX
+                            && mTextRenderNodes[blockIndex] != null) {
+                        mTextRenderNodes[blockIndex].needsToBeShifted = true;
                     }
-                    searchStartIndex = blockIndex + 1;
                 }
-
-                if (mTextRenderNodes[blockIndex] == null) {
-                    mTextRenderNodes[blockIndex] =
-                            new TextRenderNode("Text " + blockIndex);
-                }
-
-                final boolean blockDisplayListIsInvalid =
-                        mTextRenderNodes[blockIndex].needsRecord();
-                RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode;
-                if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
-                    final int blockBeginLine = endOfPreviousBlock + 1;
-                    final int top = layout.getLineTop(blockBeginLine);
-                    final int bottom = layout.getLineBottom(blockEndLine);
-                    int left = 0;
-                    int right = mTextView.getWidth();
-                    if (mTextView.getHorizontallyScrolling()) {
-                        float min = Float.MAX_VALUE;
-                        float max = Float.MIN_VALUE;
-                        for (int line = blockBeginLine; line <= blockEndLine; line++) {
-                            min = Math.min(min, layout.getLineLeft(line));
-                            max = Math.max(max, layout.getLineRight(line));
-                        }
-                        left = (int) min;
-                        right = (int) (max + 0.5f);
-                    }
-
-                    // Rebuild display list if it is invalid
-                    if (blockDisplayListIsInvalid) {
-                        final DisplayListCanvas displayListCanvas = blockDisplayList.start(
-                                right - left, bottom - top);
-                        try {
-                            // drawText is always relative to TextView's origin, this translation
-                            // brings this range of text back to the top left corner of the viewport
-                            displayListCanvas.translate(-left, -top);
-                            layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
-                            mTextRenderNodes[blockIndex].isDirty = false;
-                            // No need to untranslate, previous context is popped after
-                            // drawDisplayList
-                        } finally {
-                            blockDisplayList.end(displayListCanvas);
-                            // Same as drawDisplayList below, handled by our TextView's parent
-                            blockDisplayList.setClipToBounds(false);
-                        }
-                    }
-
-                    // Valid disply list whose index is >= indexFirstChangedBlock
-                    // only needs to update its drawing location.
-                    blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
-                }
-
-                ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
-
-                endOfPreviousBlock = blockEndLine;
             }
 
-            dynamicLayout.setIndexFirstChangedBlock(numberOfBlocks);
+            int startBlock = Arrays.binarySearch(blockEndLines, 0, numberOfBlocks, firstLine);
+            if (startBlock < 0) {
+                startBlock = -(startBlock + 1);
+            }
+            startBlock = Math.min(indexFirstChangedBlock, startBlock);
+
+            int startIndexToFindAvailableRenderNode = 0;
+            int lastIndex = numberOfBlocks;
+
+            for (int i = startBlock; i < numberOfBlocks; i++) {
+                final int blockIndex = blockIndices[i];
+                if (i >= indexFirstChangedBlock
+                        && blockIndex != DynamicLayout.INVALID_BLOCK_INDEX
+                        && mTextRenderNodes[blockIndex] != null) {
+                    mTextRenderNodes[blockIndex].needsToBeShifted = true;
+                }
+                if (blockEndLines[i] < firstLine) {
+                    // Blocks in [indexFirstChangedBlock, firstLine) are not redrawn here. They will
+                    // be redrawn after they get scrolled into drawing range.
+                    continue;
+                }
+                startIndexToFindAvailableRenderNode = drawHardwareAcceleratedInner(canvas, layout,
+                        highlight, highlightPaint, cursorOffsetVertical, blockEndLines,
+                        blockIndices, i, numberOfBlocks, startIndexToFindAvailableRenderNode);
+                if (blockEndLines[i] >= lastLine) {
+                    lastIndex = Math.max(indexFirstChangedBlock, i + 1);
+                    break;
+                }
+            }
+            if (blockSet != null) {
+                for (int i = 0; i < blockSet.size(); i++) {
+                    final int block = blockSet.valueAt(i);
+                    final int blockIndex = dynamicLayout.getBlockIndex(block);
+                    if (blockIndex == DynamicLayout.INVALID_BLOCK_INDEX
+                            || mTextRenderNodes[blockIndex] == null
+                            || mTextRenderNodes[blockIndex].needsToBeShifted) {
+                        startIndexToFindAvailableRenderNode = drawHardwareAcceleratedInner(canvas,
+                                layout, highlight, highlightPaint, cursorOffsetVertical,
+                                blockEndLines, blockIndices, block, numberOfBlocks,
+                                startIndexToFindAvailableRenderNode);
+                    }
+                }
+            }
+
+            dynamicLayout.setIndexFirstChangedBlock(lastIndex);
         } else {
             // Boring layout is used for empty and hint text
             layout.drawText(canvas, firstLine, lastLine);
         }
     }
 
+    private int drawHardwareAcceleratedInner(Canvas canvas, Layout layout, Path highlight,
+            Paint highlightPaint, int cursorOffsetVertical, int[] blockEndLines,
+            int[] blockIndices, int blockInfoIndex, int numberOfBlocks,
+            int startIndexToFindAvailableRenderNode) {
+        final int blockEndLine = blockEndLines[blockInfoIndex];
+        int blockIndex = blockIndices[blockInfoIndex];
+
+        final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
+        if (blockIsInvalid) {
+            blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks,
+                    startIndexToFindAvailableRenderNode);
+            // Note how dynamic layout's internal block indices get updated from Editor
+            blockIndices[blockInfoIndex] = blockIndex;
+            if (mTextRenderNodes[blockIndex] != null) {
+                mTextRenderNodes[blockIndex].isDirty = true;
+            }
+            startIndexToFindAvailableRenderNode = blockIndex + 1;
+        }
+
+        if (mTextRenderNodes[blockIndex] == null) {
+            mTextRenderNodes[blockIndex] = new TextRenderNode("Text " + blockIndex);
+        }
+
+        final boolean blockDisplayListIsInvalid = mTextRenderNodes[blockIndex].needsRecord();
+        RenderNode blockDisplayList = mTextRenderNodes[blockIndex].renderNode;
+        if (mTextRenderNodes[blockIndex].needsToBeShifted || blockDisplayListIsInvalid) {
+            final int blockBeginLine = blockInfoIndex == 0 ?
+                    0 : blockEndLines[blockInfoIndex - 1] + 1;
+            final int top = layout.getLineTop(blockBeginLine);
+            final int bottom = layout.getLineBottom(blockEndLine);
+            int left = 0;
+            int right = mTextView.getWidth();
+            if (mTextView.getHorizontallyScrolling()) {
+                float min = Float.MAX_VALUE;
+                float max = Float.MIN_VALUE;
+                for (int line = blockBeginLine; line <= blockEndLine; line++) {
+                    min = Math.min(min, layout.getLineLeft(line));
+                    max = Math.max(max, layout.getLineRight(line));
+                }
+                left = (int) min;
+                right = (int) (max + 0.5f);
+            }
+
+            // Rebuild display list if it is invalid
+            if (blockDisplayListIsInvalid) {
+                final DisplayListCanvas displayListCanvas = blockDisplayList.start(
+                        right - left, bottom - top);
+                try {
+                    // drawText is always relative to TextView's origin, this translation
+                    // brings this range of text back to the top left corner of the viewport
+                    displayListCanvas.translate(-left, -top);
+                    layout.drawText(displayListCanvas, blockBeginLine, blockEndLine);
+                    mTextRenderNodes[blockIndex].isDirty = false;
+                    // No need to untranslate, previous context is popped after
+                    // drawDisplayList
+                } finally {
+                    blockDisplayList.end(displayListCanvas);
+                    // Same as drawDisplayList below, handled by our TextView's parent
+                    blockDisplayList.setClipToBounds(false);
+                }
+            }
+
+            // Valid display list only needs to update its drawing location.
+            blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
+            mTextRenderNodes[blockIndex].needsToBeShifted = false;
+        }
+        ((DisplayListCanvas) canvas).drawRenderNode(blockDisplayList);
+        return startIndexToFindAvailableRenderNode;
+    }
+
     private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks,
             int searchStartIndex) {
         int length = mTextRenderNodes.length;
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/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 00f368e..918b6c0 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -128,6 +129,8 @@
     private int mOverscrollDistance;
     private int mOverflingDistance;
 
+    private float mScrollFactor;
+
     /**
      * ID of the active pointer. This is used to retain consistency during
      * drags/flings if multiple pointers are used.
@@ -165,6 +168,10 @@
         setFillViewport(a.getBoolean(android.R.styleable.HorizontalScrollView_fillViewport, false));
 
         a.recycle();
+
+        if (context.getResources().getConfiguration().uiMode == Configuration.UI_MODE_TYPE_WATCH) {
+            setRevealOnFocusHint(false);
+        }
     }
 
     @Override
@@ -217,6 +224,7 @@
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mOverscrollDistance = configuration.getScaledOverscrollDistance();
         mOverflingDistance = configuration.getScaledOverflingDistance();
+        mScrollFactor = configuration.getScaledScrollFactor();
     }
 
     @Override
@@ -719,30 +727,35 @@
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_SCROLL: {
-                    if (!mIsBeingDragged) {
-                        final float hscroll;
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_SCROLL: {
+                if (!mIsBeingDragged) {
+                    final float axisValue;
+                    if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
                         if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
-                            hscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                            axisValue = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
                         } else {
-                            hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+                            axisValue = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
                         }
-                        if (hscroll != 0) {
-                            final int delta = (int) (hscroll * getHorizontalScrollFactor());
-                            final int range = getScrollRange();
-                            int oldScrollX = mScrollX;
-                            int newScrollX = oldScrollX + delta;
-                            if (newScrollX < 0) {
-                                newScrollX = 0;
-                            } else if (newScrollX > range) {
-                                newScrollX = range;
-                            }
-                            if (newScrollX != oldScrollX) {
-                                super.scrollTo(newScrollX, mScrollY);
-                                return true;
-                            }
+                    } else if (event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)) {
+                        axisValue = event.getAxisValue(MotionEvent.AXIS_SCROLL);
+                    } else {
+                        axisValue = 0;
+                    }
+
+                    final int delta = Math.round(axisValue * mScrollFactor);
+                    if (delta != 0) {
+                        final int range = getScrollRange();
+                        int oldScrollX = mScrollX;
+                        int newScrollX = oldScrollX + delta;
+                        if (newScrollX < 0) {
+                            newScrollX = 0;
+                        } else if (newScrollX > range) {
+                            newScrollX = range;
+                        }
+                        if (newScrollX != oldScrollX) {
+                            super.scrollTo(newScrollX, mScrollY);
+                            return true;
                         }
                     }
                 }
@@ -1430,11 +1443,13 @@
 
     @Override
     public void requestChildFocus(View child, View focused) {
-        if (!mIsLayoutDirty) {
-            scrollToChild(focused);
-        } else {
-            // The child may not be laid out yet, we can't compute the scroll yet
-            mChildToScrollTo = focused;
+        if (focused.getRevealOnFocusHint()) {
+            if (!mIsLayoutDirty) {
+                scrollToChild(focused);
+            } else {
+                // The child may not be laid out yet, we can't compute the scroll yet
+                mChildToScrollTo = focused;
+            }
         }
         super.requestChildFocus(child, focused);
     }
diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java
index 332b158..e1b0c91 100644
--- a/core/java/android/widget/ImageButton.java
+++ b/core/java/android/widget/ImageButton.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.widget.RemoteViews.RemoteView;
 
 /**
@@ -94,4 +96,12 @@
     public CharSequence getAccessibilityClassName() {
         return ImageButton.class.getName();
     }
+
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (getPointerIcon() == null && isClickable() && isEnabled()) {
+            return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
 }
diff --git a/core/java/android/widget/ImageSwitcher.java b/core/java/android/widget/ImageSwitcher.java
index 08f21a2..112fcc3 100644
--- a/core/java/android/widget/ImageSwitcher.java
+++ b/core/java/android/widget/ImageSwitcher.java
@@ -22,17 +22,43 @@
 import android.net.Uri;
 import android.util.AttributeSet;
 
+/**
+ * {@link ViewSwitcher} that switches between two ImageViews when a new
+ * image is set on it. The views added to an ImageSwitcher must all be
+ * {@link ImageView ImageViews}.
+ */
 public class ImageSwitcher extends ViewSwitcher
 {
+    /**
+     * Creates a new empty ImageSwitcher.
+     *
+     * @param context the application's environment
+     */
     public ImageSwitcher(Context context)
     {
         super(context);
     }
-    
+
+    /**
+     * Creates a new empty ImageSwitcher for the given context and with the
+     * specified set attributes.
+     *
+     * @param context the application environment
+     * @param attrs a collection of attributes
+     */
     public ImageSwitcher(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    /**
+     * Sets a new image on the ImageSwitcher with the given resource id.
+     * This will set that image resource on the next ImageView in the switcher and will
+     * then switch to that view.
+     *
+     * @param resid a Drawable resource id
+     *
+     * @see ImageView#setImageResource(int)
+     */
     public void setImageResource(@DrawableRes int resid)
     {
         ImageView image = (ImageView)this.getNextView();
@@ -40,6 +66,15 @@
         showNext();
     }
 
+    /**
+     * Sets a new image on the ImageSwitcher with the given Uri.
+     * This will set that image on the next ImageView in the switcher and will
+     * then switch to that view.
+     *
+     * @param uri the Uri of an image
+     *
+     * @see ImageView#setImageURI(Uri)
+     */
     public void setImageURI(Uri uri)
     {
         ImageView image = (ImageView)this.getNextView();
@@ -47,6 +82,15 @@
         showNext();
     }
 
+    /**
+     * Sets a new drawable on the ImageSwitcher.
+     * This will set that drawable on the next ImageView in the switcher and will
+     * then switch to that view.
+     *
+     * @param drawable the drawable to be set or {@code null} to clear the content
+     *
+     * @see ImageView#setImageDrawable(Drawable)
+     */
     public void setImageDrawable(Drawable drawable)
     {
         ImageView image = (ImageView)this.getNextView();
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 184544d..d9cb269 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -22,7 +22,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -115,11 +114,17 @@
     private int mBaseline = -1;
     private boolean mBaselineAlignBottom = false;
 
-    // AdjustViewBounds behavior will be in compatibility mode for older apps.
-    private boolean mAdjustViewBoundsCompat = false;
+    /** Compatibility modes dependent on targetSdkVersion of the app. */
+    private static boolean sCompatDone;
+
+    /** AdjustViewBounds behavior will be in compatibility mode for older apps. */
+    private static boolean sCompatAdjustViewBounds;
 
     /** Whether to pass Resources when creating the source from a stream. */
-    private boolean mUseCorrectStreamDensity;
+    private static boolean sCompatUseCorrectStreamDensity;
+
+    /** Whether to use pre-Nougat drawable visibility dispatching conditions. */
+    private static boolean sCompatDrawableVisibilityDispatch;
 
     private static final ScaleType[] sScaleTypeArray = {
         ScaleType.MATRIX,
@@ -206,9 +211,13 @@
         mMatrix = new Matrix();
         mScaleType = ScaleType.FIT_CENTER;
 
-        final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
-        mAdjustViewBoundsCompat = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
-        mUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
+        if (!sCompatDone) {
+            final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+            sCompatAdjustViewBounds = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
+            sCompatUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
+            sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
+            sCompatDone = true;
+        }
     }
 
     @Override
@@ -881,8 +890,8 @@
             InputStream stream = null;
             try {
                 stream = mContext.getContentResolver().openInputStream(uri);
-                return Drawable.createFromResourceStream(
-                        mUseCorrectStreamDensity ? getResources() : null, null, stream, null);
+                return Drawable.createFromResourceStream(sCompatUseCorrectStreamDensity
+                        ? getResources() : null, null, stream, null);
             } catch (Exception e) {
                 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
             } finally {
@@ -917,10 +926,13 @@
             mRecycleableBitmapDrawable.setBitmap(null);
         }
 
+        boolean sameDrawable = false;
+
         if (mDrawable != null) {
+            sameDrawable = mDrawable == d;
             mDrawable.setCallback(null);
             unscheduleDrawable(mDrawable);
-            if (isAttachedToWindow()) {
+            if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
                 mDrawable.setVisible(false, false);
             }
         }
@@ -933,8 +945,11 @@
             if (d.isStateful()) {
                 d.setState(getDrawableState());
             }
-            if (isAttachedToWindow()) {
-                d.setVisible(getWindowVisibility() == VISIBLE && isShown(), true);
+            if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
+                final boolean visible = sCompatDrawableVisibilityDispatch
+                        ? getVisibility() == VISIBLE
+                        : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
+                d.setVisible(visible, true);
             }
             d.setLevel(mLevel);
             mDrawableWidth = d.getIntrinsicWidth();
@@ -1058,7 +1073,7 @@
                                 pleft + pright;
 
                         // Allow the width to outgrow its original estimate if height is fixed.
-                        if (!resizeHeight && !mAdjustViewBoundsCompat) {
+                        if (!resizeHeight && !sCompatAdjustViewBounds) {
                             widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                         }
 
@@ -1074,7 +1089,7 @@
                                 ptop + pbottom;
 
                         // Allow the height to outgrow its original estimate if width is fixed.
-                        if (!resizeWidth && !mAdjustViewBoundsCompat) {
+                        if (!resizeWidth && !sCompatAdjustViewBounds) {
                             heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
                                     heightMeasureSpec);
                         }
@@ -1426,7 +1441,9 @@
     /**
      * Returns the alpha that will be applied to the drawable of this ImageView.
      *
-     * @return the alpha that will be applied to the drawable of this ImageView
+     * @return the alpha value that will be applied to the drawable of this
+     * ImageView (between 0 and 255 inclusive, with 0 being transparent and
+     * 255 being opaque)
      *
      * @see #setImageAlpha(int)
      */
@@ -1437,7 +1454,8 @@
     /**
      * Sets the alpha value that should be applied to the image.
      *
-     * @param alpha the alpha value that should be applied to the image
+     * @param alpha the alpha value that should be applied to the image (between
+     * 0 and 255 inclusive, with 0 being transparent and 255 being opaque)
      *
      * @see #getImageAlpha()
      */
@@ -1513,11 +1531,40 @@
     @Override
     public void onVisibilityAggregated(boolean isVisible) {
         super.onVisibilityAggregated(isVisible);
-        if (mDrawable != null) {
+        // Only do this for new apps post-Nougat
+        if (mDrawable != null && !sCompatDrawableVisibilityDispatch) {
             mDrawable.setVisible(isVisible, false);
         }
     }
 
+    @RemotableViewMethod
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+        if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+            mDrawable.setVisible(visibility == VISIBLE, false);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+        if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+            mDrawable.setVisible(getVisibility() == VISIBLE, false);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+        if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+            mDrawable.setVisible(false, false);
+        }
+    }
+
     @Override
     public CharSequence getAccessibilityClassName() {
         return ImageView.class.getName();
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index e2c535c..6511de8 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1935,8 +1935,8 @@
             @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
             @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
             @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
-            @ViewDebug.IntToString(from = Gravity.START,            to = "START"),
-            @ViewDebug.IntToString(from = Gravity.END,             to = "END"),
+            @ViewDebug.IntToString(from = Gravity.START,             to = "START"),
+            @ViewDebug.IntToString(from = Gravity.END,               to = "END"),
             @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
             @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
             @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 82f5f01..72b2e31 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
 import android.annotation.TestApi;
@@ -30,10 +32,12 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.TextWatcher;
 import android.text.method.NumberKeyListener;
 import android.util.AttributeSet;
 import android.util.SparseArray;
@@ -53,9 +57,6 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
-import com.android.internal.R;
-import libcore.icu.LocaleData;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -63,6 +64,8 @@
 import java.util.List;
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
 /**
  * A widget that enables the user to select a number from a predefined range.
  * There are two flavors of this widget and which one is presented to the user
@@ -2008,7 +2011,7 @@
             removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
         }
         if (mSetSelectionCommand != null) {
-            removeCallbacks(mSetSelectionCommand);
+            mSetSelectionCommand.cancel();
         }
         if (mBeginSoftInputOnLongPressCommand != null) {
             removeCallbacks(mBeginSoftInputOnLongPressCommand);
@@ -2050,18 +2053,14 @@
     }
 
     /**
-     * Posts an {@link SetSelectionCommand} from the given <code>selectionStart
-     * </code> to <code>selectionEnd</code>.
+     * Posts a {@link SetSelectionCommand} from the given
+     * {@code selectionStart} to {@code selectionEnd}.
      */
     private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
         if (mSetSelectionCommand == null) {
-            mSetSelectionCommand = new SetSelectionCommand();
-        } else {
-            removeCallbacks(mSetSelectionCommand);
+            mSetSelectionCommand = new SetSelectionCommand(mInputText);
         }
-        mSetSelectionCommand.mSelectionStart = selectionStart;
-        mSetSelectionCommand.mSelectionEnd = selectionEnd;
-        post(mSetSelectionCommand);
+        mSetSelectionCommand.post(selectionStart, selectionEnd);
     }
 
     /**
@@ -2107,6 +2106,12 @@
         @Override
         public CharSequence filter(
                 CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+            // We don't know what the output will be, so always cancel any
+            // pending set selection command.
+            if (mSetSelectionCommand != null) {
+                mSetSelectionCommand.cancel();
+            }
+
             if (mDisplayedValues == null) {
                 CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
                 if (filtered == null) {
@@ -2254,12 +2259,39 @@
     /**
      * Command for setting the input text selection.
      */
-    class SetSelectionCommand implements Runnable {
-        private int mSelectionStart;
+    private static class SetSelectionCommand implements Runnable {
+        private final EditText mInputText;
 
+        private int mSelectionStart;
         private int mSelectionEnd;
 
+        /** Whether this runnable is currently posted. */
+        private boolean mPosted;
+
+        public SetSelectionCommand(EditText inputText) {
+            mInputText = inputText;
+        }
+
+        public void post(int selectionStart, int selectionEnd) {
+            mSelectionStart = selectionStart;
+            mSelectionEnd = selectionEnd;
+
+            if (!mPosted) {
+                mInputText.post(this);
+                mPosted = true;
+            }
+        }
+
+        public void cancel() {
+            if (mPosted) {
+                mInputText.removeCallbacks(this);
+                mPosted = false;
+            }
+        }
+
+        @Override
         public void run() {
+            mPosted = false;
             mInputText.setSelection(mSelectionStart, mSelectionEnd);
         }
     }
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 50569d7..9938789 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -89,8 +89,9 @@
      * means no bounce. This behavior is no longer supported and this coefficient has no effect.
      * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This
      * behavior is no longer supported and this coefficient has no effect.
-     * !deprecated Use {!link #OverScroller(Context, Interpolator, boolean)} instead.
+     * @deprecated Use {@link #OverScroller(Context, Interpolator)} instead.
      */
+    @Deprecated
     public OverScroller(Context context, Interpolator interpolator,
             float bounceCoefficientX, float bounceCoefficientY) {
         this(context, interpolator, true);
@@ -107,8 +108,9 @@
      * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This
      * behavior is no longer supported and this coefficient has no effect.
      * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
-     * !deprecated Use {!link OverScroller(Context, Interpolator, boolean)} instead.
+     * @deprecated Use {@link #OverScroller(Context, Interpolator)} instead.
      */
+    @Deprecated
     public OverScroller(Context context, Interpolator interpolator,
             float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) {
         this(context, interpolator, flywheel);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 167d526..5e73a63 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -193,6 +193,8 @@
 
     private int mAnimationStyle = ANIMATION_STYLE_DEFAULT;
 
+    private int mGravity = Gravity.NO_GRAVITY;
+
     private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
         com.android.internal.R.attr.state_above_anchor
     };
@@ -1141,15 +1143,11 @@
 
         mIsShowing = true;
         mIsDropdown = false;
+        mGravity = gravity;
 
         final WindowManager.LayoutParams p = createPopupLayoutParams(token);
         preparePopup(p);
 
-        // Only override the default if some gravity was specified.
-        if (gravity != Gravity.NO_GRAVITY) {
-            p.gravity = gravity;
-        }
-
         p.x = x;
         p.y = y;
 
@@ -1394,8 +1392,8 @@
     }
 
     private int computeGravity() {
-        int gravity = Gravity.START | Gravity.TOP;
-        if (mClipToScreen || mClippingEnabled) {
+        int gravity = mGravity == Gravity.NO_GRAVITY ?  Gravity.START | Gravity.TOP : mGravity;
+        if (mIsDropdown && (mClipToScreen || mClippingEnabled)) {
             gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
         }
         return gravity;
@@ -1760,11 +1758,22 @@
      */
     public int getMaxAvailableHeight(
             @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
-        final Rect displayFrame = new Rect();
+        Rect displayFrame = null;
+        final Rect visibleDisplayFrame = new Rect();
+
+        anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame);
         if (ignoreBottomDecorations) {
+            // In the ignore bottom decorations case we want to
+            // still respect all other decorations so we use the inset visible
+            // frame on the top right and left and take the bottom
+            // value from the full frame.
+            displayFrame = new Rect();
             anchor.getWindowDisplayFrame(displayFrame);
+            displayFrame.top = visibleDisplayFrame.top;
+            displayFrame.right = visibleDisplayFrame.right;
+            displayFrame.left = visibleDisplayFrame.left;
         } else {
-            anchor.getWindowVisibleDisplayFrame(displayFrame);
+            displayFrame = visibleDisplayFrame;
         }
 
         final int[] anchorPos = mTmpDrawingLocation;
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 6f198e7..5a0e1f9 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.view.PointerIcon;
 import com.android.internal.R;
 import com.android.internal.widget.ExploreByTouchHelper;
 
@@ -1052,6 +1053,18 @@
         invalidate();
     }
 
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (!isEnabled()) {
+            return null;
+        }
+        final int degrees = getDegreesFromXY(event.getX(), event.getY(), false);
+        if (degrees != -1) {
+            return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
+
     private class RadialPickerTouchHelper extends ExploreByTouchHelper {
         private final Rect mTempRect = new Rect();
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 0555cd4..e696ff7 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.NonNull;
+import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Parcel;
@@ -134,6 +135,8 @@
     private int mOverscrollDistance;
     private int mOverflingDistance;
 
+    private int mScrollFactor;
+
     /**
      * ID of the active pointer. This is used to retain consistency during
      * drags/flings if multiple pointers are used.
@@ -186,6 +189,10 @@
         setFillViewport(a.getBoolean(R.styleable.ScrollView_fillViewport, false));
 
         a.recycle();
+
+        if (context.getResources().getConfiguration().uiMode == Configuration.UI_MODE_TYPE_WATCH) {
+            setRevealOnFocusHint(false);
+        }
     }
 
     @Override
@@ -243,6 +250,7 @@
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mOverscrollDistance = configuration.getScaledOverscrollDistance();
         mOverflingDistance = configuration.getScaledOverflingDistance();
+        mScrollFactor = configuration.getScaledScrollFactor();
     }
 
     @Override
@@ -777,30 +785,35 @@
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_SCROLL: {
-                    if (!mIsBeingDragged) {
-                        final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                        if (vscroll != 0) {
-                            final int delta = (int) (vscroll * getVerticalScrollFactor());
-                            final int range = getScrollRange();
-                            int oldScrollY = mScrollY;
-                            int newScrollY = oldScrollY - delta;
-                            if (newScrollY < 0) {
-                                newScrollY = 0;
-                            } else if (newScrollY > range) {
-                                newScrollY = range;
-                            }
-                            if (newScrollY != oldScrollY) {
-                                super.scrollTo(mScrollX, newScrollY);
-                                return true;
-                            }
-                        }
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_SCROLL:
+                final float axisValue;
+                if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+                    axisValue = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                } else if (event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)) {
+                    axisValue = event.getAxisValue(MotionEvent.AXIS_SCROLL);
+                } else {
+                    axisValue = 0;
+                }
+
+                final int delta = Math.round(axisValue * mScrollFactor);
+                if (delta != 0) {
+                    final int range = getScrollRange();
+                    int oldScrollY = mScrollY;
+                    int newScrollY = oldScrollY - delta;
+                    if (newScrollY < 0) {
+                        newScrollY = 0;
+                    } else if (newScrollY > range) {
+                        newScrollY = range;
+                    }
+                    if (newScrollY != oldScrollY) {
+                        super.scrollTo(mScrollX, newScrollY);
+                        return true;
                     }
                 }
-            }
+                break;
         }
+
         return super.onGenericMotionEvent(event);
     }
 
@@ -1455,11 +1468,13 @@
 
     @Override
     public void requestChildFocus(View child, View focused) {
-        if (!mIsLayoutDirty) {
-            scrollToChild(focused);
-        } else {
-            // The child may not be laid out yet, we can't compute the scroll yet
-            mChildToScrollTo = focused;
+        if (focused.getRevealOnFocusHint()) {
+            if (!mIsLayoutDirty) {
+                scrollToChild(focused);
+            } else {
+                // The child may not be laid out yet, we can't compute the scroll yet
+                mChildToScrollTo = focused;
+            }
         }
         super.requestChildFocus(child, focused);
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 5878cad..9139361 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -816,9 +816,11 @@
 
         switch (heightMode) {
             case MeasureSpec.AT_MOST:
-            case MeasureSpec.UNSPECIFIED:
                 height = Math.min(getPreferredHeight(), height);
                 break;
+            case MeasureSpec.UNSPECIFIED:
+                height = getPreferredHeight();
+                break;
         }
         heightMode = MeasureSpec.EXACTLY;
 
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 3a63e28..8c43782 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.view.PointerIcon;
 import com.android.internal.R;
 import com.android.internal.widget.ExploreByTouchHelper;
 
@@ -1025,6 +1026,21 @@
         return true;
     }
 
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (!isEnabled()) {
+            return null;
+        }
+        // Add 0.5f to event coordinates to match the logic in onTouchEvent.
+        final int x = (int) (event.getX() + 0.5f);
+        final int y = (int) (event.getY() + 0.5f);
+        final int dayUnderPointer = getDayAtLocation(x, y);
+        if (dayUnderPointer >= 0) {
+            return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
+
     /**
      * Provides a virtual view hierarchy for interfacing with an accessibility
      * service.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index e2df402..dc5e5a2 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.TestApi;
+import android.view.PointerIcon;
 import com.android.internal.R;
 import com.android.internal.view.menu.ShowableListMenu;
 
@@ -903,6 +904,14 @@
         }
     }
 
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (getPointerIcon() == null && isClickable() && isEnabled()) {
+            return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
+
     static class SavedState extends AbsSpinner.SavedState {
         boolean showDropdown;
 
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index eb81e6f..d51c5be 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -65,6 +65,9 @@
  * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and
  * the related setSwitchTypeface() methods control that of the thumb.
  *
+ * <p>{@link android.support.v7.widget.SwitchCompat} is a version of
+ * the Switch widget which runs on devices back to API 7.</p>
+ *
  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a>
  * guide.</p>
  *
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 20b771b..1f0cb7c 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import android.view.MotionEvent;
+import android.view.PointerIcon;
 import com.android.internal.R;
 
 import android.annotation.DrawableRes;
@@ -494,6 +496,10 @@
         child.setFocusable(true);
         child.setClickable(true);
 
+        if (child.getPointerIcon() == null) {
+            child.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND));
+        }
+
         super.addView(child);
 
         // TODO: detect this via geometry with a tabwidget listener rather
@@ -507,6 +513,14 @@
         mSelectedTab = -1;
     }
 
+    @Override
+    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+        if (!isEnabled()) {
+            return null;
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
+
     /**
      * Provides a way for {@link TabHost} to be notified that the user clicked
      * on a tab indicator.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6dafe34..5264d5c 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;
@@ -1310,6 +1310,10 @@
             createEditorIfNeeded();
             mEditor.mKeyListener = TextKeyListener.getInstance(autotext, cap);
             mEditor.mInputType = inputType;
+        } else if (editable) {
+            createEditorIfNeeded();
+            mEditor.mKeyListener = TextKeyListener.getInstance();
+            mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
         } else if (isTextSelectable()) {
             // Prevent text changes from keyboard.
             if (mEditor != null) {
@@ -1319,10 +1323,6 @@
             bufferType = BufferType.SPANNABLE;
             // So that selection can be changed using arrow keys and touch is handled.
             setMovementMethod(ArrowKeyMovementMethod.getInstance());
-        } else if (editable) {
-            createEditorIfNeeded();
-            mEditor.mKeyListener = TextKeyListener.getInstance();
-            mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
         } else {
             if (mEditor != null) mEditor.mKeyListener = null;
 
@@ -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) {
@@ -3260,6 +3242,10 @@
      * Sets the text color for all the states (normal, selected,
      * focused) to be this color.
      *
+     * @param color A color value in the form 0xAARRGGBB.
+     * Do not pass a resource ID. To get a color value from a resource ID, call
+     * {@link android.support.v4.content.ContextCompat#getColor(Context, int) getColor}.
+     *
      * @see #setTextColor(ColorStateList)
      * @see #getTextColors()
      *
@@ -8536,15 +8522,30 @@
             if (mMovement != null) {
                 handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
             }
-            handled |= mClickableSpanOnClickGestureDetector.onTouchEvent(event);
 
-            final boolean textIsSelectable = isTextSelectable();
-            if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
+            // 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);
+            }
+
+            if (touchIsFinished && (isTextEditable() || isTextSelectable())) {
                 // Show the IME, except when selecting in read-only text.
                 final InputMethodManager imm = InputMethodManager.peekInstance();
                 viewClicked(imm);
-                if (!textIsSelectable && mEditor.mShowSoftInputOnFocus) {
-                    handled |= imm != null && imm.showSoftInput(this, 0);
+                if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null) {
+                    imm.showSoftInput(this, 0);
                 }
 
                 // The above condition ensures that the mEditor is not null
@@ -8937,6 +8938,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/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 1bbe041..6a76c5b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,21 +16,24 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.Widget;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Parcelable.Creator;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
 
 import libcore.icu.LocaleData;
@@ -46,11 +49,36 @@
  */
 @Widget
 public class TimePicker extends FrameLayout {
-    private static final int MODE_SPINNER = 1;
-    private static final int MODE_CLOCK = 2;
+    /**
+     * Presentation mode for the Holo-style time picker that uses a set of
+     * {@link android.widget.NumberPicker}s.
+     *
+     * @see #getMode()
+     * @hide Visible for testing only.
+     */
+    @TestApi
+    public static final int MODE_SPINNER = 1;
+
+    /**
+     * Presentation mode for the Material-style time picker that uses a clock
+     * face.
+     *
+     * @see #getMode()
+     * @hide Visible for testing only.
+     */
+    @TestApi
+    public static final int MODE_CLOCK = 2;
+
+    /** @hide */
+    @IntDef({MODE_SPINNER, MODE_CLOCK})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TimePickerMode {}
 
     private final TimePickerDelegate mDelegate;
 
+    @TimePickerMode
+    private final int mMode;
+
     /**
      * The callback interface used to indicate the time has been adjusted.
      */
@@ -81,10 +109,19 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
+        final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false);
+        final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
         a.recycle();
 
-        switch (mode) {
+        if (requestedMode == MODE_CLOCK && isDialogMode) {
+            // You want MODE_CLOCK? YOU CAN'T HANDLE MODE_CLOCK! Well, maybe
+            // you can depending on your screen size. Let's check...
+            mMode = context.getResources().getInteger(R.integer.time_picker_mode);
+        } else {
+            mMode = requestedMode;
+        }
+
+        switch (mMode) {
             case MODE_CLOCK:
                 mDelegate = new TimePickerClockDelegate(
                         this, context, attrs, defStyleAttr, defStyleRes);
@@ -98,13 +135,25 @@
     }
 
     /**
+     * @return the picker's presentation mode, one of {@link #MODE_CLOCK} or
+     *         {@link #MODE_SPINNER}
+     * @attr ref android.R.styleable#TimePicker_timePickerMode
+     * @hide Visible for testing only.
+     */
+    @TimePickerMode
+    @TestApi
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
      * Sets the currently selected hour using 24-hour time.
      *
      * @param hour the hour to set, in the range (0-23)
      * @see #getHour()
      */
-    public void setHour(int hour) {
-        mDelegate.setHour(hour);
+    public void setHour(@IntRange(from = 0, to = 23) int hour) {
+        mDelegate.setHour(MathUtils.constrain(hour, 0, 23));
     }
 
     /**
@@ -118,13 +167,13 @@
     }
 
     /**
-     * Sets the currently selected minute..
+     * Sets the currently selected minute.
      *
      * @param minute the minute to set, in the range (0-59)
      * @see #getMinute()
      */
-    public void setMinute(int minute) {
-        mDelegate.setMinute(minute);
+    public void setMinute(@IntRange(from = 0, to = 59) int minute) {
+        mDelegate.setMinute(MathUtils.constrain(minute, 0, 59));
     }
 
     /**
@@ -138,8 +187,9 @@
     }
 
     /**
-     * Sets the current hour.
+     * Sets the currently selected hour using 24-hour time.
      *
+     * @param currentHour the hour to set, in the range (0-23)
      * @deprecated Use {@link #setHour(int)}
      */
     @Deprecated
@@ -148,33 +198,34 @@
     }
 
     /**
-     * @return the current hour in the range (0-23)
+     * @return the currently selected hour, in the range (0-23)
      * @deprecated Use {@link #getHour()}
      */
     @NonNull
     @Deprecated
     public Integer getCurrentHour() {
-        return mDelegate.getHour();
+        return getHour();
     }
 
     /**
-     * Set the current minute (0-59).
+     * Sets the currently selected minute.
      *
+     * @param currentMinute the minute to set, in the range (0-59)
      * @deprecated Use {@link #setMinute(int)}
      */
     @Deprecated
     public void setCurrentMinute(@NonNull Integer currentMinute) {
-        mDelegate.setMinute(currentMinute);
+        setMinute(currentMinute);
     }
 
     /**
-     * @return the current minute
+     * @return the currently selected minute, in the range (0-59)
      * @deprecated Use {@link #getMinute()}
      */
     @NonNull
     @Deprecated
     public Integer getCurrentMinute() {
-        return mDelegate.getMinute();
+        return getMinute();
     }
 
     /**
@@ -281,10 +332,10 @@
      * for the real behavior.
      */
     interface TimePickerDelegate {
-        void setHour(int hour);
+        void setHour(@IntRange(from = 0, to = 23) int hour);
         int getHour();
 
-        void setMinute(int minute);
+        void setMinute(@IntRange(from = 0, to = 59) int minute);
         int getMinute();
 
         void setIs24Hour(boolean is24Hour);
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index e147ed6..4efcb09 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -25,6 +25,8 @@
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -326,13 +328,6 @@
     }
 
     private static class TN extends ITransientNotification.Stub {
-        final Runnable mShow = new Runnable() {
-            @Override
-            public void run() {
-                handleShow();
-            }
-        };
-
         final Runnable mHide = new Runnable() {
             @Override
             public void run() {
@@ -343,7 +338,13 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler();
+        final Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                IBinder token = (IBinder) msg.obj;
+                handleShow(token);
+            }
+        };
 
         int mGravity;
         int mX, mY;
@@ -379,9 +380,9 @@
          * schedule handleShow into the right thread
          */
         @Override
-        public void show() {
+        public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
-            mHandler.post(mShow);
+            mHandler.obtainMessage(0, windowToken).sendToTarget();
         }
 
         /**
@@ -393,7 +394,7 @@
             mHandler.post(mHide);
         }
 
-        public void handleShow() {
+        public void handleShow(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -422,8 +423,9 @@
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 mParams.packageName = packageName;
-                mParams.removeTimeoutMilliseconds = mDuration ==
+                mParams.hideTimeoutMilliseconds = mDuration ==
                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
+                mParams.token = windowToken;
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
@@ -458,7 +460,7 @@
                 // the view isn't yet added, so let's try not to crash.
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
-                    mWM.removeView(mView);
+                    mWM.removeViewImmediate(mView);
                 }
 
                 mView = null;
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f084db2..b973324 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -70,46 +70,49 @@
  */
 public class VideoView extends SurfaceView
         implements MediaPlayerControl, SubtitleController.Anchor {
-    private String TAG = "VideoView";
-    // settable by the client
-    private Uri         mUri;
-    private Map<String, String> mHeaders;
+    private static final String TAG = "VideoView";
 
     // all possible internal states
-    private static final int STATE_ERROR              = -1;
-    private static final int STATE_IDLE               = 0;
-    private static final int STATE_PREPARING          = 1;
-    private static final int STATE_PREPARED           = 2;
-    private static final int STATE_PLAYING            = 3;
-    private static final int STATE_PAUSED             = 4;
+    private static final int STATE_ERROR = -1;
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_PREPARING = 1;
+    private static final int STATE_PREPARED = 2;
+    private static final int STATE_PLAYING = 3;
+    private static final int STATE_PAUSED = 4;
     private static final int STATE_PLAYBACK_COMPLETED = 5;
 
+    private final Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks = new Vector<>();
+
+    // settable by the client
+    private Uri mUri;
+    private Map<String, String> mHeaders;
+
     // mCurrentState is a VideoView object's current state.
     // mTargetState is the state that a method caller intends to reach.
     // For instance, regardless the VideoView object's current state,
     // calling pause() intends to bring the object to a target state
     // of STATE_PAUSED.
     private int mCurrentState = STATE_IDLE;
-    private int mTargetState  = STATE_IDLE;
+    private int mTargetState = STATE_IDLE;
 
     // All the stuff we need for playing and showing a video
     private SurfaceHolder mSurfaceHolder = null;
     private MediaPlayer mMediaPlayer = null;
-    private int         mAudioSession;
-    private int         mVideoWidth;
-    private int         mVideoHeight;
-    private int         mSurfaceWidth;
-    private int         mSurfaceHeight;
+    private int mAudioSession;
+    private int mVideoWidth;
+    private int mVideoHeight;
+    private int mSurfaceWidth;
+    private int mSurfaceHeight;
     private MediaController mMediaController;
     private OnCompletionListener mOnCompletionListener;
     private MediaPlayer.OnPreparedListener mOnPreparedListener;
-    private int         mCurrentBufferPercentage;
+    private int mCurrentBufferPercentage;
     private OnErrorListener mOnErrorListener;
-    private OnInfoListener  mOnInfoListener;
-    private int         mSeekWhenPrepared;  // recording the seek position while preparing
-    private boolean     mCanPause;
-    private boolean     mCanSeekBack;
-    private boolean     mCanSeekForward;
+    private OnInfoListener mOnInfoListener;
+    private int mSeekWhenPrepared;  // recording the seek position while preparing
+    private boolean mCanPause;
+    private boolean mCanSeekBack;
+    private boolean mCanSeekForward;
 
     /** Subtitle rendering widget overlaid on top of the video. */
     private RenderingWidget mSubtitleWidget;
@@ -118,13 +121,11 @@
     private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
 
     public VideoView(Context context) {
-        super(context);
-        initVideoView();
+        this(context, null);
     }
 
     public VideoView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
-        initVideoView();
     }
 
     public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -133,7 +134,19 @@
 
     public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        initVideoView();
+
+        mVideoWidth = 0;
+        mVideoHeight = 0;
+
+        getHolder().addCallback(mSHCallback);
+        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        requestFocus();
+
+        mCurrentState = STATE_IDLE;
+        mTargetState = STATE_IDLE;
     }
 
     @Override
@@ -209,19 +222,6 @@
         return getDefaultSize(desiredSize, measureSpec);
     }
 
-    private void initVideoView() {
-        mVideoWidth = 0;
-        mVideoHeight = 0;
-        getHolder().addCallback(mSHCallback);
-        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-        setFocusable(true);
-        setFocusableInTouchMode(true);
-        requestFocus();
-        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
-        mCurrentState = STATE_IDLE;
-        mTargetState  = STATE_IDLE;
-    }
-
     /**
      * Sets video path.
      *
@@ -294,8 +294,6 @@
         }
     }
 
-    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
-
     public void stopPlayback() {
         if (mMediaPlayer != null) {
             mMediaPlayer.stop();
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index 7d4f8ed..5cff335 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -23,6 +23,19 @@
 import android.view.View;
 import android.view.View.OnLongClickListener;
 
+/**
+ * This widget provides a simple utility for turning a continued long-press event
+ * into a series of clicks at some set frequency. There is no actual 'zoom' functionality
+ * handled by this widget directly. Instead, clients of this API should set up an
+ * {@link View#setOnClickListener(OnClickListener) onClickListener} to handle
+ * zoom functionality. That click listener is called on a frequency
+ * determined by {@link #setZoomSpeed(long)} whenever the user long-presses
+ * on the ZoomButton.
+ *
+ * @deprecated Use other means to handle this functionality. This widget is merely a
+ * simple wrapper around a long-press handler.
+ */
+@Deprecated
 public class ZoomButton extends ImageButton implements OnLongClickListener {
 
     private final Runnable mRunnable = new Runnable() {
@@ -62,11 +75,18 @@
         }
         return super.onTouchEvent(event);
     }
-        
+
+    /**
+     * Sets the delay between calls to the widget's {@link View#setOnClickListener(OnClickListener)
+     * onClickListener}.
+     *
+     * @param speed The delay between calls to the click listener, in milliseconds
+     */
     public void setZoomSpeed(long speed) {
         mZoomSpeed = speed;
     }
 
+    @Override
     public boolean onLongClick(View v) {
         mIsInLongpress = true;
         post(mRunnable);
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index c0c8aec..fb912a4 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -69,7 +69,10 @@
  * {@link View#onDetachedFromWindow} and from {@link View#onVisibilityChanged}
  * when <code>visibility != View.VISIBLE</code>.
  *
+ * @deprecated This functionality and UI is better handled with custom views and layouts
+ * rather than a dedicated zoom-control widget
  */
+@Deprecated
 public class ZoomButtonsController implements View.OnTouchListener {
 
     private static final String TAG = "ZoomButtonsController";
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 5aeb7f9..95c291a 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -888,7 +888,8 @@
             final int checkedItem = mCheckedItem;
             if (checkedItem > -1) {
                 listView.setItemChecked(checkedItem, true);
-                listView.setSelection(checkedItem);
+                listView.setSelectionFromTop(checkedItem,
+                        a.getDimensionPixelSize(R.styleable.AlertDialog_selectionScrollOffset, 0));
             }
         }
     }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0a4ac0d..1e26c92 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1469,7 +1469,7 @@
                 boolean found = false;
                 // Only loop to the end of into as it was before we started; no dupes in from.
                 for (int j = 0; j < intoCount; j++) {
-                    final ResolvedComponentInfo rci = into.get(i);
+                    final ResolvedComponentInfo rci = into.get(j);
                     if (isSameResolvedComponent(newInfo, rci)) {
                         found = true;
                         rci.add(intent, newInfo);
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 03a3a38..4d4c7ce 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -157,7 +157,10 @@
 
         // We want to put the one targeted to another user at the end of the dialog.
         if (lhs.targetUserId != UserHandle.USER_CURRENT) {
-            return 1;
+            return rhs.targetUserId != UserHandle.USER_CURRENT ? 0 : 1;
+        }
+        if (rhs.targetUserId != UserHandle.USER_CURRENT) {
+            return -1;
         }
 
         if (mHttp) {
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index a4b5a8e..cb2b019 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -145,7 +145,11 @@
                 if (itemType == TYPE_HEADER_SUGGESTED) {
                     textView.setText(R.string.language_picker_section_suggested);
                 } else {
-                    textView.setText(R.string.language_picker_section_all);
+                    if (mCountryMode) {
+                        textView.setText(R.string.region_picker_section_all);
+                    } else {
+                        textView.setText(R.string.language_picker_section_all);
+                    }
                 }
                 textView.setTextLocale(Locale.getDefault());
                 break;
diff --git a/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
new file mode 100644
index 0000000..62f18ea
--- /dev/null
+++ b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
@@ -0,0 +1,254 @@
+/*
+ * 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.internal.graphics.drawable;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * An internal DrawableContainer class, used to draw different things depending on animation scale.
+ * i.e: animation scale can be 0 in battery saver mode.
+ * This class contains 2 drawable, one is animatable, the other is static. When animation scale is
+ * not 0, the animatable drawable will the drawn. Otherwise, the static drawable will be drawn.
+ * <p>This class implements Animatable since ProgressBar can pick this up similarly as an
+ * AnimatedVectorDrawable.
+ * <p>It can be defined in an XML file with the {@code <AnimationScaleListDrawable>}
+ * element.
+ */
+public class AnimationScaleListDrawable extends DrawableContainer implements Animatable {
+    private static final String TAG = "AnimationScaleListDrawable";
+    private AnimationScaleListState mAnimationScaleListState;
+    private boolean mMutated;
+
+    public AnimationScaleListDrawable() {
+        this(null, null);
+    }
+
+    private AnimationScaleListDrawable(@Nullable AnimationScaleListState state,
+            @Nullable Resources res) {
+        // Every scale list drawable has its own constant state.
+        final AnimationScaleListState newState = new AnimationScaleListState(state, this, res);
+        setConstantState(newState);
+        onStateChange(getState());
+    }
+
+    /**
+     * Set the current drawable according to the animation scale. If scale is 0, then pick the
+     * static drawable, otherwise, pick the animatable drawable.
+     */
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final boolean changed = super.onStateChange(stateSet);
+        int idx = mAnimationScaleListState.getCurrentDrawableIndexBasedOnScale();
+        return selectDrawable(idx) || changed;
+    }
+
+
+    @Override
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs,
+                R.styleable.AnimationScaleListDrawable);
+        updateDensity(r);
+        a.recycle();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        onStateChange(getState());
+    }
+
+    /**
+     * Inflates child elements from XML.
+     */
+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final AnimationScaleListState state = mAnimationScaleListState;
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            // Either pick up the android:drawable attribute.
+            final TypedArray a = obtainAttributes(r, theme, attrs,
+                    R.styleable.AnimationScaleListDrawableItem);
+            Drawable dr = a.getDrawable(R.styleable.AnimationScaleListDrawableItem_drawable);
+            a.recycle();
+
+            // Or parse the child element under <item>.
+            if (dr == null) {
+                while ((type = parser.next()) == XmlPullParser.TEXT) {
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException(
+                            parser.getPositionDescription()
+                                    + ": <item> tag requires a 'drawable' attribute or "
+                                    + "child tag defining a drawable");
+                }
+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+            }
+
+            state.addDrawable(dr);
+        }
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mAnimationScaleListState.mutate();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
+    @Override
+    public void start() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).start();
+        }
+    }
+
+    @Override
+    public void stop() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).stop();
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        boolean result = false;
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            result = ((Animatable) dr).isRunning();
+        }
+        return result;
+    }
+
+    static class AnimationScaleListState extends DrawableContainerState {
+        int[] mThemeAttrs = null;
+        // The index of the last static drawable.
+        int mStaticDrawableIndex = -1;
+        // The index of the last animatable drawable.
+        int mAnimatableDrawableIndex = -1;
+
+        AnimationScaleListState(AnimationScaleListState orig, AnimationScaleListDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
+
+            if (orig != null) {
+                // Perform a shallow copy and rely on mutate() to deep-copy.
+                mThemeAttrs = orig.mThemeAttrs;
+
+                mStaticDrawableIndex = orig.mStaticDrawableIndex;
+                mAnimatableDrawableIndex = orig.mAnimatableDrawableIndex;
+            }
+
+        }
+
+        void mutate() {
+            mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
+        }
+
+        /**
+         * Add the drawable into the container.
+         * This class only keep track one animatable drawable, and one static. If there are multiple
+         * defined in the XML, then pick the last one.
+         */
+        int addDrawable(Drawable drawable) {
+            final int pos = addChild(drawable);
+            if (drawable instanceof Animatable) {
+                mAnimatableDrawableIndex = pos;
+            } else {
+                mStaticDrawableIndex = pos;
+            }
+            return pos;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimationScaleListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimationScaleListDrawable(this, res);
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || super.canApplyTheme();
+        }
+
+        public int getCurrentDrawableIndexBasedOnScale() {
+            if (ValueAnimator.getDurationScale() == 0) {
+                return mStaticDrawableIndex;
+            }
+            return mAnimatableDrawableIndex;
+        }
+    }
+
+    @Override
+    public void applyTheme(@NonNull Theme theme) {
+        super.applyTheme(theme);
+
+        onStateChange(getState());
+    }
+
+    @Override
+    protected void setConstantState(@NonNull DrawableContainerState state) {
+        super.setConstantState(state);
+
+        if (state instanceof AnimationScaleListState) {
+            mAnimationScaleListState = (AnimationScaleListState) state;
+        }
+    }
+}
+
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index c067da7..3baccee 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -36,6 +36,8 @@
     public static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
     public static final String NO_CLASS_ERROR_CODE = "Error type 3";
 
+    private String[] mRawArgs;
+
     /**
      * Call to run the command.
      */
@@ -45,7 +47,8 @@
             return;
         }
 
-        mArgs.init(null, null, null, null, args, 0);
+        mRawArgs = args;
+        mArgs.init(null, null, null, null, args, null, 0);
 
         try {
             onRun();
@@ -109,4 +112,11 @@
     public String nextArgRequired() {
         return mArgs.getNextArgRequired();
     }
+
+    /**
+     * Return the original raw argument list supplied to the command.
+     */
+    public String[] getRawArgs() {
+        return mRawArgs;
+    }
 }
diff --git a/core/java/com/android/internal/os/IShellCallback.aidl b/core/java/com/android/internal/os/IShellCallback.aidl
new file mode 100644
index 0000000..57d6789
--- /dev/null
+++ b/core/java/com/android/internal/os/IShellCallback.aidl
@@ -0,0 +1,24 @@
+/**
+ * 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.internal.os;
+
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IShellCallback {
+    ParcelFileDescriptor openOutputFile(String path, String seLinuxContext);
+}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index b7e5718..e46dfc4 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -39,6 +39,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.List;
 import java.util.StringTokenizer;
 
 public class ProcessCpuTracker {
@@ -177,6 +178,11 @@
 
     private byte[] mBuffer = new byte[4096];
 
+    public interface FilterStats {
+        /** Which stats to pick when filtering */
+        boolean needed(Stats stats);
+    }
+
     public static class Stats {
         public final int pid;
         public final int uid;
@@ -695,6 +701,18 @@
         return mProcStats.get(index);
     }
 
+    final public List<Stats> getStats(FilterStats filter) {
+        final ArrayList<Stats> statses = new ArrayList<>(mProcStats.size());
+        final int N = mProcStats.size();
+        for (int p = 0; p < N; p++) {
+            Stats stats = mProcStats.get(p);
+            if (filter.needed(stats)) {
+                statses.add(stats);
+            }
+        }
+        return statses;
+    }
+
     final public int countWorkingStats() {
         buildWorkingProcs();
         return mWorkingProcs.size();
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
new file mode 100644
index 0000000..80c55fb
--- /dev/null
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -0,0 +1,51 @@
+/*
+ * 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.internal.os;
+
+import android.os.SystemProperties;
+
+/**
+ * This is a cache of various ro.* properties so that they can be read just once
+ * at class init time.
+ */
+public class RoSystemProperties {
+    public static final boolean DEBUGGABLE =
+            SystemProperties.getInt("ro.debuggable", 0) == 1;
+    public static final int FACTORYTEST =
+            SystemProperties.getInt("ro.factorytest", 0);
+
+    // ------ ro.config.* -------- //
+    public static final boolean CONFIG_LOW_RAM =
+            SystemProperties.getBoolean("ro.config.low_ram", false);
+
+    // ------ ro.fw.* ------------ //
+    public static final boolean FW_SYSTEM_USER_SPLIT =
+            SystemProperties.getBoolean("ro.fw.system_user_split", false);
+
+    // ------ ro.crypto.* -------- //
+    public static final String CRYPTO_STATE = SystemProperties.get("ro.crypto.state");
+    public static final String CRYPTO_TYPE = SystemProperties.get("ro.crypto.type");
+    // These are pseudo-properties
+    public static final boolean CRYPTO_ENCRYPTABLE =
+            !CRYPTO_STATE.isEmpty() && !"unsupported".equals(CRYPTO_STATE);
+    public static final boolean CRYPTO_ENCRYPTED =
+            "encrypted".equalsIgnoreCase(CRYPTO_STATE);
+    public static final boolean CRYPTO_FILE_ENCRYPTED =
+            "file".equalsIgnoreCase(CRYPTO_TYPE);
+    public static final boolean CRYPTO_BLOCK_ENCRYPTED =
+            "block".equalsIgnoreCase(CRYPTO_TYPE);
+}
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
index 3bd79f7e..d175202 100644
--- a/core/java/com/android/internal/os/WifiPowerEstimator.java
+++ b/core/java/com/android/internal/os/WifiPowerEstimator.java
@@ -38,13 +38,13 @@
     }
 
     /**
-     * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio.
+     * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
      */
     private static double getWifiPowerPerPacket(PowerProfile profile) {
         final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
         final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
                 / 3600;
-        return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60);
+        return WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048);
     }
 
     @Override
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 132b022..b8fa034 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,6 +24,7 @@
 
 import android.net.Credentials;
 import android.net.LocalSocket;
+import android.os.FactoryTest;
 import android.os.Process;
 import android.os.SELinux;
 import android.os.SystemProperties;
@@ -615,13 +616,10 @@
             throws ZygoteSecurityException {
 
         if (peer.getUid() == Process.SYSTEM_UID) {
-            String factoryTest = SystemProperties.get("ro.factorytest");
-            boolean uidRestricted;
-
             /* In normal operation, SYSTEM_UID can only specify a restricted
              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
              */
-            uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
+            boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
 
             if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
                 throw new ZygoteSecurityException(
@@ -651,7 +649,7 @@
      * @param args non-null; zygote spawner args
      */
     public static void applyDebuggerSystemProperty(Arguments args) {
-        if ("1".equals(SystemProperties.get("ro.debuggable"))) {
+        if (RoSystemProperties.DEBUGGABLE) {
             args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
         }
     }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 40b9ab6..59a3563 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -631,6 +631,13 @@
         // an error.
         ZygoteHooks.startZygoteNoThreadCreation();
 
+        // Zygote goes into its own process group.
+        try {
+            Os.setpgid(0, 0);
+        } catch (ErrnoException ex) {
+            throw new RuntimeException("Failed to setpgid(0,0)", ex);
+        }
+
         try {
             Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
             RuntimeInit.enableDdms();
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 619303f..1abb59b 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -110,12 +110,15 @@
             int statusBarColor, int navigationBarColor) {
         mDecorView = decorView;
         mResizingBackgroundDrawable = resizingBackgroundDrawable != null
+                        && resizingBackgroundDrawable.getConstantState() != null
                 ? resizingBackgroundDrawable.getConstantState().newDrawable()
                 : null;
         mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
+                        && captionBackgroundDrawableDrawable.getConstantState() != null
                 ? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
                 : null;
         mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
+                        && userCaptionBackgroundDrawable.getConstantState() != null
                 ? userCaptionBackgroundDrawable.getConstantState().newDrawable()
                 : null;
         if (mCaptionBackgroundDrawable == null) {
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/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
new file mode 100644
index 0000000..bed7c1ba
--- /dev/null
+++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
@@ -0,0 +1,101 @@
+/*
+ * 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.internal.policy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+
+/**
+ * A class that manages emergency affordances and enables immediate calling to emergency services
+ */
+public class EmergencyAffordanceManager {
+
+    public static final boolean ENABLED = true;
+
+    /**
+     * Global setting override with the number to call with the emergency affordance.
+     * @hide
+     */
+    private static final String EMERGENCY_CALL_NUMBER_SETTING = "emergency_affordance_number";
+
+    /**
+     * Global setting, whether the emergency affordance should be shown regardless of device state.
+     * The value is a boolean (1 or 0).
+     * @hide
+     */
+    private static final String FORCE_EMERGENCY_AFFORDANCE_SETTING = "force_emergency_affordance";
+
+    private final Context mContext;
+
+    public EmergencyAffordanceManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * perform an emergency call.
+     */
+    public final void performEmergencyCall() {
+        performEmergencyCall(mContext);
+    }
+
+    private static Uri getPhoneUri(Context context) {
+        String number = context.getResources().getString(
+                com.android.internal.R.string.config_emergency_call_number);
+        if (Build.IS_DEBUGGABLE) {
+            String override = Settings.Global.getString(
+                    context.getContentResolver(), EMERGENCY_CALL_NUMBER_SETTING);
+            if (override != null) {
+                number = override;
+            }
+        }
+        return Uri.fromParts("tel", number, null);
+    }
+
+    private static void performEmergencyCall(Context context) {
+        Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
+        intent.setData(getPhoneUri(context));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    /**
+     * @return whether emergency affordance should be active.
+     */
+    public boolean needsEmergencyAffordance() {
+        if (!ENABLED) {
+            return false;
+        }
+        if (forceShowing()) {
+            return true;
+        }
+        return isEmergencyAffordanceNeeded();
+    }
+
+    private boolean isEmergencyAffordanceNeeded() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0) != 0;
+    }
+
+
+    private boolean forceShowing() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                FORCE_EMERGENCY_AFFORDANCE_SETTING, 0) != 0;
+    }
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 02e8af0..50dd33a 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -28,8 +28,9 @@
      * FLAG_SHOW_ON_LOCK_SCREEN.
      *
      * @param isOccluded Whether the Keyguard is occluded by another window.
+     * @param animate Whether to play an animation for the state change.
      */
-    void setOccluded(boolean isOccluded);
+    void setOccluded(boolean isOccluded, boolean animate);
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
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/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index 2cb9c25..fb0edea 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -150,6 +150,7 @@
                         sendCloseSystemWindows();
                         // Broadcast an intent that the Camera button was longpressed
                         Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
                         mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
                                 null, null, null, 0, null, null);
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 7d222c7..46098c5 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -108,7 +108,7 @@
         }
         if (stillScheduled) {
             Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
-            mHandler.handleMessage(msg);
+            mHandler.dispatchMessage(msg);
             msg.recycle();
         }
     }
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 831c646..effe219 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -17,6 +17,7 @@
 package com.android.internal.view;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.ActionMode;
 import android.view.Menu;
@@ -26,7 +27,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.util.DisplayMetrics;
+import android.view.WindowManager;
 
 import com.android.internal.R;
 import com.android.internal.util.Preconditions;
@@ -54,18 +55,23 @@
     private final Rect mScreenRect;
     private final View mOriginatingView;
     private final int mBottomAllowance;
+    private final Point mDisplaySize;
 
     private final Runnable mMovingOff = new Runnable() {
         public void run() {
-            mFloatingToolbarVisibilityHelper.setMoving(false);
-            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
+            if (isViewStillActive()) {
+                mFloatingToolbarVisibilityHelper.setMoving(false);
+                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
+            }
         }
     };
 
     private final Runnable mHideOff = new Runnable() {
         public void run() {
-            mFloatingToolbarVisibilityHelper.setHideRequested(false);
-            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
+            if (isViewStillActive()) {
+                mFloatingToolbarVisibilityHelper.setHideRequested(false);
+                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
+            }
         }
     };
 
@@ -103,6 +109,7 @@
         // bottom view bound if necessary.
         mBottomAllowance = context.getResources()
                 .getDimensionPixelSize(R.dimen.content_rect_bottom_clip_allowance);
+        mDisplaySize = new Point();
     }
 
     public void setFloatingToolbar(FloatingToolbar floatingToolbar) {
@@ -210,9 +217,9 @@
     }
 
     private boolean isContentRectWithinBounds() {
-        DisplayMetrics metrics = mContext.getApplicationContext()
-                .getResources().getDisplayMetrics();
-        mScreenRect.set(0, 0, metrics.widthPixels, metrics.heightPixels);
+        mContext.getSystemService(WindowManager.class)
+            .getDefaultDisplay().getRealSize(mDisplaySize);
+        mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
 
         return intersectsClosed(mContentRectOnScreen, mScreenRect)
             && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen);
@@ -298,6 +305,11 @@
         mOriginatingView.removeCallbacks(mHideOff);
     }
 
+    private boolean isViewStillActive() {
+        return mOriginatingView.getWindowVisibility() == View.VISIBLE
+                && mOriginatingView.isShown();
+    }
+
     /**
      * A helper for showing/hiding the floating toolbar depending on certain states.
      */
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 891c920..9bf0948 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -20,7 +20,9 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
@@ -265,4 +267,92 @@
 
         return 0;
     }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int paddingLeft = mPaddingLeft;
+
+        // Where right end of child should go
+        final int width = right - left;
+        final int childRight = width - mPaddingRight;
+
+        // Space available for child
+        final int childSpace = width - paddingLeft - mPaddingRight;
+
+        final int totalLength = getMeasuredHeight();
+        final int count = getChildCount();
+        final int gravity = getGravity();
+        final int majorGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int minorGravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
+
+        int childTop;
+        switch (majorGravity) {
+            case Gravity.BOTTOM:
+                // totalLength contains the padding already
+                childTop = mPaddingTop + bottom - top - totalLength;
+                break;
+
+            // totalLength contains the padding already
+            case Gravity.CENTER_VERTICAL:
+                childTop = mPaddingTop + (bottom - top - totalLength) / 2;
+                break;
+
+            case Gravity.TOP:
+            default:
+                childTop = mPaddingTop;
+                break;
+        }
+
+        final Drawable dividerDrawable = getDividerDrawable();
+        final int dividerHeight = dividerDrawable == null ?
+                0 : dividerDrawable.getIntrinsicHeight();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child != null && child.getVisibility() != GONE) {
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+
+                final LinearLayout.LayoutParams lp =
+                        (LinearLayout.LayoutParams) child.getLayoutParams();
+
+                int layoutGravity = lp.gravity;
+                if (layoutGravity < 0) {
+                    layoutGravity = minorGravity;
+                }
+                final int layoutDirection = getLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(
+                        layoutGravity, layoutDirection);
+
+                final int childLeft;
+                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+                                + lp.leftMargin - lp.rightMargin;
+                        break;
+
+                    case Gravity.RIGHT:
+                        childLeft = childRight - childWidth - lp.rightMargin;
+                        break;
+
+                    case Gravity.LEFT:
+                    default:
+                        childLeft = paddingLeft + lp.leftMargin;
+                        break;
+                }
+
+                if (hasDividerBeforeChildAt(i)) {
+                    childTop += dividerHeight;
+                }
+
+                childTop += lp.topMargin;
+                setChildFrame(child, childLeft, childTop, childWidth, childHeight);
+                childTop += childHeight + lp.bottomMargin;
+            }
+        }
+    }
+
+    private void setChildFrame(View child, int left, int top, int width, int height) {
+        child.layout(left, top, left + width, top + height);
+    }
 }
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 926ebd1..358be60 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -40,6 +40,9 @@
     /** Number of lines from the top to indent */
     private int mIndentLines;
 
+    /** Resolved layout direction */
+    private int mResolvedDirection = LAYOUT_DIRECTION_UNDEFINED;
+
     public ImageFloatingTextView(Context context) {
         this(context, null);
     }
@@ -82,7 +85,7 @@
                 margins[i] = endMargin;
             }
         }
-        if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+        if (mResolvedDirection == LAYOUT_DIRECTION_RTL) {
             builder.setIndents(margins, null);
         } else {
             builder.setIndents(null, margins);
@@ -91,6 +94,19 @@
         return builder.build();
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+
+        if (layoutDirection != mResolvedDirection && isLayoutDirectionResolved()) {
+            mResolvedDirection = layoutDirection;
+            if (mIndentLines > 0) {
+                // Invalidate layout.
+                setHint(getHint());
+            }
+        }
+    }
+
     @RemotableViewMethod
     public void setHasImage(boolean hasImage) {
         setNumIndentLines(hasImage ? 2 : 0);
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/java/com/android/internal/widget/WatchListDecorLayout.java b/core/java/com/android/internal/widget/WatchListDecorLayout.java
index 538ceca..5b49611 100644
--- a/core/java/com/android/internal/widget/WatchListDecorLayout.java
+++ b/core/java/com/android/internal/widget/WatchListDecorLayout.java
@@ -306,8 +306,9 @@
             if (mListView.getChildCount() > 0) {
                 if (mListView.getLastVisiblePosition() >= mListView.getCount() - 1) {
                     View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
-                    setScrolling(mBottomPanel,
-                            lastChild.getY() + lastChild.getHeight() - mBottomPanel.getTop());
+                    setScrolling(mBottomPanel, Math.max(
+                            0,
+                            lastChild.getY() + lastChild.getHeight() - mBottomPanel.getTop()));
                 } else {
                     // shift to hide the frame, last child is not the last position
                     setScrolling(mBottomPanel, mBottomPanel.getHeight());
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index fbc51cd..5a50fbf 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -79,6 +79,9 @@
     private static final String LOG_FILES_FILE = "log-files.xml";
     private static final AtomicFile sFile = new AtomicFile(new File(
             Environment.getDataSystemDirectory(), LOG_FILES_FILE));
+    private static final String LAST_HEADER_FILE = "last-header.txt";
+    private static final File lastHeaderFile = new File(
+            Environment.getDataSystemDirectory(), LAST_HEADER_FILE);
 
     @Override
     public void onReceive(final Context context, Intent intent) {
@@ -113,9 +116,17 @@
         Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
     }
 
-    private void logBootEvents(Context ctx) throws IOException {
-        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
-        final String headers = new StringBuilder(512)
+    private String getPreviousBootHeaders() {
+        try {
+            return FileUtils.readTextFile(lastHeaderFile, 0, null);
+        } catch (IOException e) {
+            Slog.e(TAG, "Error reading " + lastHeaderFile, e);
+            return null;
+        }
+    }
+
+    private String getCurrentBootHeaders() throws IOException {
+        return new StringBuilder(512)
             .append("Build: ").append(Build.FINGERPRINT).append("\n")
             .append("Hardware: ").append(Build.BOARD).append("\n")
             .append("Revision: ")
@@ -125,6 +136,31 @@
             .append("Kernel: ")
             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
             .append("\n").toString();
+    }
+
+
+    private String getBootHeadersToLogAndUpdate() throws IOException {
+        final String oldHeaders = getPreviousBootHeaders();
+        final String newHeaders = getCurrentBootHeaders();
+
+        try {
+            FileUtils.stringToFile(lastHeaderFile, newHeaders);
+        } catch (IOException e) {
+            Slog.e(TAG, "Error writing " + lastHeaderFile, e);
+        }
+
+        if (oldHeaders == null) {
+            // If we failed to read the old headers, use the current headers
+            // but note this in the headers so we know
+            return "isPrevious: false\n" + newHeaders;
+        }
+
+        return "isPrevious: true\n" + oldHeaders;
+    }
+
+    private void logBootEvents(Context ctx) throws IOException {
+        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
+        final String headers = getBootHeadersToLogAndUpdate();
         final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
 
         String recovery = RecoverySystem.handleAftermath(ctx);
diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
new file mode 100644
index 0000000..39b18c0
--- /dev/null
+++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
@@ -0,0 +1,85 @@
+/*
+ * 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.backup;
+
+import android.accounts.AccountManagerInternal;
+import android.app.backup.BlobBackupHelper;
+import android.os.UserHandle;
+import android.util.Slog;
+import com.android.server.LocalServices;
+
+/**
+ * Helper for handling backup of account manager specific state.
+ */
+public class AccountManagerBackupHelper extends BlobBackupHelper {
+    private static final String TAG = "AccountsBackup";
+    private static final boolean DEBUG = false;
+
+    // current schema of the backup state blob
+    private static final int STATE_VERSION = 1;
+
+    // key under which the account access grant state blob is committed to backup
+    private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
+
+    public AccountManagerBackupHelper() {
+        super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+        if (DEBUG) {
+            Slog.d(TAG, "Handling backup of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_ACCOUNT_ACCESS_GRANTS: {
+                    return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
+                }
+
+                default: {
+                    Slog.w(TAG, "Unexpected backup key " + key);
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to store payload " + key);
+        }
+
+        return new byte[0];
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+        if (DEBUG) {
+            Slog.d(TAG, "Handling restore of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_ACCOUNT_ACCESS_GRANTS: {
+                    am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
+                } break;
+
+                default: {
+                    Slog.w(TAG, "Unexpected restore key " + key);
+                }
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to restore key " + key);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 9d296fa..5375651 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -49,6 +49,7 @@
     private static final String PERMISSION_HELPER = "permissions";
     private static final String USAGE_STATS_HELPER = "usage_stats";
     private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
+    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -82,6 +83,7 @@
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
         super.onBackup(oldState, data, newState);
     }
 
@@ -111,6 +113,7 @@
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2a9498c..4c6350b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -19,10 +19,6 @@
     LOCAL_CFLAGS += -DENABLE_CPUSETS
 endif
 
-ifneq ($(ENABLE_SCHED_BOOST),)
-    LOCAL_CFLAGS += -DENABLE_SCHED_BOOST
-endif
-
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
@@ -80,6 +76,7 @@
     android_text_StaticLayout.cpp \
     android_os_Debug.cpp \
     android_os_HwBinder.cpp \
+    android_os_HwBlob.cpp \
     android_os_HwParcel.cpp \
     android_os_HwRemoteBinder.cpp \
     android_os_MemoryFile.cpp \
@@ -127,7 +124,6 @@
     android/graphics/PathMeasure.cpp \
     android/graphics/PathEffect.cpp \
     android/graphics/Picture.cpp \
-    android/graphics/PorterDuff.cpp \
     android/graphics/BitmapRegionDecoder.cpp \
     android/graphics/Rasterizer.cpp \
     android/graphics/Region.cpp \
@@ -135,7 +131,6 @@
     android/graphics/SurfaceTexture.cpp \
     android/graphics/Typeface.cpp \
     android/graphics/Utils.cpp \
-    android/graphics/Xfermode.cpp \
     android/graphics/YuvToJpegEncoder.cpp \
     android/graphics/pdf/PdfDocument.cpp \
     android/graphics/pdf/PdfEditor.cpp \
@@ -264,6 +259,7 @@
     libradio_metadata \
     libnativeloader \
     libmemunreachable \
+    libhidl \
     libhwbinder \
 
 LOCAL_SHARED_LIBRARIES += \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index dc27485..cdaa4dc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,11 +127,9 @@
 extern int register_android_graphics_Path(JNIEnv* env);
 extern int register_android_graphics_PathMeasure(JNIEnv* env);
 extern int register_android_graphics_Picture(JNIEnv*);
-extern int register_android_graphics_PorterDuff(JNIEnv* env);
 extern int register_android_graphics_Rasterizer(JNIEnv* env);
 extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
-extern int register_android_graphics_Xfermode(JNIEnv* env);
 extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
 extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
@@ -156,6 +154,7 @@
 extern int register_android_nio_utils(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_HwBinder(JNIEnv *env);
+extern int register_android_os_HwBlob(JNIEnv *env);
 extern int register_android_os_HwParcel(JNIEnv *env);
 extern int register_android_os_HwRemoteBinder(JNIEnv *env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
@@ -1290,6 +1289,7 @@
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_os_Parcel),
     REG_JNI(register_android_os_HwBinder),
+    REG_JNI(register_android_os_HwBlob),
     REG_JNI(register_android_os_HwParcel),
     REG_JNI(register_android_os_HwRemoteBinder),
     REG_JNI(register_android_nio_utils),
@@ -1341,13 +1341,11 @@
     REG_JNI(register_android_graphics_PathMeasure),
     REG_JNI(register_android_graphics_PathEffect),
     REG_JNI(register_android_graphics_Picture),
-    REG_JNI(register_android_graphics_PorterDuff),
     REG_JNI(register_android_graphics_Rasterizer),
     REG_JNI(register_android_graphics_Region),
     REG_JNI(register_android_graphics_Shader),
     REG_JNI(register_android_graphics_SurfaceTexture),
     REG_JNI(register_android_graphics_Typeface),
-    REG_JNI(register_android_graphics_Xfermode),
     REG_JNI(register_android_graphics_YuvImage),
     REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
     REG_JNI(register_android_graphics_drawable_VectorDrawable),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2956175..6acb76d 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -127,12 +127,10 @@
     }
 };
 
-Bitmap::Bitmap(JNIEnv* env, jbyteArray storageObj, void* address,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
-        : mPixelStorageType(PixelStorageType::Java) {
-    env->GetJavaVM(&mPixelStorage.java.jvm);
-    mPixelStorage.java.jweakRef = env->NewWeakGlobalRef(storageObj);
-    mPixelStorage.java.jstrongRef = nullptr;
+Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+        : mPixelStorageType(PixelStorageType::Heap) {
+    mPixelStorage.heap.address = address;
+    mPixelStorage.heap.size = size;
     mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
     // Note: this will trigger a call to onStrongRefDestroyed(), but
     // we want the pixel ref to have a ref count of 0 at this point
@@ -151,12 +149,12 @@
     mPixelRef->unref();
 }
 
-Bitmap::Bitmap(void* address, int fd,
+Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
             const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
         : mPixelStorageType(PixelStorageType::Ashmem) {
     mPixelStorage.ashmem.address = address;
     mPixelStorage.ashmem.fd = fd;
-    mPixelStorage.ashmem.size = ashmem_get_size_region(fd);
+    mPixelStorage.ashmem.size = mappedSize;
     mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
     // Note: this will trigger a call to onStrongRefDestroyed(), but
     // we want the pixel ref to have a ref count of 0 at this point
@@ -187,12 +185,8 @@
         munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
         close(mPixelStorage.ashmem.fd);
         break;
-    case PixelStorageType::Java:
-        JNIEnv* env = jniEnv();
-        LOG_ALWAYS_FATAL_IF(mPixelStorage.java.jstrongRef,
-                "Deleting a bitmap wrapper while there are outstanding strong "
-                "references! mPinnedRefCount = %d", mPinnedRefCount);
-        env->DeleteWeakGlobalRef(mPixelStorage.java.jweakRef);
+    case PixelStorageType::Heap:
+        free(mPixelStorage.heap.address);
         break;
     }
 
@@ -219,6 +213,15 @@
     }
 }
 
+size_t Bitmap::getAllocationByteCount() const {
+    switch (mPixelStorageType) {
+    case PixelStorageType::Heap:
+        return mPixelStorage.heap.size;
+    default:
+        return rowBytes() * height();
+    }
+}
+
 const SkImageInfo& Bitmap::info() const {
     return mPixelRef->info();
 }
@@ -244,7 +247,6 @@
         // We just restored this from 0, pin the pixels and inc the strong count
         // Note that there *might be* an incoming onStrongRefDestroyed from whatever
         // last unref'd
-        pinPixelsLocked();
         mPinnedRefCount++;
     }
     return mPixelRef.get();
@@ -283,13 +285,6 @@
     return mPinnedRefCount == 0 && !mAttachedToJava;
 }
 
-JNIEnv* Bitmap::jniEnv() {
-    JNIEnv* env;
-    auto success = mPixelStorage.java.jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
-    LOG_ALWAYS_FATAL_IF(success != JNI_OK,
-        "Failed to get JNIEnv* from JVM: %p", mPixelStorage.java.jvm);
-    return env;
-}
 
 void Bitmap::onStrongRefDestroyed() {
     bool disposeSelf = false;
@@ -298,7 +293,6 @@
         if (mPinnedRefCount > 0) {
             mPinnedRefCount--;
             if (mPinnedRefCount == 0) {
-                unpinPixelsLocked();
                 disposeSelf = shouldDisposeSelfLocked();
             }
         }
@@ -308,49 +302,6 @@
     }
 }
 
-void Bitmap::pinPixelsLocked() {
-    switch (mPixelStorageType) {
-    case PixelStorageType::Invalid:
-        LOG_ALWAYS_FATAL("Cannot pin invalid pixels!");
-        break;
-    case PixelStorageType::External:
-    case PixelStorageType::Ashmem:
-        // Nothing to do
-        break;
-    case PixelStorageType::Java: {
-        JNIEnv* env = jniEnv();
-        if (!mPixelStorage.java.jstrongRef) {
-            mPixelStorage.java.jstrongRef = reinterpret_cast<jbyteArray>(
-                    env->NewGlobalRef(mPixelStorage.java.jweakRef));
-            if (!mPixelStorage.java.jstrongRef) {
-                LOG_ALWAYS_FATAL("Failed to acquire strong reference to pixels");
-            }
-        }
-        break;
-    }
-    }
-}
-
-void Bitmap::unpinPixelsLocked() {
-    switch (mPixelStorageType) {
-    case PixelStorageType::Invalid:
-        LOG_ALWAYS_FATAL("Cannot unpin invalid pixels!");
-        break;
-    case PixelStorageType::External:
-    case PixelStorageType::Ashmem:
-        // Don't need to do anything
-        break;
-    case PixelStorageType::Java: {
-        JNIEnv* env = jniEnv();
-        if (mPixelStorage.java.jstrongRef) {
-            env->DeleteGlobalRef(mPixelStorage.java.jstrongRef);
-            mPixelStorage.java.jstrongRef = nullptr;
-        }
-        break;
-    }
-    }
-}
-
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
     assertValid();
     android::AutoMutex _lock(mLock);
@@ -723,7 +674,7 @@
     SkBitmap bitmap;
     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
 
-    Bitmap* nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
+    Bitmap* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
     if (!nativeBitmap) {
         return NULL;
     }
@@ -742,8 +693,8 @@
     SkBitmap src;
     reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
-    SkBitmap            result;
-    JavaPixelAllocator  allocator(env);
+    SkBitmap result;
+    HeapAllocator allocator;
 
     if (!src.copyTo(&result, dstCT, &allocator)) {
         return NULL;
@@ -798,8 +749,7 @@
 }
 
 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
-        jint width, jint height, jint configHandle, jint allocSize,
-        jboolean requestPremul) {
+        jint width, jint height, jint configHandle, jboolean requestPremul) {
     LocalScopedBitmap bitmap(bitmapHandle);
     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
 
@@ -807,8 +757,8 @@
     if (colorType == kARGB_4444_SkColorType) {
         colorType = kN32_SkColorType;
     }
-
-    if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
+    size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
+    if (requestedSize > bitmap->getAllocationByteCount()) {
         // done in native as there's no way to get BytesPerPixel in Java
         doThrowIAE(env, "Bitmap not large enough to support new configuration");
         return;
@@ -1027,7 +977,7 @@
 
         // Map the pixels in place and take ownership of the ashmem region.
         nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(),
-                ctable, dupFd, const_cast<void*>(blob.data()), !isMutable);
+                ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable);
         SkSafeUnref(ctable);
         if (!nativeBitmap) {
             close(dupFd);
@@ -1053,7 +1003,7 @@
 #endif
 
         // Copy the pixels into a new buffer.
-        nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable);
+        nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable);
         SkSafeUnref(ctable);
         if (!nativeBitmap) {
             blob.release();
@@ -1165,7 +1115,7 @@
     const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
     SkIPoint  offset;
     SkBitmap dst;
-    JavaPixelAllocator allocator(env);
+    HeapAllocator allocator;
 
     src.extractAlpha(&dst, paint, &allocator, &offset);
     // If Skia can't allocate pixels for destination bitmap, it resets
@@ -1370,6 +1320,11 @@
     android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
 }
 
+static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
+    LocalScopedBitmap bitmapHandle(bitmapPtr);
+    return static_cast<jint>(bitmapHandle->getAllocationByteCount());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gBitmapMethods[] = {
@@ -1383,7 +1338,7 @@
         (void*)Bitmap_copyAshmemConfig },
     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
-    {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
+    {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
         (void*)Bitmap_compress },
     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
@@ -1414,6 +1369,7 @@
     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
     {   "nativeRefPixelRef",        "(J)J", (void*)Bitmap_refPixelRef },
     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
+    {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
 };
 
 int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index eadba5c..9ae1f3f 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -28,7 +28,7 @@
 enum class PixelStorageType {
     Invalid,
     External,
-    Java,
+    Heap,
     Ashmem,
 };
 
@@ -47,21 +47,15 @@
  */
 class Bitmap {
 public:
-    Bitmap(JNIEnv* env, jbyteArray storageObj, void* address,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+    Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
+            SkColorTable* ctable);
     Bitmap(void* address, void* context, FreeFunc freeFunc,
             const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
-    Bitmap(void* address, int fd, const SkImageInfo& info, size_t rowBytes,
-            SkColorTable* ctable);
+    Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
+            size_t rowBytes, SkColorTable* ctable);
 
     const SkImageInfo& info() const;
 
-    // Returns nullptr if it is not backed by a jbyteArray
-    jbyteArray javaByteArray() const {
-        return mPixelStorageType == PixelStorageType::Java
-                ? mPixelStorage.java.jstrongRef : nullptr;
-    }
-
     int width() const { return info().width(); }
     int height() const { return info().height(); }
     size_t rowBytes() const;
@@ -81,6 +75,7 @@
     bool hasHardwareMipMap();
     void setHasHardwareMipMap(bool hasMipMap);
     int getAshmemFd() const;
+    size_t getAllocationByteCount() const;
 
 private:
     friend class WrappedPixelRef;
@@ -90,8 +85,6 @@
     void onStrongRefDestroyed();
 
     void pinPixelsLocked();
-    void unpinPixelsLocked();
-    JNIEnv* jniEnv();
     bool shouldDisposeSelfLocked();
     void assertValid() const;
     SkPixelRef* refPixelRefLocked();
@@ -114,10 +107,9 @@
             size_t size;
         } ashmem;
         struct {
-            JavaVM* jvm;
-            jweak jweakRef;
-            jbyteArray jstrongRef;
-        } java;
+            void* address;
+            size_t size;
+        } heap;
     } mPixelStorage;
 };
 
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 695aed5..5a540ce 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -193,7 +193,7 @@
         bitmap->setPixelRef(mBitmap->refPixelRef())->unref();
 
         // since we're already allocated, we lockPixels right away
-        // HeapAllocator/JavaPixelAllocator behaves this way too
+        // HeapAllocator behaves this way too
         bitmap->lockPixels();
         return true;
     }
@@ -339,7 +339,7 @@
         }
     }
 
-    JavaPixelAllocator javaAllocator(env);
+    HeapAllocator defaultAllocator;
     RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
     ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
     SkBitmap::HeapAllocator heapAllocator;
@@ -353,10 +353,10 @@
         decodeAllocator = &recyclingAllocator;
     } else if (willScale) {
         // This will allocate pixels using a HeapAllocator, since there will be an extra
-        // scaling step that copies these pixels into Java memory.
+        // scaling step.
         decodeAllocator = &heapAllocator;
     } else {
-        decodeAllocator = &javaAllocator;
+        decodeAllocator = &defaultAllocator;
     }
 
     // Set the decode colorType.  This is necessary because we can't always support
@@ -384,9 +384,12 @@
     // Set the alpha type for the decode.
     SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
 
-    const SkImageInfo decodeInfo = codec->getInfo().makeWH(size.width(), size.height())
-                                                   .makeColorType(decodeColorType)
-                                                   .makeAlphaType(alphaType);
+    // Enable legacy behavior to avoid any gamma correction.  Android's assets are
+    // adjusted to expect a non-gamma correct premultiply.
+    sk_sp<SkColorSpace> colorSpace = nullptr;
+    const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType,
+                                                     alphaType, colorSpace);
+
     SkImageInfo bitmapInfo = decodeInfo;
     if (decodeColorType == kGray_8_SkColorType) {
         // The legacy implementation of BitmapFactory used kAlpha8 for
@@ -409,7 +412,7 @@
 
     // Use SkAndroidCodec to perform the decode.
     SkAndroidCodec::AndroidOptions codecOptions;
-    codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ?
+    codecOptions.fZeroInitialized =  decodeAllocator == &defaultAllocator ?
             SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
     codecOptions.fColorPtr = colorPtr;
     codecOptions.fColorCount = colorCount;
@@ -474,7 +477,7 @@
         if (javaBitmap != nullptr) {
             outputAllocator = &recyclingAllocator;
         } else {
-            outputAllocator = &javaAllocator;
+            outputAllocator = &defaultAllocator;
         }
 
         SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType());
@@ -537,7 +540,7 @@
     if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
 
     // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),
+    return GraphicsJNI::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
 }
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 970001a..21850bd 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -161,13 +161,13 @@
     // Set up the pixel allocator
     SkBRDAllocator* allocator = nullptr;
     RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
-    JavaPixelAllocator javaAlloc(env);
+    HeapAllocator heapAlloc;
     if (javaBitmap) {
         allocator = &recycleAlloc;
         // We are required to match the color type of the recycled bitmap.
         colorType = recycledBitmap->info().colorType();
     } else {
-        allocator = &javaAlloc;
+        allocator = &heapAlloc;
     }
 
     // Decode the region.
@@ -200,7 +200,7 @@
     if (!requireUnpremul) {
         bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
     }
-    return GraphicsJNI::createBitmap(env, javaAlloc.getStorageObjAndReset(), bitmapCreateFlags);
+    return GraphicsJNI::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
 }
 
 static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index b5630d5..8cee814 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -416,9 +416,8 @@
     assert_premultiplied(bitmap->info(), isPremultiplied);
 
     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
-            reinterpret_cast<jlong>(bitmap), bitmap->javaByteArray(),
-            bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied,
-            ninePatchChunk, ninePatchInsets);
+            reinterpret_cast<jlong>(bitmap), bitmap->width(), bitmap->height(), density, isMutable,
+            isPremultiplied, ninePatchChunk, ninePatchInsets);
     hasException(env); // For the side effect of logging.
     return obj;
 }
@@ -483,37 +482,28 @@
     return true;
 }
 
-android::Bitmap* GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
-                                             SkColorTable* ctable) {
+android::Bitmap* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
     if (info.colorType() == kUnknown_SkColorType) {
-        doThrowIAE(env, "unknown bitmap configuration");
-        return NULL;
+        LOG_ALWAYS_FATAL("unknown bitmap configuration");
+        return nullptr;
     }
 
     size_t size;
     if (!computeAllocationSize(*bitmap, &size)) {
-        return NULL;
+        return nullptr;
     }
 
     // we must respect the rowBytes value already set on the bitmap instead of
     // attempting to compute our own.
     const size_t rowBytes = bitmap->rowBytes();
 
-    jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
-                                                             gVMRuntime_newNonMovableArray,
-                                                             gByte_class, size);
-    if (env->ExceptionCheck() != 0) {
-        return NULL;
+    void* addr = calloc(size, 1);
+    if (!addr) {
+        return nullptr;
     }
-    SkASSERT(arrayObj);
-    jbyte* addr = (jbyte*) env->CallLongMethod(gVMRuntime, gVMRuntime_addressOf, arrayObj);
-    if (env->ExceptionCheck() != 0) {
-        return NULL;
-    }
-    SkASSERT(addr);
-    android::Bitmap* wrapper = new android::Bitmap(env, arrayObj, (void*) addr,
-            info, rowBytes, ctable);
+
+    android::Bitmap* wrapper = new android::Bitmap(addr, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -613,7 +603,7 @@
         return nullptr;
     }
 
-    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -623,7 +613,7 @@
 }
 
 android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
-        SkColorTable* ctable, int fd, void* addr, bool readOnly) {
+        SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) {
     const SkImageInfo& info = bitmap->info();
     if (info.colorType() == kUnknown_SkColorType) {
         doThrowIAE(env, "unknown bitmap configuration");
@@ -633,7 +623,8 @@
     if (!addr) {
         // Map existing ashmem region if not already mapped.
         int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
-        addr = mmap(NULL, ashmem_get_size_region(fd), flags, MAP_SHARED, fd, 0);
+        size = ashmem_get_size_region(fd);
+        addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
         if (addr == MAP_FAILED) {
             return nullptr;
         }
@@ -643,7 +634,7 @@
     // attempting to compute our own.
     const size_t rowBytes = bitmap->rowBytes();
 
-    android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable);
+    android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     if (readOnly) {
         bitmap->pixelRef()->setImmutable();
@@ -657,21 +648,16 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) {
-    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJavaVM) != JNI_OK,
-            "env->GetJavaVM failed");
-}
+HeapAllocator::HeapAllocator() {}
 
-JavaPixelAllocator::~JavaPixelAllocator() {
+HeapAllocator::~HeapAllocator() {
     if (mStorage) {
         mStorage->detachFromJava();
     }
 }
 
-bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
-    JNIEnv* env = vm2env(mJavaVM);
-
-    mStorage = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
+bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+    mStorage = GraphicsJNI::allocateHeapPixelRef(bitmap, ctable);
     return mStorage != nullptr;
 }
 
@@ -829,7 +815,7 @@
 
     gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
     gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
-    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
+    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
     gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
     gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
     gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index a5e94a10..738ad54 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -93,14 +93,13 @@
 
     static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
 
-    static android::Bitmap* allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
-            SkColorTable* ctable);
+    static android::Bitmap* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
 
     static android::Bitmap* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
             SkColorTable* ctable);
 
     static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
-            SkColorTable* ctable, int fd, void* addr, bool readOnly);
+            SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly);
 
     /**
      * Given a bitmap we natively allocate a memory block to store the contents
@@ -119,15 +118,10 @@
             const SkBitmap& dstBitmap);
 };
 
-/** Allocator which allocates the backing buffer in the Java heap.
- *  Instances can only be used to perform a single allocation, which helps
- *  ensure that the allocated buffer is properly accounted for with a
- *  reference in the heap (or a JNI global reference).
- */
-class JavaPixelAllocator : public SkBRDAllocator {
+class HeapAllocator : public SkBRDAllocator {
 public:
-    JavaPixelAllocator(JNIEnv* env);
-    ~JavaPixelAllocator();
+   HeapAllocator();
+    ~HeapAllocator();
 
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) override;
 
@@ -140,14 +134,8 @@
         return result;
     };
 
-    /**
-     *  Indicates that this allocator allocates zero initialized
-     *  memory.
-     */
     SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; }
-
 private:
-    JavaVM* mJavaVM;
     android::Bitmap* mStorage = nullptr;
 };
 
@@ -214,7 +202,7 @@
 
 class AshmemPixelAllocator : public SkBitmap::Allocator {
 public:
-    AshmemPixelAllocator(JNIEnv* env);
+    explicit AshmemPixelAllocator(JNIEnv* env);
     ~AshmemPixelAllocator();
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
     android::Bitmap* getStorageObjAndReset() {
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index b0f3bb4..f8bb77a 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -25,14 +25,25 @@
 
 namespace android {
 
+static_assert(sizeof(SkMatrix) == 40, "Unexpected sizeof(SkMatrix), "
+        "update size in Matrix.java#NATIVE_ALLOCATION_SIZE and here");
+static_assert(SK_SCALAR_IS_FLOAT, "SK_SCALAR_IS_FLOAT is false, "
+        "only float scalar is supported");
+
 class SkMatrixGlue {
 public:
 
-    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
+    // ---------------- Regular JNI -----------------------------
+
+    static void finalizer(jlong objHandle) {
         SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
         delete obj;
     }
 
+    static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
+        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
+    }
+
     static jlong create(JNIEnv* env, jobject clazz, jlong srcHandle) {
         const SkMatrix* src = reinterpret_cast<SkMatrix*>(srcHandle);
         SkMatrix* obj = new SkMatrix();
@@ -43,156 +54,39 @@
         return reinterpret_cast<jlong>(obj);
     }
 
-    static jboolean isIdentity(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
-    }
+    // ---------------- @FastNative -----------------------------
 
-    static jboolean isAffine(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
-    }
-
-    static jboolean rectStaysRect(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
-    }
-
-    static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->reset();
-    }
-     static void set(JNIEnv* env, jobject clazz, jlong objHandle, jlong otherHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
-        *obj = *other;
-    }
-     static void setTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setTranslate(dx, dy);
-    }
-     static void setScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setScale(sx, sy, px, py);
-    }
-     static void setScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setScale(sx, sy);
-    }
-     static void setRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setRotate(degrees, px, py);
-    }
-     static void setRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setRotate(degrees);
-    }
-     static void setSinCos__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sinValue, jfloat cosValue, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setSinCos(sinValue, cosValue, px, py);
-    }
-     static void setSinCos__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sinValue, jfloat cosValue) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setSinCos(sinValue, cosValue);
-    }
-     static void setSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setSkew(kx, ky, px, py);
-    }
-     static void setSkew__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->setSkew(kx, ky);
-    }
-     static void setConcat(JNIEnv* env, jobject clazz, jlong objHandle, jlong aHandle, jlong bHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
-        SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
-        obj->setConcat(*a, *b);
-    }
-
-    static void preTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preTranslate(dx, dy);
-    }
-
-    static void preScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preScale(sx, sy, px, py);
-    }
-
-    static void preScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preScale(sx, sy);
-    }
-
-    static void preRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preRotate(degrees, px, py);
-    }
-
-    static void preRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preRotate(degrees);
-    }
-
-    static void preSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preSkew(kx, ky, px, py);
-    }
-
-    static void preSkew__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->preSkew(kx, ky);
-    }
-
-    static void preConcat(JNIEnv* env, jobject clazz, jlong objHandle, jlong otherHandle) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
-        obj->preConcat(*other);
-    }
-
-    static void postTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postTranslate(dx, dy);
-    }
-
-    static void postScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postScale(sx, sy, px, py);
-    }
-
-    static void postScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postScale(sx, sy);
-    }
-
-    static void postRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postRotate(degrees, px, py);
-    }
-
-    static void postRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postRotate(degrees);
-    }
-
-    static void postSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
-        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
-        obj->postSkew(kx, ky, px, py);
-    }
-
-    static void postSkew__FF(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloat kx, jfloat ky) {
+    static void mapPoints(JNIEnv* env, jobject clazz, jlong matrixHandle,
+            jfloatArray dst, jint dstIndex, jfloatArray src, jint srcIndex,
+            jint ptCount, jboolean isPts) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        matrix->postSkew(kx, ky);
+        SkASSERT(ptCount >= 0);
+        AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1),
+                kRO_JNIAccess);
+        AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1),
+                kRW_JNIAccess);
+        float* srcArray = autoSrc.ptr() + srcIndex;
+        float* dstArray = autoDst.ptr() + dstIndex;
+        if (isPts)
+            matrix->mapPoints((SkPoint*) dstArray, (const SkPoint*) srcArray,
+                    ptCount);
+        else
+            matrix->mapVectors((SkVector*) dstArray, (const SkVector*) srcArray,
+                    ptCount);
     }
 
-    static void postConcat(JNIEnv* env, jobject clazz, jlong matrixHandle, jlong otherHandle) {
+    static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz,
+            jlong matrixHandle, jobjectArray dst, jobject src) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
-        matrix->postConcat(*other);
+        SkRect dst_, src_;
+        GraphicsJNI::jrectf_to_rect(env, src, &src_);
+        jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
+        GraphicsJNI::rect_to_jrectf(dst_, env, dst);
+        return rectStaysRect ? JNI_TRUE : JNI_FALSE;
     }
 
-    static jboolean setRectToRect(JNIEnv* env, jobject clazz, jlong matrixHandle, jobject src, jobject dst, jint stfHandle) {
+    static jboolean setRectToRect(JNIEnv* env, jobject clazz,
+            jlong matrixHandle, jobject src, jobject dst, jint stfHandle) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         SkMatrix::ScaleToFit stf = static_cast<SkMatrix::ScaleToFit>(stfHandle);
         SkRect src_;
@@ -202,150 +96,290 @@
         return matrix->setRectToRect(src_, dst_, stf) ? JNI_TRUE : JNI_FALSE;
     }
 
-    static jboolean setPolyToPoly(JNIEnv* env, jobject clazz, jlong matrixHandle,
-                                  jfloatArray jsrc, jint srcIndex,
-                                  jfloatArray jdst, jint dstIndex, jint ptCount) {
+    static jboolean setPolyToPoly(JNIEnv* env, jobject clazz,
+            jlong matrixHandle, jfloatArray jsrc, jint srcIndex,
+            jfloatArray jdst, jint dstIndex, jint ptCount) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         SkASSERT(srcIndex >= 0);
         SkASSERT(dstIndex >= 0);
-        SkASSERT((unsigned)ptCount <= 4);
+        SkASSERT((unsigned )ptCount <= 4);
 
-        AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1), kRO_JNIAccess);
-        AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1), kRW_JNIAccess);
+        AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1),
+                kRO_JNIAccess);
+        AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1),
+                kRW_JNIAccess);
         float* src = autoSrc.ptr() + srcIndex;
         float* dst = autoDst.ptr() + dstIndex;
         bool result;
 
-#ifdef SK_SCALAR_IS_FLOAT
-        result = matrix->setPolyToPoly((const SkPoint*)src, (const SkPoint*)dst,
-                                     ptCount);
-#else
-        SkASSERT(false);
-#endif
+        result = matrix->setPolyToPoly((const SkPoint*) src,
+                (const SkPoint*) dst, ptCount);
         return result ? JNI_TRUE : JNI_FALSE;
     }
 
-    static jboolean invert(JNIEnv* env, jobject clazz, jlong matrixHandle, jlong inverseHandle) {
+    static void getValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
+            jfloatArray values) {
+        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+        AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
+        float* dst = autoValues.ptr();
+        for (int i = 0; i < 9; i++) {
+            dst[i] = matrix->get(i);
+        }
+    }
+
+    static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
+            jfloatArray values) {
+        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+        AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
+        const float* src = autoValues.ptr();
+
+        for (int i = 0; i < 9; i++) {
+            matrix->set(i, src[i]);
+        }
+    }
+
+    // ---------------- @CriticalNative -----------------------------
+
+    static jboolean isIdentity(jlong objHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
+    }
+
+    static jboolean isAffine(jlong objHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
+    }
+
+    static jboolean rectStaysRect(jlong objHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
+    }
+
+    static void reset(jlong objHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->reset();
+    }
+
+    static void set(jlong objHandle, jlong otherHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+        *obj = *other;
+    }
+
+    static void setTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setTranslate(dx, dy);
+    }
+
+    static void setScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setScale(sx, sy, px, py);
+    }
+
+    static void setScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setScale(sx, sy);
+    }
+
+    static void setRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setRotate(degrees, px, py);
+    }
+
+    static void setRotate__F(jlong objHandle, jfloat degrees) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setRotate(degrees);
+    }
+
+    static void setSinCos__FFFF(jlong objHandle, jfloat sinValue,
+            jfloat cosValue, jfloat px, jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setSinCos(sinValue, cosValue, px, py);
+    }
+
+    static void setSinCos__FF(jlong objHandle, jfloat sinValue,
+            jfloat cosValue) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setSinCos(sinValue, cosValue);
+    }
+
+    static void setSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setSkew(kx, ky, px, py);
+    }
+
+    static void setSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->setSkew(kx, ky);
+    }
+
+    static void setConcat(jlong objHandle, jlong aHandle, jlong bHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
+        SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
+        obj->setConcat(*a, *b);
+    }
+
+    static void preTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preTranslate(dx, dy);
+    }
+
+    static void preScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preScale(sx, sy, px, py);
+    }
+
+    static void preScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preScale(sx, sy);
+    }
+
+    static void preRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preRotate(degrees, px, py);
+    }
+
+    static void preRotate__F(jlong objHandle, jfloat degrees) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preRotate(degrees);
+    }
+
+    static void preSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preSkew(kx, ky, px, py);
+    }
+
+    static void preSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->preSkew(kx, ky);
+    }
+
+    static void preConcat(jlong objHandle, jlong otherHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+        obj->preConcat(*other);
+    }
+
+    static void postTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postTranslate(dx, dy);
+    }
+
+    static void postScale__FFFF(jlong objHandle, jfloat sx, jfloat sy,
+            jfloat px, jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postScale(sx, sy, px, py);
+    }
+
+    static void postScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postScale(sx, sy);
+    }
+
+    static void postRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postRotate(degrees, px, py);
+    }
+
+    static void postRotate__F(jlong objHandle, jfloat degrees) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postRotate(degrees);
+    }
+
+    static void postSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+            jfloat py) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        obj->postSkew(kx, ky, px, py);
+    }
+
+    static void postSkew__FF(jlong matrixHandle, jfloat kx, jfloat ky) {
+        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+        matrix->postSkew(kx, ky);
+    }
+
+    static void postConcat(jlong matrixHandle, jlong otherHandle) {
+        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+        matrix->postConcat(*other);
+    }
+
+    static jboolean invert(jlong matrixHandle, jlong inverseHandle) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         SkMatrix* inverse = reinterpret_cast<SkMatrix*>(inverseHandle);
         return matrix->invert(inverse);
     }
 
-    static void mapPoints(JNIEnv* env, jobject clazz, jlong matrixHandle,
-                              jfloatArray dst, jint dstIndex,
-                              jfloatArray src, jint srcIndex,
-                              jint ptCount, jboolean isPts) {
-        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        SkASSERT(ptCount >= 0);
-        AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1), kRO_JNIAccess);
-        AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1), kRW_JNIAccess);
-        float* srcArray = autoSrc.ptr() + srcIndex;
-        float* dstArray = autoDst.ptr() + dstIndex;
-#ifdef SK_SCALAR_IS_FLOAT
-        if (isPts)
-            matrix->mapPoints((SkPoint*)dstArray, (const SkPoint*)srcArray,
-                              ptCount);
-        else
-            matrix->mapVectors((SkVector*)dstArray, (const SkVector*)srcArray,
-                               ptCount);
-#else
-        SkASSERT(false);
-#endif
-    }
-
-    static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz, jlong matrixHandle, jobjectArray dst, jobject src) {
-        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        SkRect dst_, src_;
-        GraphicsJNI::jrectf_to_rect(env, src, &src_);
-        jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
-        GraphicsJNI::rect_to_jrectf(dst_, env, dst);
-        return rectStaysRect ? JNI_TRUE : JNI_FALSE;
-    }
-
-    static jfloat mapRadius(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloat radius) {
+    static jfloat mapRadius(jlong matrixHandle, jfloat radius) {
         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
         float result;
         result = SkScalarToFloat(matrix->mapRadius(radius));
         return static_cast<jfloat>(result);
     }
-    static void getValues(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloatArray values) {
-        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
-        float* dst = autoValues.ptr();
-#ifdef SK_SCALAR_IS_FLOAT
-        for (int i = 0; i < 9; i++) {
-            dst[i] = matrix->get(i);
-        }
-#else
-        SkASSERT(false);
-#endif
-    }
 
-    static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloatArray values) {
-        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-        AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
-        const float* src = autoValues.ptr();
-
-#ifdef SK_SCALAR_IS_FLOAT
-        for (int i = 0; i < 9; i++) {
-            matrix->set(i, src[i]);
-        }
-#else
-        SkASSERT(false);
-#endif
-    }
-
-    static jboolean equals(JNIEnv* env, jobject clazz, jlong aHandle, jlong bHandle) {
+    static jboolean equals(jlong aHandle, jlong bHandle) {
         const SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
         const SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
         return *a == *b;
     }
- };
+};
 
 static const JNINativeMethod methods[] = {
-    {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
-    {"native_create","(J)J", (void*) SkMatrixGlue::create},
+    {"nGetNativeFinalizer", "()J", (void*) SkMatrixGlue::getNativeFinalizer},
+    {"nCreate","(J)J", (void*) SkMatrixGlue::create},
 
-    {"native_isIdentity","!(J)Z", (void*) SkMatrixGlue::isIdentity},
-    {"native_isAffine","!(J)Z", (void*) SkMatrixGlue::isAffine},
-    {"native_rectStaysRect","!(J)Z", (void*) SkMatrixGlue::rectStaysRect},
-    {"native_reset","!(J)V", (void*) SkMatrixGlue::reset},
-    {"native_set","!(JJ)V", (void*) SkMatrixGlue::set},
-    {"native_setTranslate","!(JFF)V", (void*) SkMatrixGlue::setTranslate},
-    {"native_setScale","!(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
-    {"native_setScale","!(JFF)V", (void*) SkMatrixGlue::setScale__FF},
-    {"native_setRotate","!(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
-    {"native_setRotate","!(JF)V", (void*) SkMatrixGlue::setRotate__F},
-    {"native_setSinCos","!(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
-    {"native_setSinCos","!(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
-    {"native_setSkew","!(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
-    {"native_setSkew","!(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
-    {"native_setConcat","!(JJJ)V", (void*) SkMatrixGlue::setConcat},
-    {"native_preTranslate","!(JFF)V", (void*) SkMatrixGlue::preTranslate},
-    {"native_preScale","!(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
-    {"native_preScale","!(JFF)V", (void*) SkMatrixGlue::preScale__FF},
-    {"native_preRotate","!(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
-    {"native_preRotate","!(JF)V", (void*) SkMatrixGlue::preRotate__F},
-    {"native_preSkew","!(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
-    {"native_preSkew","!(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
-    {"native_preConcat","!(JJ)V", (void*) SkMatrixGlue::preConcat},
-    {"native_postTranslate","!(JFF)V", (void*) SkMatrixGlue::postTranslate},
-    {"native_postScale","!(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
-    {"native_postScale","!(JFF)V", (void*) SkMatrixGlue::postScale__FF},
-    {"native_postRotate","!(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
-    {"native_postRotate","!(JF)V", (void*) SkMatrixGlue::postRotate__F},
-    {"native_postSkew","!(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
-    {"native_postSkew","!(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
-    {"native_postConcat","!(JJ)V", (void*) SkMatrixGlue::postConcat},
-    {"native_setRectToRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
-    {"native_setPolyToPoly","!(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
-    {"native_invert","!(JJ)Z", (void*) SkMatrixGlue::invert},
-    {"native_mapPoints","!(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
-    {"native_mapRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
-    {"native_mapRadius","!(JF)F", (void*) SkMatrixGlue::mapRadius},
-    {"native_getValues","!(J[F)V", (void*) SkMatrixGlue::getValues},
-    {"native_setValues","!(J[F)V", (void*) SkMatrixGlue::setValues},
-    {"native_equals", "!(JJ)Z", (void*) SkMatrixGlue::equals}
+    // ------- @FastNative below here ---------------
+    {"nMapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
+    {"nMapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z",
+            (void*) SkMatrixGlue::mapRect__RectFRectF},
+    {"nSetRectToRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z",
+            (void*) SkMatrixGlue::setRectToRect},
+    {"nSetPolyToPoly","(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
+    {"nGetValues","(J[F)V", (void*) SkMatrixGlue::getValues},
+    {"nSetValues","(J[F)V", (void*) SkMatrixGlue::setValues},
+
+    // ------- @CriticalNative below here ---------------
+    {"nIsIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
+    {"nIsAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
+    {"nRectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
+    {"nReset","(J)V", (void*) SkMatrixGlue::reset},
+    {"nSet","(JJ)V", (void*) SkMatrixGlue::set},
+    {"nSetTranslate","(JFF)V", (void*) SkMatrixGlue::setTranslate},
+    {"nSetScale","(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
+    {"nSetScale","(JFF)V", (void*) SkMatrixGlue::setScale__FF},
+    {"nSetRotate","(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
+    {"nSetRotate","(JF)V", (void*) SkMatrixGlue::setRotate__F},
+    {"nSetSinCos","(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
+    {"nSetSinCos","(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
+    {"nSetSkew","(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
+    {"nSetSkew","(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
+    {"nSetConcat","(JJJ)V", (void*) SkMatrixGlue::setConcat},
+    {"nPreTranslate","(JFF)V", (void*) SkMatrixGlue::preTranslate},
+    {"nPreScale","(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
+    {"nPreScale","(JFF)V", (void*) SkMatrixGlue::preScale__FF},
+    {"nPreRotate","(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
+    {"nPreRotate","(JF)V", (void*) SkMatrixGlue::preRotate__F},
+    {"nPreSkew","(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
+    {"nPreSkew","(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
+    {"nPreConcat","(JJ)V", (void*) SkMatrixGlue::preConcat},
+    {"nPostTranslate","(JFF)V", (void*) SkMatrixGlue::postTranslate},
+    {"nPostScale","(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
+    {"nPostScale","(JFF)V", (void*) SkMatrixGlue::postScale__FF},
+    {"nPostRotate","(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
+    {"nPostRotate","(JF)V", (void*) SkMatrixGlue::postRotate__F},
+    {"nPostSkew","(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
+    {"nPostSkew","(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
+    {"nPostConcat","(JJ)V", (void*) SkMatrixGlue::postConcat},
+    {"nInvert","(JJ)Z", (void*) SkMatrixGlue::invert},
+    {"nMapRadius","(JF)F", (void*) SkMatrixGlue::mapRadius},
+    {"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals}
 };
 
 static jfieldID sNativeInstanceField;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 9be659e..4b1530a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -105,372 +105,80 @@
         return reinterpret_cast<jlong>(obj);
     }
 
-    static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        obj->reset();
-        defaultSettingsForAndroid(obj);
-    }
+    static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
+            int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
+            const bool forwardScan) {
+        size_t measuredCount = 0;
+        float measured = 0;
 
-    static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
-        Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
-        const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
-        *dst = *src;
-    }
+        std::unique_ptr<float[]> advancesArray(new float[count]);
+        MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
+                advancesArray.get());
 
-    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
-    static const uint32_t sFilterBitmapFlag = 0x02;
-
-    static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
-        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
-        uint32_t result = nativePaint->getFlags();
-        result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
-        if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
-            result |= sFilterBitmapFlag;
+        for (int i = 0; i < count; i++) {
+            // traverse in the given direction
+            int index = forwardScan ? i : (count - i - 1);
+            float width = advancesArray[index];
+            if (measured + width > maxWidth) {
+                break;
+            }
+            // properly handle clusters when scanning backwards
+            if (forwardScan || width != 0.0f) {
+                measuredCount = i + 1;
+            }
+            measured += width;
         }
-        return static_cast<jint>(result);
-    }
 
-    static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
-        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
-        // Instead of modifying 0x02, change the filter level.
-        nativePaint->setFilterQuality(flags & sFilterBitmapFlag
-                ? kLow_SkFilterQuality
-                : kNone_SkFilterQuality);
-        // Don't pass through filter flag, which is no longer stored in paint's flags.
-        flags &= ~sFilterBitmapFlag;
-        // Use the existing value for 0x02.
-        const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
-        flags |= existing0x02Flag;
-        nativePaint->setFlags(flags);
-    }
-
-    static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
-        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
-                == Paint::kNo_Hinting ? 0 : 1;
-    }
-
-    static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
-        reinterpret_cast<Paint*>(paintHandle)->setHinting(
-                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
-    }
-
-    static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
-        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
-    }
-
-    static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
-        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
-    }
-
-    static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
-        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
-    }
-
-    static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
-        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
-    }
-
-    static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
-    }
-
-    static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
-        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
-    }
-
-    static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
-        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
-                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
-    }
-
-    static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
-        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
-    }
-
-    static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStyle());
-    }
-
-    static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Style style = static_cast<Paint::Style>(styleHandle);
-        obj->setStyle(style);
-    }
-
-    static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
-        int color;
-        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
-        return static_cast<jint>(color);
-    }
-
-    static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
-        int alpha;
-        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
-        return static_cast<jint>(alpha);
-    }
-
-    static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
-        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
-    }
-
-    static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
-        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
-    }
-
-    static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
-    }
-
-    static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
-    }
-
-    static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
-    }
-
-    static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
-        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
-    }
-
-    static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStrokeCap());
-    }
-
-    static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
-        obj->setStrokeCap(cap);
-    }
-
-    static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getStrokeJoin());
-    }
-
-    static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Join join = (Paint::Join) joinHandle;
-        obj->setStrokeJoin(join);
-    }
-
-    static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
-        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
-        return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
-    }
-
-    static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-        return reinterpret_cast<jlong>(obj->setShader(shader));
-    }
-
-    static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
-        Paint* obj = reinterpret_cast<Paint *>(objHandle);
-        SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
-        return reinterpret_cast<jlong>(obj->setColorFilter(filter));
-    }
-
-    static jlong setXfermode(JNIEnv* env, jobject clazz, jlong objHandle, jlong xfermodeHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkXfermode* xfermode = reinterpret_cast<SkXfermode*>(xfermodeHandle);
-        return reinterpret_cast<jlong>(obj->setXfermode(xfermode));
-    }
-
-    static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
-        return reinterpret_cast<jlong>(obj->setPathEffect(effect));
-    }
-
-    static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
-        return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
-    }
-
-    static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
-        // TODO: in Paint refactoring, set typeface on android Paint, not Paint
-        return NULL;
-    }
-
-    static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
-        return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
-    }
-
-    static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        return static_cast<jint>(obj->getTextAlign());
-    }
-
-    static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        Paint::Align align = static_cast<Paint::Align>(alignHandle);
-        obj->setTextAlign(align);
-    }
-
-    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        ScopedUtfChars localesChars(env, locales);
-        jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
-        obj->setMinikinLangListId(minikinLangListId);
-        return minikinLangListId;
-    }
-
-    static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle,
-            jint minikinLangListId) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        obj->setMinikinLangListId(minikinLangListId);
-    }
-
-    static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
-        return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
-    }
-
-    static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
-        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
-        obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
-    }
-
-    static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
-    }
-
-    static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
-    }
-
-    static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
-    }
-
-    static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
-    }
-
-    static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
-        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
-    }
-
-    static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
-        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
-    }
-
-    static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getLetterSpacing();
-    }
-
-    static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setLetterSpacing(letterSpacing);
-    }
-
-    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        if (!settings) {
-            paint->setFontFeatureSettings(std::string());
-        } else {
-            ScopedUtfChars settingsChars(env, settings);
-            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
+            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
+            jfloat* array = autoMeasured.ptr();
+            array[0] = measured;
         }
+        return measuredCount;
     }
 
-    static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getHyphenEdit();
-    }
+    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle,
+            jcharArray jtext, jint index, jint count, jfloat maxWidth, jint bidiFlags,
+            jfloatArray jmeasuredWidth) {
+        NPE_CHECK_RETURN_ZERO(env, jtext);
 
-    static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        paint->setHyphenEdit((uint32_t)hyphen);
-    }
-
-    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
-            Paint::FontMetrics *metrics) {
-        const int kElegantTop = 2500;
-        const int kElegantBottom = -1000;
-        const int kElegantAscent = 1900;
-        const int kElegantDescent = -500;
-        const int kElegantLeading = 0;
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        typeface = Typeface::resolveDefault(typeface);
-        minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
-        float saveSkewX = paint->getTextSkewX();
-        bool savefakeBold = paint->isFakeBoldText();
-        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
-        SkScalar spacing = paint->getFontMetrics(metrics);
-        // The populateSkPaint call may have changed fake bold / text skew
-        // because we want to measure with those effects applied, so now
-        // restore the original settings.
-        paint->setTextSkewX(saveSkewX);
-        paint->setFakeBoldText(savefakeBold);
-        if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
-            SkScalar size = paint->getTextSize();
-            metrics->fTop = -size * kElegantTop / 2048;
-            metrics->fBottom = -size * kElegantBottom / 2048;
-            metrics->fAscent = -size * kElegantAscent / 2048;
-            metrics->fDescent = -size * kElegantDescent / 2048;
-            metrics->fLeading = size * kElegantLeading / 2048;
-            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+
+        bool forwardTextDirection;
+        if (count < 0) {
+            forwardTextDirection = false;
+            count = -count;
         }
-        return spacing;
-    }
-
-    static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
-        Paint::FontMetrics metrics;
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        return SkScalarToFloat(metrics.fAscent);
-    }
-
-    static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
-        Paint::FontMetrics metrics;
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        return SkScalarToFloat(metrics.fDescent);
-    }
-
-    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
-            jlong typefaceHandle, jobject metricsObj) {
-        Paint::FontMetrics metrics;
-        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+        else {
+            forwardTextDirection = true;
         }
-        return SkScalarToFloat(spacing);
+
+        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+
+        const jchar* text = env->GetCharArrayElements(jtext, nullptr);
+        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
+                          bidiFlags, jmeasuredWidth, forwardTextDirection);
+        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
+                                      JNI_ABORT);
+        return count;
     }
 
-    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
-            jlong typefaceHandle, jobject metricsObj) {
-        Paint::FontMetrics metrics;
+    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
+                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
+        NPE_CHECK_RETURN_ZERO(env, jtext);
 
-        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-        int ascent = SkScalarRoundToInt(metrics.fAscent);
-        int descent = SkScalarRoundToInt(metrics.fDescent);
-        int leading = SkScalarRoundToInt(metrics.fLeading);
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
 
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
-        }
-        return descent - ascent + leading;
+        int count = env->GetStringLength(jtext);
+        const jchar* text = env->GetStringChars(jtext, nullptr);
+        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
+        env->ReleaseStringChars(jtext, text);
+        return count;
     }
 
     static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface,
@@ -510,7 +218,7 @@
             jint bidiFlags, jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        jchar* textArray = env->GetCharArrayElements(text, nullptr);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
                 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -523,7 +231,7 @@
             jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
                 advances, advancesIndex);
@@ -542,7 +250,7 @@
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
             jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        jchar* textArray = env->GetCharArrayElements(text, nullptr);
         jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
                 offset, cursorOpt);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -552,7 +260,7 @@
     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
             jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         jint result = doTextRunCursor(env, paint, textArray, contextStart,
                 contextEnd - contextStart, dir, offset, cursorOpt);
         env->ReleaseStringChars(text, textArray);
@@ -615,7 +323,7 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, nullptr);
         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
     }
@@ -626,103 +334,11 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
 
-    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
-                               jfloat dx, jfloat dy, jint color) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        if (radius <= 0) {
-            paint->setLooper(NULL);
-        }
-        else {
-            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
-            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
-        }
-    }
-
-    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
-    }
-
-    static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
-                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
-                         const bool forwardScan) {
-        size_t measuredCount = 0;
-        float measured = 0;
-
-        std::unique_ptr<float[]> advancesArray(new float[count]);
-        MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
-                advancesArray.get());
-
-        for (int i = 0; i < count; i++) {
-            // traverse in the given direction
-            int index = forwardScan ? i : (count - i - 1);
-            float width = advancesArray[index];
-            if (measured + width > maxWidth) {
-                break;
-            }
-            // properly handle clusters when scanning backwards
-            if (forwardScan || width != 0.0f) {
-                measuredCount = i + 1;
-            }
-            measured += width;
-        }
-
-        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
-            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
-            jfloat* array = autoMeasured.ptr();
-            array[0] = measured;
-        }
-        return measuredCount;
-    }
-
-    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
-            jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jtext);
-
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
-        bool forwardTextDirection;
-        if (count < 0) {
-            forwardTextDirection = false;
-            count = -count;
-        }
-        else {
-            forwardTextDirection = true;
-        }
-
-        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-
-        const jchar* text = env->GetCharArrayElements(jtext, NULL);
-        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
-                          bidiFlags, jmeasuredWidth, forwardTextDirection);
-        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
-                                      JNI_ABORT);
-        return count;
-    }
-
-    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
-                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
-        NPE_CHECK_RETURN_ZERO(env, jtext);
-
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
-        int count = env->GetStringLength(jtext);
-        const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
-        env->ReleaseStringChars(jtext, text);
-        return count;
-    }
-
     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
             const Paint& paint, Typeface* typeface, jint bidiFlags) {
         SkRect  r;
@@ -744,7 +360,7 @@
                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
+        const jchar* textArray = env->GetStringChars(text, nullptr);
         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
         env->ReleaseStringChars(text, textArray);
     }
@@ -753,12 +369,28 @@
                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
+        const jchar* textArray = env->GetCharArrayElements(text, nullptr);
         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
     }
 
+    // Returns true if the given string is exact one pair of regional indicators.
+    static bool isFlag(const jchar* str, size_t length) {
+        const jchar RI_LEAD_SURROGATE = 0xD83C;
+        const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
+        const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
+
+        if (length != 4) {
+            return false;
+        }
+        if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
+            return false;
+        }
+        return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
+            RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
+    }
+
     static jboolean layoutContainsNotdef(const minikin::Layout& layout) {
         for (size_t i = 0; i < layout.nGlyphs(); i++) {
             if (layout.getGlyphId(i) == 0) {
@@ -783,22 +415,6 @@
         return count;
     }
 
-    // Returns true if the given string is exact one pair of regional indicators.
-    static bool isFlag(const jchar* str, size_t length) {
-        const jchar RI_LEAD_SURROGATE = 0xD83C;
-        const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
-        const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
-
-        if (length != 4) {
-            return false;
-        }
-        if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
-            return false;
-        }
-        return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
-            RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
-    }
-
     static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
             jint bidiFlags, jstring string) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -893,7 +509,7 @@
             jint contextEnd, jboolean isRtl, jint offset) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
         jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
                 offset - contextStart);
@@ -915,7 +531,7 @@
             jint contextEnd, jboolean isRtl, jfloat advance) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
         jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
                 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
         result += contextStart;
@@ -923,76 +539,422 @@
         return result;
     }
 
+    // ------------------ @FastNative ---------------------------
+
+    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        ScopedUtfChars localesChars(env, locales);
+        jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
+        obj->setMinikinLangListId(minikinLangListId);
+        return minikinLangListId;
+    }
+
+    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (!settings) {
+            paint->setFontFeatureSettings(std::string());
+        } else {
+            ScopedUtfChars settingsChars(env, settings);
+            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+        }
+    }
+
+    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
+            Paint::FontMetrics *metrics) {
+        const int kElegantTop = 2500;
+        const int kElegantBottom = -1000;
+        const int kElegantAscent = 1900;
+        const int kElegantDescent = -500;
+        const int kElegantLeading = 0;
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
+        typeface = Typeface::resolveDefault(typeface);
+        minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
+        float saveSkewX = paint->getTextSkewX();
+        bool savefakeBold = paint->isFakeBoldText();
+        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
+        SkScalar spacing = paint->getFontMetrics(metrics);
+        // The populateSkPaint call may have changed fake bold / text skew
+        // because we want to measure with those effects applied, so now
+        // restore the original settings.
+        paint->setTextSkewX(saveSkewX);
+        paint->setFakeBoldText(savefakeBold);
+        if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
+            SkScalar size = paint->getTextSize();
+            metrics->fTop = -size * kElegantTop / 2048;
+            metrics->fBottom = -size * kElegantBottom / 2048;
+            metrics->fAscent = -size * kElegantAscent / 2048;
+            metrics->fDescent = -size * kElegantDescent / 2048;
+            metrics->fLeading = size * kElegantLeading / 2048;
+            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+        }
+        return spacing;
+    }
+
+    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
+        Paint::FontMetrics metrics;
+        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+
+        if (metricsObj) {
+            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
+            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+        }
+        return SkScalarToFloat(spacing);
+    }
+
+    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
+        Paint::FontMetrics metrics;
+
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        int ascent = SkScalarRoundToInt(metrics.fAscent);
+        int descent = SkScalarRoundToInt(metrics.fDescent);
+        int leading = SkScalarRoundToInt(metrics.fLeading);
+
+        if (metricsObj) {
+            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
+            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
+        }
+        return descent - ascent + leading;
+    }
+
+
+    // ------------------ @CriticalNative ---------------------------
+
+    static void reset(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        obj->reset();
+        defaultSettingsForAndroid(obj);
+    }
+
+    static void assign(jlong dstPaintHandle, jlong srcPaintHandle) {
+        Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
+        const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
+        *dst = *src;
+    }
+
+    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
+    static const uint32_t sFilterBitmapFlag = 0x02;
+
+    static jint getFlags(jlong paintHandle) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+        uint32_t result = nativePaint->getFlags();
+        result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
+        if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
+            result |= sFilterBitmapFlag;
+        }
+        return static_cast<jint>(result);
+    }
+
+    static void setFlags(jlong paintHandle, jint flags) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+        // Instead of modifying 0x02, change the filter level.
+        nativePaint->setFilterQuality(flags & sFilterBitmapFlag
+                ? kLow_SkFilterQuality
+                : kNone_SkFilterQuality);
+        // Don't pass through filter flag, which is no longer stored in paint's flags.
+        flags &= ~sFilterBitmapFlag;
+        // Use the existing value for 0x02.
+        const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
+        flags |= existing0x02Flag;
+        nativePaint->setFlags(flags);
+    }
+
+    static jint getHinting(jlong paintHandle) {
+        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
+                == Paint::kNo_Hinting ? 0 : 1;
+    }
+
+    static void setHinting(jlong paintHandle, jint mode) {
+        reinterpret_cast<Paint*>(paintHandle)->setHinting(
+                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
+    }
+
+    static void setAntiAlias(jlong paintHandle, jboolean aa) {
+        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
+    }
+
+    static void setLinearText(jlong paintHandle, jboolean linearText) {
+        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
+    }
+
+    static void setSubpixelText(jlong paintHandle, jboolean subpixelText) {
+        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
+    }
+
+    static void setUnderlineText(jlong paintHandle, jboolean underlineText) {
+        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
+    }
+
+    static void setStrikeThruText(jlong paintHandle, jboolean strikeThruText) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
+    }
+
+    static void setFakeBoldText(jlong paintHandle, jboolean fakeBoldText) {
+        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
+    }
+
+    static void setFilterBitmap(jlong paintHandle, jboolean filterBitmap) {
+        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
+                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
+    }
+
+    static void setDither(jlong paintHandle, jboolean dither) {
+        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
+    }
+
+    static jint getStyle(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStyle());
+    }
+
+    static void setStyle(jlong objHandle, jint styleHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Style style = static_cast<Paint::Style>(styleHandle);
+        obj->setStyle(style);
+    }
+
+    static jint getColor(jlong paintHandle) {
+        int color;
+        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
+        return static_cast<jint>(color);
+    }
+
+    static jint getAlpha(jlong paintHandle) {
+        int alpha;
+        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
+        return static_cast<jint>(alpha);
+    }
+
+    static void setColor(jlong paintHandle, jint color) {
+        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
+    }
+
+    static void setAlpha(jlong paintHandle, jint a) {
+        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
+    }
+
+    static jfloat getStrokeWidth(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
+    }
+
+    static void setStrokeWidth(jlong paintHandle, jfloat width) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
+    }
+
+    static jfloat getStrokeMiter(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
+    }
+
+    static void setStrokeMiter(jlong paintHandle, jfloat miter) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
+    }
+
+    static jint getStrokeCap(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStrokeCap());
+    }
+
+    static void setStrokeCap(jlong objHandle, jint capHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
+        obj->setStrokeCap(cap);
+    }
+
+    static jint getStrokeJoin(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getStrokeJoin());
+    }
+
+    static void setStrokeJoin(jlong objHandle, jint joinHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Join join = (Paint::Join) joinHandle;
+        obj->setStrokeJoin(join);
+    }
+
+    static jboolean getFillPath(jlong objHandle, jlong srcHandle, jlong dstHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
+        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
+        return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
+    }
+
+    static jlong setShader(jlong objHandle, jlong shaderHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
+        return reinterpret_cast<jlong>(obj->setShader(shader));
+    }
+
+    static jlong setColorFilter(jlong objHandle, jlong filterHandle) {
+        Paint* obj = reinterpret_cast<Paint *>(objHandle);
+        SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
+        return reinterpret_cast<jlong>(obj->setColorFilter(filter));
+    }
+
+    static void setXfermode(jlong paintHandle, jint xfermodeHandle) {
+        // validate that the Java enum values match our expectations
+        static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
+        static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
+        static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
+        static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
+        static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
+        static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
+        static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
+        static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
+        static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
+        static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
+        static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
+        static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
+        static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
+        static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
+        static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
+        static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
+        static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
+        static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
+
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setXfermodeMode(mode);
+    }
+
+    static jlong setPathEffect(jlong objHandle, jlong effectHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
+        return reinterpret_cast<jlong>(obj->setPathEffect(effect));
+    }
+
+    static jlong setMaskFilter(jlong objHandle, jlong maskfilterHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
+        return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
+    }
+
+    static jlong setTypeface(jlong objHandle, jlong typefaceHandle) {
+        // TODO: in Paint refactoring, set typeface on android Paint, not Paint
+        return 0;
+    }
+
+    static jlong setRasterizer(jlong objHandle, jlong rasterizerHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
+        return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
+    }
+
+    static jint getTextAlign(jlong objHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        return static_cast<jint>(obj->getTextAlign());
+    }
+
+    static void setTextAlign(jlong objHandle, jint alignHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        Paint::Align align = static_cast<Paint::Align>(alignHandle);
+        obj->setTextAlign(align);
+    }
+
+    static void setTextLocalesByMinikinLangListId(jlong objHandle,
+            jint minikinLangListId) {
+        Paint* obj = reinterpret_cast<Paint*>(objHandle);
+        obj->setMinikinLangListId(minikinLangListId);
+    }
+
+    static jboolean isElegantTextHeight(jlong paintHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+        return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
+    }
+
+    static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+        obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
+    }
+
+    static jfloat getTextSize(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
+    }
+
+    static void setTextSize(jlong paintHandle, jfloat textSize) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
+    }
+
+    static jfloat getTextScaleX(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
+    }
+
+    static void setTextScaleX(jlong paintHandle, jfloat scaleX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
+    }
+
+    static jfloat getTextSkewX(jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
+    }
+
+    static void setTextSkewX(jlong paintHandle, jfloat skewX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
+    }
+
+    static jfloat getLetterSpacing(jlong paintHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getLetterSpacing();
+    }
+
+    static void setLetterSpacing(jlong paintHandle, jfloat letterSpacing) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setLetterSpacing(letterSpacing);
+    }
+
+    static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getHyphenEdit();
+    }
+
+    static void setHyphenEdit(jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setHyphenEdit((uint32_t)hyphen);
+    }
+
+    static jfloat ascent(jlong paintHandle, jlong typefaceHandle) {
+        Paint::FontMetrics metrics;
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        return SkScalarToFloat(metrics.fAscent);
+    }
+
+    static jfloat descent(jlong paintHandle, jlong typefaceHandle) {
+        Paint::FontMetrics metrics;
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+        return SkScalarToFloat(metrics.fDescent);
+    }
+
+    static void setShadowLayer(jlong paintHandle, jfloat radius,
+                               jfloat dx, jfloat dy, jint color) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        if (radius <= 0) {
+            paint->setLooper(nullptr);
+        }
+        else {
+            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
+        }
+    }
+
+    static jboolean hasShadowLayer(jlong paintHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
+    }
+
 }; // namespace PaintGlue
 
 static const JNINativeMethod methods[] = {
     {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
     {"nInit","()J", (void*) PaintGlue::init},
     {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
-
-    {"nReset","!(J)V", (void*) PaintGlue::reset},
-    {"nSet","!(JJ)V", (void*) PaintGlue::assign},
-    {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
-    {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
-    {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
-    {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
-    {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
-    {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
-    {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
-    {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
-    {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
-    {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
-    {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
-    {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
-    {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
-    {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
-    {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
-    {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
-    {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
-    {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
-    {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
-    {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
-    {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
-    {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
-    {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
-    {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
-    {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
-    {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
-    {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
-    {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
-    {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
-    {"nSetXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
-    {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
-    {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
-    {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
-    {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
-    {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
-    {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
-    {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
-    {"nSetTextLocalesByMinikinLangListId","!(JI)V",
-            (void*) PaintGlue::setTextLocalesByMinikinLangListId},
-    {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
-    {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
-    {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
-    {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
-    {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
-    {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
-    {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
-    {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
-    {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
-    {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
-    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
-            (void*) PaintGlue::setFontFeatureSettings},
-    {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
-    {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
-    {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
-    {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
-
-    {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
-            (void*)PaintGlue::getFontMetrics},
-    {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
-            (void*)PaintGlue::getFontMetricsInt},
-
     {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
     {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
     {"nGetTextAdvances","(JJ[CIIIII[FI)F",
@@ -1014,8 +976,74 @@
     {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
 
-    {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
-    {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
+    // --------------- @FastNative ----------------------
+
+    {"nSetTextLocales","(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
+    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
+                (void*) PaintGlue::setFontFeatureSettings},
+    {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+                (void*)PaintGlue::getFontMetrics},
+    {"nGetFontMetricsInt", "(JJLandroid/graphics/Paint$FontMetricsInt;)I",
+            (void*)PaintGlue::getFontMetricsInt},
+
+    // --------------- @CriticalNative ------------------
+
+    {"nReset","(J)V", (void*) PaintGlue::reset},
+    {"nSet","(JJ)V", (void*) PaintGlue::assign},
+    {"nGetFlags","(J)I", (void*) PaintGlue::getFlags},
+    {"nSetFlags","(JI)V", (void*) PaintGlue::setFlags},
+    {"nGetHinting","(J)I", (void*) PaintGlue::getHinting},
+    {"nSetHinting","(JI)V", (void*) PaintGlue::setHinting},
+    {"nSetAntiAlias","(JZ)V", (void*) PaintGlue::setAntiAlias},
+    {"nSetSubpixelText","(JZ)V", (void*) PaintGlue::setSubpixelText},
+    {"nSetLinearText","(JZ)V", (void*) PaintGlue::setLinearText},
+    {"nSetUnderlineText","(JZ)V", (void*) PaintGlue::setUnderlineText},
+    {"nSetStrikeThruText","(JZ)V", (void*) PaintGlue::setStrikeThruText},
+    {"nSetFakeBoldText","(JZ)V", (void*) PaintGlue::setFakeBoldText},
+    {"nSetFilterBitmap","(JZ)V", (void*) PaintGlue::setFilterBitmap},
+    {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
+    {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
+    {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
+    {"nGetColor","(J)I", (void*) PaintGlue::getColor},
+    {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
+    {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
+    {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
+    {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
+    {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
+    {"nGetStrokeMiter","(J)F", (void*) PaintGlue::getStrokeMiter},
+    {"nSetStrokeMiter","(JF)V", (void*) PaintGlue::setStrokeMiter},
+    {"nGetStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
+    {"nSetStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
+    {"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
+    {"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
+    {"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
+    {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
+    {"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
+    {"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
+    {"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
+    {"nSetMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
+    {"nSetTypeface","(JJ)J", (void*) PaintGlue::setTypeface},
+    {"nSetRasterizer","(JJ)J", (void*) PaintGlue::setRasterizer},
+    {"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
+    {"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
+    {"nSetTextLocalesByMinikinLangListId","(JI)V",
+            (void*) PaintGlue::setTextLocalesByMinikinLangListId},
+    {"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
+    {"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
+    {"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
+    {"nSetTextSize","(JF)V", (void*) PaintGlue::setTextSize},
+    {"nGetTextScaleX","(J)F", (void*) PaintGlue::getTextScaleX},
+    {"nSetTextScaleX","(JF)V", (void*) PaintGlue::setTextScaleX},
+    {"nGetTextSkewX","(J)F", (void*) PaintGlue::getTextSkewX},
+    {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
+    {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
+    {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
+    {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
+    {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
+    {"nAscent","(JJ)F", (void*) PaintGlue::ascent},
+    {"nDescent","(JJ)F", (void*) PaintGlue::descent},
+    {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+    {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
 };
 
 int register_android_graphics_Paint(JNIEnv* env) {
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
deleted file mode 100644
index dfc3c9d..0000000
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/* libs/android_runtime/android/graphics/PorterDuff.cpp
-**
-** Copyright 2006, 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.
-*/
-
-// This file was generated from the C++ include file: SkPorterDuff.h
-// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, 
-// or one of the auxilary file specifications in device/tools/gluemaker.
-
-#include "jni.h"
-#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
-
-#include "SkXfermode.h"
-
-namespace android {
-
-class SkPorterDuffGlue {
-public:
-
-    static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) {
-        // validate that the Java enum values match our expectations
-        static_assert(0  == SkXfermode::kClear_Mode,    "xfermode_mismatch");
-        static_assert(1  == SkXfermode::kSrc_Mode,      "xfermode_mismatch");
-        static_assert(2  == SkXfermode::kDst_Mode,      "xfermode_mismatch");
-        static_assert(3  == SkXfermode::kSrcOver_Mode,  "xfermode_mismatch");
-        static_assert(4  == SkXfermode::kDstOver_Mode,  "xfermode_mismatch");
-        static_assert(5  == SkXfermode::kSrcIn_Mode,    "xfermode_mismatch");
-        static_assert(6  == SkXfermode::kDstIn_Mode,    "xfermode_mismatch");
-        static_assert(7  == SkXfermode::kSrcOut_Mode,   "xfermode_mismatch");
-        static_assert(8  == SkXfermode::kDstOut_Mode,   "xfermode_mismatch");
-        static_assert(9  == SkXfermode::kSrcATop_Mode,  "xfermode_mismatch");
-        static_assert(10 == SkXfermode::kDstATop_Mode,  "xfermode_mismatch");
-        static_assert(11 == SkXfermode::kXor_Mode,      "xfermode_mismatch");
-        static_assert(16 == SkXfermode::kDarken_Mode,   "xfermode_mismatch");
-        static_assert(17 == SkXfermode::kLighten_Mode,  "xfermode_mismatch");
-        static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
-        static_assert(14 == SkXfermode::kScreen_Mode,   "xfermode_mismatch");
-        static_assert(12 == SkXfermode::kPlus_Mode,     "xfermode_mismatch");
-        static_assert(15 == SkXfermode::kOverlay_Mode,  "xfermode_mismatch");
-
-        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(SkXfermode::Create(mode));
-    }
-
-};
-
-static const JNINativeMethod methods[] = {
-    {"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode},
-};
-
-int register_android_graphics_PorterDuff(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/graphics/PorterDuffXfermode", methods, NELEM(methods));
-}
-
-}
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index de32dd9..03462a6 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -1,5 +1,6 @@
 #include "GraphicsJNI.h"
 #include "SkGradientShader.h"
+#include "SkImagePriv.h"
 #include "SkShader.h"
 #include "SkXfermode.h"
 #include "core_jni_helpers.h"
@@ -94,12 +95,15 @@
         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
         GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     }
-    SkShader* s = SkShader::CreateBitmapShader(bitmap,
-                                        (SkShader::TileMode)tileModeX,
-                                        (SkShader::TileMode)tileModeY);
+    sk_sp<SkShader> s = SkMakeBitmapShader(bitmap,
+                                           (SkShader::TileMode)tileModeX,
+                                           (SkShader::TileMode)tileModeY,
+                                           nullptr,
+                                           kNever_SkCopyPixelsMode,
+                                           nullptr);
 
-    ThrowIAE_IfNull(env, s);
-    return reinterpret_cast<jlong>(s);
+    ThrowIAE_IfNull(env, s.get());
+    return reinterpret_cast<jlong>(s.release());
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -225,24 +229,13 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong ComposeShader_create1(JNIEnv* env, jobject o,
-        jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle)
-{
-    SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
-    SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
-    SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
-    SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, mode);
-    return reinterpret_cast<jlong>(shader);
-}
-
-static jlong ComposeShader_create2(JNIEnv* env, jobject o,
+static jlong ComposeShader_create(JNIEnv* env, jobject o,
         jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
 {
     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
     SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
-    SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
-    SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, xfermode.get());
+    SkShader* shader = SkShader::CreateComposeShader(shaderA, shaderB, mode);
     return reinterpret_cast<jlong>(shader);
 }
 
@@ -278,8 +271,7 @@
 };
 
 static const JNINativeMethod gComposeShaderMethods[] = {
-    { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
-    { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
+    { "nativeCreate",      "(JJI)J",   (void*)ComposeShader_create     },
 };
 
 int register_android_graphics_Shader(JNIEnv* env)
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index d1a74a0..fffec5b 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -28,7 +28,7 @@
 
 class AssetStreamAdaptor : public SkStreamRewindable {
 public:
-    AssetStreamAdaptor(Asset*);
+    explicit AssetStreamAdaptor(Asset*);
 
     virtual bool rewind();
     virtual size_t read(void* buffer, size_t size);
@@ -53,7 +53,7 @@
  */
 class AutoFDSeek {
 public:
-    AutoFDSeek(int fd) : fFD(fd) {
+    explicit AutoFDSeek(int fd) : fFD(fd) {
         fCurr = ::lseek(fd, 0, SEEK_CUR);
     }
     ~AutoFDSeek() {
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
deleted file mode 100644
index 78975a4f..0000000
--- a/core/jni/android/graphics/Xfermode.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2007 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 "jni.h"
-//#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
-
-#include <SkXfermode.h>
-
-namespace android {
-
-class SkXfermodeGlue {
-public:
-    static void finalizer(JNIEnv* env, jobject, jlong objHandle)
-    {
-        SkXfermode* obj = reinterpret_cast<SkXfermode *>(objHandle);
-        SkSafeUnref(obj);
-    }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const JNINativeMethod gXfermodeMethods[] = {
-    {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer}
-};
-
-int register_android_graphics_Xfermode(JNIEnv* env) {
-    android::RegisterMethodsOrDie(env, "android/graphics/Xfermode", gXfermodeMethods,
-                                  NELEM(gXfermodeMethods));
-    return 0;
-}
-
-}
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.h b/core/jni/android/graphics/YuvToJpegEncoder.h
index 1ea844a..7e7b935 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.h
+++ b/core/jni/android/graphics/YuvToJpegEncoder.h
@@ -18,7 +18,7 @@
      */
     static YuvToJpegEncoder* create(int pixelFormat, int* strides);
 
-    YuvToJpegEncoder(int* strides);
+    explicit YuvToJpegEncoder(int* strides);
 
     /** Encode YUV data to jpeg,  which is output to a stream.
      *
@@ -47,7 +47,7 @@
 
 class Yuv420SpToJpegEncoder : public YuvToJpegEncoder {
 public:
-    Yuv420SpToJpegEncoder(int* strides);
+    explicit Yuv420SpToJpegEncoder(int* strides);
     virtual ~Yuv420SpToJpegEncoder() {}
 
 private:
@@ -61,7 +61,7 @@
 
 class Yuv422IToJpegEncoder : public YuvToJpegEncoder {
 public:
-    Yuv422IToJpegEncoder(int* strides);
+    explicit Yuv422IToJpegEncoder(int* strides);
     virtual ~Yuv422IToJpegEncoder() {}
 
 private:
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 7213414..3fc3aaf 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -16,6 +16,7 @@
 
 #undef LOG_TAG
 #define LOG_TAG "CursorWindow"
+#define LOG_NDEBUG 0
 
 #include <inttypes.h>
 #include <jni.h>
@@ -30,6 +31,11 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 1
 
 #include <androidfw/CursorWindow.h>
 #include "android_os_Parcel.h"
@@ -61,6 +67,22 @@
     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
 }
 
+static int getFdCount() {
+    char fdpath[PATH_MAX];
+    int count = 0;
+    snprintf(fdpath, PATH_MAX, "/proc/%d/fd", getpid());
+    DIR *dir = opendir(fdpath);
+    if (dir != NULL) {
+        struct dirent *dirent;
+        while ((dirent = readdir(dir))) {
+            count++;
+        }
+        count -= 2; // discount "." and ".."
+        closedir(dir);
+    }
+    return count;
+}
+
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
     String8 name;
     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
@@ -85,7 +107,8 @@
     CursorWindow* window;
     status_t status = CursorWindow::createFromParcel(parcel, &window);
     if (status || !window) {
-        ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
+        ALOGE("Could not create CursorWindow from Parcel due to error %d, process fd count=%d",
+                status, getFdCount());
         return 0;
     }
 
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9459257..b926270 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -350,9 +350,16 @@
     postData(msgType, dataPtr, NULL);
 }
 
-void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) {
-    // This is not needed at app layer. This should not be called because JNICameraContext cannot
-    // start video recording.
+void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t* handle) {
+    // Video buffers are not needed at app layer so just return the video buffers here.
+    // This may be called when stagefright just releases camera but there are still outstanding
+    // video buffers.
+    if (mCamera != nullptr) {
+        mCamera->releaseRecordingFrameHandle(handle);
+    } else {
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
 }
 
 void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 1ba9fc5..7ec17bf 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -235,7 +235,7 @@
 {
     struct usb_device* device = get_device_from_object(env, thiz);
     if (!device) {
-        ALOGE("device is closed in native_request_wait");
+        ALOGE("device is closed in native_get_serial");
         return NULL;
     }
     char* serial = usb_device_get_serial(device);
@@ -246,6 +246,18 @@
     return result;
 }
 
+static jboolean
+android_hardware_UsbDeviceConnection_reset_device(JNIEnv *env, jobject thiz)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        ALOGE("device is closed in native_reset_device");
+        return JNI_FALSE;
+    }
+    int ret = usb_device_reset(device);
+    return (ret == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
 static const JNINativeMethod method_table[] = {
     {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
                                         (void *)android_hardware_UsbDeviceConnection_open},
@@ -264,6 +276,7 @@
                                         (void *)android_hardware_UsbDeviceConnection_request_wait},
     { "native_get_serial",      "()Ljava/lang/String;",
                                         (void*)android_hardware_UsbDeviceConnection_get_serial },
+    {"native_reset_device","()Z", (void *)android_hardware_UsbDeviceConnection_reset_device},
 };
 
 int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index 399e7b1..4cbe3e4 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -47,7 +47,7 @@
     struct usb_device* device = get_device_from_object(env, java_device);
     if (!device) {
         ALOGE("device null in native_init");
-        return false;
+        return JNI_FALSE;
     }
 
     // construct an endpoint descriptor from the Java object fields
@@ -83,13 +83,13 @@
     struct usb_request* request = get_request_from_object(env, thiz);
     if (!request) {
         ALOGE("request is closed in native_queue");
-        return false;
+        return JNI_FALSE;
     }
 
     if (buffer && length) {
         request->buffer = malloc(length);
         if (!request->buffer)
-            return false;
+            return JNI_FALSE;
         memset(request->buffer, 0, length);
         if (out) {
             // copy data from Java buffer to native buffer
@@ -110,9 +110,9 @@
             request->buffer = NULL;
         }
         env->DeleteGlobalRef((jobject)request->client_data);
-        return false;
+        return JNI_FALSE;
     }
-    return true;
+    return JNI_TRUE;
 }
 
 static jint
@@ -141,13 +141,13 @@
     struct usb_request* request = get_request_from_object(env, thiz);
     if (!request) {
         ALOGE("request is closed in native_queue");
-        return false;
+        return JNI_FALSE;
     }
 
     if (buffer && length) {
         request->buffer = env->GetDirectBufferAddress(buffer);
         if (!request->buffer)
-            return false;
+            return JNI_FALSE;
     } else {
         request->buffer = NULL;
     }
@@ -161,9 +161,9 @@
     if (usb_request_queue(request)) {
         request->buffer = NULL;
         env->DeleteGlobalRef((jobject)request->client_data);
-        return false;
+        return JNI_FALSE;
     }
-    return true;
+    return JNI_TRUE;
 }
 
 static jint
@@ -185,7 +185,7 @@
     struct usb_request* request = get_request_from_object(env, thiz);
     if (!request) {
         ALOGE("request is closed in native_cancel");
-        return false;
+        return JNI_FALSE;
     }
     return (usb_request_cancel(request) == 0);
 }
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 7a8a574..fbccfd5 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -26,19 +26,25 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+
+// TOOD: On master, alphabetize these and move <mutex> into this
+//     grouping.
+#include <chrono>
 #include <unordered_map>
 #include <queue>
 
+#include <android-base/macros.h>
 #include <cutils/log.h>
 
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 
-static constexpr int OS_APP_ID = -1;
+static constexpr jint OS_APP_ID = -1;
+static constexpr jint INVALID_APP_ID = -2;
 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
 
-static constexpr int MIN_APP_ID = 1;
-static constexpr int MAX_APP_ID = 128;
+static constexpr jint MIN_APP_ID = 1;
+static constexpr jint MAX_APP_ID = 128;
 
 static constexpr size_t MSG_HEADER_SIZE = 4;
 static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
@@ -50,6 +56,10 @@
 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
 static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
 
+// Monotonically increasing clock we use to determine if we can cancel
+// a transaction.
+using std::chrono::steady_clock;
+
 namespace android {
 
 namespace {
@@ -102,10 +112,21 @@
 struct app_instance_info_s {
     uint64_t truncName;          // Possibly truncated name for logging
     uint32_t hubHandle;          // Id of the hub this app is on
-    int instanceId;              // system wide unique instance id - assigned
+    jint instanceId;             // system wide unique instance id - assigned
     struct hub_app_info appInfo; // returned from the HAL
 };
 
+
+// If a transaction takes longer than this, we'll allow it to be
+// canceled by a new transaction.  Note we do _not_ automatically
+// cancel a transaction after this much time.  We can have a
+// legal transaction which takes longer than this amount of time,
+// as long as no other new transactions are attempted after this
+// time has expired.
+// TODO(b/31105001): Establish a clean timing approach for all
+// of our HAL interactions.
+constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
+
 /*
  * TODO(ashutoshj): From original code review:
  *
@@ -147,14 +168,15 @@
     std::mutex m;                 // mutex for manager
     hub_messages_e txnIdentifier; // What are we doing
     void *txnData;                // Details
+    steady_clock::time_point firstTimeTxnCanBeCanceled;
 };
 
 struct contextHubServiceDb_s {
     int initialized;
     context_hub_info_s hubInfo;
     jniInfo_s jniInfo;
-    std::queue<int> freeIds;
-    std::unordered_map<int, app_instance_info_s> appInstances;
+    std::queue<jint> freeIds;
+    std::unordered_map<jint, app_instance_info_s> appInstances;
     txnManager_s txnManager;
 };
 
@@ -176,25 +198,40 @@
     std::lock_guard<std::mutex>lock(mgr->m);
 
     mgr->txnPending = true;
+    mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
+        kMinTransactionCancelTime;
     mgr->txnData = txnData;
     mgr->txnIdentifier = txnIdentifier;
 
     return 0;
 }
 
-static int closeTxn() {
+// Only call this if you hold the db.txnManager.m lock.
+static void closeTxnUnlocked() {
     txnManager_s *mgr = &db.txnManager;
-    std::lock_guard<std::mutex>lock(mgr->m);
     mgr->txnPending = false;
     free(mgr->txnData);
     mgr->txnData = nullptr;
+}
 
+static int closeTxn() {
+    std::lock_guard<std::mutex>lock(db.txnManager.m);
+    closeTxnUnlocked();
     return 0;
 }
 
+// If a transaction has been pending for longer than
+// kMinTransactionCancelTime, this call will "cancel" that
+// transaction and return that there are none pending.
 static bool isTxnPending() {
     txnManager_s *mgr = &db.txnManager;
     std::lock_guard<std::mutex>lock(mgr->m);
+    if (mgr->txnPending) {
+        if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
+            ALOGW("Transaction canceled");
+            closeTxnUnlocked();
+        }
+    }
     return mgr->txnPending;
 }
 
@@ -259,16 +296,17 @@
     }
 }
 
-static int get_hub_handle_for_app_instance(int id) {
+static int get_hub_handle_for_app_instance(jint id) {
     if (!db.appInstances.count(id)) {
-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        ALOGD("%s: Cannot find app for app instance %" PRId32,
+              __FUNCTION__, id);
         return -1;
     }
 
     return db.appInstances[id].hubHandle;
 }
 
-static int get_hub_id_for_app_instance(int id) {
+static int get_hub_id_for_app_instance(jint id) {
     int hubHandle = get_hub_handle_for_app_instance(id);
 
     if (hubHandle < 0) {
@@ -278,7 +316,7 @@
     return db.hubInfo.hubs[hubHandle].hub_id;
 }
 
-static int get_app_instance_for_app_id(uint64_t app_id) {
+static jint get_app_instance_for_app_id(uint64_t app_id) {
     auto end = db.appInstances.end();
     for (auto current = db.appInstances.begin(); current != end; ++current) {
         if (current->second.appInfo.app_name.id == app_id) {
@@ -289,9 +327,10 @@
     return -1;
 }
 
-static int set_dest_app(hub_message_t *msg, int id) {
+static int set_dest_app(hub_message_t *msg, jint id) {
     if (!db.appInstances.count(id)) {
-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        ALOGD("%s: Cannot find app for app instance %" PRId32,
+              __FUNCTION__, id);
         return -1;
     }
 
@@ -299,11 +338,15 @@
     return 0;
 }
 
-static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
+static void query_hub_for_apps(uint32_t hubHandle) {
     hub_message_t msg;
     query_apps_request_t queryMsg;
 
-    queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
+    // TODO(b/30835598): When we're able to tell which request our
+    //     response matches, then we should allow this to be more
+    //     targetted, instead of always being every app in the
+    //     system.
+    queryMsg.app_name.id = ALL_APPS;
 
     msg.message_type = CONTEXT_HUB_QUERY_APPS;
     msg.message_len  = sizeof(queryMsg);
@@ -316,13 +359,13 @@
     }
 }
 
-static void sendQueryForApps(uint64_t appId) {
+static void sendQueryForApps() {
     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
-        query_hub_for_apps(appId, i);
+        query_hub_for_apps(i);
     }
 }
 
-static int return_id(int id) {
+static int return_id(jint id) {
     // Note : This method is not thread safe.
     // id returned is guaranteed to be in use
     if (id >= 0) {
@@ -333,9 +376,9 @@
     return -1;
 }
 
-static int generate_id() {
+static jint generate_id() {
     // Note : This method is not thread safe.
-    int retVal = -1;
+    jint retVal = -1;
 
     if (!db.freeIds.empty()) {
         retVal = db.freeIds.front();
@@ -346,23 +389,14 @@
 }
 
 
-static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
-        int appInstanceHandle, JNIEnv *env) {
-
-    ALOGI("Loading App");
-
+static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
+        jint appInstanceHandle, JNIEnv *env) {
     // Not checking if the apps are indeed distinct
     app_instance_info_s entry;
     assert(appInfo);
 
-    if (db.appInstances.count(appInstanceHandle) == 0) {
-        appInstanceHandle = generate_id();
-        if (appInstanceHandle < 0) {
-            ALOGE("Cannot find resources to add app instance %d",
-                  appInstanceHandle);
-            return -1;
-        }
-    }
+    const char *action =
+        (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
 
     entry.appInfo = *appInfo;
 
@@ -372,42 +406,49 @@
 
     db.appInstances[appInstanceHandle] = entry;
 
-    // Finally - let the service know of this app instance
+    // Finally - let the service know of this app instance, to populate
+    // the Java cache.
     env->CallIntMethod(db.jniInfo.jContextHubService,
                        db.jniInfo.contextHubServiceAddAppInstance,
                        hubHandle, entry.instanceId, entry.truncName,
                        entry.appInfo.version);
 
-    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
-          " as appInstance %d", entry.truncName,
+    ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
+          " as appInstance %" PRId32, action, entry.truncName,
           entry.hubHandle, appInstanceHandle);
 
     return appInstanceHandle;
 }
 
-int delete_app_instance(int id, JNIEnv *env) {
-    if (!db.appInstances.count(id)) {
-        ALOGW("Cannot find App id : %d", id);
-        return -1;
-    }
+int delete_app_instance(jint id, JNIEnv *env) {
+    bool fullyDeleted = true;
 
+    if (db.appInstances.count(id)) {
+        db.appInstances.erase(id);
+    } else {
+        ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
+        fullyDeleted = false;
+    }
     return_id(id);
-    db.appInstances.erase(id);
-    if (env->CallIntMethod(db.jniInfo.jContextHubService,
+
+    if ((env == nullptr) ||
+        (env->CallIntMethod(db.jniInfo.jContextHubService,
                        db.jniInfo.contextHubServiceDeleteAppInstance,
-                       id) != 0) {
-        ALOGW("Could not delete App id : %d", id);
-        return -1;
+                       id) != 0)) {
+        ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
+        fullyDeleted = false;
     }
 
-    ALOGI("Deleted App id : %d", id);
-
-    return 0;
+    if (fullyDeleted) {
+        ALOGI("Deleted App id : %" PRId32, id);
+        return 0;
+    }
+    return -1;
 }
 
 static int startLoadAppTxn(uint64_t appId, int hubHandle) {
     app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
-    int instanceId = generate_id();
+    jint instanceId = generate_id();
 
     if (!txnInfo || instanceId < 0) {
         return_id(instanceId);
@@ -432,8 +473,8 @@
     return 0;
 }
 
-static int startUnloadAppTxn(uint32_t appInstanceHandle) {
-    uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
+static int startUnloadAppTxn(jint appInstanceHandle) {
+    jint *txnData = (jint *) malloc(sizeof(jint));
     if (!txnData) {
         ALOGW("Cannot allocate memory to start unload transaction");
         return -1;
@@ -454,7 +495,6 @@
     int err = 0;
     db.hubInfo.hubs = nullptr;
     db.hubInfo.numHubs = 0;
-    int i;
 
     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
@@ -465,7 +505,7 @@
     }
 
     // Prep for storing app info
-    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+    for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
         db.freeIds.push(i);
     }
 
@@ -485,7 +525,7 @@
                 return;
             }
 
-            for (i = 0; i < db.hubInfo.numHubs; i++) {
+            for (int i = 0; i < db.hubInfo.numHubs; i++) {
                 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
                 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
                 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
@@ -495,7 +535,7 @@
             }
         }
 
-        sendQueryForApps(ALL_APPS);
+        sendQueryForApps();
     } else {
         ALOGW("No Context Hub Module present");
     }
@@ -539,21 +579,70 @@
             return -1;
     }
 
-    int numApps = msgLen/sizeof(hub_app_info);
-    hub_app_info info;
+    int numApps = msgLen / sizeof(hub_app_info);
     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
 
-    for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
-        memcpy(&info, unalignedInfoAddr, sizeof(info));
+    // We use this information to sync our JNI and Java caches of nanoapp info.
+    // We want to accomplish two things here:
+    // 1) Remove entries from our caches which are stale, and pertained to
+    //    apps no longer running on Context Hub.
+    // 2) Populate our caches with the latest information of all these apps.
+
+    // We make a couple of assumptions here:
+    // A) The JNI and Java caches are in sync with each other (this isn't
+    //    necessarily true; any failure of a single call into Java land to
+    //    update its cache will leave that cache in a bad state.  For NYC,
+    //    we're willing to tolerate this for now).
+    // B) The total number of apps is relatively small, so horribly inefficent
+    //    algorithms aren't too painful.
+    // C) We're going to call this relatively infrequently, so its inefficency
+    //    isn't a big impact.
+
+
+    // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
+    // assumption (B).  Per assumption (A), it is sufficient to iterate
+    // over just the JNI cache.
+    auto end = db.appInstances.end();
+    for (auto current = db.appInstances.begin(); current != end; ) {
+        app_instance_info_s cache_entry = current->second;
+        // We perform our iteration here because if we call
+        // delete_app_instance() below, it will erase() this entry.
+        current++;
+        bool entryIsStale = true;
+        for (int i = 0; i < numApps; i++) {
+            // We use memcmp since this could be unaligned.
+            if (memcmp(&unalignedInfoAddr[i].app_name.id,
+                       &cache_entry.appInfo.app_name.id,
+                       sizeof(cache_entry.appInfo.app_name.id)) == 0) {
+                // We found a match; this entry is current.
+                entryIsStale = false;
+                break;
+            }
+        }
+        if (entryIsStale) {
+            delete_app_instance(cache_entry.instanceId, env);
+        }
+    }
+
+    // (2).  Update our caches with the latest.
+    for (int i = 0; i < numApps; i++) {
+        hub_app_info query_info;
+        memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
         // We will only have one instance of the app
         // TODO : Change this logic once we support multiple instances of the same app
-        int appInstance = get_app_instance_for_app_id(info.app_name.id);
-        add_app_instance(&info, hubHandle, appInstance, env);
+        jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
+        if (appInstance == -1) {
+            // This is a previously unknown app, let's allocate an "id" for it.
+            appInstance = generate_id();
+        }
+        add_app_instance(&query_info, hubHandle, appInstance, env);
     }
 
     return 0;
 }
 
+// TODO(b/30807327): Do not use raw bytes for additional data.  Use the
+//     JNI interfaces for the appropriate types.
 static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
                              status_response_t *rsp, int8_t *additionalData,
                              size_t additionalDataLen) {
@@ -584,17 +673,42 @@
     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
 
-    msg[0] = rsp->result;
+    // Due to API constraints, at the moment we can't change the fact that
+    // we're changing our 4-byte response to a 1-byte value.  But we can prevent
+    // the possible change in sign (and thus meaning) that would happen from
+    // a naive cast.  Further, we can log when we're losing part of the value.
+    // TODO(b/30918279): Don't truncate this result.
+    int8_t truncatedResult;
+    bool neededToTruncate;
+    if (rsp->result < INT8_MIN) {
+        neededToTruncate = true;
+        truncatedResult = INT8_MIN;
+    } else if (rsp->result > INT8_MAX) {
+        neededToTruncate = true;
+        truncatedResult = INT8_MAX;
+    } else {
+        neededToTruncate = false;
+        // Since this value fits within an int8_t, this is a safe cast which
+        // won't change the value or sign.
+        truncatedResult = static_cast<int8_t>(rsp->result);
+    }
+    if (neededToTruncate) {
+        ALOGW("Response from Context Hub truncated.  Value was %" PRId32
+              ", but giving Java layer %" PRId8,
+              rsp->result, (int)truncatedResult);
+    }
+
+    msg[0] = truncatedResult;
 
     if (additionalData) {
         memcpy(&msg[1], additionalData, additionalDataLen);
     }
 
     jbyteArray jmsg = env->NewByteArray(msgLen);
-    jintArray jheader = env->NewIntArray(sizeof(header));
+    jintArray jheader = env->NewIntArray(arraysize(header));
 
     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
-    env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
+    env->SetIntArrayRegion(jheader, 0, arraysize(header), (jint *)header);
 
     ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
           header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
@@ -615,7 +729,13 @@
 
     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
         txnId == CONTEXT_HUB_UNLOAD_APP) {
-        db.appInstances.erase(*(uint32_t *)txnData);
+        JNIEnv *env;
+        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+            ALOGW("Could not attach to JVM !");
+            env = nullptr;
+        }
+        jint handle = *reinterpret_cast<jint *>(txnData);
+        delete_app_instance(handle, env);
     } else {
         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
     }
@@ -623,7 +743,7 @@
     closeTxn();
 }
 
-void closeLoadTxn(bool success, int *appInstanceHandle) {
+static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
     void *txnData;
     hub_messages_e txnId;
 
@@ -637,13 +757,22 @@
             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
         } else {
             ALOGW("Could not attach to JVM !");
+            success = false;
         }
-        sendQueryForApps(info->appInfo.app_name.id);
+        // While we just called add_app_instance above, our info->appInfo was
+        // incomplete (for example, the 'version' is hardcoded to -1).  So we
+        // trigger an additional query to the CHRE, so we'll be able to get
+        // all the app "info", and have our JNI and Java caches with the
+        // full information.
+        sendQueryForApps();
     } else {
         ALOGW("Could not load the app successfully ! Unexpected failure");
+        *appInstanceHandle = INVALID_APP_ID;
+        success = false;
     }
 
     closeTxn();
+    return success;
 }
 
 static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
@@ -665,23 +794,6 @@
     return true;
 }
 
-static void invalidateNanoApps(uint32_t hubHandle) {
-    JNIEnv *env;
-
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-        ALOGW("Could not attach to JVM !");
-    }
-
-    auto end = db.appInstances.end();
-    for (auto current = db.appInstances.begin(); current != end; ) {
-        app_instance_info_s info = current->second;
-        current++;
-        if (info.hubHandle == hubHandle) {
-             delete_app_instance(info.instanceId, env);
-        }
-    }
-}
-
 static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
                              const uint8_t *msg, int msgLen) {
     int retVal = -1;
@@ -699,8 +811,27 @@
       case CONTEXT_HUB_UNLOAD_APP:
           if (isValidOsStatus(msg, msgLen, &rsp)) {
               if (msgType == CONTEXT_HUB_LOAD_APP) {
-                  int appInstanceHandle;
-                  closeLoadTxn(rsp.result == 0, &appInstanceHandle);
+                  jint appInstanceHandle = INVALID_APP_ID;
+                  bool appRunningOnHub = (rsp.result == 0);
+                  if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
+                      if (appRunningOnHub) {
+                          // Now we're in an odd situation.  Our nanoapp
+                          // is up and running on the Context Hub.  However,
+                          // something went wrong in our Service code so that
+                          // we're not able to properly track this nanoapp
+                          // in our Service code.  If we tell the Java layer
+                          // things are good, it's a lie because the handle
+                          // we give them will fail when used with the Service.
+                          // If we tell the Java layer this failed, it's kind
+                          // of a lie as well, since this nanoapp is running.
+                          //
+                          // We leave a more robust fix for later, and for
+                          // now just tell the user things have failed.
+                          //
+                          // TODO(b/30835981): Make this situation better.
+                          rsp.result = -1;
+                      }
+                  }
                   passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
                                    sizeof(appInstanceHandle));
               } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
@@ -730,8 +861,7 @@
               ALOGW("Context Hub handle %d restarted", hubHandle);
               closeTxn();
               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
-              invalidateNanoApps(hubHandle);
-              query_hub_for_apps(ALL_APPS, hubHandle);
+              query_hub_for_apps(hubHandle);
               retVal = 0;
           }
           break;
@@ -780,7 +910,7 @@
     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
     } else {
-        int appHandle = get_app_instance_for_app_id(msg->app_name.id);
+        jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
         if (appHandle < 0) {
             ALOGE("Filtering out message due to invalid App Instance.");
         } else {
@@ -1053,7 +1183,8 @@
         ALOGD("Asking HAL to remove app");
         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
     } else {
-      ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+      ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
+            ", setAddress %d",
             header[HEADER_FIELD_APP_INSTANCE],
             header[HEADER_FIELD_HUB_HANDLE],
             (int)setAddressSuccess);
@@ -1062,7 +1193,8 @@
     if (retVal != 0) {
         ALOGD("Send Message failure - %d", retVal);
         if (msgType == CONTEXT_HUB_LOAD_APP) {
-            closeLoadTxn(false, nullptr);
+            jint ignored;
+            closeLoadTxn(false, &ignored);
         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
             closeUnloadTxn(false);
         }
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_Debug.cpp b/core/jni/android_os_Debug.cpp
index e0bfecb..97c7f04 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -839,7 +839,8 @@
     size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
 extern "C" void free_malloc_leak_info(uint8_t* info);
 #define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
-#define BACKTRACE_SIZE          32
+
+static size_t gNumBacktraceElements;
 
 /*
  * This is a qsort() callback.
@@ -859,11 +860,11 @@
         return -1;
     }
 
-    intptr_t* bt1 = (intptr_t*)(rec1 + 2);
-    intptr_t* bt2 = (intptr_t*)(rec2 + 2);
-    for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
-        intptr_t addr1 = bt1[idx];
-        intptr_t addr2 = bt2[idx];
+    uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
+    uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
+    for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
+        uintptr_t addr1 = bt1[idx];
+        uintptr_t addr2 = bt2[idx];
         if (addr1 == addr2) {
             if (addr1 == 0)
                 break;
@@ -907,9 +908,10 @@
     if (info == NULL) {
         fprintf(fp, "Native heap dump not available. To enable, run these"
                     " commands (requires root):\n");
-        fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
-        fprintf(fp, "$ adb shell stop\n");
-        fprintf(fp, "$ adb shell start\n");
+        fprintf(fp, "# adb shell stop\n");
+        fprintf(fp, "# adb shell setprop libc.debug.malloc.options "
+                    "backtrace\n");
+        fprintf(fp, "# adb shell start\n");
         return;
     }
     assert(infoSize != 0);
@@ -920,13 +922,11 @@
     size_t recordCount = overallSize / infoSize;
     fprintf(fp, "Total memory: %zu\n", totalMemory);
     fprintf(fp, "Allocation records: %zd\n", recordCount);
-    if (backtraceSize != BACKTRACE_SIZE) {
-        fprintf(fp, "WARNING: mismatched backtrace sizes (%zu vs. %d)\n",
-            backtraceSize, BACKTRACE_SIZE);
-    }
+    fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
     fprintf(fp, "\n");
 
     /* re-sort the entries */
+    gNumBacktraceElements = backtraceSize;
     qsort(info, recordCount, infoSize, compareHeapRecords);
 
     /* dump the entries to the file */
@@ -934,7 +934,7 @@
     for (size_t idx = 0; idx < recordCount; idx++) {
         size_t size = *(size_t*) ptr;
         size_t allocations = *(size_t*) (ptr + sizeof(size_t));
-        intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
+        uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
 
         fprintf(fp, "z %d  sz %8zu  num %4zu  bt",
                 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index a45e1ee..7da0314 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -25,9 +25,9 @@
 
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <hwbinder/IServiceManager.h>
+#include <hidl/IServiceManager.h>
+#include <hidl/Status.h>
 #include <hwbinder/ProcessState.h>
-#include <hwbinder/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include "core_jni_helpers.h"
@@ -213,7 +213,9 @@
     sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
 
     status_t err = hardware::defaultServiceManager()->addService(
-                String16(reinterpret_cast<const char16_t *>(serviceName)),
+                String16(
+                    reinterpret_cast<const char16_t *>(serviceName),
+                    env->GetStringLength(serviceNameObj)),
                 binder,
                 kVersion);
 
@@ -245,12 +247,15 @@
 
     LOG(INFO) << "looking for service '"
               << String8(String16(
-                          reinterpret_cast<const char16_t *>(serviceName))).string()
+                          reinterpret_cast<const char16_t *>(serviceName),
+                          env->GetStringLength(serviceNameObj))).string()
               << "'";
 
     sp<hardware::IBinder> service =
         hardware::defaultServiceManager()->getService(
-                String16(reinterpret_cast<const char16_t *>(serviceName)),
+                String16(
+                    reinterpret_cast<const char16_t *>(serviceName),
+                    env->GetStringLength(serviceNameObj)),
                 kVersion);
 
     env->ReleaseStringCritical(serviceNameObj, serviceName);
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
new file mode 100644
index 0000000..b2dee06
--- /dev/null
+++ b/core/jni/android_os_HwBlob.cpp
@@ -0,0 +1,452 @@
+/*
+ * 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 LOG_NDEBUG 0
+#define LOG_TAG "android_os_HwBlob"
+#include <android-base/logging.h>
+
+#include "android_os_HwBlob.h"
+
+#include "android_os_HwParcel.h"
+
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <hidl/Status.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "core_jni_helpers.h"
+
+using android::AndroidRuntime;
+using android::hardware::hidl_string;
+
+#define PACKAGE_PATH    "android/os"
+#define CLASS_NAME      "HwBlob"
+#define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+static struct fields_t {
+    jfieldID contextID;
+    jmethodID constructID;
+
+} gFields;
+
+// static
+void JHwBlob::InitClass(JNIEnv *env) {
+    ScopedLocalRef<jclass> clazz(
+            env, FindClassOrDie(env, CLASS_PATH));
+
+    gFields.contextID =
+        GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
+
+    gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
+}
+
+// static
+sp<JHwBlob> JHwBlob::SetNativeContext(
+        JNIEnv *env, jobject thiz, const sp<JHwBlob> &context) {
+    sp<JHwBlob> old = (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
+
+    if (context != NULL) {
+        context->incStrong(NULL /* id */);
+    }
+
+    if (old != NULL) {
+        old->decStrong(NULL /* id */);
+    }
+
+    env->SetLongField(thiz, gFields.contextID, (long)context.get());
+
+    return old;
+}
+
+// static
+sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
+    return (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
+}
+
+JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size)
+    : mBuffer(nullptr),
+      mSize(size),
+      mOwnsBuffer(true),
+      mHandle(0) {
+    jclass clazz = env->GetObjectClass(thiz);
+    CHECK(clazz != NULL);
+
+    mClass = (jclass)env->NewGlobalRef(clazz);
+    mObject = env->NewWeakGlobalRef(thiz);
+
+    if (size > 0) {
+        mBuffer = malloc(size);
+    }
+}
+
+JHwBlob::~JHwBlob() {
+    if (mOwnsBuffer) {
+        free(mBuffer);
+        mBuffer = nullptr;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteWeakGlobalRef(mObject);
+    mObject = NULL;
+
+    env->DeleteGlobalRef(mClass);
+    mClass = NULL;
+}
+
+void JHwBlob::setTo(const void *ptr, size_t handle) {
+    CHECK_EQ(mSize, 0u);
+    CHECK(mBuffer == nullptr);
+
+    mBuffer = const_cast<void *>(ptr);
+    mSize = SIZE_MAX;  // XXX
+    mOwnsBuffer = false;
+    mHandle = handle;
+}
+
+status_t JHwBlob::getHandle(size_t *handle) const {
+    if (mOwnsBuffer) {
+        return INVALID_OPERATION;
+    }
+
+    *handle = mHandle;
+
+    return OK;
+}
+
+status_t JHwBlob::read(size_t offset, void *data, size_t size) const {
+    if (offset + size > mSize) {
+        return -ERANGE;
+    }
+
+    memcpy(data, (const uint8_t *)mBuffer + offset, size);
+
+    return OK;
+}
+
+status_t JHwBlob::write(size_t offset, const void *data, size_t size) {
+    if (offset + size > mSize) {
+        return -ERANGE;
+    }
+
+    memcpy((uint8_t *)mBuffer + offset, data, size);
+
+    return OK;
+}
+
+status_t JHwBlob::getString(size_t offset, const hidl_string **s) const {
+    if ((offset + sizeof(hidl_string)) > mSize) {
+        return -ERANGE;
+    }
+
+    *s = reinterpret_cast<const hidl_string *>(
+            (const uint8_t *)mBuffer + offset);
+
+    return OK;
+}
+
+const void *JHwBlob::data() const {
+    return mBuffer;
+}
+
+size_t JHwBlob::size() const {
+    return mSize;
+}
+
+status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
+    size_t index = mSubBlobs.add();
+    BlobInfo *info = &mSubBlobs.editItemAt(index);
+
+    info->mOffset = offset;
+    info->mBlob = blob;
+
+    const void *data = blob->data();
+
+    return write(offset, &data, sizeof(data));
+}
+
+status_t JHwBlob::writeToParcel(hardware::Parcel *parcel) const {
+    size_t handle;
+    status_t err = parcel->writeBuffer(data(), size(), &handle);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mSubBlobs.size(); ++i) {
+        const BlobInfo &info = mSubBlobs[i];
+
+        err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+status_t JHwBlob::writeEmbeddedToParcel(
+        hardware::Parcel *parcel,
+        size_t parentHandle,
+        size_t parentOffset) const {
+    size_t handle;
+    status_t err = parcel->writeEmbeddedBuffer(
+            data(), size(), &handle, parentHandle, parentOffset);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mSubBlobs.size(); ++i) {
+        const BlobInfo &info = mSubBlobs[i];
+
+        err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+// static
+jobject JHwBlob::NewObject(JNIEnv *env, const void *ptr, size_t handle) {
+    jobject obj = JHwBlob::NewObject(env, 0 /* size */);
+    JHwBlob::GetNativeContext(env, obj)->setTo(ptr, handle);
+
+    return obj;
+}
+
+// static
+jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
+    ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
+
+    jmethodID constructID =
+        GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
+
+    // XXX Again cannot refer to gFields.constructID because InitClass may
+    // not have been called yet.
+
+    return env->NewObject(clazz.get(), constructID, size);
+}
+
+}  // namespace android
+
+////////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+static void releaseNativeContext(void *nativeContext) {
+    sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
+
+    if (parcel != NULL) {
+        parcel->decStrong(NULL /* id */);
+    }
+}
+
+static jlong JHwBlob_native_init(JNIEnv *env) {
+    JHwBlob::InitClass(env);
+
+    return reinterpret_cast<jlong>(&releaseNativeContext);
+}
+
+static void JHwBlob_native_setup(
+        JNIEnv *env, jobject thiz, jint size) {
+    sp<JHwBlob> context = new JHwBlob(env, thiz, size);
+
+    JHwBlob::SetNativeContext(env, thiz, context);
+}
+
+#define DEFINE_BLOB_GETTER(Suffix,Type)                                        \
+static Type JHwBlob_native_get ## Suffix(                                      \
+        JNIEnv *env, jobject thiz, jlong offset) {                             \
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
+                                                                               \
+    Type x;                                                                    \
+    status_t err = blob->read(offset, &x, sizeof(x));                          \
+                                                                               \
+    if (err != OK) {                                                           \
+        signalExceptionForError(env, err);                                     \
+        return 0;                                                              \
+    }                                                                          \
+                                                                               \
+    return x;                                                                  \
+}
+
+DEFINE_BLOB_GETTER(Int8,jbyte)
+DEFINE_BLOB_GETTER(Int16,jshort)
+DEFINE_BLOB_GETTER(Int32,jint)
+DEFINE_BLOB_GETTER(Int64,jlong)
+DEFINE_BLOB_GETTER(Float,jfloat)
+DEFINE_BLOB_GETTER(Double,jdouble)
+
+static jboolean JHwBlob_native_getBool(
+        JNIEnv *env, jobject thiz, jlong offset) {
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    bool x;
+    status_t err = blob->read(offset, &x, sizeof(x));
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return 0;
+    }
+
+    return (jboolean)x;
+}
+
+static jstring JHwBlob_native_getString(
+        JNIEnv *env, jobject thiz, jlong offset) {
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    const hidl_string *s;
+    status_t err = blob->getString(offset, &s);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return nullptr;
+    }
+
+    return env->NewStringUTF(s->c_str());
+}
+
+#define DEFINE_BLOB_PUTTER(Suffix,Type)                                        \
+static void JHwBlob_native_put ## Suffix(                                      \
+        JNIEnv *env, jobject thiz, jlong offset, Type x) {                     \
+                                                                               \
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
+                                                                               \
+    status_t err = blob->write(offset, &x, sizeof(x));                         \
+                                                                               \
+    if (err != OK) {                                                           \
+        signalExceptionForError(env, err);                                     \
+    }                                                                          \
+}
+
+DEFINE_BLOB_PUTTER(Int8,jbyte)
+DEFINE_BLOB_PUTTER(Int16,jshort)
+DEFINE_BLOB_PUTTER(Int32,jint)
+DEFINE_BLOB_PUTTER(Int64,jlong)
+DEFINE_BLOB_PUTTER(Float,jfloat)
+DEFINE_BLOB_PUTTER(Double,jdouble)
+
+static void JHwBlob_native_putBool(
+        JNIEnv *env, jobject thiz, jlong offset, jboolean x) {
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    bool b = (bool)x;
+    status_t err = blob->write(offset, &b, sizeof(b));
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+    }
+}
+
+static void JHwBlob_native_putString(
+        JNIEnv *env, jobject thiz, jlong offset, jstring stringObj) {
+    if (stringObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        return;
+    }
+
+    const char *s = env->GetStringUTFChars(stringObj, nullptr);
+
+    if (s == nullptr) {
+        return;
+    }
+
+    size_t size = strlen(s) + 1;
+    ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
+    sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
+    subBlob->write(0 /* offset */, s, size);
+
+    env->ReleaseStringUTFChars(stringObj, s);
+    s = nullptr;
+
+    hidl_string tmp;
+    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+    blob->write(offset, &tmp, sizeof(tmp));
+    blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
+}
+
+static void JHwBlob_native_putBlob(
+        JNIEnv *env, jobject thiz, jlong offset, jobject blobObj) {
+    if (blobObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        return;
+    }
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+    sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, blobObj);
+
+    blob->putBlob(offset, subBlob);
+}
+
+static jlong JHwBlob_native_handle(JNIEnv *env, jobject thiz) {
+    size_t handle;
+    status_t err = JHwBlob::GetNativeContext(env, thiz)->getHandle(&handle);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return 0;
+    }
+
+    return handle;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "native_init", "()J", (void *)JHwBlob_native_init },
+    { "native_setup", "(I)V", (void *)JHwBlob_native_setup },
+
+    { "getBool", "(J)Z", (void *)JHwBlob_native_getBool },
+    { "getInt8", "(J)B", (void *)JHwBlob_native_getInt8 },
+    { "getInt16", "(J)S", (void *)JHwBlob_native_getInt16 },
+    { "getInt32", "(J)I", (void *)JHwBlob_native_getInt32 },
+    { "getInt64", "(J)J", (void *)JHwBlob_native_getInt64 },
+    { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
+    { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
+    { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+
+    { "putBool", "(JZ)V", (void *)JHwBlob_native_putBool },
+    { "putInt8", "(JB)V", (void *)JHwBlob_native_putInt8 },
+    { "putInt16", "(JS)V", (void *)JHwBlob_native_putInt16 },
+    { "putInt32", "(JI)V", (void *)JHwBlob_native_putInt32 },
+    { "putInt64", "(JJ)V", (void *)JHwBlob_native_putInt64 },
+    { "putFloat", "(JF)V", (void *)JHwBlob_native_putFloat },
+    { "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
+    { "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
+
+    { "putBlob", "(JL" PACKAGE_PATH "/HwBlob;)V",
+        (void *)JHwBlob_native_putBlob },
+
+    { "handle", "()J", (void *)JHwBlob_native_handle },
+};
+
+namespace android {
+
+int register_android_os_HwBlob(JNIEnv *env) {
+    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+}
+
+}  // namespace android
+
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
new file mode 100644
index 0000000..6bd82e9
--- /dev/null
+++ b/core/jni/android_os_HwBlob.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_OS_HW_BLOB_H
+#define ANDROID_OS_HW_BLOB_H
+
+#include <android-base/macros.h>
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct JHwBlob : public RefBase {
+    static void InitClass(JNIEnv *env);
+
+    static sp<JHwBlob> SetNativeContext(
+            JNIEnv *env, jobject thiz, const sp<JHwBlob> &context);
+
+    static sp<JHwBlob> GetNativeContext(JNIEnv *env, jobject thiz);
+
+    static jobject NewObject(JNIEnv *env, const void *ptr, size_t handle);
+    static jobject NewObject(JNIEnv *env, size_t size);
+
+    JHwBlob(JNIEnv *env, jobject thiz, size_t size);
+
+    void setTo(const void *ptr, size_t handle);
+
+    status_t getHandle(size_t *handle) const;
+
+    status_t read(size_t offset, void *data, size_t size) const;
+    status_t write(size_t offset, const void *data, size_t size);
+
+    status_t getString(
+            size_t offset, const android::hardware::hidl_string **s) const;
+
+    const void *data() const;
+    size_t size() const;
+
+    status_t putBlob(size_t offset, const sp<JHwBlob> &blob);
+
+    status_t writeToParcel(hardware::Parcel *parcel) const;
+
+    status_t writeEmbeddedToParcel(
+            hardware::Parcel *parcel,
+            size_t parentHandle,
+            size_t parentOffset) const;
+
+protected:
+    virtual ~JHwBlob();
+
+private:
+    struct BlobInfo {
+        size_t mOffset;
+        sp<JHwBlob> mBlob;
+    };
+
+    jclass mClass;
+    jobject mObject;
+
+    void *mBuffer;
+    size_t mSize;
+    bool mOwnsBuffer;
+
+    size_t mHandle;
+
+    Vector<BlobInfo> mSubBlobs;
+
+    DISALLOW_COPY_AND_ASSIGN(JHwBlob);
+};
+
+int register_android_os_HwBlob(JNIEnv *env);
+
+}  // namespace android
+
+#endif  // ANDROID_OS_HW_BLOB_H
+
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 0202303..5c879b88 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -21,11 +21,12 @@
 #include "android_os_HwParcel.h"
 
 #include "android_os_HwBinder.h"
+#include "android_os_HwBlob.h"
 #include "android_os_HwRemoteBinder.h"
 
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <hwbinder/Status.h>
+#include <hidl/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include "core_jni_helpers.h"
@@ -71,6 +72,7 @@
             break;
         }
 
+        case -ERANGE:
         case BAD_INDEX:
         {
             jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
@@ -200,8 +202,10 @@
 jobject JHwParcel::NewObject(JNIEnv *env) {
     ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
 
-    return env->NewObject(
-            clazz.get(), gFields.constructID, false /* allocate */);
+    jmethodID constructID =
+        GetMethodIDOrDie(env, clazz.get(), "<init>", "(Z)V");
+
+    return env->NewObject(clazz.get(), constructID, false /* allocate */);
 }
 
 void JHwParcel::setTransactCallback(
@@ -333,6 +337,7 @@
     return val;                                                         \
 }
 
+DEFINE_PARCEL_WRITER(Bool,jboolean)
 DEFINE_PARCEL_WRITER(Int8,jbyte)
 DEFINE_PARCEL_WRITER(Int16,jshort)
 DEFINE_PARCEL_WRITER(Int32,jint)
@@ -347,6 +352,17 @@
 DEFINE_PARCEL_READER(Float,jfloat)
 DEFINE_PARCEL_READER(Double,jdouble)
 
+static jboolean JHwParcel_native_readBool(JNIEnv *env, jobject thiz) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    bool val;
+    status_t err = parcel->readBool(&val);
+    signalExceptionForError(env, err);
+
+    return (jboolean)val;
+}
+
 static void JHwParcel_native_writeStatus(
         JNIEnv *env, jobject thiz, jint statusCode) {
     using hardware::Status;
@@ -415,35 +431,6 @@
     signalExceptionForError(env, err);
 }
 
-#define DEFINE_PARCEL_ARRAY_WRITER(Suffix,Type)                                \
-static void JHwParcel_native_write ## Suffix ## Array(                         \
-        JNIEnv *env, jobject thiz, jint size, Type ## Array valObj) {          \
-    if (valObj == NULL) {                                                      \
-        jniThrowException(env, "java/lang/NullPointerException", NULL);        \
-        return;                                                                \
-    }                                                                          \
-                                                                               \
-    jsize len = env->GetArrayLength(valObj);                                   \
-                                                                               \
-    if (len != size) {                                                         \
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);    \
-        return;                                                                \
-    }                                                                          \
-                                                                               \
-    sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);               \
-                                                                               \
-    const Type *val =                                                          \
-        impl->getStorage()->allocTemporary ## Suffix ## Array(env, valObj);    \
-                                                                               \
-    hardware::Parcel *parcel = impl->getParcel();                              \
-                                                                               \
-    size_t parentHandle;                                                       \
-    status_t err = parcel->writeBuffer(                                        \
-            val, size * sizeof(*val), &parentHandle);                          \
-                                                                               \
-    signalExceptionForError(env, err);                                         \
-}
-
 #define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type)                               \
 static void JHwParcel_native_write ## Suffix ## Vector(                        \
         JNIEnv *env, jobject thiz, Type ## Array valObj) {                     \
@@ -475,13 +462,6 @@
     signalExceptionForError(env, err);                                         \
 }
 
-DEFINE_PARCEL_ARRAY_WRITER(Int8,jbyte)
-DEFINE_PARCEL_ARRAY_WRITER(Int16,jshort)
-DEFINE_PARCEL_ARRAY_WRITER(Int32,jint)
-DEFINE_PARCEL_ARRAY_WRITER(Int64,jlong)
-DEFINE_PARCEL_ARRAY_WRITER(Float,jfloat)
-DEFINE_PARCEL_ARRAY_WRITER(Double,jdouble)
-
 DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)
 DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort)
 DEFINE_PARCEL_VECTOR_WRITER(Int32,jint)
@@ -489,6 +469,54 @@
 DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat)
 DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble)
 
+static void JHwParcel_native_writeBoolVector(
+        JNIEnv *env, jobject thiz, jbooleanArray valObj) {
+    if (valObj == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return;
+    }
+
+    sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
+
+    void *vecPtr =
+        impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec<bool>));
+
+    hidl_vec<bool> *vec = new (vecPtr) hidl_vec<bool>;
+
+    jsize len = env->GetArrayLength(valObj);
+
+    jboolean *src = env->GetBooleanArrayElements(valObj, nullptr);
+
+    bool *dst =
+        (bool *)impl->getStorage()->allocTemporaryStorage(len * sizeof(bool));
+
+    for (jsize i = 0; i < len; ++i) {
+        dst[i] = src[i];
+    }
+
+    env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */);
+    src = nullptr;
+
+    vec->setToExternal(dst, len);
+
+    hardware::Parcel *parcel = impl->getParcel();
+
+    size_t parentHandle;
+    status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);
+
+    if (err == OK) {
+        size_t childHandle;
+
+        err = vec->writeEmbeddedToParcel(
+                parcel,
+                parentHandle,
+                0 /* parentOffset */,
+                &childHandle);
+    }
+
+    signalExceptionForError(env, err);
+}
+
 static void JHwParcel_native_writeStrongBinder(
         JNIEnv *env, jobject thiz, jobject binderObj) {
     sp<hardware::IBinder> binder;
@@ -550,22 +578,6 @@
     return MakeStringObjFromHidlString(env, *s);
 }
 
-#define DEFINE_PARCEL_ARRAY_READER(Suffix,Type,NewType)                        \
-static Type ## Array JHwParcel_native_read ## Suffix ## Array(                 \
-        JNIEnv *env, jobject thiz, jint size) {                                \
-    hardware::Parcel *parcel =                                                 \
-        JHwParcel::GetNativeContext(env, thiz)->getParcel();                   \
-                                                                               \
-    size_t parentHandle;                                                       \
-    const Type *val = static_cast<const Type *>(                               \
-            parcel->readBuffer(&parentHandle));                                \
-                                                                               \
-    Type ## Array valObj = env->New ## NewType ## Array(size);                 \
-    env->Set ## NewType ## ArrayRegion(valObj, 0, size, val);                  \
-                                                                               \
-    return valObj;                                                             \
-}
-
 #define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType)                       \
 static Type ## Array JHwParcel_native_read ## Suffix ## Vector(                \
         JNIEnv *env, jobject thiz) {                                           \
@@ -602,13 +614,6 @@
     return valObj;                                                             \
 }
 
-DEFINE_PARCEL_ARRAY_READER(Int8,jbyte,Byte)
-DEFINE_PARCEL_ARRAY_READER(Int16,jshort,Short)
-DEFINE_PARCEL_ARRAY_READER(Int32,jint,Int)
-DEFINE_PARCEL_ARRAY_READER(Int64,jlong,Long)
-DEFINE_PARCEL_ARRAY_READER(Float,jfloat,Float)
-DEFINE_PARCEL_ARRAY_READER(Double,jdouble,Double)
-
 DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)
 DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short)
 DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int)
@@ -616,6 +621,45 @@
 DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
 DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
 
+static jbooleanArray JHwParcel_native_readBoolVector(
+        JNIEnv *env, jobject thiz) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    size_t parentHandle;
+
+    const hidl_vec<bool> *vec =
+        (const hidl_vec<bool> *)parcel->readBuffer(&parentHandle);
+
+    if (vec == NULL) {
+        signalExceptionForError(env, UNKNOWN_ERROR);
+        return NULL;
+    }
+
+    size_t childHandle;
+
+    status_t err = const_cast<hidl_vec<bool> *>(vec)
+        ->readEmbeddedFromParcel(
+                *parcel,
+                parentHandle,
+                0 /* parentOffset */,
+                &childHandle);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return NULL;
+    }
+
+    jbooleanArray valObj = env->NewBooleanArray(vec->size());
+
+    for (size_t i = 0; i < vec->size(); ++i) {
+        jboolean x = (*vec)[i];
+        env->SetBooleanArrayRegion(valObj, i, 1, &x);
+    }
+
+    return valObj;
+}
+
 static jobjectArray MakeStringArray(
         JNIEnv *env, const hidl_string *array, size_t size) {
     ScopedLocalRef<jclass> stringKlass(
@@ -638,80 +682,6 @@
     return arrayObj;
 }
 
-static jobjectArray JHwParcel_native_readStringArray(
-        JNIEnv *env, jobject thiz, jint size) {
-    hardware::Parcel *parcel =
-        JHwParcel::GetNativeContext(env, thiz)->getParcel();
-
-    size_t parentHandle;
-    const hidl_string *val = static_cast<const hidl_string *>(
-            parcel->readBuffer(&parentHandle));
-
-    if (val == NULL) {
-        signalExceptionForError(env, UNKNOWN_ERROR);
-        return NULL;
-    }
-
-    status_t err = OK;
-    for (jint i = 0; (err == OK) && (i < size); ++i) {
-        err = const_cast<hidl_string *>(&val[i])
-            ->readEmbeddedFromParcel(
-                    *parcel,
-                    parentHandle,
-                    i * sizeof(hidl_string));
-    }
-
-    if (err != OK) {
-        signalExceptionForError(env, err);
-        return NULL;
-    }
-
-    return MakeStringArray(env, val, size);
-}
-
-static void JHwParcel_native_writeStringArray(
-        JNIEnv *env, jobject thiz, jint size, jobjectArray arrayObj) {
-    if (arrayObj == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", NULL);
-        return;
-    }
-
-    jsize len = env->GetArrayLength(arrayObj);
-
-    if (len != size) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
-
-    hidl_string *strings = impl->getStorage()->allocStringArray(len);
-
-    for (jsize i = 0; i < len; ++i) {
-        ScopedLocalRef<jstring> stringObj(
-                env,
-                (jstring)env->GetObjectArrayElement(arrayObj, i));
-
-        const hidl_string *s =
-            impl->getStorage()->allocTemporaryString(env, stringObj.get());
-
-        strings[i].setToExternal(s->c_str(), s->size());
-    }
-
-    hardware::Parcel *parcel = impl->getParcel();
-
-    size_t parentHandle;
-    status_t err = parcel->writeBuffer(
-            strings, sizeof(hidl_string) * len, &parentHandle);
-
-    for (jsize i = 0; (err == OK) && (i < len); ++i) {
-        err = strings[i].writeEmbeddedToParcel(
-                parcel, parentHandle, i * sizeof(hidl_string));
-    }
-
-    signalExceptionForError(env, err);
-}
-
 static jobjectArray JHwParcel_native_readStringVector(
         JNIEnv *env, jobject thiz) {
     typedef hidl_vec<hidl_string> string_vec;
@@ -763,9 +733,10 @@
 
     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
 
-    string_vec *vec =
-        (string_vec *)impl->getStorage()->allocTemporaryStorage(
-                sizeof(string_vec));
+    void *vecPtr =
+        impl->getStorage()->allocTemporaryStorage(sizeof(string_vec));
+
+    string_vec *vec = new (vecPtr) string_vec;
 
     hidl_string *strings = impl->getStorage()->allocStringArray(len);
     vec->setToExternal(strings, len);
@@ -818,6 +789,57 @@
     return JHwRemoteBinder::NewObject(env, binder);
 }
 
+static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    size_t handle;
+    const void *ptr = parcel->readBuffer(&handle);
+
+    if (ptr == nullptr) {
+        jniThrowException(env, "java/util/NoSuchElementException", NULL);
+        return nullptr;
+    }
+
+    return JHwBlob::NewObject(env, ptr, handle);
+}
+
+static jobject JHwParcel_native_readEmbeddedBuffer(
+        JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    size_t childHandle;
+
+    const void *ptr =
+        parcel->readEmbeddedBuffer(&childHandle, parentHandle, offset);
+
+    if (ptr == nullptr) {
+        jniThrowException(env, "java/util/NoSuchElementException", NULL);
+        return 0;
+    }
+
+    return JHwBlob::NewObject(env, ptr, childHandle);
+}
+
+static void JHwParcel_native_writeBuffer(
+        JNIEnv *env, jobject thiz, jobject blobObj) {
+    if (blobObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return;
+    }
+
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, blobObj);
+    status_t err = blob->writeToParcel(parcel);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+    }
+}
+
 static JNINativeMethod gMethods[] = {
     { "native_init", "()J", (void *)JHwParcel_native_init },
     { "native_setup", "(Z)V", (void *)JHwParcel_native_setup },
@@ -825,6 +847,7 @@
     { "writeInterfaceToken", "(Ljava/lang/String;)V",
         (void *)JHwParcel_native_writeInterfaceToken },
 
+    { "writeBool", "(Z)V", (void *)JHwParcel_native_writeBool },
     { "writeInt8", "(B)V", (void *)JHwParcel_native_writeInt8 },
     { "writeInt16", "(S)V", (void *)JHwParcel_native_writeInt16 },
     { "writeInt32", "(I)V", (void *)JHwParcel_native_writeInt32 },
@@ -835,24 +858,16 @@
     { "writeString", "(Ljava/lang/String;)V",
         (void *)JHwParcel_native_writeString },
 
-    { "writeInt8Array", "(I[B)V", (void *)JHwParcel_native_writeInt8Array },
+    { "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector },
     { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector },
-    { "writeInt16Array", "(I[S)V", (void *)JHwParcel_native_writeInt16Array },
     { "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector },
-    { "writeInt32Array", "(I[I)V", (void *)JHwParcel_native_writeInt32Array },
     { "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector },
-    { "writeInt64Array", "(I[J)V", (void *)JHwParcel_native_writeInt64Array },
     { "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector },
-    { "writeFloatArray", "(I[F)V", (void *)JHwParcel_native_writeFloatArray },
     { "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector },
-    { "writeDoubleArray", "(I[D)V", (void *)JHwParcel_native_writeDoubleArray },
 
     { "writeDoubleVector", "([D)V",
         (void *)JHwParcel_native_writeDoubleVector },
 
-    { "writeStringArray", "(I[Ljava/lang/String;)V",
-        (void *)JHwParcel_native_writeStringArray },
-
     { "writeStringVector", "([Ljava/lang/String;)V",
         (void *)JHwParcel_native_writeStringVector },
 
@@ -862,6 +877,7 @@
     { "enforceInterface", "(Ljava/lang/String;)V",
         (void *)JHwParcel_native_enforceInterface },
 
+    { "readBool", "()Z", (void *)JHwParcel_native_readBool },
     { "readInt8", "()B", (void *)JHwParcel_native_readInt8 },
     { "readInt16", "()S", (void *)JHwParcel_native_readInt16 },
     { "readInt32", "()I", (void *)JHwParcel_native_readInt32 },
@@ -872,22 +888,14 @@
     { "readString", "()Ljava/lang/String;",
         (void *)JHwParcel_native_readString },
 
-    { "readInt8Array", "(I)[B", (void *)JHwParcel_native_readInt8Array },
+    { "readBoolVector", "()[Z", (void *)JHwParcel_native_readBoolVector },
     { "readInt8Vector", "()[B", (void *)JHwParcel_native_readInt8Vector },
-    { "readInt16Array", "(I)[S", (void *)JHwParcel_native_readInt16Array },
     { "readInt16Vector", "()[S", (void *)JHwParcel_native_readInt16Vector },
-    { "readInt32Array", "(I)[I", (void *)JHwParcel_native_readInt32Array },
     { "readInt32Vector", "()[I", (void *)JHwParcel_native_readInt32Vector },
-    { "readInt64Array", "(I)[J", (void *)JHwParcel_native_readInt64Array },
     { "readInt64Vector", "()[J", (void *)JHwParcel_native_readInt64Vector },
-    { "readFloatArray", "(I)[F", (void *)JHwParcel_native_readFloatArray },
     { "readFloatVector", "()[F", (void *)JHwParcel_native_readFloatVector },
-    { "readDoubleArray", "(I)[D", (void *)JHwParcel_native_readDoubleArray },
     { "readDoubleVector", "()[D", (void *)JHwParcel_native_readDoubleVector },
 
-    { "readStringArray", "(I)[Ljava/lang/String;",
-        (void *)JHwParcel_native_readStringArray },
-
     { "readStringVector", "()[Ljava/lang/String;",
         (void *)JHwParcel_native_readStringVector },
 
@@ -902,6 +910,15 @@
         (void *)JHwParcel_native_releaseTemporaryStorage },
 
     { "send", "()V", (void *)JHwParcel_native_send },
+
+    { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
+        (void *)JHwParcel_native_readBuffer },
+
+    { "readEmbeddedBuffer", "(JJ)L" PACKAGE_PATH "/HwBlob;",
+        (void *)JHwParcel_native_readEmbeddedBuffer },
+
+    { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
+        (void *)JHwParcel_native_writeBuffer },
 };
 
 namespace android {
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index 23d4fced..3023ba8 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -24,8 +24,8 @@
 
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <hwbinder/IServiceManager.h>
-#include <hwbinder/Status.h>
+#include <hidl/IServiceManager.h>
+#include <hidl/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include "core_jni_helpers.h"
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0a8ae2b..8f7908a 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -722,33 +722,50 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gParcelMethods[] = {
-    {"nativeDataSize",            "!(J)I", (void*)android_os_Parcel_dataSize},
-    {"nativeDataAvail",           "!(J)I", (void*)android_os_Parcel_dataAvail},
-    {"nativeDataPosition",        "!(J)I", (void*)android_os_Parcel_dataPosition},
-    {"nativeDataCapacity",        "!(J)I", (void*)android_os_Parcel_dataCapacity},
-    {"nativeSetDataSize",         "!(JI)J", (void*)android_os_Parcel_setDataSize},
-    {"nativeSetDataPosition",     "!(JI)V", (void*)android_os_Parcel_setDataPosition},
-    {"nativeSetDataCapacity",     "!(JI)V", (void*)android_os_Parcel_setDataCapacity},
+    // @FastNative
+    {"nativeDataSize",            "(J)I", (void*)android_os_Parcel_dataSize},
+    // @FastNative
+    {"nativeDataAvail",           "(J)I", (void*)android_os_Parcel_dataAvail},
+    // @FastNative
+    {"nativeDataPosition",        "(J)I", (void*)android_os_Parcel_dataPosition},
+    // @FastNative
+    {"nativeDataCapacity",        "(J)I", (void*)android_os_Parcel_dataCapacity},
+    // @FastNative
+    {"nativeSetDataSize",         "(JI)J", (void*)android_os_Parcel_setDataSize},
+    // @FastNative
+    {"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},
+    // @FastNative
+    {"nativeSetDataCapacity",     "(JI)V", (void*)android_os_Parcel_setDataCapacity},
 
-    {"nativePushAllowFds",        "!(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
-    {"nativeRestoreAllowFds",     "!(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
+    // @FastNative
+    {"nativePushAllowFds",        "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
+    // @FastNative
+    {"nativeRestoreAllowFds",     "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
 
     {"nativeWriteByteArray",      "(J[BII)V", (void*)android_os_Parcel_writeNative},
     {"nativeWriteBlob",           "(J[BII)V", (void*)android_os_Parcel_writeBlob},
-    {"nativeWriteInt",            "!(JI)V", (void*)android_os_Parcel_writeInt},
-    {"nativeWriteLong",           "!(JJ)V", (void*)android_os_Parcel_writeLong},
-    {"nativeWriteFloat",          "!(JF)V", (void*)android_os_Parcel_writeFloat},
-    {"nativeWriteDouble",         "!(JD)V", (void*)android_os_Parcel_writeDouble},
+    // @FastNative
+    {"nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
+    // @FastNative
+    {"nativeWriteLong",           "(JJ)V", (void*)android_os_Parcel_writeLong},
+    // @FastNative
+    {"nativeWriteFloat",          "(JF)V", (void*)android_os_Parcel_writeFloat},
+    // @FastNative
+    {"nativeWriteDouble",         "(JD)V", (void*)android_os_Parcel_writeDouble},
     {"nativeWriteString",         "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
     {"nativeWriteStrongBinder",   "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
     {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
 
     {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
     {"nativeReadBlob",            "(J)[B", (void*)android_os_Parcel_readBlob},
-    {"nativeReadInt",             "!(J)I", (void*)android_os_Parcel_readInt},
-    {"nativeReadLong",            "!(J)J", (void*)android_os_Parcel_readLong},
-    {"nativeReadFloat",           "!(J)F", (void*)android_os_Parcel_readFloat},
-    {"nativeReadDouble",          "!(J)D", (void*)android_os_Parcel_readDouble},
+    // @FastNative
+    {"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
+    // @FastNative
+    {"nativeReadLong",            "(J)J", (void*)android_os_Parcel_readLong},
+    // @FastNative
+    {"nativeReadFloat",           "(J)F", (void*)android_os_Parcel_readFloat},
+    // @FastNative
+    {"nativeReadDouble",          "(J)D", (void*)android_os_Parcel_readDouble},
     {"nativeReadString",          "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
     {"nativeReadStrongBinder",    "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
     {"nativeReadFileDescriptor",  "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
@@ -765,7 +782,8 @@
     {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
     {"nativeUnmarshall",          "(J[BII)J", (void*)android_os_Parcel_unmarshall},
     {"nativeAppendFrom",          "(JJII)J", (void*)android_os_Parcel_appendFrom},
-    {"nativeHasFileDescriptors",  "!(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
+    // @FastNative
+    {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
     {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
     {"nativeEnforceInterface",    "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
 
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 8ba77ae..4b68c0d 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -23,9 +23,9 @@
 #include "selinux/selinux.h"
 #include "selinux/android.h"
 #include <errno.h>
+#include <memory>
 #include <ScopedLocalRef.h>
 #include <ScopedUtfChars.h>
-#include <UniquePtr.h>
 
 namespace android {
 
@@ -34,7 +34,7 @@
         freecon(p);
     }
 };
-typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
+typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
 
 static jboolean isSELinuxDisabled = true;
 
@@ -112,7 +112,7 @@
         return false;
     }
 
-    UniquePtr<ScopedUtfChars> context;
+    std::unique_ptr<ScopedUtfChars> context;
     const char* context_c_str = NULL;
     if (contextStr != NULL) {
         context.reset(new ScopedUtfChars(env, contextStr));
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index ccb833a..2fade69 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -36,29 +36,18 @@
 
 namespace android {
 
-/*
- * native public static long uptimeMillis();
- */
-static jlong android_os_SystemClock_uptimeMillis(JNIEnv* env,
-        jobject clazz)
-{
-    return (jlong)uptimeMillis();
-}
-
-/*
- * native public static long elapsedRealtime();
- */
-static jlong android_os_SystemClock_elapsedRealtime(JNIEnv* env,
-        jobject clazz)
-{
-    return (jlong)elapsedRealtime();
-}
+static_assert(std::is_same<int64_t, jlong>::value, "jlong isn't an int64_t");
+static_assert(std::is_same<decltype(uptimeMillis()), int64_t>::value,
+        "uptimeMillis signature change, expected int64_t return value");
+static_assert(std::is_same<decltype(elapsedRealtime()), int64_t>::value,
+        "uptimeMillis signature change, expected int64_t return value");
+static_assert(std::is_same<decltype(elapsedRealtimeNano()), int64_t>::value,
+        "uptimeMillis signature change, expected int64_t return value");
 
 /*
  * native public static long currentThreadTimeMillis();
  */
-static jlong android_os_SystemClock_currentThreadTimeMillis(JNIEnv* env,
-        jobject clazz)
+static jlong android_os_SystemClock_currentThreadTimeMillis()
 {
     struct timespec tm;
 
@@ -70,8 +59,7 @@
 /*
  * native public static long currentThreadTimeMicro();
  */
-static jlong android_os_SystemClock_currentThreadTimeMicro(JNIEnv* env,
-        jobject clazz)
+static jlong android_os_SystemClock_currentThreadTimeMicro()
 {
     struct timespec tm;
 
@@ -83,8 +71,7 @@
 /*
  * native public static long currentTimeMicro();
  */
-static jlong android_os_SystemClock_currentTimeMicro(JNIEnv* env,
-        jobject clazz)
+static jlong android_os_SystemClock_currentTimeMicro()
 {
     struct timeval tv;
 
@@ -93,31 +80,22 @@
 }
 
 /*
- * public static native long elapsedRealtimeNano();
- */
-static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env,
-        jobject clazz)
-{
-    return (jlong)elapsedRealtimeNano();
-}
-
-/*
  * JNI registration.
  */
 static const JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "uptimeMillis",      "!()J",
-            (void*) android_os_SystemClock_uptimeMillis },
-    { "elapsedRealtime",      "!()J",
-            (void*) android_os_SystemClock_elapsedRealtime },
-    { "currentThreadTimeMillis",      "!()J",
+    // All of these are @CriticalNative, so we can defer directly to SystemClock.h for
+    // some of these
+    { "uptimeMillis", "()J", (void*) uptimeMillis },
+    { "elapsedRealtime", "()J", (void*) elapsedRealtime },
+    { "elapsedRealtimeNanos", "()J", (void*) elapsedRealtimeNano },
+
+    // SystemClock doesn't have an implementation for these that we can directly call
+    { "currentThreadTimeMillis", "()J",
             (void*) android_os_SystemClock_currentThreadTimeMillis },
-    { "currentThreadTimeMicro",       "!()J",
+    { "currentThreadTimeMicro", "()J",
             (void*) android_os_SystemClock_currentThreadTimeMicro },
-    { "currentTimeMicro",             "!()J",
+    { "currentTimeMicro", "()J",
             (void*) android_os_SystemClock_currentTimeMicro },
-    { "elapsedRealtimeNanos",      "!()J",
-            (void*) android_os_SystemClock_elapsedRealtimeNano },
 };
 int register_android_os_SystemClock(JNIEnv* env)
 {
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 30fc47b..ea893f0 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -110,27 +110,30 @@
     { "nativeGetEnabledTags",
             "()J",
             (void*)android_os_Trace_nativeGetEnabledTags },
-    { "nativeTraceCounter",
-            "!(JLjava/lang/String;I)V",
-            (void*)android_os_Trace_nativeTraceCounter },
-    { "nativeTraceBegin",
-            "!(JLjava/lang/String;)V",
-            (void*)android_os_Trace_nativeTraceBegin },
-    { "nativeTraceEnd",
-            "!(J)V",
-            (void*)android_os_Trace_nativeTraceEnd },
-    { "nativeAsyncTraceBegin",
-            "!(JLjava/lang/String;I)V",
-            (void*)android_os_Trace_nativeAsyncTraceBegin },
-    { "nativeAsyncTraceEnd",
-            "!(JLjava/lang/String;I)V",
-            (void*)android_os_Trace_nativeAsyncTraceEnd },
     { "nativeSetAppTracingAllowed",
             "(Z)V",
             (void*)android_os_Trace_nativeSetAppTracingAllowed },
     { "nativeSetTracingEnabled",
             "(Z)V",
             (void*)android_os_Trace_nativeSetTracingEnabled },
+
+    // ----------- @FastNative  ----------------
+
+    { "nativeTraceCounter",
+            "(JLjava/lang/String;I)V",
+            (void*)android_os_Trace_nativeTraceCounter },
+    { "nativeTraceBegin",
+            "(JLjava/lang/String;)V",
+            (void*)android_os_Trace_nativeTraceBegin },
+    { "nativeTraceEnd",
+            "(J)V",
+            (void*)android_os_Trace_nativeTraceEnd },
+    { "nativeAsyncTraceBegin",
+            "(JLjava/lang/String;I)V",
+            (void*)android_os_Trace_nativeAsyncTraceBegin },
+    { "nativeAsyncTraceEnd",
+            "(JLjava/lang/String;I)V",
+            (void*)android_os_Trace_nativeAsyncTraceEnd },
 };
 
 int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 1e6b125..428159a 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
+#include <sys/system_properties.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 
@@ -41,6 +42,7 @@
 #include "ScopedUtfChars.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
+#include "utils/String8.h"
 
 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
@@ -184,11 +186,20 @@
                 argv[argc++] = AssetManager::TARGET_APK_PATH;
                 argv[argc++] = AssetManager::IDMAP_DIR;
 
-                // Directories to scan for overlays
-                // /vendor/overlay
-                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
-                    argv[argc++] = AssetManager::OVERLAY_DIR;
-                 }
+                // Directories to scan for overlays: if OVERLAY_SKU_DIR_PROPERTY is defined,
+                // use OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> if exists, otherwise
+                // use OVERLAY_DIR if exists.
+                char subdir[PROP_VALUE_MAX];
+                int len = __system_property_get(AssetManager::OVERLAY_SKU_DIR_PROPERTY, subdir);
+                String8 overlayPath;
+                if (len > 0) {
+                    overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+                } else {
+                    overlayPath = String8(AssetManager::OVERLAY_DIR);
+                }
+                if (stat(overlayPath.string(), &st) == 0) {
+                    argv[argc++] = overlayPath.string();
+                }
 
                 // Finally, invoke idmap (if any overlay directory exists)
                 if (argc > 5) {
diff --git a/core/jni/android_util_MemoryIntArray.cpp b/core/jni/android_util_MemoryIntArray.cpp
index f45be12..9513c8b 100644
--- a/core/jni/android_util_MemoryIntArray.cpp
+++ b/core/jni/android_util_MemoryIntArray.cpp
@@ -61,6 +61,11 @@
         return -1;
     }
 
+    if (!ashmem_valid(fd)) {
+        jniThrowIOException(env, errno);
+        return -1;
+    }
+
     int ashmemSize = ashmem_get_size_region(fd);
     if (ashmemSize <= 0) {
         jniThrowException(env, "java/io/IOException", "bad ashmem size");
@@ -98,6 +103,11 @@
         return;
     }
 
+    if (!ashmem_valid(fd)) {
+        jniThrowIOException(env, errno);
+        return;
+    }
+
     int ashmemSize = ashmem_get_size_region(fd);
     if (ashmemSize <= 0) {
         jniThrowException(env, "java/io/IOException", "bad ashmem size");
@@ -128,6 +138,11 @@
         return -1;
     }
 
+    if (!ashmem_valid(fd)) {
+        jniThrowIOException(env, errno);
+        return -1;
+    }
+
     if (ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
         return -1;
@@ -145,6 +160,11 @@
         return;
     }
 
+    if (!ashmem_valid(fd)) {
+        jniThrowIOException(env, errno);
+        return;
+    }
+
     if (ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
         return;
@@ -160,17 +180,13 @@
         return -1;
     }
 
-    // Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region.
-    // ASHMEM_GET_SIZE should succeed for all ashmem regions, and the kernel
-    // should return ENOTTY for all other valid file descriptors
+    if (!ashmem_valid(fd)) {
+        jniThrowIOException(env, errno);
+        return -1;
+    }
+
     int ashmemSize = ashmem_get_size_region(fd);
     if (ashmemSize < 0) {
-        if (errno == ENOTTY) {
-            // ENOTTY means that the ioctl does not apply to this object,
-            // i.e., it is not an ashmem region.
-            return -1;
-        }
-        // Some other error, throw exception
         jniThrowIOException(env, errno);
         return -1;
     }
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/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ea5a760..2eada3e 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -161,7 +161,8 @@
     { "nativeDispose",
             "(J)V",
             (void*)nativeDispose },
-    { "nativeScheduleVsync", "!(J)V",
+    // @FastNative
+    { "nativeScheduleVsync", "(J)V",
             (void*)nativeScheduleVsync }
 };
 
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 0245d38..2132f3d 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -383,17 +383,6 @@
     return 0;
 }
 
-static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
-        jlong destNativePtr, jlong sourceNativePtr, jboolean keepHistory) {
-    MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
-    if (!destEvent) {
-        destEvent = new MotionEvent();
-    }
-    MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
-    destEvent->copyFrom(sourceEvent, keepHistory);
-    return reinterpret_cast<jlong>(destEvent);
-}
-
 static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
         jlong nativePtr) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -426,228 +415,6 @@
     event->setMetaState(event->getMetaState() | metaState);
 }
 
-static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getDeviceId();
-}
-
-static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getSource();
-}
-
-static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint source) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setSource(source);
-}
-
-static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getAction();
-}
-
-static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint action) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setAction(action);
-}
-
-static int android_view_MotionEvent_nativeGetActionButton(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getActionButton();
-}
-
-static void android_view_MotionEvent_nativeSetActionButton(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint button) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setActionButton(button);
-}
-
-static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->isTouchEvent();
-}
-
-static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getFlags();
-}
-
-static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint flags) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setFlags(flags);
-}
-
-static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getEdgeFlags();
-}
-
-static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint edgeFlags) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setEdgeFlags(edgeFlags);
-}
-
-static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getMetaState();
-}
-
-static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getButtonState();
-}
-
-static void android_view_MotionEvent_nativeSetButtonState(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint buttonState) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setButtonState(buttonState);
-}
-
-static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jfloat deltaX, jfloat deltaY) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->offsetLocation(deltaX, deltaY);
-}
-
-static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getXOffset();
-}
-
-static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getYOffset();
-}
-
-static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getXPrecision();
-}
-
-static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getYPrecision();
-}
-
-static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return event->getDownTime();
-}
-
-static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jlong downTimeNanos) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->setDownTime(downTimeNanos);
-}
-
-static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return jint(event->getPointerCount());
-}
-
-static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint pointerIndex) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    size_t pointerCount = event->getPointerCount();
-    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
-        return -1;
-    }
-    return event->getPointerId(pointerIndex);
-}
-
-static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint pointerIndex) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    size_t pointerCount = event->getPointerCount();
-    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
-        return -1;
-    }
-    return event->getToolType(pointerIndex);
-}
-
-static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint pointerId) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return jint(event->findPointerIndex(pointerId));
-}
-
-static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
-        jlong nativePtr) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return jint(event->getHistorySize());
-}
-
-static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint historyPos) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    if (historyPos == HISTORY_CURRENT) {
-        return event->getEventTime();
-    } else {
-        size_t historySize = event->getHistorySize();
-        if (!validateHistoryPos(env, historyPos, historySize)) {
-            return 0;
-        }
-        return event->getHistoricalEventTime(historyPos);
-    }
-}
-
-static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    size_t pointerCount = event->getPointerCount();
-    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
-        return 0;
-    }
-
-    if (historyPos == HISTORY_CURRENT) {
-        return event->getRawAxisValue(axis, pointerIndex);
-    } else {
-        size_t historySize = event->getHistorySize();
-        if (!validateHistoryPos(env, historyPos, historySize)) {
-            return 0;
-        }
-        return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
-    }
-}
-
-static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    size_t pointerCount = event->getPointerCount();
-    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
-        return 0;
-    }
-
-    if (historyPos == HISTORY_CURRENT) {
-        return event->getAxisValue(axis, pointerIndex);
-    } else {
-        size_t historySize = event->getHistorySize();
-        if (!validateHistoryPos(env, historyPos, historySize)) {
-            return 0;
-        }
-        return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
-    }
-}
-
 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
         jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -684,30 +451,6 @@
     pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
 }
 
-static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jfloat scale) {
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    event->scale(scale);
-}
-
-static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
-        jlong nativePtr, jobject matrixObj) {
-    SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
-    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-
-    float m[9];
-    m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
-    m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
-    m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
-    m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
-    m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
-    m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
-    m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
-    m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
-    m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
-    event->transform(m);
-}
-
 static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
         jlong nativePtr, jobject parcelObj) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -750,6 +493,243 @@
     return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
 }
 
+// ---------------- @FastNative ----------------------------------
+
+static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
+        jlong nativePtr, jint pointerIndex) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    size_t pointerCount = event->getPointerCount();
+    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+        return -1;
+    }
+    return event->getPointerId(pointerIndex);
+}
+
+static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
+        jlong nativePtr, jint pointerIndex) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    size_t pointerCount = event->getPointerCount();
+    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+        return -1;
+    }
+    return event->getToolType(pointerIndex);
+}
+
+static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
+        jlong nativePtr, jint historyPos) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    if (historyPos == HISTORY_CURRENT) {
+        return event->getEventTime();
+    } else {
+        size_t historySize = event->getHistorySize();
+        if (!validateHistoryPos(env, historyPos, historySize)) {
+            return 0;
+        }
+        return event->getHistoricalEventTime(historyPos);
+    }
+}
+
+static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
+        jlong nativePtr, jint axis,
+        jint pointerIndex, jint historyPos) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    size_t pointerCount = event->getPointerCount();
+    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+        return 0;
+    }
+
+    if (historyPos == HISTORY_CURRENT) {
+        return event->getRawAxisValue(axis, pointerIndex);
+    } else {
+        size_t historySize = event->getHistorySize();
+        if (!validateHistoryPos(env, historyPos, historySize)) {
+            return 0;
+        }
+        return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
+    }
+}
+
+static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
+        jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    size_t pointerCount = event->getPointerCount();
+    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+        return 0;
+    }
+
+    if (historyPos == HISTORY_CURRENT) {
+        return event->getAxisValue(axis, pointerIndex);
+    } else {
+        size_t historySize = event->getHistorySize();
+        if (!validateHistoryPos(env, historyPos, historySize)) {
+            return 0;
+        }
+        return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
+    }
+}
+
+// ----------------- @CriticalNative ------------------------------
+
+static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sourceNativePtr,
+        jboolean keepHistory) {
+    MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
+    if (!destEvent) {
+        destEvent = new MotionEvent();
+    }
+    MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
+    destEvent->copyFrom(sourceEvent, keepHistory);
+    return reinterpret_cast<jlong>(destEvent);
+}
+
+static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getDeviceId();
+}
+
+static jint android_view_MotionEvent_nativeGetSource(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getSource();
+}
+
+static void android_view_MotionEvent_nativeSetSource(jlong nativePtr, jint source) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setSource(source);
+}
+
+static jint android_view_MotionEvent_nativeGetAction(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getAction();
+}
+
+static void android_view_MotionEvent_nativeSetAction(jlong nativePtr, jint action) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setAction(action);
+}
+
+static int android_view_MotionEvent_nativeGetActionButton(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getActionButton();
+}
+
+static void android_view_MotionEvent_nativeSetActionButton(jlong nativePtr, jint button) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setActionButton(button);
+}
+
+static jboolean android_view_MotionEvent_nativeIsTouchEvent(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->isTouchEvent();
+}
+
+static jint android_view_MotionEvent_nativeGetFlags(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getFlags();
+}
+
+static void android_view_MotionEvent_nativeSetFlags(jlong nativePtr, jint flags) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setFlags(flags);
+}
+
+static jint android_view_MotionEvent_nativeGetEdgeFlags(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getEdgeFlags();
+}
+
+static void android_view_MotionEvent_nativeSetEdgeFlags(jlong nativePtr, jint edgeFlags) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setEdgeFlags(edgeFlags);
+}
+
+static jint android_view_MotionEvent_nativeGetMetaState(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getMetaState();
+}
+
+static jint android_view_MotionEvent_nativeGetButtonState(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getButtonState();
+}
+
+static void android_view_MotionEvent_nativeSetButtonState(jlong nativePtr, jint buttonState) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setButtonState(buttonState);
+}
+
+static void android_view_MotionEvent_nativeOffsetLocation(jlong nativePtr, jfloat deltaX,
+        jfloat deltaY) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->offsetLocation(deltaX, deltaY);
+}
+
+static jfloat android_view_MotionEvent_nativeGetXOffset(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getXOffset();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYOffset(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getYOffset();
+}
+
+static jfloat android_view_MotionEvent_nativeGetXPrecision(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getXPrecision();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYPrecision(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getYPrecision();
+}
+
+static jlong android_view_MotionEvent_nativeGetDownTimeNanos(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getDownTime();
+}
+
+static void android_view_MotionEvent_nativeSetDownTimeNanos(jlong nativePtr, jlong downTimeNanos) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->setDownTime(downTimeNanos);
+}
+
+static jint android_view_MotionEvent_nativeGetPointerCount(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return jint(event->getPointerCount());
+}
+
+static jint android_view_MotionEvent_nativeFindPointerIndex(jlong nativePtr, jint pointerId) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return jint(event->findPointerIndex(pointerId));
+}
+
+static jint android_view_MotionEvent_nativeGetHistorySize(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return jint(event->getHistorySize());
+}
+
+static void android_view_MotionEvent_nativeScale(jlong nativePtr, jfloat scale) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    event->scale(scale);
+}
+
+static void android_view_MotionEvent_nativeTransform(jlong nativePtr, jlong matrixPtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+
+    static_assert(SkMatrix::kMScaleX == 0, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMSkewX == 1, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMTransX == 2, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMSkewY == 3, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMScaleY == 4, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMTransY == 5, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMPersp0 == 6, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMPersp1 == 7, "SkMatrix unexpected index");
+    static_assert(SkMatrix::kMPersp2 == 8, "SkMatrix unexpected index");
+    float m[9];
+    matrix->get9(m);
+    event->transform(m);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMotionEventMethods[] = {
@@ -758,117 +738,12 @@
             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
                     "[Landroid/view/MotionEvent$PointerCoords;)J",
             (void*)android_view_MotionEvent_nativeInitialize },
-    { "nativeCopy",
-            "(JJZ)J",
-            (void*)android_view_MotionEvent_nativeCopy },
     { "nativeDispose",
             "(J)V",
             (void*)android_view_MotionEvent_nativeDispose },
     { "nativeAddBatch",
             "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
             (void*)android_view_MotionEvent_nativeAddBatch },
-    { "nativeGetDeviceId",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetDeviceId },
-    { "nativeGetSource",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetSource },
-    { "nativeSetSource",
-            "!(JI)I",
-            (void*)android_view_MotionEvent_nativeSetSource },
-    { "nativeGetAction",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetAction },
-    { "nativeSetAction",
-            "!(JI)V",
-            (void*)android_view_MotionEvent_nativeSetAction },
-    { "nativeGetActionButton",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetActionButton},
-    { "nativeSetActionButton",
-            "!(JI)V",
-            (void*)android_view_MotionEvent_nativeSetActionButton},
-    { "nativeIsTouchEvent",
-            "!(J)Z",
-            (void*)android_view_MotionEvent_nativeIsTouchEvent },
-    { "nativeGetFlags",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetFlags },
-    { "nativeSetFlags",
-            "!(JI)V",
-            (void*)android_view_MotionEvent_nativeSetFlags },
-    { "nativeGetEdgeFlags",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetEdgeFlags },
-    { "nativeSetEdgeFlags",
-            "!(JI)V",
-            (void*)android_view_MotionEvent_nativeSetEdgeFlags },
-    { "nativeGetMetaState",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetMetaState },
-    { "nativeGetButtonState",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetButtonState },
-    { "nativeSetButtonState",
-            "!(JI)V",
-            (void*)android_view_MotionEvent_nativeSetButtonState },
-    { "nativeOffsetLocation",
-            "!(JFF)V",
-            (void*)android_view_MotionEvent_nativeOffsetLocation },
-    { "nativeGetXOffset",
-            "!(J)F",
-            (void*)android_view_MotionEvent_nativeGetXOffset },
-    { "nativeGetYOffset",
-            "!(J)F",
-            (void*)android_view_MotionEvent_nativeGetYOffset },
-    { "nativeGetXPrecision",
-            "!(J)F",
-            (void*)android_view_MotionEvent_nativeGetXPrecision },
-    { "nativeGetYPrecision",
-            "!(J)F",
-            (void*)android_view_MotionEvent_nativeGetYPrecision },
-    { "nativeGetDownTimeNanos",
-            "!(J)J",
-            (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
-    { "nativeSetDownTimeNanos",
-            "!(JJ)V",
-            (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
-    { "nativeGetPointerCount",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetPointerCount },
-    { "nativeGetPointerId",
-            "!(JI)I",
-            (void*)android_view_MotionEvent_nativeGetPointerId },
-    { "nativeGetToolType",
-            "!(JI)I",
-            (void*)android_view_MotionEvent_nativeGetToolType },
-    { "nativeFindPointerIndex",
-            "!(JI)I",
-            (void*)android_view_MotionEvent_nativeFindPointerIndex },
-    { "nativeGetHistorySize",
-            "!(J)I",
-            (void*)android_view_MotionEvent_nativeGetHistorySize },
-    { "nativeGetEventTimeNanos",
-            "!(JI)J",
-            (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
-    { "nativeGetRawAxisValue",
-            "!(JIII)F",
-            (void*)android_view_MotionEvent_nativeGetRawAxisValue },
-    { "nativeGetAxisValue",
-            "!(JIII)F",
-            (void*)android_view_MotionEvent_nativeGetAxisValue },
-    { "nativeGetPointerCoords",
-            "(JIILandroid/view/MotionEvent$PointerCoords;)V",
-            (void*)android_view_MotionEvent_nativeGetPointerCoords },
-    { "nativeGetPointerProperties",
-            "(JILandroid/view/MotionEvent$PointerProperties;)V",
-            (void*)android_view_MotionEvent_nativeGetPointerProperties },
-    { "nativeScale",
-            "!(JF)V",
-            (void*)android_view_MotionEvent_nativeScale },
-    { "nativeTransform",
-            "(JLandroid/graphics/Matrix;)V",
-            (void*)android_view_MotionEvent_nativeTransform },
     { "nativeReadFromParcel",
             "(JLandroid/os/Parcel;)J",
             (void*)android_view_MotionEvent_nativeReadFromParcel },
@@ -879,6 +754,116 @@
             (void*)android_view_MotionEvent_nativeAxisToString },
     { "nativeAxisFromString", "(Ljava/lang/String;)I",
             (void*)android_view_MotionEvent_nativeAxisFromString },
+    { "nativeGetPointerProperties",
+            "(JILandroid/view/MotionEvent$PointerProperties;)V",
+            (void*)android_view_MotionEvent_nativeGetPointerProperties },
+    { "nativeGetPointerCoords",
+            "(JIILandroid/view/MotionEvent$PointerCoords;)V",
+            (void*)android_view_MotionEvent_nativeGetPointerCoords },
+
+    // --------------- @FastNative ----------------------
+    { "nativeGetPointerId",
+            "(JI)I",
+            (void*)android_view_MotionEvent_nativeGetPointerId },
+    { "nativeGetToolType",
+            "(JI)I",
+            (void*)android_view_MotionEvent_nativeGetToolType },
+    { "nativeGetEventTimeNanos",
+            "(JI)J",
+            (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
+    { "nativeGetRawAxisValue",
+            "(JIII)F",
+            (void*)android_view_MotionEvent_nativeGetRawAxisValue },
+    { "nativeGetAxisValue",
+            "(JIII)F",
+            (void*)android_view_MotionEvent_nativeGetAxisValue },
+
+    // --------------- @CriticalNative ------------------
+
+    { "nativeCopy",
+            "(JJZ)J",
+            (void*)android_view_MotionEvent_nativeCopy },
+    { "nativeGetDeviceId",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetDeviceId },
+    { "nativeGetSource",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetSource },
+    { "nativeSetSource",
+            "(JI)I",
+            (void*)android_view_MotionEvent_nativeSetSource },
+    { "nativeGetAction",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetAction },
+    { "nativeSetAction",
+            "(JI)V",
+            (void*)android_view_MotionEvent_nativeSetAction },
+    { "nativeGetActionButton",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetActionButton},
+    { "nativeSetActionButton",
+            "(JI)V",
+            (void*)android_view_MotionEvent_nativeSetActionButton},
+    { "nativeIsTouchEvent",
+            "(J)Z",
+            (void*)android_view_MotionEvent_nativeIsTouchEvent },
+    { "nativeGetFlags",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetFlags },
+    { "nativeSetFlags",
+            "(JI)V",
+            (void*)android_view_MotionEvent_nativeSetFlags },
+    { "nativeGetEdgeFlags",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetEdgeFlags },
+    { "nativeSetEdgeFlags",
+            "(JI)V",
+            (void*)android_view_MotionEvent_nativeSetEdgeFlags },
+    { "nativeGetMetaState",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetMetaState },
+    { "nativeGetButtonState",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetButtonState },
+    { "nativeSetButtonState",
+            "(JI)V",
+            (void*)android_view_MotionEvent_nativeSetButtonState },
+    { "nativeOffsetLocation",
+            "(JFF)V",
+            (void*)android_view_MotionEvent_nativeOffsetLocation },
+    { "nativeGetXOffset",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetXOffset },
+    { "nativeGetYOffset",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetYOffset },
+    { "nativeGetXPrecision",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetXPrecision },
+    { "nativeGetYPrecision",
+            "(J)F",
+            (void*)android_view_MotionEvent_nativeGetYPrecision },
+    { "nativeGetDownTimeNanos",
+            "(J)J",
+            (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
+    { "nativeSetDownTimeNanos",
+            "(JJ)V",
+            (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
+    { "nativeGetPointerCount",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetPointerCount },
+    { "nativeFindPointerIndex",
+            "(JI)I",
+            (void*)android_view_MotionEvent_nativeFindPointerIndex },
+    { "nativeGetHistorySize",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetHistorySize },
+    { "nativeScale",
+            "(JF)V",
+            (void*)android_view_MotionEvent_nativeScale },
+    { "nativeTransform",
+            "(JJ)V",
+            (void*)android_view_MotionEvent_nativeTransform },
 };
 
 int register_android_view_MotionEvent(JNIEnv* env) {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index b0028e1..dd2a7a9 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -120,12 +120,15 @@
     return reinterpret_cast<jlong>(renderNode);
 }
 
-static void android_view_RenderNode_destroyRenderNode(JNIEnv* env,
-        jobject clazz, jlong renderNodePtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+static void releaseRenderNode(RenderNode* renderNode) {
     renderNode->decStrong(0);
 }
 
+static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env,
+        jobject clazz) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseRenderNode));
+}
+
 static void android_view_RenderNode_setDisplayList(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jlong displayListPtr) {
     class RemovedObserver : public TreeObserver {
@@ -643,87 +646,91 @@
 const char* const kClassPathName = "android/view/RenderNode";
 
 static const JNINativeMethod gMethods[] = {
+// ----------------------------------------------------------------------------
+// Regular JNI
+// ----------------------------------------------------------------------------
     { "nCreate",               "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
-    { "nDestroyRenderNode",    "(J)V",    (void*) android_view_RenderNode_destroyRenderNode },
+    { "nGetNativeFinalizer",   "()J",    (void*) android_view_RenderNode_getNativeFinalizer },
     { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
     { "nOutput",               "(J)V",    (void*) android_view_RenderNode_output },
     { "nGetDebugSize",         "(J)I",    (void*) android_view_RenderNode_getDebugSize },
-
-    { "nSetLayerType",         "!(JI)Z",  (void*) android_view_RenderNode_setLayerType },
-    { "nSetLayerPaint",        "!(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
-    { "nSetStaticMatrix",      "!(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
-    { "nSetAnimationMatrix",   "!(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
-    { "nSetClipToBounds",      "!(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
-    { "nSetClipBounds",        "!(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
-    { "nSetClipBoundsEmpty",   "!(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
-    { "nSetProjectBackwards",  "!(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
-    { "nSetProjectionReceiver","!(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
-
-    { "nSetOutlineRoundRect",  "!(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
-    { "nSetOutlineConvexPath", "!(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
-    { "nSetOutlineEmpty",      "!(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
-    { "nSetOutlineNone",       "!(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
-    { "nHasShadow",            "!(J)Z",   (void*) android_view_RenderNode_hasShadow },
-    { "nSetClipToOutline",     "!(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
-    { "nSetRevealClip",        "!(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
-
-    { "nSetAlpha",             "!(JF)Z",  (void*) android_view_RenderNode_setAlpha },
-    { "nSetHasOverlappingRendering", "!(JZ)Z",
-            (void*) android_view_RenderNode_setHasOverlappingRendering },
-    { "nSetElevation",         "!(JF)Z",  (void*) android_view_RenderNode_setElevation },
-    { "nSetTranslationX",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
-    { "nSetTranslationY",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
-    { "nSetTranslationZ",      "!(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
-    { "nSetRotation",          "!(JF)Z",  (void*) android_view_RenderNode_setRotation },
-    { "nSetRotationX",         "!(JF)Z",  (void*) android_view_RenderNode_setRotationX },
-    { "nSetRotationY",         "!(JF)Z",  (void*) android_view_RenderNode_setRotationY },
-    { "nSetScaleX",            "!(JF)Z",  (void*) android_view_RenderNode_setScaleX },
-    { "nSetScaleY",            "!(JF)Z",  (void*) android_view_RenderNode_setScaleY },
-    { "nSetPivotX",            "!(JF)Z",  (void*) android_view_RenderNode_setPivotX },
-    { "nSetPivotY",            "!(JF)Z",  (void*) android_view_RenderNode_setPivotY },
-    { "nSetCameraDistance",    "!(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
-    { "nSetLeft",              "!(JI)Z",  (void*) android_view_RenderNode_setLeft },
-    { "nSetTop",               "!(JI)Z",  (void*) android_view_RenderNode_setTop },
-    { "nSetRight",             "!(JI)Z",  (void*) android_view_RenderNode_setRight },
-    { "nSetBottom",            "!(JI)Z",  (void*) android_view_RenderNode_setBottom },
-    { "nSetLeftTopRightBottom","!(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
-    { "nOffsetLeftAndRight",   "!(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
-    { "nOffsetTopAndBottom",   "!(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
-
-    { "nHasOverlappingRendering", "!(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
-    { "nGetClipToOutline",        "!(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
-    { "nGetAlpha",                "!(J)F",  (void*) android_view_RenderNode_getAlpha },
-    { "nGetCameraDistance",       "!(J)F",  (void*) android_view_RenderNode_getCameraDistance },
-    { "nGetScaleX",               "!(J)F",  (void*) android_view_RenderNode_getScaleX },
-    { "nGetScaleY",               "!(J)F",  (void*) android_view_RenderNode_getScaleY },
-    { "nGetElevation",            "!(J)F",  (void*) android_view_RenderNode_getElevation },
-    { "nGetTranslationX",         "!(J)F",  (void*) android_view_RenderNode_getTranslationX },
-    { "nGetTranslationY",         "!(J)F",  (void*) android_view_RenderNode_getTranslationY },
-    { "nGetTranslationZ",         "!(J)F",  (void*) android_view_RenderNode_getTranslationZ },
-    { "nGetRotation",             "!(J)F",  (void*) android_view_RenderNode_getRotation },
-    { "nGetRotationX",            "!(J)F",  (void*) android_view_RenderNode_getRotationX },
-    { "nGetRotationY",            "!(J)F",  (void*) android_view_RenderNode_getRotationY },
-    { "nIsPivotExplicitlySet",    "!(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
-    { "nHasIdentityMatrix",       "!(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
-
-    { "nGetTransformMatrix",       "!(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
-    { "nGetInverseTransformMatrix","!(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
-
-    { "nGetPivotX",                "!(J)F",  (void*) android_view_RenderNode_getPivotX },
-    { "nGetPivotY",                "!(J)F",  (void*) android_view_RenderNode_getPivotY },
-
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
-
     { "nRequestPositionUpdates",   "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates },
+
+// ----------------------------------------------------------------------------
+// Fast JNI via @FastNative annotation in RenderNode.java
+// ----------------------------------------------------------------------------
+    { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
+    { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
+    { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
+    { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
+    { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
+    { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
+    { "nSetClipBoundsEmpty",   "(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
+    { "nSetProjectBackwards",  "(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
+    { "nSetProjectionReceiver","(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
+
+    { "nSetOutlineRoundRect",  "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
+    { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
+    { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
+    { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
+    { "nHasShadow",            "(J)Z",   (void*) android_view_RenderNode_hasShadow },
+    { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
+    { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
+
+    { "nSetAlpha",             "(JF)Z",  (void*) android_view_RenderNode_setAlpha },
+    { "nSetHasOverlappingRendering", "(JZ)Z",
+            (void*) android_view_RenderNode_setHasOverlappingRendering },
+    { "nSetElevation",         "(JF)Z",  (void*) android_view_RenderNode_setElevation },
+    { "nSetTranslationX",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
+    { "nSetTranslationY",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
+    { "nSetTranslationZ",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
+    { "nSetRotation",          "(JF)Z",  (void*) android_view_RenderNode_setRotation },
+    { "nSetRotationX",         "(JF)Z",  (void*) android_view_RenderNode_setRotationX },
+    { "nSetRotationY",         "(JF)Z",  (void*) android_view_RenderNode_setRotationY },
+    { "nSetScaleX",            "(JF)Z",  (void*) android_view_RenderNode_setScaleX },
+    { "nSetScaleY",            "(JF)Z",  (void*) android_view_RenderNode_setScaleY },
+    { "nSetPivotX",            "(JF)Z",  (void*) android_view_RenderNode_setPivotX },
+    { "nSetPivotY",            "(JF)Z",  (void*) android_view_RenderNode_setPivotY },
+    { "nSetCameraDistance",    "(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
+    { "nSetLeft",              "(JI)Z",  (void*) android_view_RenderNode_setLeft },
+    { "nSetTop",               "(JI)Z",  (void*) android_view_RenderNode_setTop },
+    { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
+    { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
+    { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
+    { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
+    { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
+
+    { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
+    { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
+    { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
+    { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
+    { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
+    { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
+    { "nGetElevation",            "(J)F",  (void*) android_view_RenderNode_getElevation },
+    { "nGetTranslationX",         "(J)F",  (void*) android_view_RenderNode_getTranslationX },
+    { "nGetTranslationY",         "(J)F",  (void*) android_view_RenderNode_getTranslationY },
+    { "nGetTranslationZ",         "(J)F",  (void*) android_view_RenderNode_getTranslationZ },
+    { "nGetRotation",             "(J)F",  (void*) android_view_RenderNode_getRotation },
+    { "nGetRotationX",            "(J)F",  (void*) android_view_RenderNode_getRotationX },
+    { "nGetRotationY",            "(J)F",  (void*) android_view_RenderNode_getRotationY },
+    { "nIsPivotExplicitlySet",    "(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
+    { "nHasIdentityMatrix",       "(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
+
+    { "nGetTransformMatrix",       "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
+    { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
+
+    { "nGetPivotX",                "(J)F",  (void*) android_view_RenderNode_getPivotX },
+    { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
 };
 
 int register_android_view_RenderNode(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
-            "updateWindowPositionRT", "(JIIII)V");
+            "updateWindowPosition_renderWorker", "(JIIII)V");
     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
-            "windowPositionLostRT", "(J)V");
+            "windowPositionLost_uiRtSync", "(J)V");
     clazz = FindClassOrDie(env, "android/view/RenderNode");
     gOnRenderNodeDetached = GetMethodIDOrDie(env, clazz,
             "onRenderNodeDetached", "()V");
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 5637dbc..3f2b924 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -487,6 +487,11 @@
     return surface->setScalingMode(scalingMode);
 }
 
+static jint nativeForceScopedDisconnect(JNIEnv *env, jclass clazz, jlong nativeObject) {
+    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+    return surface->disconnect(-1, IGraphicBufferProducer::DisconnectMode::AllLocal);
+}
+
 namespace uirenderer {
 
 using namespace android::uirenderer::renderthread;
@@ -564,6 +569,7 @@
     {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
     {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
     {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
+    {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect},
 
     // HWUI context
     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0d8a95c..73b3f52 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -371,7 +371,12 @@
     if (sur != NULL) {
         bufferProducer = sur->getIGraphicBufferProducer();
     }
-    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
+    status_t err = SurfaceComposerClient::setDisplaySurface(token,
+            bufferProducer);
+    if (err != NO_ERROR) {
+        doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
+                " Surface created with singleBufferMode?");
+    }
 }
 
 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 87a8ef8..309bb2f 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -899,11 +899,12 @@
 }
 
 static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
-        jobject clazz, jobject jsurface, jobject jbitmap) {
+        jobject clazz, jobject jsurface, jint left, jint top,
+        jint right, jint bottom, jobject jbitmap) {
     SkBitmap bitmap;
     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
     sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
-    return RenderProxy::copySurfaceInto(surface, &bitmap);
+    return RenderProxy::copySurfaceInto(surface, left, top, right, bottom, &bitmap);
 }
 
 // ----------------------------------------------------------------------------
@@ -953,7 +954,7 @@
 const char* const kClassPathName = "android/view/ThreadedRenderer";
 
 static const JNINativeMethod gMethods[] = {
-    { "nSupportsOpenGL", "!()Z", (void*) android_view_ThreadedRenderer_supportsOpenGL },
+    { "nSupportsOpenGL", "()Z", (void*) android_view_ThreadedRenderer_supportsOpenGL },
     { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
     { "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
@@ -1001,7 +1002,7 @@
     { "nRemoveFrameMetricsObserver",
             "(JJ)V",
             (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
-    { "nCopySurfaceInto", "(Landroid/view/Surface;Landroid/graphics/Bitmap;)I",
+    { "nCopySurfaceInto", "(Landroid/view/Surface;IIIILandroid/graphics/Bitmap;)I",
                 (void*)android_view_ThreadedRenderer_copySurfaceInto },
 };
 
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 364ac44..7e01657 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -20,7 +20,6 @@
 #include "core_jni_helpers.h"
 
 #include <ScopedUtfChars.h>
-#include <UniquePtr.h>
 #include <androidfw/ZipFileRO.h>
 #include <androidfw/ZipUtils.h>
 #include <utils/Log.h>
@@ -37,6 +36,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <memory>
 
 #define APK_LIB "lib/"
 #define APK_LIB_LEN (sizeof(APK_LIB) - 1)
@@ -398,7 +398,7 @@
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    std::unique_ptr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
     if (it.get() == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
@@ -446,7 +446,7 @@
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
+    std::unique_ptr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile));
     if (it.get() == NULL) {
         return INSTALL_FAILED_INVALID_APK;
     }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cdfb722..af117d1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -32,6 +32,7 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/capability.h>
+#include <sys/cdefs.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
@@ -55,6 +56,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
+#include "fd_utils-inl.h"
 
 #include "nativebridge/native_bridge.h"
 
@@ -434,26 +436,8 @@
   }
 }
 
-#ifdef ENABLE_SCHED_BOOST
-static void SetForkLoad(bool boost) {
-  // set scheduler knob to boost forked processes
-  pid_t currentPid = getpid();
-  // fits at most "/proc/XXXXXXX/sched_init_task_load\0"
-  char schedPath[35];
-  snprintf(schedPath, sizeof(schedPath), "/proc/%u/sched_init_task_load", currentPid);
-  int schedBoostFile = open(schedPath, O_WRONLY);
-  if (schedBoostFile < 0) {
-    ALOGW("Unable to set zygote scheduler boost");
-    return;
-  }
-  if (boost) {
-    write(schedBoostFile, "100\0", 4);
-  } else {
-    write(schedBoostFile, "0\0", 2);
-  }
-  close(schedBoostFile);
-}
-#endif
+// The list of open zygote file descriptors.
+static FileDescriptorTable* gOpenFdTable = NULL;
 
 // Utility routine to fork zygote and specialize the child process.
 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
@@ -465,9 +449,21 @@
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
-#ifdef ENABLE_SCHED_BOOST
-  SetForkLoad(true);
-#endif
+  // Close any logging related FDs before we start evaluating the list of
+  // file descriptors.
+  __android_log_close();
+
+  // If this is the first fork for this zygote, create the open FD table.
+  // If it isn't, we just need to check whether the list of open files has
+  // changed (and it shouldn't in the normal case).
+  if (gOpenFdTable == NULL) {
+    gOpenFdTable = FileDescriptorTable::Create();
+    if (gOpenFdTable == NULL) {
+      RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+    }
+  } else if (!gOpenFdTable->Restat()) {
+    RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+  }
 
   ResetNicePriority(env);
 
@@ -480,6 +476,12 @@
     // Clean up any descriptors which must be closed immediately
     DetachDescriptors(env, fdsToClose);
 
+    // Re-open all remaining open file descriptors so that they aren't shared
+    // with the zygote across a fork.
+    if (!gOpenFdTable->ReopenOrDetach()) {
+      RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
+    }
+
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
       EnableKeepCapabilities(env);
@@ -607,12 +609,6 @@
     }
   } else if (pid > 0) {
     // the parent process
-
-#ifdef ENABLE_SCHED_BOOST
-    // unset scheduler knob
-    SetForkLoad(false);
-#endif
-
   }
   return pid;
 }
@@ -690,11 +686,39 @@
 static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
     // Zygote process unmount root storage space initially before every child processes are forked.
     // Every forked child processes (include SystemServer) only mount their own root storage space
-    // And no need unmount storage operation in MountEmulatedStorage method.
-    // Zygote process does not utilize root storage spaces and unshared its mount namespace from the ART.
+    // and no need unmount storage operation in MountEmulatedStorage method.
+    // Zygote process does not utilize root storage spaces and unshares its mount namespace below.
+
+    // See storage config details at http://source.android.com/tech/storage/
+    // Create private mount namespace shared by all children
+    if (unshare(CLONE_NEWNS) == -1) {
+        RuntimeAbort(env, __LINE__, "Failed to unshare()");
+        return;
+    }
+
+    // Mark rootfs as being a slave so that changes from default
+    // namespace only flow into our children.
+    if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
+        RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE");
+        return;
+    }
+
+    // Create a staging tmpfs that is shared by our children; they will
+    // bind mount storage into their respective private namespaces, which
+    // are isolated from each other.
+    const char* target_base = getenv("EMULATED_STORAGE_TARGET");
+    if (target_base != nullptr) {
+#define STRINGIFY_UID(x) __STRING(x)
+        if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
+                  "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) {
+            ALOGE("Failed to mount tmpfs to %s", target_base);
+            RuntimeAbort(env, __LINE__, "Failed to mount tmpfs");
+            return;
+        }
+#undef STRINGIFY_UID
+    }
 
     UnmountTree("/storage");
-    return;
 }
 
 static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
new file mode 100644
index 0000000..af27069
--- /dev/null
+++ b/core/jni/fd_utils-inl.h
@@ -0,0 +1,563 @@
+/*
+ * 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 <string>
+#include <unordered_map>
+#include <set>
+#include <vector>
+#include <algorithm>
+
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
+// Whitelist of open paths that the zygote is allowed to keep open.
+//
+// In addition to the paths listed here, all files ending with
+// ".jar" under /system/framework" are whitelisted. See
+// FileDescriptorInfo::IsWhitelisted for the canonical definition.
+//
+// If the whitelisted path is associated with a regular file or a
+// character device, the file is reopened after a fork with the same
+// offset and mode. If the whilelisted  path is associated with a
+// AF_UNIX socket, the socket will refer to /dev/null after each
+// fork, and all operations on it will fail.
+static const char* kPathWhitelist[] = {
+  "/dev/null",
+  "/dev/socket/zygote",
+  "/dev/socket/zygote_secondary",
+  "/sys/kernel/debug/tracing/trace_marker",
+  "/system/framework/framework-res.apk",
+  "/dev/urandom",
+  "/dev/ion",
+  "/dev/dri/renderD129", // Fixes b/31172436
+};
+
+static const char* kFdPath = "/proc/self/fd";
+
+// Keeps track of all relevant information (flags, offset etc.) of an
+// open zygote file descriptor.
+class FileDescriptorInfo {
+ public:
+  // Create a FileDescriptorInfo for a given file descriptor. Returns
+  // |NULL| if an error occurred.
+  static FileDescriptorInfo* createFromFd(int fd) {
+    struct stat f_stat;
+    // This should never happen; the zygote should always have the right set
+    // of permissions required to stat all its open files.
+    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+      ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    if (S_ISSOCK(f_stat.st_mode)) {
+      std::string socket_name;
+      if (!GetSocketName(fd, &socket_name)) {
+        return NULL;
+      }
+
+      if (!IsWhitelisted(socket_name)) {
+        ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd);
+        return NULL;
+      }
+
+      return new FileDescriptorInfo(fd);
+    }
+
+    // We only handle whitelisted regular files and character devices. Whitelisted
+    // character devices must provide a guarantee of sensible behaviour when
+    // reopened.
+    //
+    // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
+    // S_ISLINK : Not supported.
+    // S_ISBLK : Not supported.
+    // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
+    // with the child process across forks but those should have been closed
+    // before we got to this point.
+    if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
+      ALOGE("Unsupported st_mode %d", f_stat.st_mode);
+      return NULL;
+    }
+
+    std::string file_path;
+    if (!Readlink(fd, &file_path)) {
+      return NULL;
+    }
+
+    if (!IsWhitelisted(file_path)) {
+      ALOGE("Not whitelisted : %s", file_path.c_str());
+      return NULL;
+    }
+
+    // File descriptor flags : currently on FD_CLOEXEC. We can set these
+    // using F_SETFD - we're single threaded at this point of execution so
+    // there won't be any races.
+    const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
+    if (fd_flags == -1) {
+      ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    // File status flags :
+    // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
+    //   to the open() call.
+    //
+    // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
+    //   do about these, since the file has already been created. We shall ignore
+    //   them here.
+    //
+    // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
+    //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
+    //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
+    //   their presence and pass them in to open().
+    int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
+    if (fs_flags == -1) {
+      ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    // File offset : Ignore the offset for non seekable files.
+    const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
+
+    // We pass the flags that open accepts to open, and use F_SETFL for
+    // the rest of them.
+    static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
+    int open_flags = fs_flags & (kOpenFlags);
+    fs_flags = fs_flags & (~(kOpenFlags));
+
+    return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
+  }
+
+  // Checks whether the file descriptor associated with this object
+  // refers to the same description.
+  bool Restat() const {
+    struct stat f_stat;
+    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+      return false;
+    }
+
+    return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
+  }
+
+  bool ReopenOrDetach() const {
+    if (is_sock) {
+      return DetachSocket();
+    }
+
+    // NOTE: This might happen if the file was unlinked after being opened.
+    // It's a common pattern in the case of temporary files and the like but
+    // we should not allow such usage from the zygote.
+    const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
+
+    if (new_fd == -1) {
+      ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
+      close(new_fd);
+      ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
+      close(new_fd);
+      ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
+      return false;
+    }
+
+    if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
+      close(new_fd);
+      ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
+      close(new_fd);
+      ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
+      return false;
+    }
+
+    close(new_fd);
+
+    return true;
+  }
+
+  const int fd;
+  const struct stat stat;
+  const std::string file_path;
+  const int open_flags;
+  const int fd_flags;
+  const int fs_flags;
+  const off_t offset;
+  const bool is_sock;
+
+ private:
+  FileDescriptorInfo(int fd) :
+    fd(fd),
+    stat(),
+    open_flags(0),
+    fd_flags(0),
+    fs_flags(0),
+    offset(0),
+    is_sock(true) {
+  }
+
+  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+                     int fd_flags, int fs_flags, off_t offset) :
+    fd(fd),
+    stat(stat),
+    file_path(file_path),
+    open_flags(open_flags),
+    fd_flags(fd_flags),
+    fs_flags(fs_flags),
+    offset(offset),
+    is_sock(false) {
+  }
+
+  // Returns true iff. a given path is whitelisted. A path is whitelisted
+  // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
+  // under /system/framework that ends with ".jar" or if it is a system
+  // framework overlay.
+  static bool IsWhitelisted(const std::string& path) {
+    for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
+      if (kPathWhitelist[i] == path) {
+        return true;
+      }
+    }
+
+    static const char* kFrameworksPrefix = "/system/framework/";
+    static const char* kJarSuffix = ".jar";
+    if (android::base::StartsWith(path, kFrameworksPrefix)
+        && android::base::EndsWith(path, kJarSuffix)) {
+      return true;
+    }
+
+    // Whitelist files needed for Runtime Resource Overlay, like these:
+    // /system/vendor/overlay/framework-res.apk
+    // /system/vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
+    // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
+    // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
+    static const char* kOverlayDir = "/system/vendor/overlay/";
+    static const char* kApkSuffix = ".apk";
+
+    if (android::base::StartsWith(path, kOverlayDir)
+        && android::base::EndsWith(path, kApkSuffix)
+        && path.find("/../") == std::string::npos) {
+      return true;
+    }
+
+    static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
+    static const char* kOverlayIdmapSuffix = ".apk@idmap";
+    if (android::base::StartsWith(path, kOverlayIdmapPrefix)
+        && android::base::EndsWith(path, kOverlayIdmapSuffix)) {
+      return true;
+    }
+
+    return false;
+  }
+
+  // TODO: Call android::base::Readlink instead of copying the code here.
+  static bool Readlink(const int fd, std::string* result) {
+    char path[64];
+    snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+
+    // Code copied from android::base::Readlink starts here :
+
+    // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
+    // and truncates to whatever size you do supply, so it can't be used to query.
+    // We could call lstat first, but that would introduce a race condition that
+    // we couldn't detect.
+    // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
+    char buf[4096];
+    ssize_t len = readlink(path, buf, sizeof(buf));
+    if (len == -1) return false;
+
+    result->assign(buf, len);
+    return true;
+  }
+
+  // Returns the locally-bound name of the socket |fd|. Returns true
+  // iff. all of the following hold :
+  //
+  // - the socket's sa_family is AF_UNIX.
+  // - the length of the path is greater than zero (i.e, not an unnamed socket).
+  // - the first byte of the path isn't zero (i.e, not a socket with an abstract
+  //   address).
+  static bool GetSocketName(const int fd, std::string* result) {
+    sockaddr_storage ss;
+    sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
+    socklen_t addr_len = sizeof(ss);
+
+    if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
+      ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno));
+      return false;
+    }
+
+    if (addr->sa_family != AF_UNIX) {
+      ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family);
+      return false;
+    }
+
+    const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
+
+    size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
+    // This is an unnamed local socket, we do not accept it.
+    if (path_len == 0) {
+      ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd);
+      return false;
+    }
+
+    // This is a local socket with an abstract address, we do not accept it.
+    if (unix_addr->sun_path[0] == '\0') {
+      ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd);
+      return false;
+    }
+
+    // If we're here, sun_path must refer to a null terminated filesystem
+    // pathname (man 7 unix). Remove the terminator before assigning it to an
+    // std::string.
+    if (unix_addr->sun_path[path_len - 1] ==  '\0') {
+      --path_len;
+    }
+
+    result->assign(unix_addr->sun_path, path_len);
+    return true;
+  }
+
+  bool DetachSocket() const {
+    const int dev_null_fd = open("/dev/null", O_RDWR);
+    if (dev_null_fd < 0) {
+      ALOGE("Failed to open /dev/null : %s", strerror(errno));
+      return false;
+    }
+
+    if (dup2(dev_null_fd, fd) == -1) {
+      ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno));
+      return false;
+    }
+
+    if (close(dev_null_fd) == -1) {
+      ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno));
+      return false;
+    }
+
+    return true;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
+};
+
+// A FileDescriptorTable is a collection of FileDescriptorInfo objects
+// keyed by their FDs.
+class FileDescriptorTable {
+ public:
+  // Creates a new FileDescriptorTable. This function scans
+  // /proc/self/fd for the list of open file descriptors and collects
+  // information about them. Returns NULL if an error occurs.
+  static FileDescriptorTable* Create() {
+    DIR* d = opendir(kFdPath);
+    if (d == NULL) {
+      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+      return NULL;
+    }
+    int dir_fd = dirfd(d);
+    dirent* e;
+
+    std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
+    while ((e = readdir(d)) != NULL) {
+      const int fd = ParseFd(e, dir_fd);
+      if (fd == -1) {
+        continue;
+      }
+
+      FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
+      if (info == NULL) {
+        if (closedir(d) == -1) {
+          ALOGE("Unable to close directory : %s", strerror(errno));
+        }
+        return NULL;
+      }
+      open_fd_map[fd] = info;
+    }
+
+    if (closedir(d) == -1) {
+      ALOGE("Unable to close directory : %s", strerror(errno));
+      return NULL;
+    }
+    return new FileDescriptorTable(open_fd_map);
+  }
+
+  bool Restat() {
+    std::set<int> open_fds;
+
+    // First get the list of open descriptors.
+    DIR* d = opendir(kFdPath);
+    if (d == NULL) {
+      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+      return false;
+    }
+
+    int dir_fd = dirfd(d);
+    dirent* e;
+    while ((e = readdir(d)) != NULL) {
+      const int fd = ParseFd(e, dir_fd);
+      if (fd == -1) {
+        continue;
+      }
+
+      open_fds.insert(fd);
+    }
+
+    if (closedir(d) == -1) {
+      ALOGE("Unable to close directory : %s", strerror(errno));
+      return false;
+    }
+
+    return RestatInternal(open_fds);
+  }
+
+  // Reopens all file descriptors that are contained in the table. Returns true
+  // if all descriptors were successfully re-opened or detached, and false if an
+  // error occurred.
+  bool ReopenOrDetach() {
+    std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
+    for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
+      const FileDescriptorInfo* info = it->second;
+      if (info == NULL || !info->ReopenOrDetach()) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+ private:
+  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map)
+      : open_fd_map_(map) {
+  }
+
+  bool RestatInternal(std::set<int>& open_fds) {
+    bool error = false;
+
+    // Iterate through the list of file descriptors we've already recorded
+    // and check whether :
+    //
+    // (a) they continue to be open.
+    // (b) they refer to the same file.
+    std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
+    while (it != open_fd_map_.end()) {
+      std::set<int>::const_iterator element = open_fds.find(it->first);
+      if (element == open_fds.end()) {
+        // The entry from the file descriptor table is no longer in the list
+        // of open files. We warn about this condition and remove it from
+        // the list of FDs under consideration.
+        //
+        // TODO(narayan): This will be an error in a future android release.
+        // error = true;
+        // ALOGW("Zygote closed file descriptor %d.", it->first);
+        it = open_fd_map_.erase(it);
+      } else {
+        // The entry from the file descriptor table is still open. Restat
+        // it and check whether it refers to the same file.
+        const bool same_file = it->second->Restat();
+        if (!same_file) {
+          // The file descriptor refers to a different description. We must
+          // update our entry in the table.
+          delete it->second;
+          it->second = FileDescriptorInfo::createFromFd(*element);
+          if (it->second == NULL) {
+            // The descriptor no longer no longer refers to a whitelisted file.
+            // We flag an error and remove it from the list of files we're
+            // tracking.
+            error = true;
+            it = open_fd_map_.erase(it);
+          } else {
+            // Successfully restatted the file, move on to the next open FD.
+            ++it;
+          }
+        } else {
+          // It's the same file. Nothing to do here. Move on to the next open
+          // FD.
+          ++it;
+        }
+
+        // Finally, remove the FD from the set of open_fds. We do this last because
+        // |element| will not remain valid after a call to erase.
+        open_fds.erase(element);
+      }
+    }
+
+    if (open_fds.size() > 0) {
+      // The zygote has opened new file descriptors since our last inspection.
+      // We warn about this condition and add them to our table.
+      //
+      // TODO(narayan): This will be an error in a future android release.
+      // error = true;
+      // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
+
+      // TODO(narayan): This code will be removed in a future android release.
+      std::set<int>::const_iterator it;
+      for (it = open_fds.begin(); it != open_fds.end(); ++it) {
+        const int fd = (*it);
+        FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
+        if (info == NULL) {
+          // A newly opened file is not on the whitelist. Flag an error and
+          // continue.
+          error = true;
+        } else {
+          // Track the newly opened file.
+          open_fd_map_[fd] = info;
+        }
+      }
+    }
+
+    return !error;
+  }
+
+  static int ParseFd(dirent* e, int dir_fd) {
+    char* end;
+    const int fd = strtol(e->d_name, &end, 10);
+    if ((*end) != '\0') {
+      return -1;
+    }
+
+    // Don't bother with the standard input/output/error, they're handled
+    // specially post-fork anyway.
+    if (fd <= STDERR_FILENO || fd == dir_fd) {
+      return -1;
+    }
+
+    return fd;
+  }
+
+  // Invariant: All values in this unordered_map are non-NULL.
+  std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
+};
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index e508708..4996bc8 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -71,21 +71,6 @@
     return s;
 }
 
-#define DEFINE_ALLOC_ARRAY_METHODS(Suffix,Type,NewType)                        \
-const Type *EphemeralStorage::allocTemporary ## Suffix ## Array(               \
-        JNIEnv *env, Type ## Array arrayObj) {                                 \
-    Type ## Array obj = (Type ## Array)env->NewGlobalRef(arrayObj);            \
-    const Type *val = env->Get ## NewType ## ArrayElements(obj, NULL);         \
-                                                                               \
-    Item item;                                                                 \
-    item.mType = TYPE_ ## Suffix ## _ARRAY;                                    \
-    item.mObj = obj;                                                           \
-    item.mPtr = (void *)val;                                                   \
-    mItems.push_back(item);                                                    \
-                                                                               \
-    return val;                                                                \
-}
-
 #define DEFINE_ALLOC_VECTOR_METHODS(Suffix,Type,NewType)                       \
 const hidl_vec<Type> *EphemeralStorage::allocTemporary ## Suffix ## Vector(    \
         JNIEnv *env, Type ## Array arrayObj) {                                 \
@@ -99,21 +84,14 @@
     item.mPtr = (void *)val;                                                   \
     mItems.push_back(item);                                                    \
                                                                                \
-    hidl_vec<Type> *vec =                                                      \
-        (hidl_vec<Type> *)allocTemporaryStorage(sizeof(hidl_vec<Type>));       \
+    void *vecPtr = allocTemporaryStorage(sizeof(hidl_vec<Type>));              \
                                                                                \
+    hidl_vec<Type> *vec = new (vecPtr) hidl_vec<Type>;                         \
     vec->setToExternal(const_cast<Type *>(val), len);                          \
                                                                                \
     return vec;                                                                \
 }
 
-DEFINE_ALLOC_ARRAY_METHODS(Int8,jbyte,Byte)
-DEFINE_ALLOC_ARRAY_METHODS(Int16,jshort,Short)
-DEFINE_ALLOC_ARRAY_METHODS(Int32,jint,Int)
-DEFINE_ALLOC_ARRAY_METHODS(Int64,jlong,Long)
-DEFINE_ALLOC_ARRAY_METHODS(Float,jfloat,Float)
-DEFINE_ALLOC_ARRAY_METHODS(Double,jdouble,Double)
-
 DEFINE_ALLOC_VECTOR_METHODS(Int8,jbyte,Byte)
 DEFINE_ALLOC_VECTOR_METHODS(Int16,jshort,Short)
 DEFINE_ALLOC_VECTOR_METHODS(Int32,jint,Int)
diff --git a/core/jni/hwbinder/EphemeralStorage.h b/core/jni/hwbinder/EphemeralStorage.h
index 1273003..f07c782 100644
--- a/core/jni/hwbinder/EphemeralStorage.h
+++ b/core/jni/hwbinder/EphemeralStorage.h
@@ -19,16 +19,13 @@
 #define EPHEMERAL_STORAGE_H_
 
 #include <android-base/macros.h>
-#include <hwbinder/HidlSupport.h>
+#include <hidl/HidlSupport.h>
 #include <jni.h>
 #include <utils/Vector.h>
 
 namespace android {
 
 #define DECLARE_ALLOC_METHODS(Suffix,Type)                          \
-    const Type *allocTemporary ## Suffix ## Array(                  \
-            JNIEnv *env, Type ## Array arrayObj);                   \
-                                                                    \
     const ::android::hardware::hidl_vec<Type> *                     \
     allocTemporary ## Suffix ## Vector(                             \
             JNIEnv *env, Type ## Array arrayObj);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3ceba08..d4bef17 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" />
@@ -194,11 +199,14 @@
     <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
     <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
+    <protected-broadcast android:name="android.btopp.intent.action.ACCEPT" />
     <protected-broadcast android:name="com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
     <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" />
 
@@ -282,6 +290,7 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
+    <protected-broadcast android:name="android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
@@ -395,6 +404,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" />
@@ -485,6 +496,8 @@
 
     <protected-broadcast android:name="com.android.server.retaildemo.ACTION_RESET_DEMO" />
 
+    <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -1312,6 +1325,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. -->
@@ -1632,7 +1646,7 @@
 
     <!-- @hide Allows an application to create, remove users and get the list of
          users on the device. Applications holding this permission can only create restricted,
-         guest, managed, and ephemeral users. For creating other kind of users,
+         guest, managed, demo, and ephemeral users. For creating other kind of users,
          {@link android.Manifest.permission#MANAGE_USERS} is needed.
          This permission is not available to third party applications. -->
     <permission android:name="android.permission.CREATE_USERS"
@@ -3115,7 +3129,7 @@
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true"
-                 android:theme="@style/Theme.Material.Light.DarkActionBar"
+                 android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
@@ -3152,7 +3166,7 @@
                 android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-                android:theme="@style/Theme.Material.Light.Dialog"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
@@ -3185,7 +3199,7 @@
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.Light.Dialog"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3193,14 +3207,14 @@
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.Light.Dialog"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
-                android:theme="@style/Theme.Material.Light.Dialog"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
@@ -3208,19 +3222,19 @@
         <activity android:name="android.accounts.CantAddAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
+                android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
                 android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-               android:theme="@style/Theme.Material.Light.Dialog"
+               android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                android:label="@string/sync_too_many_deletes"
                android:process=":ui">
         </activity>
@@ -3240,7 +3254,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                android:theme="@style/Theme.Material.Light.Dialog.Alert"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -3261,7 +3275,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                 android:excludeFromRecents="true"
                 android:process=":ui"
-                android:theme="@style/Theme.Material.Light.Dialog.Alert">
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3269,7 +3283,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                android:theme="@style/Theme.Material.Light.Dialog.Alert"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -3329,6 +3343,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver"
+                android:permission="android.permission.UPDATE_CONFIG">
+            <intent-filter>
+                <action android:name="android.intent.action.UPDATE_CT_LOGS" />
+                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.MasterClearReceiver"
             android:permission="android.permission.MASTER_CLEAR">
             <intent-filter
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
deleted file mode 100644
index 493a1ea..0000000
--- a/core/res/assets/images/clock64.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/images/clock_font.png b/core/res/assets/images/clock_font.png
new file mode 100644
index 0000000..be927ae
--- /dev/null
+++ b/core/res/assets/images/clock_font.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/anim-watch/progress_indeterminate_material.xml b/core/res/res/anim-watch/progress_indeterminate_material.xml
new file mode 100644
index 0000000..8f00d6c
--- /dev/null
+++ b/core/res/res/anim-watch/progress_indeterminate_material.xml
@@ -0,0 +1,42 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="3333"
+        android:interpolator="@interpolator/trim_start_interpolator"
+        android:propertyName="trimPathStart"
+        android:repeatCount="-1"
+        android:valueFrom="0"
+        android:valueTo="0.75"
+        android:valueType="floatType" />
+    <objectAnimator
+        android:duration="3333"
+        android:interpolator="@interpolator/trim_end_interpolator"
+        android:propertyName="trimPathEnd"
+        android:repeatCount="-1"
+        android:valueFrom="0"
+        android:valueTo="0.75"
+        android:valueType="floatType" />
+    <objectAnimator
+        android:duration="3333"
+        android:interpolator="@interpolator/trim_offset_interpolator"
+        android:propertyName="trimPathOffset"
+        android:repeatCount="-1"
+        android:valueFrom="0"
+        android:valueTo="0.25"
+        android:valueType="floatType" />
+</set>
diff --git a/core/res/res/anim-watch/progress_indeterminate_rotation_material.xml b/core/res/res/anim-watch/progress_indeterminate_rotation_material.xml
new file mode 100644
index 0000000..63e66ec
--- /dev/null
+++ b/core/res/res/anim-watch/progress_indeterminate_rotation_material.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@interpolator/progress_indeterminate_rotation_interpolator"
+    android:duration="16666"
+    android:propertyName="rotation"
+    android:repeatCount="-1"
+    android:valueFrom="0"
+    android:valueTo="720"
+    android:valueType="floatType" />
diff --git a/core/res/res/anim/dock_bottom_exit_keyguard.xml b/core/res/res/anim/dock_bottom_exit_keyguard.xml
new file mode 100644
index 0000000..4de3ce5
--- /dev/null
+++ b/core/res/res/anim/dock_bottom_exit_keyguard.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ 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
+  -->
+
+<!-- Animation for when a dock window at the bottom of the screen is exiting while on Keyguard -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:interpolator/fast_out_linear_in">
+    <translate android:fromYDelta="0" android:toYDelta="100%"
+        android:duration="200"/>
+</set>
\ No newline at end of file
diff --git a/core/res/res/anim/watch_switch_thumb_to_off_animation.xml b/core/res/res/anim/watch_switch_thumb_to_off_animation.xml
deleted file mode 100644
index c300894..0000000
--- a/core/res/res/anim/watch_switch_thumb_to_off_animation.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="sequentially">
-    <objectAnimator
-        android:duration="33"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="49"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="83"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="50"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="33"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-</set>
diff --git a/core/res/res/anim/watch_switch_thumb_to_on_animation.xml b/core/res/res/anim/watch_switch_thumb_to_on_animation.xml
deleted file mode 100644
index c300894..0000000
--- a/core/res/res/anim/watch_switch_thumb_to_on_animation.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:ordering="sequentially">
-    <objectAnimator
-        android:duration="33"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="49"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="83"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="50"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-    <objectAnimator
-        android:duration="33"
-        android:interpolator="@android:interpolator/linear"
-        android:propertyName="pathData"
-        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
-        android:valueType="pathType" />
-</set>
diff --git a/core/res/res/color/background_cache_hint_selector_device_default.xml b/core/res/res/color/background_cache_hint_selector_device_default.xml
new file mode 100644
index 0000000..3cb4bbc
--- /dev/null
+++ b/core/res/res/color/background_cache_hint_selector_device_default.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_accelerated="false" android:color="?attr/colorBackground" />
+    <item android:color="@android:color/transparent" />
+</selector>
diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
index 77883d9..5cc9559 100644
--- a/core/res/res/color/hint_foreground_material_dark.xml
+++ b/core/res/res/color/hint_foreground_material_dark.xml
@@ -15,6 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+          android:state_pressed="true"
+          android:alpha="@dimen/hint_pressed_alpha_material_dark"
+          android:color="@color/foreground_material_dark" />
     <item android:alpha="@dimen/hint_alpha_material_dark"
           android:color="@color/foreground_material_dark" />
 </selector>
diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
index 99168fd..f7465e0 100644
--- a/core/res/res/color/hint_foreground_material_light.xml
+++ b/core/res/res/color/hint_foreground_material_light.xml
@@ -15,6 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+          android:state_pressed="true"
+          android:alpha="@dimen/hint_pressed_alpha_material_light"
+          android:color="@color/foreground_material_light" />
     <item android:alpha="@dimen/hint_alpha_material_light"
           android:color="@color/foreground_material_light" />
 </selector>
diff --git a/core/res/res/color/watch_switch_track_color_material.xml b/core/res/res/color/watch_switch_track_color_material.xml
deleted file mode 100644
index 402a536..0000000
--- a/core/res/res/color/watch_switch_track_color_material.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<!-- Used for the background of switch track for watch switch preference. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="0.4" android:color="?attr/colorPrimary" />
-    <item android:color="?attr/colorPrimary" />
-</selector>
diff --git a/core/res/res/drawable-hdpi/vpn_connected.png b/core/res/res/drawable-hdpi/vpn_connected.png
index c3547e8..e05e76f 100644
--- a/core/res/res/drawable-hdpi/vpn_connected.png
+++ b/core/res/res/drawable-hdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/vpn_disconnected.png b/core/res/res/drawable-hdpi/vpn_disconnected.png
index 10a9065..3508984 100644
--- a/core/res/res/drawable-hdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-hdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_14w.png b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_14w.png
new file mode 100644
index 0000000..371469c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_14w.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_15w.png b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_15w.png
new file mode 100644
index 0000000..e477260
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_15w.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_16w.png b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_16w.png
new file mode 100644
index 0000000..19a1bd3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_16w.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_17w.png b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_17w.png
new file mode 100644
index 0000000..79dc733
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_17w.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_18w.png b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_18w.png
new file mode 100644
index 0000000..6d921c0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_thumb_mtrl_18w.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png
new file mode 100644
index 0000000..ecee3e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/watch_switch_track_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/vpn_connected.png b/core/res/res/drawable-mdpi/vpn_connected.png
index 7e167f8..f7ac2a1 100644
--- a/core/res/res/drawable-mdpi/vpn_connected.png
+++ b/core/res/res/drawable-mdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/vpn_disconnected.png b/core/res/res/drawable-mdpi/vpn_disconnected.png
index a08c42a..9db4199 100644
--- a/core/res/res/drawable-mdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-mdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/vpn_connected.xml b/core/res/res/drawable-nodpi/vpn_connected.xml
new file mode 100644
index 0000000..22a4a6cb4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/vpn_connected.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/vpn_disconnected.xml b/core/res/res/drawable-nodpi/vpn_disconnected.xml
new file mode 100644
index 0000000..22a4a6cb4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/vpn_disconnected.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M25.3,20c-1.65,-4.66 -6.08,-8 -11.3,-8 -6.63,0 -12,5.37 -12,12s5.37,12 12,12c5.22,0 9.65,-3.34 11.3,-8H34v8h8v-8h4v-8H25.3zM14,28c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
+</vector>
diff --git a/core/res/res/drawable-watch/ic_input_extract_action_done.xml b/core/res/res/drawable-watch/ic_input_extract_action_done.xml
new file mode 100644
index 0000000..a04b944
--- /dev/null
+++ b/core/res/res/drawable-watch/ic_input_extract_action_done.xml
@@ -0,0 +1,19 @@
+<!--
+     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.
+-->
+<vector android:height="22dp" android:viewportHeight="22.0"
+    android:viewportWidth="22.0" android:width="22dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FFFFFF" android:pathData="M9.25,14.82L5.43,11l-1.3,1.3 5.12,5.12 11,-11 -1.3,-1.3 -9.7,9.7z"/>
+</vector>
diff --git a/core/res/res/drawable-watch/ic_input_extract_action_send.xml b/core/res/res/drawable-watch/ic_input_extract_action_send.xml
new file mode 100644
index 0000000..3689172
--- /dev/null
+++ b/core/res/res/drawable-watch/ic_input_extract_action_send.xml
@@ -0,0 +1,24 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="22dp"
+        android:height="22dp"
+        android:viewportWidth="22.0"
+        android:viewportHeight="22.0">
+    <path
+        android:pathData="M2.77,19.32L22,11.07 2.78,2.82v6.42l13.74,1.83L2.77,12.9v6.42z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable-xhdpi/vpn_connected.png b/core/res/res/drawable-xhdpi/vpn_connected.png
index 1f46be2..a8761c9 100644
--- a/core/res/res/drawable-xhdpi/vpn_connected.png
+++ b/core/res/res/drawable-xhdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/vpn_disconnected.png b/core/res/res/drawable-xhdpi/vpn_disconnected.png
index 847d3f5..7118918 100644
--- a/core/res/res/drawable-xhdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-xhdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_14w.png b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_14w.png
new file mode 100644
index 0000000..7f7ca14
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_14w.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_15w.png b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_15w.png
new file mode 100644
index 0000000..52120b8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_15w.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_16w.png b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_16w.png
new file mode 100644
index 0000000..d6e9be9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_16w.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_17w.png b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_17w.png
new file mode 100644
index 0000000..8d76393
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_17w.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_18w.png b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_18w.png
new file mode 100644
index 0000000..ca9c66e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_thumb_mtrl_18w.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png
new file mode 100644
index 0000000..1aa5442
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/watch_switch_track_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_connected.png b/core/res/res/drawable-xxhdpi/vpn_connected.png
index ea4930c..16b1e4e 100644
--- a/core/res/res/drawable-xxhdpi/vpn_connected.png
+++ b/core/res/res/drawable-xxhdpi/vpn_connected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/vpn_disconnected.png b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
index 4cd0dd4..a025818 100644
--- a/core/res/res/drawable-xxhdpi/vpn_disconnected.png
+++ b/core/res/res/drawable-xxhdpi/vpn_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_14w.png b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_14w.png
new file mode 100644
index 0000000..c0d72d7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_14w.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_15w.png b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_15w.png
new file mode 100644
index 0000000..d7c0ec0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_15w.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_16w.png b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_16w.png
new file mode 100644
index 0000000..5815ba9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_16w.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_17w.png b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_17w.png
new file mode 100644
index 0000000..41da8c0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_17w.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_18w.png b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_18w.png
new file mode 100644
index 0000000..975eb01
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_thumb_mtrl_18w.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png
new file mode 100644
index 0000000..af2042b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/watch_switch_track_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/emergency_icon.xml b/core/res/res/drawable/emergency_icon.xml
new file mode 100644
index 0000000..b2ffa2b
--- /dev/null
+++ b/core/res/res/drawable/emergency_icon.xml
@@ -0,0 +1,40 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.8,17.3C5.3,15.9 4.5,14.0 4.5,12.0c0.0,-2.0 0.8,-3.8 2.1,-5.2l1.4,1.4c-1.0,1.0 -1.6,2.4 -1.6,3.8c0.0,1.5 0.6,2.9 1.6,3.9L6.8,17.3z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.3,20.2C1.2,18.0 0.0,15.1 0.0,12.0c0.0,-3.1 1.2,-6.0 3.3,-8.2l1.4,1.4C3.0,7.0 2.0,9.4 2.0,12.0s1.0,5.0 2.7,6.9L3.3,20.2z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M17.2,17.3l-1.4,-1.4c1.1,-1.0 1.6,-2.4 1.6,-3.9c0.0,-1.4 -0.6,-2.8 -1.6,-3.8l1.4,-1.4c1.4,1.4 2.1,3.3 2.1,5.2C19.5,14.0 18.7,15.9 17.2,17.3z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20.7,20.2l-1.4,-1.4C21.0,17.0 22.0,14.6 22.0,12.0c0.0,-2.6 -1.0,-5.0 -2.7,-6.9l1.4,-1.4C22.8,6.0 24.0,8.9 24.0,12.0C24.0,15.1 22.8,18.0 20.7,20.2z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11.0,15.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11.0,7.0l2.0,0.0l0.0,6.0l-2.0,0.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_check_circle_24px.xml b/core/res/res/drawable/ic_check_circle_24px.xml
index 066a8a7..e9af9e4 100644
--- a/core/res/res/drawable/ic_check_circle_24px.xml
+++ b/core/res/res/drawable/ic_check_circle_24px.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm-2.0,15.0l-5.0,-5.0 1.41,-1.41L10.0,14.17l7.59,-7.59L19.0,8.0l-9.0,9.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
index 603c159..124e99e 100644
--- a/core/res/res/drawable/ic_collapse_notification.xml
+++ b/core/res/res/drawable/ic_collapse_notification.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M12.0,8.0l-6.0,6.0l1.4,1.4l4.6,-4.6l4.6,4.6L18.0,14.0L12.0,8.0z"/>
-    <path
-        android:pathData="M0,0h24v24H0V0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_expand_more_48dp.xml b/core/res/res/drawable/ic_expand_more_48dp.xml
index 11323e3..5a71669 100644
--- a/core/res/res/drawable/ic_expand_more_48dp.xml
+++ b/core/res/res/drawable/ic_expand_more_48dp.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
index db7d3eb..847e326 100644
--- a/core/res/res/drawable/ic_expand_notification.xml
+++ b/core/res/res/drawable/ic_expand_notification.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M16.6,8.6L12.0,13.2L7.4,8.6L6.0,10.0l6.0,6.0l6.0,-6.0L16.6,8.6z"/>
-    <path
-        android:pathData="M0,0h24v24H0V0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml
index b2d1cb8..365863d 100644
--- a/core/res/res/drawable/ic_feedback.xml
+++ b/core/res/res/drawable/ic_feedback.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_more_items.xml b/core/res/res/drawable/ic_more_items.xml
index 5fdcdce..0ec754c 100644
--- a/core/res/res/drawable/ic_more_items.xml
+++ b/core/res/res/drawable/ic_more_items.xml
@@ -24,6 +24,5 @@
         android:fillColor="#000000"
         android:pathData="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7
 7v2h14V7H7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
+
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
index 1f67168..1297407 100644
--- a/core/res/res/drawable/ic_refresh.xml
+++ b/core/res/res/drawable/ic_refresh.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
-    <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml
index 899dc82..55d54b1 100644
--- a/core/res/res/drawable/ic_schedule.xml
+++ b/core/res/res/drawable/ic_schedule.xml
@@ -22,9 +22,6 @@
         android:fillColor="#FF000000"
         android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
     <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/>
 </vector>
diff --git a/core/res/res/drawable/perm_group_calendar.xml b/core/res/res/drawable/perm_group_calendar.xml
index 4dc7b37..85a783e 100644
--- a/core/res/res/drawable/perm_group_calendar.xml
+++ b/core/res/res/drawable/perm_group_calendar.xml
@@ -24,6 +24,5 @@
         android:fillColor="#000000"
         android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
+
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
index 741a40e..61903a5 100644
--- a/core/res/res/drawable/perm_group_camera.xml
+++ b/core/res/res/drawable/perm_group_camera.xml
@@ -28,6 +28,4 @@
         android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
 5-2.24 5-5 5z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
index d698fd1..8f9dc3e 100644
--- a/core/res/res/drawable/perm_group_contacts.xml
+++ b/core/res/res/drawable/perm_group_contacts.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" />
-    <path
         android:fillColor="#000000"
         android:pathData="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1
 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25
diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
index fbc6066..cc1ec90 100644
--- a/core/res/res/drawable/perm_group_location.xml
+++ b/core/res/res/drawable/perm_group_location.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0
 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
index c565d20..d494e67 100644
--- a/core/res/res/drawable/perm_group_microphone.xml
+++ b/core/res/res/drawable/perm_group_microphone.xml
@@ -25,6 +25,4 @@
         android:pathData="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3
 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6
 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_phone_calls.xml b/core/res/res/drawable/perm_group_phone_calls.xml
index a647894..324d864 100644
--- a/core/res/res/drawable/perm_group_phone_calls.xml
+++ b/core/res/res/drawable/perm_group_phone_calls.xml
@@ -19,9 +19,6 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="#000000"
         android:pathData="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27 .67 -.36 1.02-.24 1.12
diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
index 9b32c601..47bca19e 100644
--- a/core/res/res/drawable/perm_group_sms.xml
+++ b/core/res/res/drawable/perm_group_sms.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M20 2H4c-1.1 0-1.99 .9 -1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9
 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
index 477270d..1ff1693 100644
--- a/core/res/res/drawable/perm_group_storage.xml
+++ b/core/res/res/drawable/perm_group_storage.xml
@@ -24,6 +24,4 @@
         android:fillColor="#000000"
         android:pathData="M10 4H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_indeterminate_anim_large_material.xml b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
new file mode 100644
index 0000000..560ec5a
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_bar_large" >
+    <target
+            android:name="progressBar"
+            android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+            android:name="root"
+            android:animation="@anim/progress_indeterminate_rotation_material" />
+</animated-vector>
+
diff --git a/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
new file mode 100644
index 0000000..fbea22f
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
+
+    <target
+        android:name="progressBar"
+        android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
index 526f914..ee82e35 100644
--- a/core/res/res/drawable/progress_large_material.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -13,16 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_large" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_large_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
index cc35816..5c92600 100644
--- a/core/res/res/drawable/progress_medium_material.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -13,15 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
\ No newline at end of file
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_medium_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
index c6e4380..cec9d95 100644
--- a/core/res/res/drawable/progress_small_material.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -13,16 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_small" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item>
+        <animated-vector android:drawable="@drawable/vector_drawable_progress_bar_small" >
+            <target
+                    android:name="progressBar"
+                    android:animation="@anim/progress_indeterminate_material" />
+            <target
+                    android:name="root"
+                    android:animation="@anim/progress_indeterminate_rotation_material" />
+        </animated-vector>
+    </item>
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_static_material.xml b/core/res/res/drawable/progress_static_material.xml
new file mode 100644
index 0000000..b078fa9
--- /dev/null
+++ b/core/res/res/drawable/progress_static_material.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        >
+    <path
+        android:fillColor="?attr/colorControlActivated"
+        android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
+</vector>
diff --git a/core/res/res/drawable/watch_switch_thumb_material.xml b/core/res/res/drawable/watch_switch_thumb_material.xml
deleted file mode 100644
index 3463a4f..0000000
--- a/core/res/res/drawable/watch_switch_thumb_material.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="20dp"
-    android:height="40dp"
-    android:viewportHeight="40"
-    android:viewportWidth="20">
-    <group
-        android:translateX="10"
-        android:translateY="20">
-        <path
-            android:name="thumb_path"
-            android:fillColor="@color/white"
-            android:pathData="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z" />
-    </group>
-</vector>
diff --git a/core/res/res/drawable/watch_switch_thumb_material_anim.xml b/core/res/res/drawable/watch_switch_thumb_material_anim.xml
index 686fb97..9e3e893 100644
--- a/core/res/res/drawable/watch_switch_thumb_material_anim.xml
+++ b/core/res/res/drawable/watch_switch_thumb_material_anim.xml
@@ -15,21 +15,79 @@
     android:constantSize="true">
     <item
         android:id="@+id/off"
-        android:drawable="@drawable/watch_switch_thumb_material"
+        android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
         android:state_enabled="false" />
     <item
         android:id="@+id/on"
-        android:drawable="@drawable/watch_switch_thumb_material"
+        android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
         android:state_checked="true" />
     <item
         android:id="@+id/off"
-        android:drawable="@drawable/watch_switch_thumb_material" />
+        android:drawable="@drawable/watch_switch_thumb_mtrl_14w" />
     <transition
-        android:drawable="@drawable/watch_switch_thumb_to_on_anim_mtrl"
         android:fromId="@id/off"
-        android:toId="@id/on" />
+        android:toId="@id/on">
+        <animation-list>
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
+                android:duration="30" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_15w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_16w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_17w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_18w"
+                android:duration="75" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_17w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_16w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_15w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
+                android:duration="30" />
+        </animation-list>
+    </transition>
     <transition
-        android:drawable="@drawable/watch_switch_thumb_to_off_anim_mtrl"
         android:fromId="@id/on"
-        android:toId="@id/off" />
+        android:toId="@id/off">
+        <animation-list>
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
+                android:duration="30" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_15w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_16w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_17w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_18w"
+                android:duration="75" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_17w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_16w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_15w"
+                android:duration="15" />
+            <item
+                android:drawable="@drawable/watch_switch_thumb_mtrl_14w"
+                android:duration="30" />
+        </animation-list>
+    </transition>
 </animated-selector>
diff --git a/core/res/res/drawable/watch_switch_thumb_to_off_anim_mtrl.xml b/core/res/res/drawable/watch_switch_thumb_to_off_anim_mtrl.xml
deleted file mode 100644
index 2c6ba2f..0000000
--- a/core/res/res/drawable/watch_switch_thumb_to_off_anim_mtrl.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/watch_switch_thumb_material">
-    <target
-        android:name="thumb_path"
-        android:animation="@anim/watch_switch_thumb_to_off_animation" />
-</animated-vector>
diff --git a/core/res/res/drawable/watch_switch_thumb_to_on_anim_mtrl.xml b/core/res/res/drawable/watch_switch_thumb_to_on_anim_mtrl.xml
deleted file mode 100644
index 9f92361..0000000
--- a/core/res/res/drawable/watch_switch_thumb_to_on_anim_mtrl.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/watch_switch_thumb_material">
-    <target
-        android:name="thumb_path"
-        android:animation="@anim/watch_switch_thumb_to_on_animation" />
-</animated-vector>
diff --git a/core/res/res/drawable/watch_switch_track_material.xml b/core/res/res/drawable/watch_switch_track_material.xml
index 00cdadb..79e92a3 100644
--- a/core/res/res/drawable/watch_switch_track_material.xml
+++ b/core/res/res/drawable/watch_switch_track_material.xml
@@ -11,13 +11,11 @@
      limitations under the License.
 -->
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:gravity="center_vertical|center_horizontal">
-        <shape android:shape="oval">
-            <solid android:color="@android:color/white" />
-            <size
-                android:width="40dp"
-                android:height="40dp" />
-        </shape>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false">
+        <bitmap android:alpha="0.1" android:src="@drawable/watch_switch_track_mtrl_alpha" />
     </item>
-</layer-list>
\ No newline at end of file
+    <item>
+        <bitmap android:alpha="0.2" android:src="@drawable/watch_switch_track_mtrl_alpha" />
+    </item>
+</selector>
diff --git a/core/res/res/interpolator-watch/progress_indeterminate_rotation_interpolator.xml b/core/res/res/interpolator-watch/progress_indeterminate_rotation_interpolator.xml
new file mode 100644
index 0000000..ed2655c
--- /dev/null
+++ b/core/res/res/interpolator-watch/progress_indeterminate_rotation_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.032,0.0 0.016,0.2 0.08,0.2 l 0.12,0.0 c 0.032,0.0 0.016,0.2 0.08,0.2 l 0.12,0.0 c 0.032,0.0 0.016,0.2 0.08,0.2 l 0.12,0.0 c 0.032,0.0 0.016,0.2 0.08,0.2 l 0.12,0.0 c 0.032,0.0 0.016,0.2 0.08,0.2 l 0.12,0.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator-watch/trim_end_interpolator.xml b/core/res/res/interpolator-watch/trim_end_interpolator.xml
new file mode 100644
index 0000000..f46d5e0
--- /dev/null
+++ b/core/res/res/interpolator-watch/trim_end_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.08,0.0 0.04,1.0 0.2,1.0 l 0.8,0.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator-watch/trim_offset_interpolator.xml b/core/res/res/interpolator-watch/trim_offset_interpolator.xml
new file mode 100644
index 0000000..d58672e
--- /dev/null
+++ b/core/res/res/interpolator-watch/trim_offset_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 0.4,1.0 l 0.6,0.0 L 1.0,1.0" />
diff --git a/core/res/res/interpolator-watch/trim_start_interpolator.xml b/core/res/res/interpolator-watch/trim_start_interpolator.xml
new file mode 100644
index 0000000..365609c
--- /dev/null
+++ b/core/res/res/interpolator-watch/trim_start_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 0.2,0.0 c 0.08,0.0 0.04,1.0 0.2,1.0 l 0.6,0.0 L 1.0,1.0" />
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 7a0c38f..70833d6 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -61,6 +61,7 @@
                 android:ellipsize="none"
                 android:gravity="right"
                 android:focusable="true"
+                android:pointerIcon="hand"
                 android:nextFocusForward="@+id/minutes" />
 
             <TextView
@@ -83,6 +84,7 @@
                 android:ellipsize="none"
                 android:gravity="left"
                 android:focusable="true"
+                android:pointerIcon="hand"
                 android:nextFocusForward="@+id/am_label" />
         </LinearLayout>
 
diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
index 5e3ca14..cd6af46 100644
--- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
@@ -22,4 +22,4 @@
     android:layout_height="wrap_content"
     android:spinnersShown="true"
     android:calendarViewShown="true"
-    android:datePickerMode="@integer/date_picker_mode" />
+    android:dialogMode="true" />
diff --git a/core/res/res/layout-watch/alert_dialog_material.xml b/core/res/res/layout-watch/alert_dialog_material.xml
index 002dde8..2fe13de 100644
--- a/core/res/res/layout-watch/alert_dialog_material.xml
+++ b/core/res/res/layout-watch/alert_dialog_material.xml
@@ -45,7 +45,7 @@
             <!-- Content Panel -->
             <FrameLayout android:id="@+id/contentPanel"
                     android:layout_width="match_parent"
-                    android:layout_height="match_parent"
+                    android:layout_height="wrap_content"
                     android:clipToPadding="false">
                 <TextView android:id="@+id/message"
                         android:layout_width="match_parent"
diff --git a/core/res/res/layout-watch/input_method_extract_view.xml b/core/res/res/layout-watch/input_method_extract_view.xml
index 038b766..3478bb5 100644
--- a/core/res/res/layout-watch/input_method_extract_view.xml
+++ b/core/res/res/layout-watch/input_method_extract_view.xml
@@ -49,7 +49,7 @@
             android:layout_width="@dimen/input_extract_action_button_width"
             android:layout_height="@dimen/input_extract_action_button_width"
             android:background="@drawable/input_extract_action_bg_material_dark"
-            android:padding="4dp"
+            android:padding="@dimen/input_extract_action_icon_padding"
             android:scaleType="centerInside" />
     </FrameLayout>
 </android.inputmethodservice.CompactExtractEditLayout>
diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml
index ffc00b4..5881cf0 100644
--- a/core/res/res/layout-watch/preference_widget_switch.xml
+++ b/core/res/res/layout-watch/preference_widget_switch.xml
@@ -23,8 +23,8 @@
     android:layout_gravity="center"
     android:thumb="@drawable/watch_switch_thumb_material_anim"
     android:thumbTint="@color/watch_switch_thumb_color_material"
+    android:thumbTintMode="multiply"
     android:track="@drawable/watch_switch_track_material"
-    android:trackTint="@color/watch_switch_track_color_material"
     android:focusable="false"
     android:clickable="false"
     android:background="@null" />
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 8f36e95..32a7360 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -22,4 +22,4 @@
     android:layout_height="wrap_content"
     android:spinnersShown="true"
     android:calendarViewShown="false"
-    android:datePickerMode="@integer/date_picker_mode" />
+    android:dialogMode="true" />
diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml
index 755317e..81f08fd 100644
--- a/core/res/res/layout/date_picker_header_material.xml
+++ b/core/res/res/layout/date_picker_header_material.xml
@@ -45,6 +45,7 @@
             android:padding="8dp"
             android:background="?attr/selectableItemBackground"
             android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel"
+            android:pointerIcon="hand"
             android:nextFocusForward="@+id/prev" />
 
         <TextView
@@ -55,6 +56,7 @@
             android:includeFontPadding="false"
             android:gravity="start"
             android:maxLines="@integer/date_picker_header_max_lines_material"
+            android:pointerIcon="hand"
             android:ellipsize="none" />
     </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index d1f3902..ada18d1 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -22,4 +22,4 @@
     android:layout_gravity="center_horizontal"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:timePickerMode="@integer/time_picker_mode" />
+    android:dialogMode="true" />
diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
index 8fd87b8..ced1722 100644
--- a/core/res/res/layout/time_picker_header_material.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -38,6 +38,7 @@
         android:ellipsize="none"
         android:gravity="right"
         android:focusable="true"
+        android:pointerIcon="hand"
         android:nextFocusForward="@+id/minutes" />
 
     <TextView
@@ -64,6 +65,7 @@
         android:ellipsize="none"
         android:gravity="left"
         android:focusable="true"
+        android:pointerIcon="hand"
         android:nextFocusForward="@+id/am_label" />
 
     <!-- The layout alignment of this view will switch between toRightOf
diff --git a/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 002be41..0000000
--- a/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>نافذة جديدة للتصفح المتخفي</title>
-  </head>
-  <body>
-    <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
-
-    <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
-
-    <ul>
-      <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
-      <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
-      <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
-      <li>المراقبة من قبل العملاء السريين</li>
-      <li>الأشخاص الذين يقفون خلفك</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ar/incognito_mode_start_page.html b/core/res/res/raw-ar/incognito_mode_start_page.html
deleted file mode 100644
index 002be41..0000000
--- a/core/res/res/raw-ar/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>نافذة جديدة للتصفح المتخفي</title>
-  </head>
-  <body>
-    <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
-
-    <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
-
-    <ul>
-      <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
-      <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
-      <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
-      <li>المراقبة من قبل العملاء السريين</li>
-      <li>الأشخاص الذين يقفون خلفك</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html b/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index ee25ae4..0000000
--- a/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нов прозорец „инкогнито“</title>
-  </head>
-  <body>
-    <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
-
-    <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
-
-    <ul>
-      <li>уебсайтове, които събират или споделят информация за вас;</li>
-      <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
-      <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
-      <li>наблюдение от тайните служби;</li>
-      <li>хора, които стоят зад вас.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-bg/incognito_mode_start_page.html b/core/res/res/raw-bg/incognito_mode_start_page.html
deleted file mode 100644
index ee25ae4..0000000
--- a/core/res/res/raw-bg/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нов прозорец „инкогнито“</title>
-  </head>
-  <body>
-    <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
-
-    <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
-
-    <ul>
-      <li>уебсайтове, които събират или споделят информация за вас;</li>
-      <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
-      <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
-      <li>наблюдение от тайните служби;</li>
-      <li>хора, които стоят зад вас.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index bec3dac..0000000
--- a/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova finestra d'incògnit</title>
-  </head>
-  <body>
-    <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
-
-    <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
-
-    <ul>
-      <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
-      <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
-      <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
-      <li>vigilància per part d'agents secrets,</li>
-      <li>persones que estan darrere teu.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ca/incognito_mode_start_page.html b/core/res/res/raw-ca/incognito_mode_start_page.html
deleted file mode 100644
index bec3dac..0000000
--- a/core/res/res/raw-ca/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova finestra d'incògnit</title>
-  </head>
-  <body>
-    <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
-
-    <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
-
-    <ul>
-      <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
-      <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
-      <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
-      <li>vigilància per part d'agents secrets,</li>
-      <li>persones que estan darrere teu.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html b/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 7420393..0000000
--- a/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nové anonymní okno</title>
-  </head>
-  <body>
-    <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
-
-    <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
-
-    <ul>
-      <li>Weby, které sbírají nebo sdílejí informace o vás</li>
-      <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
-      <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
-      <li>Tajné agenty</li>
-      <li>Lidi, kteří vám koukají přes rameno</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-cs/incognito_mode_start_page.html b/core/res/res/raw-cs/incognito_mode_start_page.html
deleted file mode 100644
index 7420393..0000000
--- a/core/res/res/raw-cs/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nové anonymní okno</title>
-  </head>
-  <body>
-    <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
-
-    <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
-
-    <ul>
-      <li>Weby, které sbírají nebo sdílejí informace o vás</li>
-      <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
-      <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
-      <li>Tajné agenty</li>
-      <li>Lidi, kteří vám koukají přes rameno</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-da-xlarge/incognito_mode_start_page.html b/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index eae989f..0000000
--- a/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nyt inkognitovindue</title>
-  </head>
-  <body>
-    <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
-
-    <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
-
-    <ul>
-      <li>Websider, der indsamler eller deler oplysninger om dig</li>
-      <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
-      <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
-      <li>Overvågning af hemmelige agenter</li>
-      <li>Folk, der kigger dig over skulderen</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-da/incognito_mode_start_page.html b/core/res/res/raw-da/incognito_mode_start_page.html
deleted file mode 100644
index eae989f..0000000
--- a/core/res/res/raw-da/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nyt inkognitovindue</title>
-  </head>
-  <body>
-    <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
-
-    <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
-
-    <ul>
-      <li>Websider, der indsamler eller deler oplysninger om dig</li>
-      <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
-      <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
-      <li>Overvågning af hemmelige agenter</li>
-      <li>Folk, der kigger dig over skulderen</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-de-xlarge/incognito_mode_start_page.html b/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 1d2cb69..0000000
--- a/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Neues Inkognito-Fenster</title>
-  </head>
-  <body>
-    <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
-
-    <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
-
-    <ul>
-      <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
-      <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
-      <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
-      <li>Geheimagenten</li>
-      <li>Personen, die hinter Ihnen stehen</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-de/incognito_mode_start_page.html b/core/res/res/raw-de/incognito_mode_start_page.html
deleted file mode 100644
index 1d2cb69..0000000
--- a/core/res/res/raw-de/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Neues Inkognito-Fenster</title>
-  </head>
-  <body>
-    <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
-
-    <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
-
-    <ul>
-      <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
-      <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
-      <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
-      <li>Geheimagenten</li>
-      <li>Personen, die hinter Ihnen stehen</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-el-xlarge/incognito_mode_start_page.html b/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 5641650..0000000
--- a/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
-  </head>
-  <body>
-    <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
-
-    <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
-
-    <ul>
-      <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
-      <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
-      <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
-      <li>Παρακολούθηση από μυστικούς πράκτορες</li>
-      <li>Άτομα που στέκονται πίσω σας</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-el/incognito_mode_start_page.html b/core/res/res/raw-el/incognito_mode_start_page.html
deleted file mode 100644
index 5641650..0000000
--- a/core/res/res/raw-el/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
-  </head>
-  <body>
-    <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
-
-    <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
-
-    <ul>
-      <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
-      <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
-      <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
-      <li>Παρακολούθηση από μυστικούς πράκτορες</li>
-      <li>Άτομα που στέκονται πίσω σας</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html b/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 7436f98..0000000
--- a/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <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 that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
-
-    <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
-
-    <ul>
-      <li>Websites that collect or share information about you</li>
-      <li>Internet service providers or employers that track the pages that 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/res/raw-en-rGB/incognito_mode_start_page.html b/core/res/res/raw-en-rGB/incognito_mode_start_page.html
deleted file mode 100644
index 7436f98..0000000
--- a/core/res/res/raw-en-rGB/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <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 that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
-
-    <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
-
-    <ul>
-      <li>Websites that collect or share information about you</li>
-      <li>Internet service providers or employers that track the pages that 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/res/raw-es-rUS-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index d283df5..0000000
--- a/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nueva ventana de incógnito</title>
-  </head>
-  <body>
-    <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
-
-    <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
-
-    <ul>
-      <li>Sitios web que recaban o comparten tu información</li>
-      <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
-      <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
-      <li>Vigilancia a cargo de agentes secretos</li>
-      <li>Personas paradas atrás tuyo</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-es-rUS/incognito_mode_start_page.html b/core/res/res/raw-es-rUS/incognito_mode_start_page.html
deleted file mode 100644
index d283df5..0000000
--- a/core/res/res/raw-es-rUS/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nueva ventana de incógnito</title>
-  </head>
-  <body>
-    <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
-
-    <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
-
-    <ul>
-      <li>Sitios web que recaban o comparten tu información</li>
-      <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
-      <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
-      <li>Vigilancia a cargo de agentes secretos</li>
-      <li>Personas paradas atrás tuyo</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-es-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 6d9b501..0000000
--- a/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nueva ventana de incógnito</title>
-  </head>
-  <body>
-    <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
-
-    <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
-
-    <ul>
-      <li>sitios web que recopilan o comparten información personal</li>
-      <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
-      <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
-      <li>actividades de seguimiento por parte de terceros</li>
-      <li>personas merodeando cerca de tu ordenador</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-es/incognito_mode_start_page.html b/core/res/res/raw-es/incognito_mode_start_page.html
deleted file mode 100644
index 6d9b501..0000000
--- a/core/res/res/raw-es/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nueva ventana de incógnito</title>
-  </head>
-  <body>
-    <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
-
-    <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
-
-    <ul>
-      <li>sitios web que recopilan o comparten información personal</li>
-      <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
-      <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
-      <li>actividades de seguimiento por parte de terceros</li>
-      <li>personas merodeando cerca de tu ordenador</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index f004120..0000000
--- a/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>پنجره ناشناس جدید</title>
-  </head>
-  <body>
-    <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
-
-    <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
-
-    <ul>
-      <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
-      <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
-      <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
-      <li>نظارت توسط نمایندگان سری</li>
-      <li>افرادی که پشت سرتان ایستاده اند</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fa/incognito_mode_start_page.html b/core/res/res/raw-fa/incognito_mode_start_page.html
deleted file mode 100644
index f004120..0000000
--- a/core/res/res/raw-fa/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>پنجره ناشناس جدید</title>
-  </head>
-  <body>
-    <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
-
-    <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
-
-    <ul>
-      <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
-      <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
-      <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
-      <li>نظارت توسط نمایندگان سری</li>
-      <li>افرادی که پشت سرتان ایستاده اند</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index feb9f4f..0000000
--- a/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Uusi incognito-ikkuna</title>
-  </head>
-  <body>
-    <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
-
-    <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
-
-    <ul>
-      <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
-      <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
-      <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
-      <li>Salaisten agenttien seurantaa</li>
-      <li>Ihmisiä jotka seisovat takanasi</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fi/incognito_mode_start_page.html b/core/res/res/raw-fi/incognito_mode_start_page.html
deleted file mode 100644
index feb9f4f..0000000
--- a/core/res/res/raw-fi/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Uusi incognito-ikkuna</title>
-  </head>
-  <body>
-    <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
-
-    <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
-
-    <ul>
-      <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
-      <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
-      <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
-      <li>Salaisten agenttien seurantaa</li>
-      <li>Ihmisiä jotka seisovat takanasi</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 8962cdf..0000000
--- a/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nouvelle fenêtre de navigation privée</title>
-  </head>
-  <body>
-    <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
-
-    <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
-
-    <ul>
-      <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
-      <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
-      <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
-      <li>Des personnes qui pourraient surveiller vos activités</li>
-      <li>Des personnes qui se tiennent derrière vous</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-fr/incognito_mode_start_page.html b/core/res/res/raw-fr/incognito_mode_start_page.html
deleted file mode 100644
index 8962cdf..0000000
--- a/core/res/res/raw-fr/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nouvelle fenêtre de navigation privée</title>
-  </head>
-  <body>
-    <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
-
-    <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
-
-    <ul>
-      <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
-      <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
-      <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
-      <li>Des personnes qui pourraient surveiller vos activités</li>
-      <li>Des personnes qui se tiennent derrière vous</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index f73c41d..0000000
--- a/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>नई गुप्त विंडो</title>
-  </head>
-  <body>
-    <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास  या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
-
-    <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
-
-    <ul>
-      <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
-      <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
-      <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
-      <li>गुप्तचरों द्वारा निगरानी</li>
-      <li>आपके पीछे खड़े लोग</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hi/incognito_mode_start_page.html b/core/res/res/raw-hi/incognito_mode_start_page.html
deleted file mode 100644
index f73c41d..0000000
--- a/core/res/res/raw-hi/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>नई गुप्त विंडो</title>
-  </head>
-  <body>
-    <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास  या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
-
-    <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
-
-    <ul>
-      <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
-      <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
-      <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
-      <li>गुप्तचरों द्वारा निगरानी</li>
-      <li>आपके पीछे खड़े लोग</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 6f20fe0..0000000
--- a/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Novi anonimni prozor</title>
-  </head>
-  <body>
-    <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
-
-    <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
-
-    <ul>
-      <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
-      <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
-      <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
-      <li>Nadzor tajnih službi</li>
-      <li>Osobe koje stoje iza vas</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hr/incognito_mode_start_page.html b/core/res/res/raw-hr/incognito_mode_start_page.html
deleted file mode 100644
index 6f20fe0..0000000
--- a/core/res/res/raw-hr/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Novi anonimni prozor</title>
-  </head>
-  <body>
-    <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
-
-    <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
-
-    <ul>
-      <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
-      <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
-      <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
-      <li>Nadzor tajnih službi</li>
-      <li>Osobe koje stoje iza vas</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 38b0806..0000000
--- a/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Új inkognitóablak</title>
-  </head>
-  <body>
-    <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
-
-    <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
-
-    <ul>
-      <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
-      <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
-      <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
-      <li>Titkos ügynökök megfigyelése</li>
-      <li>Az Ön mögött álló emberek</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-hu/incognito_mode_start_page.html b/core/res/res/raw-hu/incognito_mode_start_page.html
deleted file mode 100644
index 38b0806..0000000
--- a/core/res/res/raw-hu/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Új inkognitóablak</title>
-  </head>
-  <body>
-    <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
-
-    <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
-
-    <ul>
-      <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
-      <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
-      <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
-      <li>Titkos ügynökök megfigyelése</li>
-      <li>Az Ön mögött álló emberek</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-id-xlarge/incognito_mode_start_page.html b/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 788c088..0000000
--- a/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Jendela penyamaran baru</title>
-  </head>
-  <body>
-    <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
-
-    <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
-
-    <ul>
-      <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
-      <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
-      <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
-      <li>Pemantauan oleh agen rahasia</li>
-      <li>Orang yang berdiri di belakang Anda</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-id/incognito_mode_start_page.html b/core/res/res/raw-id/incognito_mode_start_page.html
deleted file mode 100644
index 788c088..0000000
--- a/core/res/res/raw-id/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Jendela penyamaran baru</title>
-  </head>
-  <body>
-    <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
-
-    <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
-
-    <ul>
-      <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
-      <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
-      <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
-      <li>Pemantauan oleh agen rahasia</li>
-      <li>Orang yang berdiri di belakang Anda</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-it-xlarge/incognito_mode_start_page.html b/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 4a34874..0000000
--- a/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nuova finestra di navigazione in incognito</title>
-  </head>
-  <body>
-    <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
-
-    <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
-
-    <ul>
-      <li>Siti web che raccolgono o condividono informazioni su di te</li>
-      <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
-      <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
-      <li>Agenti segreti</li>
-      <li>Persone che ti stanno alle spalle</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-it/incognito_mode_start_page.html b/core/res/res/raw-it/incognito_mode_start_page.html
deleted file mode 100644
index 4a34874..0000000
--- a/core/res/res/raw-it/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nuova finestra di navigazione in incognito</title>
-  </head>
-  <body>
-    <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
-
-    <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
-
-    <ul>
-      <li>Siti web che raccolgono o condividono informazioni su di te</li>
-      <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
-      <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
-      <li>Agenti segreti</li>
-      <li>Persone che ti stanno alle spalle</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 368dea0..0000000
--- a/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>חלון חדש של גלישה בסתר</title>
-  </head>
-  <body>
-    <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
-
-    <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים  אחרים או תוכנות אחרות. היזהר מ:</strong></p>
-
-    <ul>
-      <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
-      <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
-      <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
-      <li>מעקב של סוכנים חשאיים</li>
-      <li>אנשים שעומדים מאחוריך</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-iw/incognito_mode_start_page.html b/core/res/res/raw-iw/incognito_mode_start_page.html
deleted file mode 100644
index 368dea0..0000000
--- a/core/res/res/raw-iw/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="RTL">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>חלון חדש של גלישה בסתר</title>
-  </head>
-  <body>
-    <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
-
-    <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים  אחרים או תוכנות אחרות. היזהר מ:</strong></p>
-
-    <ul>
-      <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
-      <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
-      <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
-      <li>מעקב של סוכנים חשאיים</li>
-      <li>אנשים שעומדים מאחוריך</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index a58ad05..0000000
--- a/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新しいシークレットウィンドウ</title>
-  </head>
-  <body>
-    <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
-
-    <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
-
-    <ul>
-      <li>ユーザーの情報を収集、共有するウェブサイト</li>
-      <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
-      <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
-      <li>スパイ、諜報活動</li>
-      <li>背後にいる人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ja/incognito_mode_start_page.html b/core/res/res/raw-ja/incognito_mode_start_page.html
deleted file mode 100644
index a58ad05..0000000
--- a/core/res/res/raw-ja/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新しいシークレットウィンドウ</title>
-  </head>
-  <body>
-    <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
-
-    <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
-
-    <ul>
-      <li>ユーザーの情報を収集、共有するウェブサイト</li>
-      <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
-      <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
-      <li>スパイ、諜報活動</li>
-      <li>背後にいる人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 0e703b1..0000000
--- a/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>새 시크릿 창</title>
-  </head>
-  <body>
-    <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
-
-    <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
-
-    <ul>
-      <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
-      <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
-      <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
-      <li>비밀 개체를 통한 감시</li>
-      <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ko/incognito_mode_start_page.html b/core/res/res/raw-ko/incognito_mode_start_page.html
deleted file mode 100644
index 0e703b1..0000000
--- a/core/res/res/raw-ko/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>새 시크릿 창</title>
-  </head>
-  <body>
-    <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
-
-    <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
-
-    <ul>
-      <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
-      <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
-      <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
-      <li>비밀 개체를 통한 감시</li>
-      <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 9244ae4..0000000
--- a/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Naujas inkognito langas</title>
-  </head>
-  <body>
-    <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
-
-    <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
-
-    <ul>
-      <li>svetainių, kurios renka ar platina informaciją apie jus</li>
-      <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
-      <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
-      <li>jus galinčių sekti slaptųjų agentų</li>
-      <li>už nugaros stovinčių asmenų</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-lt/incognito_mode_start_page.html b/core/res/res/raw-lt/incognito_mode_start_page.html
deleted file mode 100644
index 9244ae4..0000000
--- a/core/res/res/raw-lt/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Naujas inkognito langas</title>
-  </head>
-  <body>
-    <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
-
-    <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
-
-    <ul>
-      <li>svetainių, kurios renka ar platina informaciją apie jus</li>
-      <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
-      <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
-      <li>jus galinčių sekti slaptųjų agentų</li>
-      <li>už nugaros stovinčių asmenų</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index f325ef5..0000000
--- a/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Jauns inkognito logs</title>
-  </head>
-  <body>
-    <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
-
-    <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
-
-    <ul>
-      <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
-      <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
-      <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
-      <li>slepeno aģentu veiktas izmeklēšanas;</li>
-      <li>personām, kas stāv aiz jums.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-lv/incognito_mode_start_page.html b/core/res/res/raw-lv/incognito_mode_start_page.html
deleted file mode 100644
index f325ef5..0000000
--- a/core/res/res/raw-lv/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Jauns inkognito logs</title>
-  </head>
-  <body>
-    <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
-
-    <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
-
-    <ul>
-      <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
-      <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
-      <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
-      <li>slepeno aģentu veiktas izmeklēšanas;</li>
-      <li>personām, kas stāv aiz jums.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 724e734..0000000
--- a/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nytt inkognitovindu</title>
-  </head>
-  <body>
-    <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
-
-    <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
-
-    <ul>
-      <li>Nettsider som samler eller deler informasjon om deg</li>
-      <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
-      <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
-      <li>Hemmelige agenter som spionerer på deg</li>
-      <li>Folk som titter over skulderen din</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-nb/incognito_mode_start_page.html b/core/res/res/raw-nb/incognito_mode_start_page.html
deleted file mode 100644
index 724e734..0000000
--- a/core/res/res/raw-nb/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nytt inkognitovindu</title>
-  </head>
-  <body>
-    <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
-
-    <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
-
-    <ul>
-      <li>Nettsider som samler eller deler informasjon om deg</li>
-      <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
-      <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
-      <li>Hemmelige agenter som spionerer på deg</li>
-      <li>Folk som titter over skulderen din</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 92fedd7..0000000
--- a/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nieuw incognitovenster</title>
-  </head>
-  <body>
-    <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
-
-    <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
-
-    <ul>
-      <li>Websites die informatie over u verzamelen of delen</li>
-      <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
-      <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
-      <li>Spionage door geheim agenten</li>
-      <li>Mensen die achter u staan</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-nl/incognito_mode_start_page.html b/core/res/res/raw-nl/incognito_mode_start_page.html
deleted file mode 100644
index 92fedd7..0000000
--- a/core/res/res/raw-nl/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nieuw incognitovenster</title>
-  </head>
-  <body>
-    <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
-
-    <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
-
-    <ul>
-      <li>Websites die informatie over u verzamelen of delen</li>
-      <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
-      <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
-      <li>Spionage door geheim agenten</li>
-      <li>Mensen die achter u staan</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 9748ead..0000000
--- a/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nowe okno incognito</title>
-  </head>
-  <body>
-    <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
-
-    <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
-
-    <ul>
-      <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
-      <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
-      <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
-      <li>aktywność wywiadowczą tajnych agentów</li>
-      <li>osoby stojące za plecami</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pl/incognito_mode_start_page.html b/core/res/res/raw-pl/incognito_mode_start_page.html
deleted file mode 100644
index 9748ead..0000000
--- a/core/res/res/raw-pl/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nowe okno incognito</title>
-  </head>
-  <body>
-    <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
-
-    <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
-
-    <ul>
-      <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
-      <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
-      <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
-      <li>aktywność wywiadowczą tajnych agentów</li>
-      <li>osoby stojące za plecami</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 89a5ab0..0000000
--- a/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova janela de navegação anónima</title>
-  </head>
-  <body>
-    <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
-
-    <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
-
-    <ul>
-      <li>Web sites que recolhem ou partilham informações sobre si</li>
-      <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
-      <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
-      <li>Vigilância de agentes secretos</li>
-      <li>Pessoas que estejam perto de si</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pt-rPT/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
deleted file mode 100644
index 89a5ab0..0000000
--- a/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova janela de navegação anónima</title>
-  </head>
-  <body>
-    <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
-
-    <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
-
-    <ul>
-      <li>Web sites que recolhem ou partilham informações sobre si</li>
-      <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
-      <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
-      <li>Vigilância de agentes secretos</li>
-      <li>Pessoas que estejam perto de si</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index b301eda..0000000
--- a/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova janela anônima</title>
-  </head>
-  <body>
-    <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
-
-    <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
-
-    <ul>
-      <li>Websites que coletam ou compartilham informações sobre você</li>
-      <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
-      <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
-      <li>Vigilância por agentes secretos</li>
-      <li>Pessoas paradas detrás de você</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-pt/incognito_mode_start_page.html b/core/res/res/raw-pt/incognito_mode_start_page.html
deleted file mode 100644
index b301eda..0000000
--- a/core/res/res/raw-pt/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nova janela anônima</title>
-  </head>
-  <body>
-    <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
-
-    <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
-
-    <ul>
-      <li>Websites que coletam ou compartilham informações sobre você</li>
-      <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
-      <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
-      <li>Vigilância por agentes secretos</li>
-      <li>Pessoas paradas detrás de você</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 3e499d3..0000000
--- a/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Fereastră incognito nouă</title>
-  </head>
-  <body>
-    <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
-
-    <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
-
-    <ul>
-      <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
-      <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
-      <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
-      <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
-      <li>persoanele din spatele dvs.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ro/incognito_mode_start_page.html b/core/res/res/raw-ro/incognito_mode_start_page.html
deleted file mode 100644
index 3e499d3..0000000
--- a/core/res/res/raw-ro/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Fereastră incognito nouă</title>
-  </head>
-  <body>
-    <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
-
-    <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
-
-    <ul>
-      <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
-      <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
-      <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
-      <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
-      <li>persoanele din spatele dvs.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index ae7b59c..0000000
--- a/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Новое окно в режиме инкогнито</title>
-  </head>
-  <body>
-    <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
-
-    <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
-
-    <ul>
-      <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
-      <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
-      <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
-      <li>Слежки тайными агентами</li>
-      <li>Людей, которые стоят у вас за спиной</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-ru/incognito_mode_start_page.html b/core/res/res/raw-ru/incognito_mode_start_page.html
deleted file mode 100644
index ae7b59c..0000000
--- a/core/res/res/raw-ru/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Новое окно в режиме инкогнито</title>
-  </head>
-  <body>
-    <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
-
-    <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
-
-    <ul>
-      <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
-      <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
-      <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
-      <li>Слежки тайными агентами</li>
-      <li>Людей, которые стоят у вас за спиной</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 5b138f1..0000000
--- a/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nové okno inkognito</title>
-  </head>
-  <body>
-    <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
-
-    <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
-
-    <ul>
-      <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
-      <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
-      <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
-      <li>sledovanie tajnými agentmi;</li>
-      <li>ľudí, ktorí stoja za vami.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sk/incognito_mode_start_page.html b/core/res/res/raw-sk/incognito_mode_start_page.html
deleted file mode 100644
index 5b138f1..0000000
--- a/core/res/res/raw-sk/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nové okno inkognito</title>
-  </head>
-  <body>
-    <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
-
-    <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
-
-    <ul>
-      <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
-      <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
-      <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
-      <li>sledovanie tajnými agentmi;</li>
-      <li>ľudí, ktorí stoja za vami.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 33a8b08..0000000
--- a/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Novo okno brez beleženja zgodovine</title>
-  </head>
-  <body>
-    <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
-
-    <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
-
-    <ul>
-      <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
-      <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
-      <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
-      <li>Nadzor tajnih agentov.</li>
-      <li>Osebe, ki stojijo za vašim hrbtom.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sl/incognito_mode_start_page.html b/core/res/res/raw-sl/incognito_mode_start_page.html
deleted file mode 100644
index 33a8b08..0000000
--- a/core/res/res/raw-sl/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Novo okno brez beleženja zgodovine</title>
-  </head>
-  <body>
-    <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
-
-    <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
-
-    <ul>
-      <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
-      <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
-      <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
-      <li>Nadzor tajnih agentov.</li>
-      <li>Osebe, ki stojijo za vašim hrbtom.</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index b1fbcb1..0000000
--- a/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нов прозор без архивирања</title>
-  </head>
-  <body>
-    <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
-
-    <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
-
-    <ul>
-      <li>Веб сајтова који прикупљају и деле податке о вама</li>
-      <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
-      <li>Злонамерног софтвера који прати шта куцате</li>
-      <li>Надзора тајних агената</li>
-      <li>Људи који вам стоје иза леђа</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sr/incognito_mode_start_page.html b/core/res/res/raw-sr/incognito_mode_start_page.html
deleted file mode 100644
index b1fbcb1..0000000
--- a/core/res/res/raw-sr/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нов прозор без архивирања</title>
-  </head>
-  <body>
-    <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
-
-    <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
-
-    <ul>
-      <li>Веб сајтова који прикупљају и деле податке о вама</li>
-      <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
-      <li>Злонамерног софтвера који прати шта куцате</li>
-      <li>Надзора тајних агената</li>
-      <li>Људи који вам стоје иза леђа</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 5ebbb22..0000000
--- a/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nytt inkognitofönster</title>
-  </head>
-  <body>
-    <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
-
-    <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
-
-    <ul>
-      <li>Webbplatser som samlar eller delar information om dig</li>
-      <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
-      <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
-      <li>Övervakning av hemliga agenter</li>
-      <li>Personer som står bakom dig</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-sv/incognito_mode_start_page.html b/core/res/res/raw-sv/incognito_mode_start_page.html
deleted file mode 100644
index 5ebbb22..0000000
--- a/core/res/res/raw-sv/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Nytt inkognitofönster</title>
-  </head>
-  <body>
-    <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
-
-    <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
-
-    <ul>
-      <li>Webbplatser som samlar eller delar information om dig</li>
-      <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
-      <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
-      <li>Övervakning av hemliga agenter</li>
-      <li>Personer som står bakom dig</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-th-xlarge/incognito_mode_start_page.html b/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 29c64eb..0000000
--- a/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
-  </head>
-  <body>
-    <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
-
-    <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
-
-    <ul>
-      <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
-      <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
-      <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
-      <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
-      <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-th/incognito_mode_start_page.html b/core/res/res/raw-th/incognito_mode_start_page.html
deleted file mode 100644
index 29c64eb..0000000
--- a/core/res/res/raw-th/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
-  </head>
-  <body>
-    <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
-
-    <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
-
-    <ul>
-      <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
-      <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
-      <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
-      <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
-      <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 6ce5853..0000000
--- a/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Bagong incognito window</title>
-  </head>
-  <body>
-    <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
-
-    <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
-
-    <ul>
-      <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
-      <li>Mga internet service provider o mga employer na  sinusubaybayan ang mga pahinang binibisita mo</li>
-      <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
-      <li>Pagmamasid ng mga secret agent</li>
-      <li>Mga tao na nakatayo sa likuran mo</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-tl/incognito_mode_start_page.html b/core/res/res/raw-tl/incognito_mode_start_page.html
deleted file mode 100644
index 6ce5853..0000000
--- a/core/res/res/raw-tl/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Bagong incognito window</title>
-  </head>
-  <body>
-    <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
-
-    <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
-
-    <ul>
-      <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
-      <li>Mga internet service provider o mga employer na  sinusubaybayan ang mga pahinang binibisita mo</li>
-      <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
-      <li>Pagmamasid ng mga secret agent</li>
-      <li>Mga tao na nakatayo sa likuran mo</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index c570cc7..0000000
--- a/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Yeni gizli pencere</title>
-  </head>
-  <body>
-    <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
-
-    <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
-
-    <ul>
-      <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
-      <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
-      <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
-      <li>Gizli ajanlar tarafından takip edilme</li>
-      <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-tr/incognito_mode_start_page.html b/core/res/res/raw-tr/incognito_mode_start_page.html
deleted file mode 100644
index c570cc7..0000000
--- a/core/res/res/raw-tr/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Yeni gizli pencere</title>
-  </head>
-  <body>
-    <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
-
-    <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
-
-    <ul>
-      <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
-      <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
-      <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
-      <li>Gizli ajanlar tarafından takip edilme</li>
-      <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 8852854..0000000
--- a/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нове анонімне вікно</title>
-  </head>
-  <body>
-    <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
-
-    <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
-
-    <ul>
-      <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
-      <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
-      <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
-      <li>нагляду збоку секретних служб</li>
-      <li>людей за вашою спиною</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-uk/incognito_mode_start_page.html b/core/res/res/raw-uk/incognito_mode_start_page.html
deleted file mode 100644
index 8852854..0000000
--- a/core/res/res/raw-uk/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Нове анонімне вікно</title>
-  </head>
-  <body>
-    <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
-
-    <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
-
-    <ul>
-      <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
-      <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
-      <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
-      <li>нагляду збоку секретних служб</li>
-      <li>людей за вашою спиною</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 9902cde..0000000
--- a/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Cửa sổ ẩn danh mới</title>
-  </head>
-  <body>
-    <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
-
-    <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
-
-    <ul>
-      <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
-      <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
-      <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
-      <li>Sự theo dõi của các cơ quan tình báo</li>
-      <li>Những người đứng đằng sau bạn</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-vi/incognito_mode_start_page.html b/core/res/res/raw-vi/incognito_mode_start_page.html
deleted file mode 100644
index 9902cde..0000000
--- a/core/res/res/raw-vi/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>Cửa sổ ẩn danh mới</title>
-  </head>
-  <body>
-    <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
-
-    <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
-
-    <ul>
-      <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
-      <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
-      <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
-      <li>Sự theo dõi của các cơ quan tình báo</li>
-      <li>Những người đứng đằng sau bạn</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 492658d..0000000
--- a/core/res/res/raw-xlarge/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 tab</title>
-  </head>
-  <body>
-    <p><strong>You've gone incognito</strong>. Pages you view in this tab
-      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 tab. 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/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 2caf8f8b..0000000
--- a/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新建隐身窗口</title>
-  </head>
-  <body>
-    <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
-
-    <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
-
-    <ul>
-      <li>搜集并分享有关您的信息的网站</li>
-      <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
-      <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
-      <li>对您进行监视的秘密代理</li>
-      <li>站在您身后的人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-zh-rCN/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
deleted file mode 100644
index 2caf8f8b..0000000
--- a/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新建隐身窗口</title>
-  </head>
-  <body>
-    <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
-
-    <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
-
-    <ul>
-      <li>搜集并分享有关您的信息的网站</li>
-      <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
-      <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
-      <li>对您进行监视的秘密代理</li>
-      <li>站在您身后的人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
deleted file mode 100644
index 54eb40b..0000000
--- a/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新的無痕式視窗</title>
-  </head>
-  <body>
-    <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
-
-    <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
-
-    <ul>
-      <li>會收集或分享您的相關資訊的網站</li>
-      <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
-      <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
-      <li>情報特務的監控</li>
-      <li>站在您身後的人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw-zh-rTW/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
deleted file mode 100644
index 54eb40b..0000000
--- a/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html DIR="LTR">
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
-    <title>新的無痕式視窗</title>
-  </head>
-  <body>
-    <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
-
-    <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
-
-    <ul>
-      <li>會收集或分享您的相關資訊的網站</li>
-      <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
-      <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
-      <li>情報特務的監控</li>
-      <li>站在您身後的人</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/res/raw/incognito_mode_start_page.html b/core/res/res/raw/incognito_mode_start_page.html
deleted file mode 100644
index 5d7a3fb..0000000
--- a/core/res/res/raw/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/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d5343a8..5ca9f43 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Foonopsies"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Skermslot"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi het geen internettoegang nie"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding het nie. Heffings kan geld."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"sellulêre data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"\'n onbekende netwerktipe"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Berei tans <xliff:g id="NAME">%s</xliff:g> voor"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kyk tans vir foute"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuwe <xliff:g id="NAME">%s</xliff:g> bespeur"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Tik om die netwerk te bestuur."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Altydaan-VPN is ontkoppel"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om op te stel"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om op te stel"</string>
     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
     <string name="reset" msgid="2448168080964209908">"Stel terug"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>-USB-datastokkie"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigeer"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Dataverbruik-waarskuwing"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datagebruik-opletberig"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik om gebruik en instellings te bekyk."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-datalimiet bereik"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-datalimiet bereik"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diverse"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle tale"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Allle streke"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Soek"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is AF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Stel werkprofiel in staat om te werk, insluitend programme, agtergrondsinkronisering en verwante kenmerke."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 6eaf947..18fc6dd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"የስልክ አማራጮች"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ማያ ቆልፍ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ኃይል አጥፋ"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"ድንገተኛ አደጋ"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"የሳንካ ሪፖርት"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"የሳንካ ሪፖርት ውሰድ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi በይነመረብ መዳረሻ የለውም"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"ብሉቱዝ"</item>
+    <item msgid="5447331121797802871">"ኤተርኔት"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ን በማዘጋጀት ላይ"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ስህተቶች ካሉ በመፈተሽ ላይ"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"አዲስ <xliff:g id="NAME">%s</xliff:g> ተገኝቷል"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"ሁልጊዜ የበራ የVPN ግንኙነት ተቋርጧል"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ሁልጊዜ የበራ VPN ስህተት"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ለማዋቀር መታ ያድርጉ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ለማዋቀር መታ ያድርጉ"</string>
     <string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string>
     <string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"የ<xliff:g id="MANUFACTURER">%s</xliff:g> ዩኤስቢ አንጻፊ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"የውሂብ አጠቃቀም ማንቂያ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"አጠቃቀምን እና ቅንብሮችን ለማየት መታ ያድርጉ።"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"የ2ጂ-3ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"የ4ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጧል</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"የተለያዩ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ሁሉም ቋንቋዎች"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ሁሉም ክልሎች"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ፈልግ"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"የሥራ ሁነታ ጠፍቷል"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"መተግበሪያዎችን፣ የበስተጀርባ ሥምረት እና ተዛማጅ ባሕሪዎችን ጨምሮ የሥራ መገለጫ እንዲሰራ ይፍቀዱ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 234ea8b..3451bcc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -222,6 +222,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"خيارات الهاتف"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"تأمين الشاشة"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"إيقاف التشغيل"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"الطوارئ"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
     <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
@@ -1045,7 +1046,7 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ۲۵۰ ميغابايت وأعد التشغيل."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل"</string>
     <string name="app_running_notification_text" msgid="1197581823314971177">"انقر للحصول على مزيد من المعلومات أو لإيقاف التطبيق."</string>
     <string name="ok" msgid="5970060430562524910">"موافق"</string>
@@ -1176,6 +1177,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"‏شبكة Wi-Fi غير متصلة بالإنترنت"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"بيانات شبكة الجوّال"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"بلوتوث"</item>
+    <item msgid="5447331121797802871">"إيثرنت"</item>
+    <item msgid="8257233890381651999">"‏شبكة ظاهرية خاصة (VPN)"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
@@ -1253,7 +1265,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"جارٍ تحضير <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"جارٍ التحقق من الأخطاء"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"تم اكتشاف <xliff:g id="NAME">%s</xliff:g> جديدة"</string>
@@ -1332,8 +1343,9 @@
     <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_disconnected" msgid="4532298952570796327">"‏تم فصل الشبكة الظاهرية الخاصة (VPN) دائمة التشغيل"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"انقر للتهيئة."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"انقر للإعداد."</string>
     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
     <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
@@ -1421,7 +1433,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏محرك أقراص USB من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"‏وحدة تخزين USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"تعديل"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"تحذير استخدام البيانات"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"تنبيه استخدام البيانات"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"انقر لعرض الاستخدام والإعدادات."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏تم بلوغ حد بيانات اتصال 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏تم بلوغ حد بيانات اتصال 4G"</string>
@@ -1771,6 +1783,7 @@
       <item quantity="other">تم تحديد <xliff:g id="COUNT_1">%1$d</xliff:g> من العناصر</item>
       <item quantity="one">تم تحديد <xliff:g id="COUNT_0">%1$d</xliff:g> عنصر</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"متنوعة"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"لقد عيَّنت أهمية هذه الإشعارات."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"هل تسمح لـ <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g>؟"</string>
@@ -1780,6 +1793,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"جميع اللغات"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"كل المناطق"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"البحث"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"وضع العمل معطَّل"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"السماح باستخدام الملف الشخصي للعمل، بما في ذلك التطبيقات ومزامنة الخلفية والميزات ذات الصلة."</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index cf9dfe8..1f0d164 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçimləri"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Söndür"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Təcili"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ın İnternetə girişi yoxdur"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin İnternetə çıxışı olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Ödəniş tətbiq oluna bilər."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobil data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"naməlum şəbəkə növü"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi\'a qoşulmaq alınmadı"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" internet bağlantısı keyfiyyətsizdir."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya icazə verilsin?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanır"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Səhvlər yoxlanılır"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> aşkarlandı"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> sessiyaya qoşulun. Şəbəkəni idarə etmək üçün tıklayın."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Həmişə aktiv VPN bağlanır..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN bağlantısı həmişə aktiv"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Həmişə aktiv VPN bağlantısı kəsildi"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Həmişə aktiv VPN xətası"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Konfiqurasiya üçün tıklayın"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Quraşdırmaq üçün tıklayın"</string>
     <string name="upload_file" msgid="2897957172366730416">"Fayl seçin"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Heç bir fayl seçilməyib"</string>
     <string name="reset" msgid="2448168080964209908">"Sıfırlayın"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drayv"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB yaddaş"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzəliş edin"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data istifadə xəbərdarlığı"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data istifadə siqnalı"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"İstifadə və ayarları görmək üçün tıklayın."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limitinə çatdı"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limitinə çatdı"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Müxtəlif"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabı ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Bütün dillər"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Bütün bölgələr"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Axtarın"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"İş rejimi DEAKTİVDİR"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tətbiq, arxa fon sinxronizasiyası və digər əlaqədar xüsusiyyətlər daxil olmaqla iş profilinin fəaliyyətinə icazə verin."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 05e5fff..3469f97 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zaključaj ekran"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni poziv"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
@@ -256,9 +257,9 @@
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Skladište"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijima i datotekama na uređaju"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio snimke"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video snimke"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"upućuje telefonske pozive i upravlja njima"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string>
@@ -1101,6 +1102,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilni podaci"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Eternet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznat tip mreže"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
@@ -1172,13 +1184,12 @@
     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
-    <string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Zadrži je na ekranu dok je fizička tastatura aktivna"</string>
     <string name="hardware" msgid="194658061510127999">"Prikaži virtuelnu tastaturu"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Konfigurišite fizičku tastaturu"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
@@ -1257,8 +1268,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Veza sa stalno uključenim VPN-om je prekinuta"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurisali"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite da biste podesili"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
@@ -1343,7 +1355,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Obaveštenje o potrošnji podataka"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
@@ -1663,6 +1675,7 @@
       <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
       <item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Razno"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi podešavate važnost ovih obaveštenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li da dozvolite aplikaciji <xliff:g id="APP">%1$s</xliff:g> da napravi novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1672,6 +1685,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Svi regioni"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Režim za Work je ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Dozvoljava profilu za Work da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i srodne funkcije."</string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index e0993b7..f5f1e62 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Выключыць"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"SOS-выклік"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Справаздача пра памылкі"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Прылада выкарыстоўвае <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца дадатковая плата."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"сотавая перадача даных"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невядомы тып сеткі"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Заўсёды ўключаны VPN адключаны"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Дакраніцеся, каб сканфігураваць"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Дакраніцеся, каб наладзіць"</string>
     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Абвестка аб выкарыстанні трафіка"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Рознае"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Вы задалі важнасць гэтых апавяшчэнняў."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Гэта важна, бо з гэтым звязаны пэўныя людзі."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Дазволіць <xliff:g id="APP">%1$s</xliff:g> стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Прапанаваныя"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Усе мовы"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Усе рэгіёны"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Шукаць"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Рэжым працы АДКЛЮЧАНЫ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Дазволіць функцыянаванне працоўнага профілю, у тым ліку праграм, фонавай сінхранізацыі і звязаных з імі функцый."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8643c13..f6eb810 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефона"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Заключване на екрана"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Изключване"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Спешно обаждане"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Сигнал за програмна грешка"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Сигнал за програмна грешка"</string>
     <string name="bugreport_message" msgid="398447048750350456">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi мрежата няма достъп до интернет"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобилни данни"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"виртуална частна мрежа (VPN)"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестен тип мрежа"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>: Подготвя се"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверява се за грешки"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Открито е ново хранилище (<xliff:g id="NAME">%s</xliff:g>)"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"Няма връзка с винаги включената виртуална частна мрежа (VPN)"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Докоснете, за да конфигурирате"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Докоснете, за да настроите"</string>
     <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB устройство от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редактиране"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Предупрежд. за ползване на данни"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сигнал за преноса на данни"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Пренос и настройки: Докоснете за преглед."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнат лимит за 2G/3G данните"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнат лимит за 4G данните"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">Избрахте <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Други"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Зададохте важността на тези известия."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Всички езици"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Всички региони"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Търсене"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Работният режим е ИЗКЛЮЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Разрешаване на функционирането на служебния потребителски профил, включително приложенията, синхронизирането на заден план и свързаните функции."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 90afe1c..f873b1c 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -214,8 +214,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ফোন বিকল্পগুলি"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"স্ক্রীণ লক"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"পাওয়ার বন্ধ করুন"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"জরুরী"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির প্রতিবেদন করুন"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির অভিযোগ করুন"</string>
     <string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল বার্তা পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; দয়া করে ধৈর্য রাখুন৷"</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ইন্টারেক্টিভ প্রতিবেদন"</string>
     <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"বেশিরভাগ পরিস্থিতিতে এটিকে ব্যবহার করুন৷ এটি আপনাকে প্রতিবেদনের কাজ কতটা হয়েছে তার উপর নজর রাখতে দেয়, সমস্যাটির সম্পর্কে আরো অনেক কিছু লিখতে দেয় এবং স্ক্রীনশটগুলি নিতে দেয়৷ এটি হয়ত প্রতিবেদন করতে খুব বেশি সময় নেয় এমনকি কম-ব্যবহৃত বিভাগগুলি সরিয়ে দিতে পারে৷"</string>
@@ -1007,7 +1008,7 @@
     <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> সাড়া দিচ্ছে না"</string>
     <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> প্রক্রিয়া সাড়া দিচ্ছে না"</string>
     <string name="force_close" msgid="8346072094521265605">"ঠিক আছে"</string>
-    <string name="report" msgid="4060218260984795706">"প্রতিবেদন করুন"</string>
+    <string name="report" msgid="4060218260984795706">"অভিযোগ করুন"</string>
     <string name="wait" msgid="7147118217226317732">"অপেক্ষা করুন"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"পৃষ্ঠাটি কোনো পতিক্রিয়া করছে না৷\n\nআপনি কি এটিকে বন্ধ করতে চান?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"অ্যাপ্লিকেশানকে পুনঃনির্দেশিত করা হয়েছে"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"ওয়াই-ফাই -তে কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"যখন <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এর কোনো ইন্টারনেট অ্যাক্সেস থাকে না তখন ডিভাইস <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করে৷ চার্জ লাগতে পারে৷"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"সেলুলার ডেটা"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"ইথারনেট"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"এই নেটওয়ার্কের প্রকার অজানা"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ওয়াই-ফাই এর সাথে সংযোগ করা যায়নি"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের অনুমতি দেবেন?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> প্রস্তুত করা হচ্ছে"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ত্রুটি রয়েছে কিনা পরীক্ষা করা হচ্ছে"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"নতুন <xliff:g id="NAME">%s</xliff:g> সনাক্ত করা হয়েছে"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"সর্বদা-চালু VPN এর সংযোগ বিচ্ছিন্ন হয়েছে"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"সর্বদা-চালু VPN ত্রুটি"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"কনফিগার করতে আলতো চাপুন"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"সেট আপ করতে আলতো চাপুন"</string>
     <string name="upload_file" msgid="2897957172366730416">"ফাইল বেছে নিন"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"কোনো ফাইল নির্বাচন করা হয়নি"</string>
     <string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ড্রাইভ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB সঞ্চয়স্থান"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা করুন"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ডেটা ব্যবহারের সতর্কতা"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ডেটা ব্যবহারের সতর্কতা"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ব্যবহার এবং সেটিংস দেখতে আলতো চাপুন৷"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ডেটা সীমা ছাড়িয়েছে"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ডেটা সীমা ছাড়িয়েছে"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"বিবিধ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> কে <xliff:g id="ACCOUNT">%2$s</xliff:g> এর সাথে একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি দেবেন কি?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"সকল ভাষা"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"সমস্ত অঞ্চল"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"অনুসন্ধান করুন"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"কাজের মোড বন্ধ আছে"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"অ্যাপ্লিকেশান, পটভূমি সিঙ্ক এবং সম্পর্কিত বৈশিষ্ট্যগুলি সহ কর্মস্থলের প্রোফাইলটিকে কাজ করার অনুমতি দিন।"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index c0449e0..7cb46fe 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje ekrana"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitni slučaj"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
@@ -1103,6 +1104,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada na uređaju <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, koristi se <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilni podaci"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
@@ -1180,7 +1192,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
@@ -1259,8 +1270,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da upravljate mrežom."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Uvijek aktivni VPN nije povezan"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite za konfiguriranje"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavke"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
@@ -1345,7 +1357,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o prijenosu podataka"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
@@ -1586,7 +1598,7 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
-    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjilo korištenje podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
+    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
@@ -1665,6 +1677,7 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> stavki je odabrano</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Razno"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi određujete značaj ovih obavještenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljavate aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1674,6 +1687,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraga"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f4869d6..d1fbebb 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcions del telèfon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueig de pantalla"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"La Wi-Fi no té accés a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'apliquin càrrecs."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"dades mòbils"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"una tipus de xarxa desconegut"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"S\'està preparant <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"S\'està comprovant si hi ha errors"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"S\'ha detectat <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Pica per gestionar la xarxa."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"T\'estàs connectant a la VPN sempre activada…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Estàs connectat a la VPN sempre activada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca per configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
     <string name="reset" msgid="2448168080964209908">"Restableix"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitat USB de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edita"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertiment d\'ús de dades"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta d\'ús de dades"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca per veure l\'ús i la configuració."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límit de dades 2G-3G assolit"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límit de dades 4G assolit"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">Seleccionats: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Altres"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Has definit la importància d\'aquestes notificacions."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Tots els idiomes"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Totes les regions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode de feina desactivat"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permet que el perfil professional funcioni, incloses les aplicacions, la sincronització en segon pla i les funcions relacionades."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 449b035..0e6ba82 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefonu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Stav nouze"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
@@ -692,7 +693,7 @@
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"V telefonu není žádná SIM karta."</string>
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Vložte SIM kartu."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
-    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná karta SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Nepoužitelná SIM karta."</string>
     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Vaše SIM karta byla natrvalo zablokována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Předchozí skladba"</string>
     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Další skladba"</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nemá přístup k internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilní data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámý typ sítě"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Probíhá příprava úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrola chyb"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zjištěno nové úložiště <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Klepnutím můžete síť spravovat."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Trvalá síť VPN je odpojena"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím zahájíte konfiguraci"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím přejděte do Nastavení"</string>
     <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
     <string name="reset" msgid="2448168080964209908">"Resetovat"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upravit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornění na využití dat"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornění na používání dat"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte nastavení."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosáhli jste limitu dat 2G–3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosáhli jste limitu dat 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> položek</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Různé"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Důležitost oznámení určujete vy."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Všechny jazyky"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Všechny oblasti"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhledávání"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovní režim je VYPNUTÝ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Povolí fungování pracovního profilu, včetně aplikací, synchronizace na pozadí a souvisejících funkcí."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ca79ce8..628f9bb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Indstillinger for telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ingen internetadgang"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har adgang til internettet. Der opkræves muligvis gebyr."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobildata"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukendt netværkstype"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrollerer for fejl"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Der blev registreret et nyt <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryk for at konfigurere"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string>
     <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
     <string name="reset" msgid="2448168080964209908">"Nulstil"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel om dataforbrug"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Underretning om dataforbrug"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tryk for at se forbrug og indstillinger."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Grænsen for 2G-3G-data er nået"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Grænsen for 4G-data er nået"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>valgt</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diverse"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbejdstilstand er slået FRA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillad, at arbejdsprofilen aktiveres, bl.a. i forbindelse med apps, baggrundssynkronisering og relaterede funktioner."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 469a535..f453024 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Notfall"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"WLAN hat keinen Internetzugriff"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Auf dem Gerät wird \"<xliff:g id="NEW_NETWORK">%1$s</xliff:g>\" verwendet, wenn über \"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>\" kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobile Datennutzung"</item>
+    <item msgid="75483255295529161">"WLAN"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ein unbekannter Netzwerktyp"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> wird vorbereitet"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Nach Fehlern wird gesucht"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Neue <xliff:g id="NAME">%s</xliff:g> entdeckt"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks tippen"</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Verbindung zu durchgehend aktivem VPN getrennt"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Zum Konfigurieren tippen"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Zum Einrichten tippen"</string>
     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
     <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-Speichergerät von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Warnung zum Datenverbrauch"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Warnung zur Datennutzung"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Für Nutzung und Einstellungen tippen."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-Datenlimit erreicht"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-Datenlimit erreicht"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ausgewählt</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Verschiedenes"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du hast die Wichtigkeit dieser Benachrichtigungen festgelegt."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle Sprachen"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle Regionen"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Suche"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbeitsmodus ist AUS"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Arbeitsprofil aktivieren, einschließlich Apps, Synchronisierung im Hintergrund und verknüpfter Funktionen."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 7bd02cd..5f148e3 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Απενεργοποίηση"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Κλήση έκτακτης ανάγκης"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Αναφορά σφαλμάτων"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Λήψη αναφοράς σφάλματος"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Το δίκτυο Wi-Fi δεν έχει πρόσβαση στο διαδίκτυο"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Ενδέχεται να ισχύουν χρεώσεις."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"δεδομένα κινητής τηλεφωνίας"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"άγνωστος τύπος δικτύου"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Προετοιμασία <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Έλεγχος για σφάλματα"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Εντοπίστηκε νέο μέσο αποθήκευσης <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"Το πάντα ενεργοποιημένο VPN αποσυνδέθηκε"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Πατήστε για διαμόρφωση"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Πατήστε για ρύθμιση"</string>
     <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
     <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Προειδοποίηση χρήσης δεδομένων"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Ειδοποίηση χρήσης δεδομένων"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Πατήστε για προβολή χρήσης/ρυθμ."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Συμπλ. το όριο δεδομένων 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Συμπλ. το όριο δεδομένων 4G"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">Επιλέχτηκαν <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Διάφορα"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Να επιτραπεί στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με το λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Όλες οι γλώσσες"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Όλες οι περιοχές"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Αναζήτηση"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Λειτουργία εργασίας ΑΠΕΝΕΡΓ/ΝΗ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Να επιτρέπεται η λειτουργία του προφίλ εργασίας σας, συμπεριλαμβανομένων των εφαρμογών, του συγχρονισμού στο παρασκήνιο και των σχετικών λειτουργιών."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0425e33..38f2b88 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobile data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
     <string name="reset" msgid="2448168080964209908">"Reset"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Miscellaneous"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 0425e33..38f2b88 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobile data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
     <string name="reset" msgid="2448168080964209908">"Reset"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Miscellaneous"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 0425e33..38f2b88 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobile data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string>
     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
     <string name="reset" msgid="2448168080964209908">"Reset"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Data usage warning"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Miscellaneous"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0a9fa94..1277acc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencias"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"La red Wi-Fi no tiene acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"datos móviles"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de red desconocido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando el medio <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Verificando errores"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Se detectó un nuevo medio (<xliff:g id="NAME">%s</xliff:g>)."</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Pulsa para gestionar la red."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Se desconectó la VPN siempre activada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Presiona para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Presiona para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta por el uso de datos"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Presiona para uso y opciones."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementos seleccionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Varios"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Estableciste la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Búsqueda"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo DESACTIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se active el perfil de trabajo, incluidas las apps, la sincronización en segundo plano y las funciones relacionadas."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e019c9e..7cd4ad5 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones del teléfono"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergencia"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi sin acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"datos móviles"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo de red desconocido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando errores"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nueva <xliff:g id="NAME">%s</xliff:g> detectada"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN siempre activada desconectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advertencia de uso de datos"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta sobre el uso de datos"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para ver uso y ajustes."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Varios"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Tú determinas la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo desactivado"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se utilice el perfil de trabajo, incluidas las aplicaciones, la sincronización en segundo plano y las funciones relacionadas."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 72b83fe..d1a3215 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonivalikud"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekraanilukk"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Lülita välja"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Hädaabi"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"WiFi-l pole juurdepääsu Internetile"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub Interneti-ühendus. Rakenduda võivad tasud."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobiilne andmeside"</item>
+    <item msgid="75483255295529161">"WiFi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tundmatu võrgutüüp"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Üksuse <xliff:g id="NAME">%s</xliff:g> ettevalmistamine"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Vigade kontrollimine"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tuvastati uus üksus <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alati sees VPN pole ühendatud"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Puudutage seadistamiseks"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Puudutage seadistamiseks"</string>
     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Andmekasutuse hoiatus"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Puudutage kasutuse/seadete vaat."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-, 3G-andmeside limiit on täis"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-andmeside limiit on täis"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Muu"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Teie määrasite nende märguannete tähtsuse."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Kõik keeled"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Kõik piirkonnad"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Otsing"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Töörežiim on VÄLJA LÜLITATUD"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Lubatakse tööprofiili toimingud, sh rakendused, taustal sünkroonimine ja seotud funktsioonid."</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 9a24634..da65093 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoaren aukerak"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Pantailaren blokeoa"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Larrialdiak"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
@@ -1074,8 +1075,19 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi konexioa ezin da Internetera konektatu"</string>
+    <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi eginbidea ezin da Internetera konektatu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"datu-konexioa"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"sare mota ezezaguna"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> prestatzen"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Errorerik dagoen egiaztatzen"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> berria hauteman da"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> saiora konektatuta. Sakatu sarea kudeatzeko."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Beti aktibatuta dagoen VPNa konektatzen…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Beti aktibatuta dagoen VPNa konektatu da"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Deskonektatu egin da beti aktibatuta dagoen VPN konexioa"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Beti aktibatuta dagoen VPN errorea"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sakatu konfiguratzeko"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Konfiguratzeko, sakatu hau"</string>
     <string name="upload_file" msgid="2897957172366730416">"Aukeratu fitxategia"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ez da fitxategirik aukeratu"</string>
     <string name="reset" msgid="2448168080964209908">"Berrezarri"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB unitatea"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datuen erabilerari buruzko abisua"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datu-erabilerari buruzko abisua"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Sakatu erabilera eta ezarpenak ikusteko."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2-3 GB-ko mugara iritsi zara"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4 GB-ko mugara iritsi zara"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Askotarikoak"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Lurralde guztiak"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Desaktibatuta dago laneko modua"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Baimendu laneko profilak funtzionatzea, besteak beste, aplikazioak, atzeko planoko sinkronizazioa eta erlazionatutako eginbideak."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3fde780..374183f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"گزینه‌های تلفن"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"قفل صفحه"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"اضطراری"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
     <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام رایانامه ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
@@ -924,9 +925,9 @@
       <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
       <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
     </plurals>
-    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدیو"</string>
-    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدیو برای پخش جریانی با این دستگاه معتبر نیست."</string>
-    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدیو ممکن نیست."</string>
+    <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string>
+    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
+    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string>
     <string name="VideoView_error_button" msgid="2822238215100679592">"تأیید"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>، <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"ظهر"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi به اینترنت دسترسی ندارد"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینه‌ها ضربه بزنید"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> دسترسی به اینترنت نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده می‌کند. ممکن است هزینه‌هایی اعمال شود."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"داده شبکه تلفن همراه"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"بلوتوث"</item>
+    <item msgid="5447331121797802871">"اترنت"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبکه نامشخص"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال مجاز است؟"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"در حال آماده‌سازی <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"در حال بررسی برای خطاها"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> جدید شناسایی شد"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"‏ارتباط VPN همیشه روشن قطع شد"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطای VPN همیشه فعال"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"جهت پیکربندی ضربه بزنید"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"برای راه‌اندازی ضربه بزنید"</string>
     <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
     <string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏درایو USB ‏<xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"‏حافظهٔ USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ویرایش"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"هشدار میزان استفاده از داده"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"هشدار مصرف داده"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"برای مشاهده مصرف و تنظیمات ضربه بزنید."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏به حد مجاز مصرف داده 2G-3G رسید"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏به حد مجاز مصرف داده 4G رسید"</string>
@@ -1512,8 +1524,8 @@
     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی ناشناس"</string>
-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی ناشناس"</string>
+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"عمودی نامشخص"</string>
+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"افقی نامشخص"</string>
     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"لغو شد"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"خطا هنگام نوشتن محتوا"</string>
     <string name="reason_unknown" msgid="6048913880184628119">"نامعلوم"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
       <item quantity="other">‏<xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"متفرقه"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"به <xliff:g id="APP">%1$s</xliff:g> امکان داده شود کاربر جدیدی با <xliff:g id="ACCOUNT">%2$s</xliff:g> اضافه کند؟"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"همه زبان‌ها"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"همه منطقه‌ها"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"جستجو"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"حالت کاری خاموش است"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"به نمایه کاری اجازه فعالیت ( شامل استفاده از برنامه‌ها، همگام‌سازی در پس‌زمینه و قابلیت‌های مرتبط) داده شود."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0446fa6..9b6d57c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Puhelimen asetukset"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Näytön lukitus"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Katkaise virta"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Hätäpuhelu"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ei ole yhteydessä internetiin."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobiilidata"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tuntematon verkon tyyppi"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Valmistellaan kohdetta <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tarkistetaan virheiden varalta."</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Uusi <xliff:g id="NAME">%s</xliff:g> on havaittu."</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa napauttamalla."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Aina käytössä olevan VPN:n yhteys on katkaistu"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Määritä napauttamalla."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Määritä koskettamalla."</string>
     <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
     <string name="reset" msgid="2448168080964209908">"Palauta"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-asema: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muokkaa"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Tiedonsiirtovaroitus"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Datankäyttövaroitus"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Käyttö &amp; asetukset napauttamalla"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-tietojen raja saavutettu"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-tietojen raja saavutettu"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valittu</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Muut"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Voit valita näiden ilmoitusten tärkeyden."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Myönnetäänkö sovellukselle <xliff:g id="APP">%1$s</xliff:g> oikeus luoda käyttäjä tilille <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Kaikki kielet"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Kaikki alueet"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Haku"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Työtila on pois käytöstä"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Sallii työprofiiliin toiminnan, esimerkiksi sovellukset ja taustasynkronoinnin."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d9d4fef..034b291 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgence"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"données cellulaires"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"RPV"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un type de réseau inconnu"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation de « <xliff:g id="NAME">%s</xliff:g> » en cours"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs en cours..."</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire « <xliff:g id="NAME">%s</xliff:g> » a été détectée"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"RPV permanent déconnecté"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Touchez pour configurer"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Touchez pour configurer"</string>
     <string name="upload_file" msgid="2897957172366730416">"Choisir un fichier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte d\'utilisation des données"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Touch. pour aff. util. et param."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Divers"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Le mode Travail est désactivé"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ebed571..6dfa504 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgences"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Le réseau Wi-Fi ne dispose d\'aucun accès à Internet."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais supplémentaires peuvent s\'appliquer."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"données mobiles"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"type de réseau inconnu"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation mémoire \"<xliff:g id="NAME">%s</xliff:g>\" en cours"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" a été détectée."</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN permanent déconnecté"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Appuyez ici pour configurer."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Appuyer pour configurer"</string>
     <string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertissement utilisation données"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte de consommation des données"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Appuyez pour conso/paramètres."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Divers"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toutes les régions"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode professionnel DÉSACTIVÉ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 34d42d0..a5c3c6e 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcións de teléfono"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo da pantalla"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencia"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
@@ -598,7 +599,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>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"A wifi non ten acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"datos móbiles"</item>
+    <item msgid="75483255295529161">"wifi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de rede descoñecido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando a <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando se hai erros"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Detectouse unha <xliff:g id="NAME">%s</xliff:g> nova"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca aquí para xestionar a rede."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre activada conectándose..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre activada conectada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Desconectouse a VPN sempre activada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre activada"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Escoller un ficheiro"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Non se seleccionou ningún ficheiro"</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"almacenamento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de uso de datos"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de datos"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para uso e configuración."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos de 2G-3G acadado"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos de 4G acadado"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">Seleccionáronse <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Varios"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ti defines a importancia destas notificacións."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as rexións"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de traballo DESACTIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que funcione o perfil de traballo, incluídas as aplicacións, a sincronización en segundo plano e as funcións relacionadas."</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 4ae0966..cd3e7be 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ફોન વિકલ્પો"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"સ્ક્રીન લૉક"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"પાવર બંધ"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"કટોકટી"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"બગ રિપોર્ટ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"બગ રિપોર્ટ લો"</string>
     <string name="bugreport_message" msgid="398447048750350456">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ને કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"સેલ્યુલર ડેટા"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"ઇથરનેટ"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi સાથે કનેક્ટ કરી શકાયું નથી"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" નબળું ઇન્ટરનેટ કનેક્શન ધરાવે છે."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"કનેક્શનની મંજૂરી આપીએ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"હંમેશાં-ચાલુ VPN ડિસ્કનેક્ટ થયું"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"હંમેશાં ચાલુ VPN ભૂલ"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ગોઠવવા માટે ટૅપ કરો"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"સેટ કરવા માટે ટૅપ કરો"</string>
     <string name="upload_file" msgid="2897957172366730416">"ફાઇલ પસંદ કરો"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string>
     <string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB સંગ્રહ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"સંપાદિત કરો"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ડેટા વપરાશ ચેતવણી"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ડેટા વપરાશ ચેતવણી"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"વપરાશ અને સેટિંગ્સ જોવા ટૅપ કરો."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ડેટા મર્યાદા પર પહોંચ્યાં"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ડેટા મર્યાદા સુધી પહોંચ્યાં"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"વિવિધ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ને <xliff:g id="ACCOUNT">%2$s</xliff:g> સાથે એક નવા વપરાશકર્તાને બનાવવાની મંજૂરી આપીએ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"બધી ભાષાઓ"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"તમામ પ્રદેશ"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"શોધ"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"કાર્ય મોડ બંધ છે"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"કાર્ય પ્રોફાઇલને ઍપ્લિકેશનો, પૃષ્ઠભૂમિ સમન્વયન અને સંબંધિત સુવિધાઓ સહિતનું કાર્ય કરવાની મંજૂરી આપો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0bc5881..c8b3256 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"फ़ोन विकल्‍प"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"स्‍क्रीन लॉक"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"पावर बंद"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"आपातकाल"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ईमेल संदेश के रूप में भेजने के लिए, इसके द्वारा आपके डिवाइस की वर्तमान स्थिति के बारे में जानकारी एकत्र की जाएगी. बग रिपोर्ट प्रारंभ करने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया धैर्य रखें."</string>
@@ -295,9 +296,9 @@
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS संदेश भेजें और देखें"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"ऐप्स  को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्‍याशित शुल्‍क लागू हो सकते हैं. दुर्भावनापूर्ण ऐप्स  आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्‍यय कर सकते हैं."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"अपने लेख संदेश (SMS या MMS) पढ़ें"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या गोपनीयता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या गोपनीयता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ऐप्स  को आपके टेबलेट या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"ऐप को आपके टीवी या सिम कार्ड पर संग्रहीत SMS संदेशों को पढ़ने की अनुमति देती है. इससे ऐप को सामग्री या निजता पर ध्‍यान दिए बिना, सभी SMS संदेशों को पढ़ने की अनुमति मिल जाती है."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"ऐप्स  को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेश पढ़ने देता है. इससे सामग्री या निजता पर ध्यान दिए बिना, ऐप्स  सभी SMS संदेश पढ़ सकता है."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"लेख संदेश (WAP) प्राप्त करें"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"ऐप्स  को WAP संदेशों को प्राप्‍त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे ऐप्स पुनर्प्राप्त करें"</string>
@@ -347,9 +348,9 @@
     <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर संवेदक एक्सेस करें (जैसे हृदय गति मॉनीटर)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ऐप को आपकी शारीरिक स्‍थिति, जैसे आपकी हृदय गति पर नज़र रखने वाले संवेदकों का डेटा एक्‍सेस करने देती है."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
-    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को गोपनीयता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"ऐप को, मित्रों और सहकर्मियों के कैलेंडर ईवेंट सहित, आपके टीवी पर संग्रहीत सभी कैलेंडर ईवेंट पढ़ने देती है. इससे ऐप को निजता या संवेदनशीलता पर ध्‍यान दिए बिना, आपका कैलेडर डेटा साझा करने या सहेजने की अनुमति मिल जाती है."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"ऐप्स  को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे निजता या संवेदनशीलता पर ध्यान दिए बिना, ऐप्स  आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"अपनी जानकारी के बि‍ना कैलेंडर ईवेंट जोड़ें या संशोधि‍त करें और अति‍थि‍यों को ईमेल भेजें"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"ऐप्स  को मित्रों या सहकर्मियों के ईवेंट के साथ ही वे ईवेंट जोड़ने, निकालने, बदलने देता है जिन्हें आप अपने टेबलेट पर संशोधित कर सकते हैं. इससे ऐप्स ,अपनी जानकारी के बिना उन संदेशों को भेज सकता है जो कैलेंडर स्वामियों की ओर से आते दिखाई देते हैं, या ईवेंट संशोधित कर सकता है."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"ऐप को ऐसे ईवेंट जोड़ने, निकालने, बदलने देती है जिन्हें आप अपने डिवाइस पर बदल सकते हैं, जिनमें मित्रों या सहकर्मियों के ईवेंट शामिल हैं. इससे ऐप ऐसे संदेश भेज सकता है जो कैलेंडर स्वामी से आते हुए प्रतीत होते हैं या ऐप स्वामी की जानकारी के बिना ईवेंट बदल सकता है."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"वाई-फ़ाई में कोई इंटरनेट ऐक्‍सेस नहीं है"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में कोई इंटरनेट एक्‍सेस नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का उपयोग करता है. शुल्क लिया जा सकता है."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"सेल्युलर डेटा"</item>
+    <item msgid="75483255295529161">"वाई-फ़ाई"</item>
+    <item msgid="6862614801537202646">"ब्लूटूथ"</item>
+    <item msgid="5447331121797802871">"ईथरनेट"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्‍मीदवार"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"हमेशा-चालू VPN डिस्‍कनेक्‍ट है"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फ़िगर करने के लिए टैप करें"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करने के लिए टैप करें"</string>
     <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
     <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB डिस्‍क"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB मेमोरी"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करें"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा उपयोग की चेतावनी"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा उपयोग की सूचना"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"उपयोग व सेटिंग देखने हेतु टैप करें."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पूर्ण हो गई"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पूर्ण हो गई"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"विविध"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"सभी भाषाएं"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"सभी क्षेत्र"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"खोजें"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद है"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ऐप्स, पृष्ठभूमि समन्वयन और संबंधित सुविधाओं सहित कार्य प्रोफ़ाइल को काम करने की अनुमति दें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e7ccf23..3fc3346 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje zaslona"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
@@ -1101,6 +1102,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> &gt; <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilni podaci"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
@@ -1178,7 +1190,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema uređaja <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Traženje pogrešaka"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Otkriven je novi uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1257,8 +1268,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dotaknite za upravljanje mrežom."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Prekinuta je veza s uvijek uključenom VPN mrežom"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurirali"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavljanje"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
@@ -1343,7 +1355,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB pogon"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o upotrebi podataka"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o upotrebi podataka"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za upotrebu i postavke"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dost. ogr. 2G–3G prijenosa pod."</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dost. ogr. 4G prijenosa podataka"</string>
@@ -1663,6 +1675,7 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> odabrane</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> odabranih</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Razno"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Postavili ste važnost tih obavijesti."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Želite li dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1672,6 +1685,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Radni je način ISKLJUČEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućuje radnom profilu da funkcionira, uključujući aplikacije, sinkronizaciju u pozadini i povezane značajke."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d6fc1c5..825672b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"A Wi-Fi-hálózaton nincs internetkapcsolat"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internetkapcsolat <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobiladat"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ismeretlen hálózati típus"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> előkészítése"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hibák keresése"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Új <xliff:g id="NAME">%s</xliff:g> észlelve"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Kapcsolat bontva a mindig bekapcsolt VPN-nel"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Koppintson a konfiguráláshoz"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Koppintson ide a beállításhoz"</string>
     <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
     <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-meghajtó"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Szerkesztés"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Adathasználati figyelmeztetés"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Adathasználati értesítés"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Koppintson az adatokért."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-adatkorlát elérve"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-adatkorlát elérve"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Vegyes"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ön állította be ezen értesítések fontossági szintjét."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Minden nyelv"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Minden régió"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Keresés"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"A munka mód KI van kapcsolva"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Munkaprofil használatának engedélyezése, beleértve az alkalmazásokat, a háttérben való szinkronizálást és a kapcsolódó funkciókat."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index fa5a8ec..83f8995 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Հեռախոսի ընտրանքներ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Էկրանի փական"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Անջատել"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Արտակարգ իրավիճակ"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Գրել սխալի զեկույց"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
@@ -249,17 +250,17 @@
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Օրացույց"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"Կարճ հաղորդագրություն"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդագրությունները"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS հաղորդ․-ները"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Պահոց"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող այլ ֆայլերը"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Բարձրախոս"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրում"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրել"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Ֆոտոխցիկ"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարում և տեսագրում"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"լուսանկարել և տեսագրել"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Հեռախոս"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"հեռախոսազանգերի կատարում և կառավարում"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"կատարել զանգեր և կառավարել զանգերը"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Մարմնի սենսորներ"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել ձեր հիմնական ֆիզիոլոգիական ցուցանիշների վերաբերյալ սենսորի տվյալները"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Առբերել պատուհանի բովանդակությունը"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ստուգեք պատուհանի բովանդակությունը, որի հետ փոխգործակցում եք:"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Միացնել Հպման միջոցով հետազոտումը"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ցանցը համացանցի միացում չունի"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Եթե <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցն ինտերնետ կապ չունի, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Կարող են վճարներ գանձվել:"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"բջջային տվյալներ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ցանցի անհայտ տեսակ"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ի նախապատրաստում"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Սխալների ստուգում"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Հայտնաբերվել է նոր <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"«Միշտ միացված VPN»-ն անջատված է"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN սխալը միշտ միացված"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Հպեք՝ կազմաձևելու համար"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Հպեք՝ կարգավորելու համար"</string>
     <string name="upload_file" msgid="2897957172366730416">"Ընտրել ֆայլը"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ոչ մի ֆայլ չի ընտրված"</string>
     <string name="reset" msgid="2448168080964209908">"Վերակայել"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB սարքավար <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB կրիչ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Տվյալների օգտագործման նախազգուշացում"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Տվյալների օգտագործման զգուշացում"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Հպեք և տեսեք օգտագործումը և կարգավորումները:"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G տվյալների սահմանաչափը սպառվել է"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G տվյալների սահմանաչափը սպառվել է"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Զանազան"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Թույլ տա՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտվող ստեղծել:"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Աշխատանքային ռեժիմն ԱՆՋԱՏՎԱԾ Է"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Միացնել աշխատանքային պրոֆիլը՝ հավելվածները, ֆոնային համաժամեցումը և առնչվող գործառույթները"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 79c868b..d655477 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -116,7 +116,7 @@
     <string name="roamingText5" msgid="7604063252850354350">"Roaming - Sistem Yang Dipilih"</string>
     <string name="roamingText6" msgid="2059440825782871513">"Roaming - Sistem Tersedia"</string>
     <string name="roamingText7" msgid="7112078724097233605">"Mitra Roaming - Alliance"</string>
-    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Mitra Premium"</string>
+    <string name="roamingText8" msgid="5989569778604089291">"Roaming - Partner Premium"</string>
     <string name="roamingText9" msgid="7969296811355152491">"Fungsionalitas Layanan Roaming - Penuh"</string>
     <string name="roamingText10" msgid="3992906999815316417">"Fungsionalitas Layanan Roaming - Sebagian"</string>
     <string name="roamingText11" msgid="4154476854426920970">"Spanduk Roaming Hidup"</string>
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsi telepon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Kunci layar"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan daya"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Darurat"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tidak memiliki akses internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketuk untuk melihat opsi"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"data seluler"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis jaringan yang tidak dikenal"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyiapkan <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Memeriksa kesalahan"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baru terdeteksi"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN selalu aktif terputus"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketuk untuk mengonfigurasi"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketuk untuk menyiapkan"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Peringatan penggunaan data"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Lansiran penggunaan data"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketuk untuk lihat penggunaan &amp; setelan."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Batas data 2G-3G terlampaui"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Batas data 4G terlampaui"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Lain-Lain"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Anda menyetel nilai penting notifikasi ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua wilayah"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Telusuri"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mode kerja NONAKTIF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Izinkan profil kerja berfungsi, termasuk aplikasi, sinkronisasi latar belakang, dan fitur terkait."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index ebb1053..cd41f51 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Valkostir síma"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Skjálás"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Slökkva"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Neyðarsímtal"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi netið er ekki með tengingu við internetið"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld geta átt við."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"farsímagögn"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"óþekkt tegund netkerfis"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Undirbýr <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Leitar að villum"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nýtt <xliff:g id="NAME">%s</xliff:g> fannst"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Tengt við <xliff:g id="SESSION">%s</xliff:g>. Ýttu til að hafa umsjón með netinu."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Sívirkt VPN tengist…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Sívirkt VPN tengt"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Sívirkt VPN aftengt"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Villa í sívirku VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ýttu til að stilla"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ýttu til að setja upp"</string>
     <string name="upload_file" msgid="2897957172366730416">"Velja skrá"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Engin skrá valin"</string>
     <string name="reset" msgid="2448168080964209908">"Endurstilla"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drif frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-geymsla"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Breyta"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Viðvörun vegna gagnanotkunar"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Viðvörun um gagnanotkun"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ýttu fyrir uppl. og stillingar"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gagnahámarki 2G og 3G náð"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gagnahámarki 4G náð"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> valið</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Ýmislegt"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Þú stilltir mikilvægi þessara tilkynninga."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Öll tungumál"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Öll svæði"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Leita"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Slökkt á vinnusniði"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Leyfa virkni vinnusniðs, m.a. forrita, samstillingar í bakgrunni og tengdra eiginleika."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7267032..ec7f8f9 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opzioni telefono"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergenza"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Connessione Wi-Fi priva di accesso Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"rete dati"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo di rete sconosciuto"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparazione della <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ricerca errori"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuova <xliff:g id="NAME">%s</xliff:g> rilevata"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Connessione a VPN sempre attiva…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre attiva connessa"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre attiva disconnessa"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Errore VPN sempre attiva"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tocca per configurare"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocca per configurare"</string>
     <string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string>
     <string name="reset" msgid="2448168080964209908">"Reimposta"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unità USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifica"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avviso sull\'utilizzo dei dati"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Avviso sull\'utilizzo dei dati"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tocca per uso e impostazioni."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite di dati 2G-3G raggiunto"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite di dati 4G raggiunto"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> file selezionati</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> file selezionato</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Vari"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Stabilisci tu l\'importanza di queste notifiche."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Tutte le lingue"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tutte le aree geografiche"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modalità Lavoro DISATTIVATA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Attiva il profilo di lavoro, incluse app, sincronizzazione in background e funzioni correlate."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 3242752..290a31f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"אפשרויות טלפון"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"חירום"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
     <string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"‏אין ל-Wi-Fi גישה לאינטרנט"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"נתונים סלולריים"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"סוג רשת לא מזוהה"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"הכנת <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"בודק אם יש שגיאות"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"זוהה <xliff:g id="NAME">%s</xliff:g> חדש"</string>
@@ -1282,8 +1293,9 @@
     <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_disconnected" msgid="4532298952570796327">"‏חיבור תמידי ל-VPN מנותק"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏שגיאת VPN שמופעל תמיד"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"הקש כדי להגדיר"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"הקש כדי להגדיר"</string>
     <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
     <string name="reset" msgid="2448168080964209908">"איפוס"</string>
@@ -1362,14 +1374,14 @@
     <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>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏כונן USB של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"‏אחסון USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ערוך"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"אזהרת שימוש בנתונים"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"התראה לשימוש בנתונים"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"הקש כדי להציג נתוני שימוש והגדרות."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏הגעת למגבלת הנתונים של 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏הגעת למגבלת הנתונים של 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="other">בחרת <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">בחרת <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"שונות"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"האם לאפשר ל-<xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש לחשבון <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"כל השפות"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"כל האזורים"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"חיפוש"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"מצב העבודה כבוי"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"אפשר לפרופיל העבודה לפעול, כולל אפליקציות, סנכרון ברקע ותכונות קשורות."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index c89b86d..5305b1f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"携帯電話オプション"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急通報"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"バグレポート"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"バグレポートを取得"</string>
     <string name="bugreport_message" msgid="398447048750350456">"現在の端末の状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
@@ -374,7 +375,7 @@
     <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"IMSサービスがユーザー操作なしで電話をかけることをアプリに許可します。"</string>
-    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
+    <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末情報と ID の読み取り"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"テレビのスリープを無効化"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiはインターネットに接続していません"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"端末で「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"モバイルデータ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"イーサネット"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明なネットワーク タイプ"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>を準備中"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"エラーを確認中"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"新しい<xliff:g id="NAME">%s</xliff:g>が検出されました"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"常時接続 VPN の接続を解除しました"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"タップして設定"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"設定するにはタップします"</string>
     <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
     <string name="reset" msgid="2448168080964209908">"リセット"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>製USBドライブ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編集"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"データ使用の警告"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"データ使用量に関する通知"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"タップして使用状況と設定を表示します。"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G~3Gデータの上限に達しました"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4Gデータの上限に達しました"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件選択済み</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"その他"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"このような通知の重要度を設定します。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"すべての地域"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"検索"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index a018d24..1e34347 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ტელეფონის პარამეტრები"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ეკრანის დაბლოკვა"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"საგანგებო სამსახურები"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
     <string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-ს არ აქვს ინტერნეტზე წვდომა"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"მობილური ინტერნეტი"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"უცნობი ტიპის ქსელი"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ის მომზადება"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"შეცდომების შემოწმება"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"აღმოჩენილია ახალი <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"მუდმივად ჩართული VPN გათიშულია"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"შეცდომა მუდამ VPN-ზე"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"შეეხეთ პარამეტრების კონფიგურაციისთვის"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"შეეხეთ დასაყენებლად"</string>
     <string name="upload_file" msgid="2897957172366730416">"ფაილის არჩევა"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ფაილი არჩეული არ არის"</string>
     <string name="reset" msgid="2448168080964209908">"საწყისზე დაბრუნება"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB დისკი"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB მეხსიერება"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ინტერნეტის გამოყენების გაფრთხილება"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"მონაცემთა მოხმარების გაფრთხილება"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G მონაცემთა ლიმიტი ამოიწურა"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G მონაცემთა ლიმიტი ამოიწურა"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> შერჩეული</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"სხვადასხვა"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს, <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ყველა ენა"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ყველა რეგიონი"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ძიება"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"სამსახურის რეჟიმი გამორთულია"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"სამსახურის პროფილის მუშაობის დაშვება, მათ შორის, აპების, ფონური სინქრონიზაციის და დაკავშირებული ფუნქციების."</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 2417396..9a227c4 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон опциялары"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Экранды құлыптау"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Өшіру"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Төтенше жағдай"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Вирус туралы хабарлау"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Қате туралы есеп құру"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi желісінде интернет байланысы жоқ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ұялы дерек"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"желі түрі белгісіз"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> дайындалуда"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Қателер тексерілуде"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңа <xliff:g id="NAME">%s</xliff:g> анықталды"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> жүйесіне жалғанған. Желіні басқару үшін түріңіз."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Әрқашан қосылған ВЖЖ жалғануда…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Әрқашан қосылған ВЖЖ жалғанған"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Әрқашан қосулы VPN желісі ажыратылды"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Әрқашан қосылған ВЖЖ қателігі"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялау үшін түртіңіз"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Реттеу үшін түртіңіз"</string>
     <string name="upload_file" msgid="2897957172366730416">"Файлды таңдау"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ешқандай файл таңдалмаған"</string>
     <string name="reset" msgid="2448168080964209908">"Қайта реттеу"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB дискі"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB жады"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дерекқор қолдануға қатысты ескерту"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Деректер трафигі туралы ескерту"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Трафик пен параметрлерді көру үшін түртіңіз."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G деректер шегіне жеттіңіз"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G деректер шегіне жеттіңіз"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> таңдалды</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Өзге"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат ету керек пе?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Барлық тілдер"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Барлық аймақтар"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Іздеу"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Жұмыс режимі ӨШІРУЛІ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Жұмыс профиліне, соның ішінде, қолданбаларға, фондық синхрондауға және қатысты мүмкіндіктерге жұмыс істеуге рұқсат ету."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 86669b4..4eaadfe 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ជម្រើស​ទូរស័ព្ទ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ចាក់​សោ​អេក្រង់"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"បិទ"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"អាសន្ន"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"របាយការណ៍​កំហុស"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"យក​របាយការណ៍​កំហុស"</string>
     <string name="bugreport_message" msgid="398447048750350456">"វា​នឹង​​ប្រមូល​ព័ត៌មាន​អំពី​ស្ថានភាព​ឧបករណ៍​របស់​អ្នក ដើម្បី​ផ្ញើ​ជា​សារ​អ៊ីមែល។ វា​នឹង​ចំណាយ​ពេល​តិច​ពី​ពេល​ចាប់ផ្ដើម​របាយការណ៍​រហូត​ដល់​ពេល​វា​រួចរាល់​ដើម្បី​ផ្ញើ សូម​អត់ធ្មត់។"</string>
@@ -1078,6 +1079,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi មិនមានអ៊ិនធឺណិតនោះទេ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> គ្មានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតប្រាក់លើការប្រើប្រាស់ទិន្នន័យ។"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ទិន្នន័យចល័ត"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"ប៊្លូធូស"</item>
+    <item msgid="5447331121797802871">"អ៊ីសឺរណិត"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
@@ -1155,7 +1167,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"កំពុងរៀបចំ <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"កំពុងពិនិត្យរកកំហុស"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"បានរកឃើញ <xliff:g id="NAME">%s</xliff:g> ថ្មី"</string>
@@ -1234,8 +1245,9 @@
     <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_disconnected" msgid="4532298952570796327">"បានផ្តាច់ VPN ដែលបើកជានិច្ច"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"បើក​កំហុស VPN ជា​និច្ច"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ប៉ះដើម្បីកំណត់រចនាសម្ព័ន្ធ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ប៉ះដើម្បីដំឡើង"</string>
     <string name="upload_file" msgid="2897957172366730416">"ជ្រើស​​ឯកសារ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"គ្មាន​ឯកសារ​បាន​ជ្រើស"</string>
     <string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
@@ -1319,7 +1331,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល​"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមាន​ប្រើ​ទិន្នន័យ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ការដាស់តឿនពីការប្រើទិន្នន័យ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ប៉ះដើម្បីមើលការប្រើប្រាស់ និងការកំណត់"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"បាន​ដល់​ដែន​កំណត់​ទិន្នន័យ 4G"</string>
@@ -1629,6 +1641,7 @@
       <item quantity="other">បានជ្រើស <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"ផ្សេងៗ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"អនុញ្ញាតឲ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ឬទេ?"</string>
@@ -1638,6 +1651,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"បាន​ស្នើ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ភាសាទាំងអស់"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"តំបន់ទាំងអស់"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ស្វែងរក"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"របៀបការងារបានបិទ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"អនុញ្ញាតឲ្យប្រវត្តិរូបការងារដំណើរការ ដោយរាប់បញ្ចូលទាំងកម្មវិធី ការធ្វើសមកាលកម្មផ្ទៃខាងក្រោយ និងលក្ខណៈពិសេសដែលពាក់ព័ន្ធ។"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 2eae59c..0a9a511 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -172,7 +172,7 @@
       <item quantity="one">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
       <item quantity="other">ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರಗಳನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ</item>
     </plurals>
-    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಜ್ಞಾತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
+    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಪರಿಚಿತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ನಿರ್ವಾಹಕರಿಂದ"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> ಪ್ರಕಾರ"</string>
     <string name="work_profile_deleted" msgid="5005572078641980632">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಅಳಿಸಲಾಗಿದೆ"</string>
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ಫೋನ್ ಆಯ್ಕೆಗಳು"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ಸ್ಕ್ರೀನ್ ಲಾಕ್"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ಪವರ್ ಆಫ್ ಮಾಡು"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"ತುರ್ತು"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ದೋಷದ ವರದಿ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ದೋಷ ವರದಿ ರಚಿಸಿ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
@@ -979,8 +980,8 @@
     <string name="whichSendToApplication" msgid="8272422260066642057">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
     <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ಬಳಸಿಕೊಂಡು ಕಳುಹಿಸಿ"</string>
     <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"ಕಳುಹಿಸು"</string>
-    <string name="whichHomeApplication" msgid="4307587691506919691">"ಹೋಮ್‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಹೋಮ್‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
+    <string name="whichHomeApplication" msgid="4307587691506919691">"ಮುಖಪುಟ‌ ಅಪ್ಲಿಕೇಶನ್‌  ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ಮುಖಪುಟ‌ ಎಂಬಂತೆ %1$s ಅನ್ನು ಬಳಸಿ"</string>
     <string name="whichHomeApplicationLabel" msgid="809529747002918649">"ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
     <string name="whichImageCaptureApplication" msgid="3680261417470652882">"ಇದರ ಜೊತೆಗೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
     <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"%1$s ಜೊತೆ ಚಿತ್ರ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
@@ -1061,7 +1062,7 @@
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್‌ಟೋನ್ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"ಯಾವುದೂ ಇಲ್ಲ"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ರಿಂಗ್‌ಟೋನ್‌ಗಳು"</string>
-    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಜ್ಞಾತ ರಿಂಗ್‌ಟೋನ್"</string>
+    <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಪರಿಚಿತ ರಿಂಗ್‌ಟೋನ್"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
       <item quantity="other">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"ವೈ-ಫೈ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ"</item>
+    <item msgid="75483255295529161">"ವೈ-ಫೈ"</item>
+    <item msgid="6862614801537202646">"ಬ್ಲೂಟೂತ್‌"</item>
+    <item msgid="5447331121797802871">"ಇಥರ್ನೆಟ್"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ಅಪರಿಚಿತ ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ವೈ-ಫೈ ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ದೋಷಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ಹೊಸ <xliff:g id="NAME">%s</xliff:g> ಪತ್ತೆಯಾಗಿದೆ"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ಯಾವಾಗಲೂ-ಆನ್ VPN ದೋಷ"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="upload_file" msgid="2897957172366730416">"ಫೈಲ್ ಆಯ್ಕೆಮಾಡು"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ಯಾವುದೇ ಫೈಲ್ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string>
     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ಡ್ರೈವ್"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB ಸಂಗ್ರಹಣೆ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ಎಡಿಟ್"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ಡೇಟಾ ಬಳಕೆಯ ಎಚ್ಚರಿಕೆ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ಡೇಟಾ ಬಳಕೆ ಎಚ್ಚರಿಕೆ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ಬಳಕೆ ಮತ್ತು ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
@@ -1512,11 +1524,11 @@
     <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
     <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
-    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಜ್ಞಾತ ಪೋಟ್ರೇಟ್"</string>
-    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಜ್ಞಾತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
+    <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ಅಪರಿಚಿತ ಪೋಟ್ರೇಟ್"</string>
+    <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ಅಪರಿಚಿತ ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</string>
     <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ವಿಷಯವನ್ನು ಬರೆಯುವಲ್ಲಿ ದೋಷ ಎದುರಾಗಿದೆ"</string>
-    <string name="reason_unknown" msgid="6048913880184628119">"ಅಜ್ಞಾತ"</string>
+    <string name="reason_unknown" msgid="6048913880184628119">"ಅಪರಿಚಿತ"</string>
     <string name="reason_service_unavailable" msgid="7824008732243903268">"ಮುದ್ರಣ ಸೇವೆ ಸಕ್ರಿಯಗೊಂಡಿಲ್ಲ"</string>
     <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> ಸೇವೆಯನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿದೆ"</string>
     <string name="print_service_installed_message" msgid="5897362931070459152">"ಸಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"ಇತರೆ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸೂಚಿತ ಭಾಷೆ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕು"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌‌ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index fe3ebe4..4191865 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"휴대전화 옵션"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"종료"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"긴급 전화"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"버그 신고"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
     <string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
@@ -243,7 +244,7 @@
     <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
     <string name="managed_profile_label" msgid="5289992269827577857">"직장으로 전환"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 액세스"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 액세스"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi가 인터넷에 연결되어 있지 않습니다."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>이(가) 인터넷에 연결되지 않는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>을(를) 사용합니다. 요금이 부과될 수 있습니다."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"모바일 데이터"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"블루투스"</item>
+    <item msgid="5447331121797802871">"이더넷"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"알 수 없는 네트워크 유형"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> 준비 중"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"오류 확인 중"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"새로운 <xliff:g id="NAME">%s</xliff:g> 감지됨"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"연결 유지 VPN 연결 해제됨"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"설정하려면 탭하세요."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"탭하여 설정"</string>
     <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
     <string name="reset" msgid="2448168080964209908">"초기화"</string>
@@ -1310,14 +1322,14 @@
     <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>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 드라이브"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"수정"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"데이터 사용 경고"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"데이터 사용 알림"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"사용량 및 설정을 보려면 탭하세요."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G 데이터 한도에 도달함"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G 데이터 한도에 도달함"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 선택됨</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"기타"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"이러한 알림의 중요도를 설정했습니다."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="ACCOUNT">%2$s</xliff:g>(으)로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"모든 언어"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"모든 지역"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"검색"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"직장 모드가 사용 중지됨"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"앱, 백그라운드 동기화 및 관련 기능을 포함한 직장 프로필이 작동하도록 허용"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index bccb5fa..1a5f348 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Телефон мүмкүнчүлүктөрү"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Экран кулпусу"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Кубатын өчүрүү"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Тез жардам"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ката тууралуу билдирүү"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ката тууралуу билдирүү түзүү"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Бул сиздин түзмөгүңүздүн учурдагы абалын эмейл билдирүүсү катары жөнөтүш максатында маалымат чогултат. Ката тууралуу билдирүү түзүлүп башталып, жөнөтүлгөнгө чейин бир аз убакыт керек болот; сураныч, бир аз күтө туруңуз."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi тармагы Интернетке туташпай турат"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобилдик дайындар"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"белгисиз тармак түрү"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> даярдалууда"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Каталар текшерилүүдө"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңы <xliff:g id="NAME">%s</xliff:g> аныкталды"</string>
@@ -1197,8 +1208,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,14 +1239,13 @@
     <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_disconnected" msgid="4532298952570796327">"Дайым иштеген VPN ажыратылды"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялоо үчүн таптап коюңуз"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Жөндөө үчүн таптаңыз"</string>
     <string name="upload_file" msgid="2897957172366730416">"Файл тандоо"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Эч файл тандалган жок"</string>
     <string name="reset" msgid="2448168080964209908">"Баштапкы абалга келтирүү"</string>
@@ -1320,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB түзмөгү"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB эстутуму"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгөртүү"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дайындарды колдонуу боюнча эскрт"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дайындарды колдонуу айгайы"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Колдонулушун жана жөндөөлөрүн көрүү үчүн таптаңыз."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дайындар чегине жетти"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дайындар чегине жетти"</string>
@@ -1630,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Калган-каткандар"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string>
@@ -1639,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Бардык тилдер"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Бардык аймактар"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Издөө"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Жумуш режими ӨЧҮРҮЛГӨН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Жумуш профилин, ошондой эле колдонмолорду, фондо шайкештирүү жана ага байланыштуу функцияларды иштетиңиз."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 569b752..26c9053 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ໂຕເລືອກໂທລະສັບ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ລັອກໜ້າຈໍ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ປິດ"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"ສຸກເສີນ"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ລາຍງານຂໍ້ຜິດພາດ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ບໍ່ມີການເຂົ້າເຖິງອິນເຕີເນັດ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ຂໍ້ມູນອິນເຕີເນັດມືຖື"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"ອີເທີເນັດ"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"ກຳ​ລັງ​ກຽມ <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ກຳລັງກວດຫາຂໍ້ຜິດພາດ"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ກວດ​ພົບ <xliff:g id="NAME">%s</xliff:g> ໃໝ່​ແລ້ວ"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="SESSION">%s</xliff:g> ແລ້ວ. ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ກຳລັງເຊື່ອມຕໍ່ Always-on VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ເຊື່ອມຕໍ່ VPN ແບບເປີດຕະຫຼອດເວລາແລ້ວ"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ຕັດການເຊື່ອມຕໍ່ VPN ແບບເປີດໃຊ້ຕະຫຼອດເວລາແລ້ວ"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN ແບບເປີດຕະຫຼອດເກີດຄວາມຜິດພາດ"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ແຕະເພື່ອຕັ້ງຄ່າ"</string>
     <string name="upload_file" msgid="2897957172366730416">"ເລືອກໄຟລ໌"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ບໍ່ໄດ້ເລືອກໄຟລ໌ເທື່ອ"</string>
     <string name="reset" msgid="2448168080964209908">"ຣີເຊັດ"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ດ​ຣ້າຍ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ແກ້ໄຂ"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ເຕືອນກ່ຽວກັບການນຳໃຊ້ຂໍ້ມູນ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ແຈ້ງເຕືອນການໃຊ້ອິນເຕີເນັດ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ແຕະເພື່ອເບິ່ງການນຳໃຊ້ ແລະ ການຕັ້ງຄ່າ."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ໃຊ້​ຂໍ້​ມູນ 2G-3G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ໃຊ້​ຂໍ້​ມູນ 4G ຮອດ​ຈຳ​ນວນ​ທີ່​ຈຳ​ກັດ​ແລ້ວ"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກ​ແລ້ວ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"ອື່ນໆ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ສຳລັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ບໍ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ທຸກພາ​ສາ​"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ທຸກຂົງເຂດ"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ຄົ້ນຫາ"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"ໂໝດບ່ອນເຮັດວຽກປິດຢູ່"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ອະນຸຍາດໃຫ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກສາມາດນຳໃຊ້ໄດ້ ເຊິ່ງຮວມທັງແອັບ, ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ ແລະ ຄຸນສົມບັດທີ່ກ່ຽວຂ້ອງ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 42ef31d..a2f5eb8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefono parinktys"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekrano užraktas"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Skambutis pagalbos numeriu"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"„Wi-Fi“ tinkle nėra interneto ryšio"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Įrenginys naudoja tinklą <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kai tinkle <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobiliojo ryšio duomenys"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Eternetas"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nežinomas tinklo tipas"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ruošiama <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tikrinama, ar nėra klaidų"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Aptikta nauja <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Visada įjungtas VPN atjungtas"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Palieskite, kad konfigūruotumėte"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Palieskite, kad nustatytumėte"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
     <string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ atmintukas"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redaguoti"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Įspėjimas dėl duomenų naudojimo"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Duomenų naudojimo įspėjimas"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Pal. ir perž. naud. i. bei nust."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Pasiektas 2G–3G duomenų apribojimas"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Pasiektas 4G duomenų apribojimas"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="many">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
       <item quantity="other">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Įvairūs"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Galite nustatyti šių pranešimų svarbą."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Visos kalbos"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi regionai"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Paieška"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Darbo režimas išjungtas"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Leisti veikti darbo profiliui, įskaitant programas, sinchronizavimą fone ir susijusias funkcijas."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index e632263..6ea7d6b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Tālruņa opcijas"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekrāna bloķētājs"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Strāvas padeve ir izslēgta."</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Ārkārtas"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
@@ -1101,6 +1102,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tīklā nav piekļuves internetam."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kad tīklā <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nav piekļuves internetam, ierīcē tiek izmantots tīkls <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Var tikt piemērota maksa."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilie dati"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nezināms tīkla veids"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
@@ -1178,7 +1190,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Notiek <xliff:g id="NAME">%s</xliff:g> sagatavošana"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tiek meklētas kļūdas"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tika atrasta jauna <xliff:g id="NAME">%s</xliff:g>."</string>
@@ -1257,8 +1268,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Ir izveidots savienojums ar: <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vienmēr ieslēgts VPN ir atvienots"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Pieskarieties, lai konfigurētu."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Pieskarieties, lai iestatītu."</string>
     <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
     <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
@@ -1343,7 +1355,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disks"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediģēt"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Datu izmantošanas brīdinājums"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Brīdinājums par datu lietojumu"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Piesk., lai sk. lietoj. un iest."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Sasniegts 2G-3G datu ierobež."</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Sasniegts 4G datu ierobežojums"</string>
@@ -1663,6 +1675,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīts</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Dažādi"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1672,6 +1685,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Visas valodas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Visi reģioni"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Meklēt"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Darba režīms IZSLĒGTS"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Atļaujiet darboties darba profilam, tostarp lietotnēm, sinhronizācijai fonā un saistītajām funkcijām."</string>
diff --git a/core/res/res/values-mcc001/config.xml b/core/res/res/values-mcc001/config.xml
new file mode 100644
index 0000000..93cde03
--- /dev/null
+++ b/core/res/res/values-mcc001/config.xml
@@ -0,0 +1,21 @@
+<?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>
+    <bool name="config_use_sim_language_file">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
index 0f39e42..ddf0e9f 100755
--- a/core/res/res/values-mcc204-mnc04/config.xml
+++ b/core/res/res/values-mcc204-mnc04/config.xml
@@ -25,13 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1358</integer>
 
-    <!-- service number convert map in roaming network. -->
-    <!-- [dialstring],[replacement][,optional gid] -->
-    <string-array translatable="false" name="dial_string_replace">
-        <item>"*611:+19085594899,BAE0000000000000"</item>
-        <item>"*86:+1MDN,BAE0000000000000"</item>
-    </string-array>
-
     <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
           when evaluating RSRP for LTE antenna bar display
            0. Strict threshold
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-mcc238-mnc06/config.xml b/core/res/res/values-mcc238-mnc06/config.xml
deleted file mode 100644
index afc0cc4..0000000
--- a/core/res/res/values-mcc238-mnc06/config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- SIM does not save, but the voice mail number to be changed. -->
-    <bool name="editable_voicemailnumber">true</bool>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index 454e4b6..d638b89 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -42,4 +42,23 @@
         <item>[ApnSettingV3]Tethered Public Mobile,isp.mb.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,4D4F</item>
     </string-array>
 
+    <!-- Values for GPS configuration (Telus) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.telusmobility.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index ffc9d6c..1444250 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -32,4 +32,23 @@
         <item>[ApnSettingV3]Koodo,sp.koodo.com,,,,,,,,,302,221,,DUN,,,true,0,,,,,,,gid,4B</item>
     </string-array>
 
+    <!-- Values for GPS configuration (Telus) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.telusmobility.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 5e7e8bc..05265c7 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -43,4 +43,23 @@
         <item>302780</item>
     </string-array>
 
+  <!-- Values for GPS configuration (Rogers) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</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-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 81cec96..0af2c39 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -27,4 +27,22 @@
     -->
     <integer name="config_mobile_mtu">1428</integer>
 
+    <!-- Values for GPS configuration (Bell) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
index 706570c..e005bc0 100644
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -22,4 +22,23 @@
     <string-array translatable="false" name="config_operatorConsideredNonRoaming">
         <item>302</item>
     </string-array>
+
+    <!-- Values for GPS configuration (Bell) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index dcfa5c5..7a3540a 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -45,4 +45,23 @@
         <item>302780</item>
     </string-array>
 
+  <!-- Values for GPS configuration (Rogers) -->
+    <string-array translatable="false" name="config_gpsParameters">
+        <item>SUPL_HOST=supl.google.com</item>
+        <item>SUPL_PORT=7275</item>
+        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra3grc.bin</item>
+        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra3grc.bin</item>
+        <item>NTP_SERVER=north-america.pool.ntp.org</item>
+        <item>SUPL_MODE=1</item>
+        <item>SUPL_VER=0x20000</item>
+        <item>LPP_PROFILE=2</item>
+        <item>NMEA_PROVIDER=0</item>
+        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
+        <item>ERR_ESTIMATE=0</item>
+        <item>INTERMEDIATE_POS=0</item>
+        <item>GPS_LOCK=0</item>
+        <item>SUPL_ES=0</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 4b61688..413c698 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- If this value is true, The mms content-disposition field is supported correctly.
          If false, Content-disposition fragments are ignored -->
     <bool name="config_mms_content_disposition_support">false</bool>
diff --git a/core/res/res/values-mcc310-mnc160/config.xml b/core/res/res/values-mcc310-mnc160/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc160/config.xml
+++ b/core/res/res/values-mcc310-mnc160/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc200/config.xml b/core/res/res/values-mcc310-mnc200/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc200/config.xml
+++ b/core/res/res/values-mcc310-mnc200/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc210/config.xml b/core/res/res/values-mcc310-mnc210/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc210/config.xml
+++ b/core/res/res/values-mcc310-mnc210/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc220/config.xml b/core/res/res/values-mcc310-mnc220/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc220/config.xml
+++ b/core/res/res/values-mcc310-mnc220/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc230/config.xml b/core/res/res/values-mcc310-mnc230/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc230/config.xml
+++ b/core/res/res/values-mcc310-mnc230/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc240/config.xml b/core/res/res/values-mcc310-mnc240/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc240/config.xml
+++ b/core/res/res/values-mcc310-mnc240/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc250/config.xml b/core/res/res/values-mcc310-mnc250/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc250/config.xml
+++ b/core/res/res/values-mcc310-mnc250/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc270/config.xml b/core/res/res/values-mcc310-mnc270/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc270/config.xml
+++ b/core/res/res/values-mcc310-mnc270/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc300/config.xml b/core/res/res/values-mcc310-mnc300/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc300/config.xml
+++ b/core/res/res/values-mcc310-mnc300/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc310/config.xml b/core/res/res/values-mcc310-mnc310/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc310/config.xml
+++ b/core/res/res/values-mcc310-mnc310/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index cddd5e3..9accdf0 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -67,7 +67,4 @@
         <item>"#8"</item>
         <item>"#9"</item>
     </string-array>
-    <!-- Flag indicating whether radio is to be restarted on the error of
-         PDP_FAIL_REGULAR_DEACTIVATION/0x24 -->
-    <bool name="config_restart_radio_on_pdp_fail_regular_deactivation">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc490/config.xml b/core/res/res/values-mcc310-mnc490/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc490/config.xml
+++ b/core/res/res/values-mcc310-mnc490/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc530/config.xml b/core/res/res/values-mcc310-mnc530/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc530/config.xml
+++ b/core/res/res/values-mcc310-mnc530/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc580/config.xml b/core/res/res/values-mcc310-mnc580/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc580/config.xml
+++ b/core/res/res/values-mcc310-mnc580/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc590/config.xml b/core/res/res/values-mcc310-mnc590/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc590/config.xml
+++ b/core/res/res/values-mcc310-mnc590/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc640/config.xml b/core/res/res/values-mcc310-mnc640/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc640/config.xml
+++ b/core/res/res/values-mcc310-mnc640/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc660/config.xml b/core/res/res/values-mcc310-mnc660/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc660/config.xml
+++ b/core/res/res/values-mcc310-mnc660/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc800/config.xml b/core/res/res/values-mcc310-mnc800/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc800/config.xml
+++ b/core/res/res/values-mcc310-mnc800/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</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 -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc220/config.xml b/core/res/res/values-mcc311-mnc220/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc220/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc221/config.xml b/core/res/res/values-mcc311-mnc221/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc221/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc222/config.xml b/core/res/res/values-mcc311-mnc222/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc222/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc223/config.xml b/core/res/res/values-mcc311-mnc223/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc223/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc224/config.xml b/core/res/res/values-mcc311-mnc224/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc224/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc225/config.xml b/core/res/res/values-mcc311-mnc225/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc225/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc226/config.xml b/core/res/res/values-mcc311-mnc226/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc226/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc227/config.xml b/core/res/res/values-mcc311-mnc227/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc227/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc228/config.xml b/core/res/res/values-mcc311-mnc228/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc228/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc229/config.xml b/core/res/res/values-mcc311-mnc229/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc229/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 39ea2bf..714b312 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -52,11 +52,6 @@
     <bool name="config_carrier_volte_provisioned">true</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
-    <!-- service number convert map in roaming network. -->
-    <string-array translatable="false" name="dial_string_replace">
-        <item>"*611:+19085594899,"</item>
-        <item>"*86:+1MDN,"</item>
-    </string-array>
 
     <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
           when evaluating RSRP for LTE antenna bar display
@@ -69,4 +64,5 @@
         <item>true</item>
     </string-array>
     <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
+
 </resources>
diff --git a/core/res/res/values-mcc311-mnc490/config.xml b/core/res/res/values-mcc311-mnc490/config.xml
index d481c97..836abdf 100644
--- a/core/res/res/values-mcc311-mnc490/config.xml
+++ b/core/res/res/values-mcc311-mnc490/config.xml
@@ -21,9 +21,6 @@
      for different hardware and product builds. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values-mcc311-mnc580/config.xml b/core/res/res/values-mcc311-mnc580/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc580/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc581/config.xml b/core/res/res/values-mcc311-mnc581/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc581/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc582/config.xml b/core/res/res/values-mcc311-mnc582/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc582/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc583/config.xml b/core/res/res/values-mcc311-mnc583/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc583/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc584/config.xml b/core/res/res/values-mcc311-mnc584/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc584/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc585/config.xml b/core/res/res/values-mcc311-mnc585/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc585/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc586/config.xml b/core/res/res/values-mcc311-mnc586/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc586/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc587/config.xml b/core/res/res/values-mcc311-mnc587/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc587/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc588/config.xml b/core/res/res/values-mcc311-mnc588/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc588/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc589/config.xml b/core/res/res/values-mcc311-mnc589/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc589/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc870/config.xml b/core/res/res/values-mcc311-mnc870/config.xml
index 98cb72e..f6aed13 100644
--- a/core/res/res/values-mcc311-mnc870/config.xml
+++ b/core/res/res/values-mcc311-mnc870/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values-mcc312-mnc530/config.xml b/core/res/res/values-mcc312-mnc530/config.xml
index 98cb72e..f6aed13 100644
--- a/core/res/res/values-mcc312-mnc530/config.xml
+++ b/core/res/res/values-mcc312-mnc530/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values-mcc722-mnc36/config.xml b/core/res/res/values-mcc722-mnc36/config.xml
new file mode 100644
index 0000000..daf5373
--- /dev/null
+++ b/core/res/res/values-mcc722-mnc36/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 my 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>72234</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 875849a..3f228203 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефон"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Заклучи екран"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Исклучи"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Итен случај"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај за грешка"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема пристап на интернет"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобилен интернет"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Етернет"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мрежа"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Се подготвува <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Се проверува за грешки"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Откриена е нова <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"Секогаш вклучената VPN е неповрзана"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка на секогаш вклучена VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Допрете за конфигурирање"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Допрете за да поставите"</string>
     <string name="upload_file" msgid="2897957172366730416">"Избери датотека"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не е избрана датотека"</string>
     <string name="reset" msgid="2448168080964209908">"Ресетирај"</string>
@@ -1319,7 +1331,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> УСБ-меморија"</string>
     <string name="storage_usb" msgid="3017954059538517278">"УСБ меморија"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Уреди"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Опомена за потрошен интернет"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Известување за потрошен сообраќај"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Допрете за употреба и поставки."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Постигна лимит за 2G-3G податоци"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Постигнат лимит за 4G податоци"</string>
@@ -1629,6 +1641,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> е избрана</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Разно"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ја поставивте важноста на известувањава."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволувате ли <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1638,6 +1651,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Сите јазици"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Сите региони"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Пребарај"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Режимот на работа е ИСКЛУЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозволете работниот профил да функционира, вклучувајќи ги апликациите, синхронизирањето во заднина и други поврзани функции."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index e914a8c..beb6a67 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ഫോൺ ഓപ്‌ഷനുകൾ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"സ്‌ക്രീൻ ലോക്ക്"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"പവർ ഓഫാക്കുക"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"അടിയന്തിരാവശ്യം"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ബഗ് റിപ്പോർട്ട് എടുക്കുക"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-യിൽ ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്‌വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിലേക്ക് മാറി"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"സെല്ലുലാർ ഡാറ്റ"</item>
+    <item msgid="75483255295529161">"വൈഫൈ"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"ഇതര്‍നെറ്റ്"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്‌വർക്ക് തരം"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> തയ്യാറാകുന്നു"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"പിശകുകളുണ്ടോയെന്നു പരിശോധിക്കുന്നു"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"പുതിയ <xliff:g id="NAME">%s</xliff:g> എന്നതിനെ തിരിച്ചറിഞ്ഞു"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"\'എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN\' വിച്ഛേദിച്ചു"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"എല്ലായ്‌പ്പോഴും ഓണായിരിക്കുന്ന VPN പിശക്"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"കോൺഫിഗർ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക"</string>
     <string name="upload_file" msgid="2897957172366730416">"ഫയല്‍‌ തിരഞ്ഞെടുക്കുക"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ഫയലൊന്നും തിരഞ്ഞെടുത്തില്ല"</string>
     <string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ഡ്രൈവ്"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB സ്റ്റോറേജ്"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"എഡിറ്റുചെയ്യുക"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ഡാറ്റ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ഡാറ്റാ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ഉപയോഗവും ക്രമീകരണവും കാണാൻ ടാപ്പുചെയ്യുക."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ഡാറ്റ പരിധിയിലെത്തി"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ഡാറ്റ പരിധിയിലെത്തി"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> തിരഞ്ഞെടുത്തു</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"പലവക"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയൊരു ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്ന ആപ്പിനെ അനുവദിക്കണോ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"എല്ലാ ഭാഷകളും"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"എല്ലാ പ്രദേശങ്ങളും"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"തിരയുക"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"ഔദ്യോഗിക മോഡ് ഓഫാണ്"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ആപ്സും, പശ്ചാത്തല സമന്വയവും ബന്ധപ്പെട്ട ഫീച്ചറുകളും ഉൾപ്പെടെ, ഔദ്യോഗിക പ്രൊഫൈലിനെ പ്രവർത്തിക്കാൻ അനുവദിക്കുക."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 80a2b32..bd80f84 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Утасны сонголтууд"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Дэлгэцний түгжээ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Унтраах"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Яаралтай тусламж"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Алдаа мэдээллэх"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Согог репорт авах"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-д интернет холболт байхгүй байна"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернэт холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобайл дата"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Этернэт"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"сүлжээний тодорхойгүй төрөл"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ыг бэлдэж байна"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Алдааг шалгаж байна"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Шинэ <xliff:g id="NAME">%s</xliff:g> илэрлээ"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"Тогтмол асаалттай VPN салсан"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Байнгын VPN алдаа"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Тохируулахын тулд товшино уу"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Тохируулахын тулд товшино уу"</string>
     <string name="upload_file" msgid="2897957172366730416">"Файл сонгох"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Сонгосон файл байхгүй"</string>
     <string name="reset" msgid="2448168080964209908">"Бүгдийг цэвэрлэх"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB сан"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Засах"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Дата хэрэглээний анхааруулга"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Дата ашиглалтын сануулга"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Хэрэглээ, тохиргоог харах бол товш."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дата хязгаарт хүрсэн"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дата хязгаарт хүрсэн"</string>
@@ -1625,6 +1637,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> сонгосон</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Бусад"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g>-г <xliff:g id="ACCOUNT">%2$s</xliff:g>-р шинэ Хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
@@ -1634,6 +1647,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Бүх хэл"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Бүх бүс нутаг"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Хайх"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Ажлын горимыг УНТРААСАН байна"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ажлын профайлд апп, дэвсгэр синхрончлол болон бусад холбоотой тохиргоог ажиллахыг зөвшөөрнө үү."</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 67b0a1c..f0e437a 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन पर्याय"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"बंद"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"आणीबाणी"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"दोष अहवाल"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"दोष अहवाल घ्या"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे आपल्या वर्तमान डिव्हाइस स्थितीविषयी माहिती संकलित करेल. दोष अहवाल प्रारंभ करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फाय मध्‍ये इंटरनेट प्रवेश नाही"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट प्रवेश नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरतो. शुल्क लागू शकतील."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"मोबाइल डेटा"</item>
+    <item msgid="75483255295529161">"वाय-फाय"</item>
+    <item msgid="6862614801537202646">"ब्लूटुथ"</item>
+    <item msgid="5447331121797802871">"इथरनेट"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"नेहमी-चालू असलेले VPN डिस्कनेक्ट केले"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN त्रुटी नेहमी-चालू"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फिगर करण्यासाठी टॅप करा"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करण्यासाठी टॅप करा"</string>
     <string name="upload_file" msgid="2897957172366730416">"फाईल निवडा"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"फाईल निवडली नाही"</string>
     <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइव्‍ह"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB संचयन"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करा"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटा वापर चेतावणी"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा वापर सूचना"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"वापर आणि सेटिंग्ज पाहण्यासाठी टॅप करा."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा मर्यादा गाठली"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा मर्यादा गाठली"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडला</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"संकीर्ण"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"आपण या सूचनांचे महत्त्व सेट केले."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"सर्व भाषा"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"सर्व प्रदेश"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"शोध"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद आहे"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"कार्य प्रोफाइलला अॅप्स, पार्श्वभूमी संकालन आणि संबंधित वैशिष्ट्यांच्या समावेशासह कार्य करण्याची परवानगी द्या."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 99bd9f6..60330e5 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Pilihan telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Kunci skrin"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Kecemasan"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tiada akses Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"data selular"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis rangkaian tidak diketahui"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyediakan <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Menyemak untuk mengesan ralat"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baharu dikesan"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Bersambung kepada <xliff:g id="SESSION">%s</xliff:g>. Ketik untuk mengurus rangkaian."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sentiasa hidup diputuskan sambungannya"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketik untuk membuat konfigurasi"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketik untuk menyediakan"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pemacu USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Amaran penggunaan data"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Makluman penggunaan data"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Ketik utk lihat p\'gunaan &amp; ttpn."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Mencapai had data 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Mencapai had data 4G"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Pelbagai"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Anda menetapkan kepentingan pemberitahuan ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Semua rantau"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Cari"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Mod kerja DIMATIKAN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Benarkan profil kerja berfungsi, termasuk apl, penyegerakan latar belakang dan ciri yang berkaitan."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 07394ef..c18ff7f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ဖုန်းဆိုင်ရာရွေးချယ်မှုများ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ဖုန်းမျက်နှာပြင်အား သော့ချရန်"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ပါဝါပိတ်ရန်"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"အရေးပေါ်"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်း"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းအား ယူရန်"</string>
     <string name="bugreport_message" msgid="398447048750350456">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"ဝိုင်-ဖို်ငတွင် အင်တာနက် ဝင်ရောက်သုံးခွင့် မရှိပါ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"စက်ပစ္စည်းသည် <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ဆယ်လူလာဒေတာ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"ဘလူးတုသ်"</item>
+    <item msgid="5447331121797802871">"အီသာနက်"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ပြင်ဆင်နေသည်"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"အမှားအယွင်းများ စစ်ဆေးနေသည်"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> အသစ်တွေ့ရှိပါသည်"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"အမြဲတမ်းဖွင့်ထားရသော VPN ပြတ်တောက်နေသည်"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"အမြဲတမ်းဖွင့်ထား VPN အမှား"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string>
     <string name="upload_file" msgid="2897957172366730416">"ဖိုင်ရွေးချယ်ရန်"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"မည်သည့်ဖိုင်ကိုမှမရွေးပါ"</string>
     <string name="reset" msgid="2448168080964209908">"ပြန်လည်သတ်မှတ်ရန်"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ဒရိုက်ဗ်"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USBဖြင့် သိမ်းဆည်း"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ပြင်ဆင်ရန်"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"အသုံးပြုမှုနှင့် ဆက်တင်များကိုကြည့်ရန် တို့ပါ။"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"အထွေထွေ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ကို <xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ဖန်တီးခွင့်ပြုမလား။"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ဘာသာစကားများအားလုံး"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ဒေသအားလုံး"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ရှာဖွေရန်"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"အလုပ်မုဒ် ပိတ်ထားသည်"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"အက်ပ်များ၊ နောက်ခံစင့်ခ်လုပ်ခြင်း၊ နှင့်သက်ဆိုင်သည့်အင်္ဂါရပ်များကို ဆောင်ရွက်ရန် အလုပ်ပရိုဖိုင်ကိုခွင့်ပြုပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 5c65e0d..9ff7803 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødssituasjon"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi har ikke Internett-tilgang"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobildata"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukjent nettverkstype"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
-    <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sjekker for feil"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> ble oppdaget"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Alltid-på VPN kobler til ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Alltid-på VPN er tilkoblet"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alltid på-VPN er frakoblet"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alltid-på VPN-feil"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trykk for å konfigurere"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trykk for å konfigurere"</string>
     <string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
     <string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-stasjon"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Advarsel for høyt dataforbruk"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varsel om databruk"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trykk for å se bruken og innstillingene."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagrensen for 2G-3G er nådd"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagrensen for 4G er nådd"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diverse"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du angir viktigheten for disse varslene."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle språk"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Søk"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Jobbmodus er AV"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Slå på jobbprofilen, inkludert apper, synkronisering i bakgrunnen og relaterte funksjoner."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index c5ad97a..e039927 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"फोन विकल्पहरू"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"स्क्रिन बन्द"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"बन्द गर्नुहोस्"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"आपतकालीन"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
     <string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
@@ -255,7 +256,7 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"माइक्रोफोन"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"अडियो रेकर्ड गर्नुहोस्"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"क्यामेरा"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुहोस् तथा भिडियो रेकर्ड गर्नुहोस्"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"तस्बिर खिच्नुका साथै भिडियो रेकर्ड गर्नुहोस्"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"फोन"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"शारीरिक सेन्सर"</string>
@@ -1082,6 +1083,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi मा इन्टरनेट पहुँच छैन"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मा इन्टरनेट माथिको पहुँच नहुँदा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> को प्रयोग गर्दछ। शुल्कहरू लागू हुन सक्छन्।"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"सेलुलर डेटा"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"ब्लुटुथ"</item>
+    <item msgid="5447331121797802871">"इथरनेट"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
@@ -1159,7 +1171,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string>
@@ -1238,8 +1249,9 @@
     <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_disconnected" msgid="4532298952570796327">"सधैँ-सक्रिय VPN लाई विच्छेद गरियो"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"सधैँ भरि VPN त्रुटिमा"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"कन्फिगर गर्न ट्याप गर्नुहोस्"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट अप गर्न ट्याप गर्नुहोस्"</string>
     <string name="upload_file" msgid="2897957172366730416">"फाइल छान्नुहोस्"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"कुनै फाइल छानिएको छैन"</string>
     <string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string>
@@ -1323,7 +1335,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइभ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB भण्डारण"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"सम्पादन गर्नुहोस्"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"डेटाको प्रयोग चेतावनी"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा प्रयोग बारे सतर्कता"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"प्रयोग र सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पुग्यो"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पुग्यो"</string>
@@ -1633,6 +1645,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयन गरियो</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"विविध"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहोस् ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
@@ -1642,6 +1655,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"सम्पूर्ण भाषाहरू"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"सबै क्षेत्रहरू"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"खोज"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बन्द छ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"अनुप्रयोग, पृष्ठभूमि सिंक र सम्बन्धित विशेषताहरू सहित, कार्य प्रोफाइललाई कार्य गर्न अनुमति दिनुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 35ec37f..8e42bbc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoonopties"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutenrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Foutenrapport genereren"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een foutenrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wifi-netwerk heeft geen internettoegang"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobiele data"</item>
+    <item msgid="75483255295529161">"Wifi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"een onbekend netwerktype"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> voorbereiden"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Controleren op fouten"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nieuwe <xliff:g id="NAME">%s</xliff:g> gedetecteerd"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN-verbinding maken…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN-verbinding"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN-verbinding ontkoppeld"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fout met Always-on VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om te configureren"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om in te stellen"</string>
     <string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string>
     <string name="reset" msgid="2448168080964209908">"Resetten"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-drive"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Bewerken"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Waarschuwing v. gegevensgebruik"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Melding voor datagebruik"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diversen"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Je stelt het belang van deze meldingen in."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alle talen"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alle regio\'s"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Zoeken"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is UIT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Functioneren van werkprofiel toestaan, waaronder apps, synchronisatie op de achtergrond en gerelateerde functies."</string>
diff --git a/core/res/res/values-notround-watch/dimens.xml b/core/res/res/values-notround-watch/dimens.xml
index f103aa9..f0204d0 100644
--- a/core/res/res/values-notround-watch/dimens.xml
+++ b/core/res/res/values-notround-watch/dimens.xml
@@ -24,4 +24,5 @@
     <item name="input_extract_action_margin_bottom" type="fraction">0%</item>
     <item name="input_extract_action_button_width" type="dimen">24dp</item>
     <item name="input_extract_action_button_height" type="dimen">24dp</item>
+    <item name="input_extract_action_icon_padding" type="dimen">3dp</item>
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index a18fbaa..d3476aa 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ਫੋਨ ਚੋਣਾਂ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ਪਾਵਰ ਬੰਦ"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"ਸੰਕਟਕਾਲ"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ਬਗ ਰਿਪੋਰਟ ਲਓ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ਇਹ ਇੱਕ ਈ-ਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੀ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਤਰ ਕਰੇਗਾ। ਬਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
@@ -362,7 +363,7 @@
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"ਐਪ ਨੂੰ ਤੁਹਾਡਾ ਅਨੁਮਾਨਿਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਨੈੱਟਵਰਕ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸਰੋਤ ਵਰਤਦੇ ਹੋਏ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਰਾਹੀਂ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜਿਵੇਂ ਸੈਲ ਟਾਵਰ ਅਤੇ Wi-Fi. ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਚਾਲੂ ਅਤੇ ਐਪ ਨੂੰ ਉਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਤੇ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਐਪਸ ਇਸਦੀ ਵਰਤੋਂ ਇਹ ਅਨੁਮਾਨ ਲਗਾਉਣ ਲਈ ਕਰ ਸਕਦੇ ਹਨ ਕਿ ਤੁਸੀਂ ਕਿੱਥੇ ਹੋ।"</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ਆਪਣੀਆਂ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ਔਪ ਨੂੰ ਗਲੋਬਲ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਵੌਲਿਊਮ ਅਤੇ ਆਊਟਪੁਟ ਲਈ ਕਿਹੜਾ ਸਪੀਕਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।"</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"ਐਪ ਨੂੰ ਮਾਈਕ੍ਰੋਫੋਨ ਨਾਲ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ਦੀ ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"ਸੈਲਿਊਲਰ ਡੈਟਾ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"ਬਲੂਟੁੱਥ"</item>
+    <item msgid="5447331121797802871">"ਈਥਰਨੈੱਟ"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ਇਸਦਾ ਇੱਕ ਖ਼ਰਾਬ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਹੈ।"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਅਸ਼ੁੱਧੀ"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"ਸੰਰੂਪਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="upload_file" msgid="2897957172366730416">"ਫਾਈਲ ਚੁਣੋ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ਕੋਈ ਫਾਈਲ ਨਹੀਂ ਚੁਣੀ ਗਈ"</string>
     <string name="reset" msgid="2448168080964209908">"ਰੀਸੈੱਟ ਕਰੋ"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ਡ੍ਰਾਇਵ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB ਸਟੋਰੇਜ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ਸੰਪਾਦਿਤ ਕਰੋ"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ਡੈਟਾ ਉਪਯੋਗ ਚਿਤਾਵਨੀ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ਡੈਟਾ ਵਰਤੋਂ ਚੇਤਾਵਨੀ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"ਫੁਟਕਲ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਮਨਜ਼ੂਰੀ ਦੇਣੀ ਹੈ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ਸਾਰੇ ਖੇਤਰ"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ਖੋਜ"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"ਐਪਾਂ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਮਕਾਲੀਕਰਨ, ਅਤੇ ਸਬੰਧਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋਏ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਕੰਮ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e7d61e2..a7571ef 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opcje telefonu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Alarmowy"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieć Wi-Fi nie ma dostępu do internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"komórkowa transmisja danych"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nieznany typ sieci"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Przygotowuję: <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sprawdzanie w poszukiwaniu błędów"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Wykryto nowy nośnik: <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Nawiązano połączenie: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Łączę ze stałą siecią VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Połączono ze stałą siecią VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rozłączono ze stałą siecią VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Błąd stałej sieci VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Kliknij, by skonfigurować"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Kliknij, by skonfigurować"</string>
     <string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string>
     <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Dysk USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Edytuj"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Ostrzeżenie o transmisji danych"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert transmisji danych"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kliknij, by wyświetlić użycie i ustawienia."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Osiągnięto limit danych 2G/3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Osiągnięto limit danych 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="other">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Inne"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ustawiłeś ważność tych powiadomień."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Zezwalasz aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Wszystkie języki"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Wszystkie kraje"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Szukaj"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Tryb pracy jest WYŁĄCZONY"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Włącz profil do pracy, w tym aplikacje, synchronizację w tle i inne funkcje."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 94fda0d..24265ee 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"dados da rede celular"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diversos"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4c6f29f..6270210 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem ser aplicados custos."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"dados móveis"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"A preparar o <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"A verificar a presença de erros"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detetado"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"A ligar VPN sempre ativa..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa ligada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desligada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro da VPN sempre ativa"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
     <string name="reset" msgid="2448168080964209908">"Repor"</string>
@@ -1310,14 +1322,14 @@
     <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>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso de utilização de dados"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de utilização de dados"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver a utilização e definições"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G/3G atingido"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diversos"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Definiu a importância destas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir o funcionamento do perfil de trabalho, incluindo as aplicações, a sincronização em segundo plano e as funcionalidades relacionadas."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 94fda0d..24265ee 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"O Wi-Fi não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Cobranças podem ser aplicadas."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"dados da rede celular"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Aviso sobre uso de dados"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diversos"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2223730..29c0a59 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgență"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
@@ -1101,6 +1102,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Rețeaua Wi-Fi nu are acces la internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"date mobile"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tip de rețea necunoscut"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
@@ -1178,7 +1190,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1257,8 +1268,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Apăsați pentru a gestiona rețeaua."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rețeaua VPN activată permanent a fost deconectată"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Atingeți ca să configurați"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Atingeți pentru a configura"</string>
     <string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
     <string name="reset" msgid="2448168080964209908">"Resetați"</string>
@@ -1343,7 +1355,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitate USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alertă pentru utilizarea datelor"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Atingeți ca să vedeți utilizarea/setările."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string>
@@ -1663,6 +1675,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diverse"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Dvs. setați importanța acestor notificări."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1672,6 +1685,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Toate limbile"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Toate regiunile"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Căutați"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modul de serviciu e DEZACTIVAT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Permiteți profilului de serviciu să funcționeze, inclusiv aplicațiile, sincronizarea în fundal și funcțiile asociate."</string>
diff --git a/core/res/res/values-round-watch/config_material.xml b/core/res/res/values-round-watch/config_material.xml
index 871e910..1179870 100644
--- a/core/res/res/values-round-watch/config_material.xml
+++ b/core/res/res/values-round-watch/config_material.xml
@@ -22,4 +22,7 @@
 
     <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.TOP -->
     <integer name="config_dialogTextGravity">0x00000031</integer>
+
+    <!-- The amount to offset when scrolling to a selection in an AlertDialog -->
+    <dimen name="config_alertDialogSelectionScrollOffset">@dimen/screen_percentage_15</dimen>
 </resources>
diff --git a/core/res/res/values-round-watch/dimens.xml b/core/res/res/values-round-watch/dimens.xml
index a12f499..1d8c669 100644
--- a/core/res/res/values-round-watch/dimens.xml
+++ b/core/res/res/values-round-watch/dimens.xml
@@ -24,4 +24,5 @@
     <item name="input_extract_action_margin_bottom" type="fraction">2.1%</item>
     <item name="input_extract_action_button_width" type="dimen">32dp</item>
     <item name="input_extract_action_button_height" type="dimen">32dp</item>
+    <item name="input_extract_action_icon_padding" type="dimen">5dp</item>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8f1d260..ed6c798 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры телефона"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Экстренный вызов"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Сеть Wi-Fi не подключена к Интернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобильные данные"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестный тип сети"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Подготовка карты \"<xliff:g id="NAME">%s</xliff:g>\"…"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Поиск ошибок"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Обнаружена новая карта \"<xliff:g id="NAME">%s</xliff:g>\""</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Подключено: \"<xliff:g id="SESSION">%s</xliff:g>\". Нажмите здесь, чтобы изменить настройки сети."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Отключено"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Нажмите, чтобы настроить."</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Нажмите, чтобы настроить"</string>
     <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Сбросить"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-накопитель <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Изменить"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Осталось мало трафика"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Лимит на передачу данных"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Нажмите, чтобы проверить трафик и настройки."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнут лимит трафика 2G/3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнут лимит трафика 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="many">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Другое"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Вы определяете важность этих уведомлений."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать пользователя для аккаунта <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Все языки"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Все регионы"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Поиск"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Рабочий режим отключен"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Включить рабочий профиль: приложения, фоновую синхронизацию и связанные функции."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index e04834c..91d5bbe 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"දුරකථන විකල්ප"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"තිර අගුල"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"බලය අක්‍රිය කරන්න"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
@@ -1078,6 +1079,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi හට අන්තර්ජාල ප්‍රවේශය නැත"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්‍රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"සෙලියුලර් දත්ත"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"බ්ලූටූත්"</item>
+    <item msgid="5447331121797802871">"ඊතර්නෙට්"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"නොදන්නා ජාල වර්ගයකි"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
@@ -1155,7 +1167,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> සූදානම් කරමින්"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"වැරදි සඳහා පරීක්ෂා කරමින්"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"නව <xliff:g id="NAME">%s</xliff:g> අනාවරණය කරන ලදි"</string>
@@ -1234,8 +1245,9 @@
     <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_disconnected" msgid="4532298952570796327">"සැමවිට ක්‍රියාත්මක VPN විසන්ධි කරන ලදී"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"සැමවිට සක්‍රිය VPN දෝෂය"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"වින්‍යාස කිරීමට තට්ටු කරන්න"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"පිහිටුවීමට තට්ටු කරන්න"</string>
     <string name="upload_file" msgid="2897957172366730416">"ගොනුව තෝරන්න"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ගොනුවක් තෝරාගෙන නැත"</string>
     <string name="reset" msgid="2448168080964209908">"යළි පිහිටුවන්න"</string>
@@ -1319,7 +1331,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"දත්ත භාවිතා අවවාදය"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"දත්ත භාවිතය ගැන ඇඟවීම"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G දත්ත සීමාවට ළඟාවී ඇත"</string>
@@ -1629,6 +1641,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"විවිධ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද?"</string>
@@ -1638,6 +1651,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"සියලු භාෂා"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"සියලු ප්‍රදේශ"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"සෙවීම"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"වැඩ ප්‍රකාරය ක්‍රියාවිරහිතයි"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"යෙදුම්, පසුබිම සමමුහුර්ත කිරීම, සහ සම්බන්ධිත විශේෂාංග ඇතුළුව, ක්‍රියා කිරීමට කාර්යාල පැතිකඩට ඉඩ දෙන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3e2e21a..5c129af 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Tiesňové volanie"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Sieť Wi-Fi nemá prístup k internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Keď sieť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa sieť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobilné dáta"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámy typ siete"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravuje sa úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Prebieha kontrola chýb"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Bolo zistené nové úložisko <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po klepnutí môžete sieť spravovať."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Pripájanie k vždy zapnutej sieti VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vždy zapnutá sieť VPN bola odpojená"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím spustíte konfiguráciu"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím prejdete do Nastavení"</string>
     <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
     <string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Disk USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Upraviť"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozornenie o využití dát"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornenie na spotrebu dát"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte využitie a nastavenia."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Bol dosiahnutý limit 2G–3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Bol dosiahnutý limit 4G"</string>
@@ -1664,7 +1676,7 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ďalší budík)"</string>
-    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kým túto funkciu nevypnete"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dokým nevypnete stav Nerušiť"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Zbaliť"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="other">Vybrané: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Vybrané: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Rôzne"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Nastavili ste dôležitosť týchto upozornení."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Všetky jazyky"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Všetky regióny"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Vyhľadávanie"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovný režim je VYPNUTÝ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Povoľte fungovanie pracovného profilu vrátane aplikácií, synchronizácie na pozadí a súvisiacich funkcií."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 25df17f..76f1e66 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefona"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Zaklep zaslona"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Izklopi"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Klic v sili"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
     <string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Omrežje Wi-Fi nima dostopa do interneta"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna posebej."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"prenos podatkov v mobilnih omrežjih"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznana vrsta omrežja"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravljanje shrambe <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Iskanje napak"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zaznana je bila nova shramba <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1282,8 +1293,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Povezan z mestom <xliff:g id="SESSION">%s</xliff:g>. Tapnite za upravljanje omrežja."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Povezava s stalno vklopljenim VPN-jem je prekinjena"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dotanite se, če želite konfigurirati"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dotaknite se, če želite nastaviti"</string>
     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
     <string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Pogon USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Opozorilo o uporabi podatkov"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Opozorilo o preneseni količini podatkov"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Dot. se za ogled upor. in nast."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosežena pod. omejitev za 2G/3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosežena pod. omejitev za 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrani</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Razno"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi določite raven pomembnosti teh obvestil."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Dovolite, da aplikacija <xliff:g id="APP">%1$s</xliff:g> ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Vsi jeziki"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Vse regije"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Išči"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Delovni način IZKLOPLJEN"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Dovoljeno delovanje delovnega profila, vključno z aplikacijami, sinhronizacijo v ozadju in povezanimi funkcijami."</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index fa88470..0fb3ebe 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opsionet e telefonit"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Kyçja e ekranit"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Fik"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Urgjenca"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nuk ka qasje në internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"të dhënat celulare"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Eternet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"një lloj rrjeti i panjohur"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nuk mund të lidhej me Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ka një lidhje të dobët interneti."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Të lejohet lidhja?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Po përgatit <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Po kontrollon për gabime"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"U zbulua karta e re <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Lidhur me <xliff:g id="SESSION">%s</xliff:g>. Trokit për të menaxhuar rrjetin."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Po lidh VPN-në për aktivizim të përhershëm…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN e lidhur në mënyrë të përhershme"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rrjeti VPN gjithmonë aktiv u shkëput"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Gabimi VPN-je për aktivizimin e përhershëm"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trokit për të konfiguruar"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trokit për ta konfiguruar"</string>
     <string name="upload_file" msgid="2897957172366730416">"Zgjidh skedarin"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nuk u zgjodh asnjë skedar"</string>
     <string name="reset" msgid="2448168080964209908">"Rivendos"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-ja nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Hapësira ruajtëse e USB-së"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redakto"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Paralajmërim për përdorimin e të dhënave"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Sinjalizimi i të dhënave"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trokit për të parë përdorimin dhe cilësimet."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kufiri i të dhënave 2G-3G u arrit"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kufiri i të dhënave 4G u arrit"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> të zgjedhura</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Të ndryshme"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Dëshiron të lejosh <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Të gjitha gjuhët"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Të gjitha rajonet"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Kërko"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Modaliteti i punës është JOAKTIV"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Lejoje profilin e punës të funksionojë, duke përfshirë aplikacionet, sinkronizimin në sfond dhe funksionet e lidhura."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 634a0af..6e99a9b 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -216,6 +216,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Опције телефона"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Закључај екран"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Искључи"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Хитни позив"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај о грешци"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
@@ -256,9 +257,9 @@
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
@@ -1101,6 +1102,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi нема приступ интернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобилни подаци"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Етернет"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мреже"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
@@ -1172,13 +1184,12 @@
     <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
     <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
-    <string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
+    <string name="show_ime" msgid="2506087537466597099">"Задржи је на екрану док је физичка тастатура активна"</string>
     <string name="hardware" msgid="194658061510127999">"Прикажи виртуелну тастатуру"</string>
     <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Конфигуришите физичку тастатуру"</string>
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> се припрема"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверава се да ли постоје грешке"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Нови уређај <xliff:g id="NAME">%s</xliff:g> је откривен"</string>
@@ -1257,8 +1268,9 @@
     <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_disconnected" msgid="4532298952570796327">"Веза са стално укљученим VPN-ом је прекинута"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Додирните да бисте конфигурисали"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Додирните да бисте подесили"</string>
     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
     <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
@@ -1343,7 +1355,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Измени"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Упозорење о потрошњи података"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Обавештење о потрошњи података"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Додирните за потрошњу и подешавања."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Нема више 2G-3G података"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string>
@@ -1663,6 +1675,7 @@
       <item quantity="few">Изабране су <xliff:g id="COUNT_1">%1$d</xliff:g> ставке</item>
       <item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Разно"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ви подешавате важност ових обавештења."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Желите ли да дозволите апликацији <xliff:g id="APP">%1$s</xliff:g> да направи новог корисника за <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1672,6 +1685,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Сви језици"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Сви региони"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Претражи"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Режим за Work је ИСКЉУЧЕН"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Дозвољава профилу за Work да функционише, укључујући апликације, синхронизацију у позадини и сродне функције."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f5bcaf2..66f085f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonalternativ"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Nödsituation"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
@@ -671,7 +672,7 @@
     <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen tjänst"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Menu om du vill låsa upp eller ringa nödsamtal."</string>
-    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu om du vill låsa upp."</string>
+    <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu för att låsa upp."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rita grafiskt lösenord för att låsa upp"</string>
     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Nödsamtal"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Tillbaka till samtal"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi-nätverket är inte anslutet till internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobildata"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en okänd nätverkstyp"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Förbereder ditt <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Söker efter fel"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nytt <xliff:g id="NAME">%s</xliff:g> har hittats"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt för att hantera nätverket."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ansluter till Always-on VPN ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ansluten till Always-on VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN har kopplats från"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fel på Always-on VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryck om du vill konfigurera"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryck för att konfigurera"</string>
     <string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string>
     <string name="reset" msgid="2448168080964209908">"Återställ"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-enhet (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigera"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Varning angående dataanvändning"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Varning – dataanvändning"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Visa användning och inställning."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagränsen för 2G-3G har uppnåtts"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagränsen för 4G har uppnåtts"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Diverse"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du anger hur viktiga aviseringarna är."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Alla språk"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Alla regioner"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Söka"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Arbetsläget är inaktiverat"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Tillåt att jobbprofilen är aktiv, inklusive appar, bakgrundssynkronisering och andra tillhörande funktioner."</string>
@@ -1643,7 +1657,7 @@
     <string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nya meddelanden"</string>
     <string name="new_sms_notification_content" msgid="7002938807812083463">"Öppna sms-appen och visa meddelandet"</string>
     <string name="user_encrypted_title" msgid="9054897468831672082">"Vissa funktioner är begränsade"</string>
-    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck om du vill låsa upp"</string>
+    <string name="user_encrypted_message" msgid="4923292604515744267">"Tryck för att låsa upp"</string>
     <string name="user_encrypted_detail" msgid="5708447464349420392">"Användaruppgifterna är låsta"</string>
     <string name="profile_encrypted_detail" msgid="3700965619978314974">"Jobbprofilen är låst"</string>
     <string name="profile_encrypted_message" msgid="6964994232310195874">"Tryck och lås upp jobbprofilen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4caabba..4832546 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -212,6 +212,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Zima"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Dharura"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
@@ -1074,6 +1075,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi haina muunganisho wa intaneti"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gonga ili upate chaguo"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina Intaneti. Huenda ukalipishwa."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"data ya simu za mkononi"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethaneti"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"aina ya mtandao isiyojulikana"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
@@ -1151,7 +1163,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inaandaa <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Inakagua hitilafu"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> mpya imegunduliwa"</string>
@@ -1230,8 +1241,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Imeunganishwa kwa <xliff:g id="SESSION">%s</xliff:g>. Gonga ili kudhibiti mtandao"</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kila mara VPN iliyowashwa inaunganishwa…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Kila mara VPN iliyowashwa imeunganishwa"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Iwe imeondoa VPN kila wakati"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kila mara kuna hitilafu ya VPN iliyowashwa"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Gonga ili uweke mipangilio"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Gonga ili uweke mipangilio"</string>
     <string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string>
     <string name="reset" msgid="2448168080964209908">"Weka upya"</string>
@@ -1315,7 +1327,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Badilisha"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Onyo la matumizi ya data"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Tahadhari ya matumizi ya data"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Gonga ili uangalie matumizi na mipangilio."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kikomo data ya 2G-3G kimefikiwa"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kikomo cha data ya 4G kimefikiwa"</string>
@@ -1625,6 +1637,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> vimechaguliwa</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Mengineyo"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iunde Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1634,6 +1647,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Lugha zote"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Maeneo yote"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Tafuta"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Hali ya kazi IMEZIMWA"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ruhusu wasifu wa kazini utumike, ikiwa ni pamoja na programu, usawazishaji wa chini chini na vipengele vinavyohusiana."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 48a1d5d..f6bb25c 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"தொலைபேசி விருப்பங்கள்"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"திரைப் பூட்டு"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"முடக்கு"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"அவசர அழைப்பு"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"பிழை அறிக்கை"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"பிழை அறிக்கையை எடு"</string>
     <string name="bugreport_message" msgid="398447048750350456">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"வைஃபை இணைய அணுகல் கொண்டிருக்கவில்லை"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> இல் இணைய அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ஐப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"செல்லுலார் தரவு"</item>
+    <item msgid="75483255295529161">"வைஃபை"</item>
+    <item msgid="6862614801537202646">"புளூடூத்"</item>
+    <item msgid="5447331121797802871">"ஈத்தர்நெட்"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"தெரியாத நெட்வொர்க் வகை"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> தயாராகிறது"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"பிழைகள் உள்ளதா எனப் பார்க்கிறது"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"புதிய <xliff:g id="NAME">%s</xliff:g> கண்டறியப்பட்டது"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"எப்போதும் இயங்கும் VPN துண்டிக்கப்பட்டது"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"எப்போதும் இயங்கும் VPN பிழை"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"உள்ளமைக்க, தட்டவும்"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"அமைக்க, தட்டவும்"</string>
     <string name="upload_file" msgid="2897957172366730416">"கோப்பைத் தேர்வுசெய்"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string>
     <string name="reset" msgid="2448168080964209908">"மீட்டமை"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB டிரைவ்"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB சேமிப்பிடம்"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"திருத்து"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"தரவு பயன்பாட்டு எச்சரிக்கை"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"தரவுப் பயன்பாடு குறித்த எச்சரிக்கை"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"தரவு உபயோகம், அமைப்புகளைப் பார்க்க, தட்டவும்."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G தரவு வரம்பைக் கடந்தது"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G தரவு வரம்பைக் கடந்தது"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"மற்றவை"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g>ஐ அனுமதிக்கவா?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"எல்லா மொழிகளும்"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"எல்லா மண்டலங்களும்"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"தேடு"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 5cd75b2..24bfebd 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ఫోన్ ఎంపికలు"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"స్క్రీన్ లాక్"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"పవర్ ఆఫ్ చేయి"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"అత్యవసరం"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"బగ్ నివేదిక"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"బగ్ నివేదికను సిద్ధం చేయి"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ ప్రాప్యత లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"సెల్యులార్ డేటా"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"బ్లూటూత్"</item>
+    <item msgid="5447331121797802871">"ఈథర్‌నెట్"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"తెలియని నెట్‌వర్క్ రకం"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్‌ను కలిగి ఉంది."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్‌ను ఎంచుకోవడానికి నొక్కండి"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్‌లు"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ని సిద్ధం చేస్తోంది"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"లోపాల కోసం తనిఖీ చేస్తోంది"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"కొత్త <xliff:g id="NAME">%s</xliff:g> గుర్తించబడింది"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"ఎల్లప్పుడూ ఆన్‌లో ఉండే VPN డిస్‌కనెక్ట్ చేయబడింది"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ఎల్లప్పుడూ-ఆన్‌లో ఉండే VPN లోపం"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"కాన్ఫిగర్ చేయడానికి నొక్కండి"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"సెటప్ చేయడానికి నొక్కండి"</string>
     <string name="upload_file" msgid="2897957172366730416">"ఫైల్‌ను ఎంచుకోండి"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ఫైల్ ఎంచుకోబడలేదు"</string>
     <string name="reset" msgid="2448168080964209908">"రీసెట్ చేయి"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB డ్రైవ్"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB నిల్వ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"సవరించు"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"డేటా వినియోగం హెచ్చరిక"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"డేటా వినియోగ హెచ్చరిక"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"వినియోగం,సెట్టింగ్‌ల కోసం నొక్కండి"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G డేటా పరిమితిని చేరుకుంది"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G డేటా పరిమితిని చేరుకుంది"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"ఇతరం"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ని అనుమతించాలా ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"అన్ని భాషలు"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"అన్ని ప్రాంతాలు"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"శోధించు"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"కార్యాలయ మోడ్ ఆఫ్ చేయబడింది"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా కార్యాలయ ప్రొఫైల్‌ను పని చేయడానికి అనుమతించండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 425ccbd..818bb9f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"เหตุฉุกเฉิน"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
     <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ไม่สามารถเข้าถึงอินเทอร์เน็ต อาจมีค่าบริการ"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"เน็ตมือถือ"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"บลูทูธ"</item>
+    <item msgid="5447331121797802871">"อีเทอร์เน็ต"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"กำลังเตรียม <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"กำลังตรวจหาข้อผิดพลาด"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ตรวจพบ <xliff:g id="NAME">%s</xliff:g> ใหม่"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"ยกเลิกการเชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"แตะเพื่อกำหนดค่า"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"แตะเพื่อตั้งค่า"</string>
     <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
     <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"ไดรฟ์ USB ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"แก้ไข"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"คำเตือนการใช้ข้อมูล"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"การแจ้งเตือนการใช้อินเทอร์เน็ต"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"แตะเพื่อดูการใช้งานและการตั้งค่า"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ถึงขีดจำกัดข้อมูล 2G-3G แล้ว"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ถึงขีดจำกัดข้อมูล 4G แล้ว"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item>
       <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"เบ็ดเตล็ด"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"ทุกภาษา"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"ภูมิภาคทั้งหมด"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"ค้นหา"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"โหมดทำงานปิดอยู่"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"อนุญาตให้โปรไฟล์งานทำงานได้ ซึ่งรวมถึงแอป การซิงค์ในพื้นหลัง และคุณลักษณะอื่นที่เกี่ยวข้อง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index fef2575..81c5fd0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Pagpipilian sa telepono"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Pag-lock sa screen"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"I-off"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Walang access sa Internet ang Wi-Fi"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa Internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"cellular data"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"isang hindi kilalang uri ng network"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
@@ -1139,7 +1151,7 @@
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Nakakonekta sa isang accessory ng USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
-    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pagde-debug ng USB."</string>
+    <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inihahanda ang <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sinusuri para sa mga error"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Na-detect ang bagong <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Tapikin upang pamahalaan ang network."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Hindi nakakonekta ang palaging naka-on na VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"I-tap upang i-configure"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"I-tap upang i-set up"</string>
     <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
     <string name="reset" msgid="2448168080964209908">"I-reset"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"I-edit"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Babala sa paggamit ng data"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerto sa paggamit ng data"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"I-tap tingnan paggamit/setting."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Naabot na ang limitasyon sa 2G-3G data"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Naabot na ang limitasyon sa 4G data"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Iba Pa"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Lahat ng wika"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Lahat ng rehiyon"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Maghanap"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"NAKA-OFF ang work mode"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Payagang gumana ang profile sa trabaho, kasama na ang mga app, pag-sync sa background at mga may kaugnayang feature."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 386a1b3..9983142 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçenekleri"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Acil durum"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Kablosuz bağlantıda İnternet erişimi yok"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının İnternet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"hücresel veri"</item>
+    <item msgid="75483255295529161">"Kablosuz"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"bilinmeyen ağ türü"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanıyor"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hatalar denetleniyor"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> algılandı"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlı. Ağı yönetmek için hafifçe vurun."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Her zaman açık VPN bağlantısı kesildi"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Yapılandırmak için dokunun"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ayarlamak için dokunun"</string>
     <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
     <string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB sürücüsü"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzenle"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Veri kullanım uyarısı"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Veri kullanımı uyarısı"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Kul. ve ayar. gör. için dokunun."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G veri sınırına ulaşıldı"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G veri sınırına ulaşıldı"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe seçildi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Çeşitli"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bu bildirimlerin önem derecesini ayarladınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Tüm diller"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tüm bölgeler"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Ara"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"İş modu KAPALI"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Uygulamalar, arka planda senkronizasyon ve ilgili özellikler dahil olmak üzere iş profilinin çalışmasına izin ver."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5433f06..4c135ab 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -218,6 +218,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметри телеф."</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Заблок. екран"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Вимкнути"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Екстрений виклик"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
@@ -1126,6 +1127,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Мережа Wi-Fi не має доступу до Інтернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Пристрій використовує мережу <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету. Може стягуватися плата."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"мобільний трафік"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"Мережа VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невідомий тип мережі"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
@@ -1203,7 +1215,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Підготовка пристрою пам’яті <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Виявлення помилок"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Виявлено новий пристрій пам’яті (<xliff:g id="NAME">%s</xliff:g>)"</string>
@@ -1282,8 +1293,9 @@
     <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_disconnected" msgid="4532298952570796327">"Постійну мережу VPN від’єднано"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Торкніться, щоб налаштувати"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Торкніться, щоб налаштувати"</string>
     <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
     <string name="reset" msgid="2448168080964209908">"Віднов."</string>
@@ -1369,7 +1381,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Носій USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Редагувати"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Застереження про використ. даних"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Сповіщення про використ. трафіку"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Переглянути дані та параметри."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Досягнуто ліміту даних 2G–3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Досягнуто ліміту даних 4G"</string>
@@ -1699,6 +1711,7 @@
       <item quantity="many">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Інше"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ви вказуєте пріоритет цих сповіщень."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1708,6 +1721,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропоновані"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Усі мови"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Усі регіони"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Пошук"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Робочий профіль ВИМКНЕНО"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Увімкнути робочий профіль, зокрема додатки, фонову синхронізацію та пов’язані функції."</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 39eb1f2..d6eae64 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"فون کے اختیارات"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"اسکرین لاک"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"پاور آف"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"ایمرجنسی"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"بگ کی اطلاع"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"بگ کی اطلاع لیں"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"‏Wi-Fi کی انٹرنیٹ تک رسائی نہیں ہے"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کے پاس انٹرنیٹ تک رسائی نہ ہو تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کو استعمال کرتا ہے۔ چارجز کا اطلاق ہو سکتا ہے۔"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"سیلولر ڈیٹا"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"بلوٹوتھ"</item>
+    <item msgid="5447331121797802871">"ایتھرنیٹ"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نیٹ ورک کی نامعلوم قسم"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> تیار کیا جا رہا ہے"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"خرابیوں کیلئے چیک کیا جا رہا ہے"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"نئے <xliff:g id="NAME">%s</xliff:g> کا پتا چلا"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"‏ہمیشہ آن VPN غیر منسلک ہو گیا"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏ہمیشہ آن VPN کی خرابی"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"کنفیگر کرنے کیلئے تھپتھپائیں"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"سیٹ اپ کرنے کیلئے تھپتھپائیں"</string>
     <string name="upload_file" msgid="2897957172366730416">"فائل منتخب کریں"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"کوئی فائل منتخب نہیں کی گئی"</string>
     <string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"‏<xliff:g id="MANUFACTURER">%s</xliff:g> USB ڈرائیو"</string>
     <string name="storage_usb" msgid="3017954059538517278">"‏USB اسٹوریج"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"ترمیم کریں"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"ڈیٹا کے استعمال کی وارننگ"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"ڈیٹا کے استعمال کا الرٹ"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"استعمال اور ترتیبات دیکھنے کیلئے تھپتھپائیں۔"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"‏2G-3G ڈیٹا کی حد کو پہنچ گیا"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"‏4G ڈیٹا کی حد کو پہنچ گیا"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> منتخب کردہ</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"متفرقات"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں؟"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"سبھی زبانیں"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"تمام علاقے"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"تلاش"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"کام موڈ آف ہے"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"دفتری پروفائل کو کام کرنے دیں، بشمول ایپس، پس منظر کی مطابقت پذیری اور متعلقہ خصوصیات۔"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 99974d1..5b7cf74 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefon sozlamalari"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ekran qulfi"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Favqulodda chaqiruv"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi tarmog‘ida internet aloqasi yo‘q"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Qurilma <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmog‘ida internet o‘chganda, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> tarmog‘iga ulaniladi. To‘lov olinishi mumkin."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"mobil internet"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"noma’lum tarmoq turi"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
@@ -1087,7 +1099,7 @@
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sozlamalarni ochish uchun bosing"</string>
     <string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
-    <string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
+    <string name="decline" msgid="2112225451706137894">"Rad etish"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"taklif jo‘natildi"</string>
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ulanish taklifi"</string>
     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdan:"</string>
@@ -1101,7 +1113,7 @@
     <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Ruxsat berish"</string>
-    <string name="sms_control_no" msgid="625438561395534982">"Rad qilish"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Rad etish"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;ga xabar jo‘natishni xohlaydi."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string>
@@ -1212,7 +1223,7 @@
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ushbu so‘rovga ruxsat berishni xohlaysizmi?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Ruxsat so‘rovi"</string>
     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
-    <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
+    <string name="deny" msgid="2081879885755434506">"Rad etish"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Ruxsat so‘raldi"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hisobi uchun\nruxsat so‘raldi"</string>
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ulandi. Tarmoq sozlamalarini o‘zgartirish uchun bu yerni bosing."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ulanmoqda…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ulandi"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Doimiy VPN o‘chirildi"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Xato"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sozlash uchun bosing"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Sozlash uchun bosing"</string>
     <string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string>
     <string name="reset" msgid="2448168080964209908">"Asliga qaytarish"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB xotira qurilmasi"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB xotira"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Trafik kam qoldi"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Trafik sarfi bo‘yicha ogohlantirish"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G trafik chekloviga yetdi"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G trafik chekloviga yetdi"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta tanlandi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta tanlandi</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Boshqa"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Barcha tillar"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Barcha hududlar"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Qidiruv"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Ish rejimi O‘CHIQ"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Ishchi profilini yoqish: ilovalar, fonda sinxronlash va bog‘liq funksiyalar."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 0a9db5f..42e0b0a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Tùy chọn điện thoại"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Khoá màn hình"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Tắt nguồn"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Khẩn cấp"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi không có quyền truy cập Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"dữ liệu di động"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"Bluetooth"</item>
+    <item msgid="5447331121797802871">"Ethernet"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"loại mạng không xác định"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Đang chuẩn bị <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Đang kiểm tra lỗi"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Đã phát hiện <xliff:g id="NAME">%s</xliff:g> mới"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Đã ngắt kết nối VPN luôn bật"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Nhấn để định cấu hình"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Nhấn để thiết lập"</string>
     <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
     <string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"Ổ USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Chỉnh sửa"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Cảnh báo sử dụng dữ liệu"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Thông báo về sử dụng dữ liệu"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Nhấn để xem sử dụng và cài đặt."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Đã đạt tới giới hạn dữ liệu 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Đã đạt tới giới hạn dữ liệu 4G"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">Đã chọn <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Khác"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bạn đặt tầm quan trọng của các thông báo này."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Thông báo này quan trọng vì những người có liên quan."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Tất cả ngôn ngữ"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Tất cả khu vực"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Tìm kiếm"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Chế độ làm việc đang TẮT"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Cho phép hồ sơ công việc hoạt động, bao gồm ứng dụng, đồng bộ hóa trong nền và các tính năng liên quan."</string>
diff --git a/core/res/res/values-w225dp/dimens_material.xml b/core/res/res/values-w225dp/dimens_material.xml
new file mode 100644
index 0000000..aa822a3
--- /dev/null
+++ b/core/res/res/values-w225dp/dimens_material.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>
+    <dimen name="screen_percentage_05">11.25dp</dimen>
+    <dimen name="screen_percentage_10">22.5dp</dimen>
+    <dimen name="screen_percentage_15">33.75dp</dimen>
+</resources>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 45eb981..54eece4 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -22,5 +22,5 @@
 
     <color name="primary_material_dark">#4D4D4D</color>
 
-    <color name="button_material_dark">#ff999999</color>
+    <color name="button_material_dark">#ff919699</color>
 </resources>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 919519e..7c05b7a 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -57,4 +57,9 @@
 
     <!-- Use a custom transition for RemoteViews. -->
     <bool name="config_overrideRemoteViewsActivityTransition">true</bool>
+
+    <!-- Default value for android:focusableInTouchMode for some framework scrolling containers.
+         ListView/GridView are notably absent since this is their default anyway.
+         Set to true for watch devices. -->
+    <bool name="config_focusScrollContainersInTouchMode">true</bool>
 </resources>
diff --git a/core/res/res/values-watch/donottranslate.xml b/core/res/res/values-watch/donottranslate.xml
new file mode 100644
index 0000000..d247ff6
--- /dev/null
+++ b/core/res/res/values-watch/donottranslate.xml
@@ -0,0 +1,22 @@
+<?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>
+    <!-- DO NOT TRANSLATE Spans within this text are applied to style composing regions
+    within an EditText widget. The text content is ignored and not used.
+    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
+    <string name="candidates_style" translatable="false"><font color="#80cbc4">candidates</font></string>
+ </resources>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index d09119f..8a080d9c 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -68,8 +68,6 @@
         <item name="breakStrategy">balanced</item>
     </style>
 
-    <style name="Widget.Material.ButtonBar" parent="Widget.Material.BaseButtonBar" />
-
     <style name="TextAppearance.Material.NumberPicker" parent="TextAppearance.Material.Body1">
         <item name="textSize">@dimen/text_size_medium_material</item>
     </style>
@@ -103,9 +101,4 @@
         <item name="gravity">@integer/config_dialogTextGravity</item>
         <item name="ellipsize">end</item>
     </style>
-
-    <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions
-    within an EditText widget. The text content is ignored and not used.
-    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
-    <string name="candidates_style"><font color="#80cbc4">candidates</font></string>
 </resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 2313b26..0471444 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -32,12 +32,12 @@
  -->
 <resources>
     <!-- Theme used for the intent picker activity. -->
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material">
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault">
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
     </style>
 
     <!-- Use a dark theme for watches. -->
-    <style name="Theme.DeviceDefault.System" parent="Theme.Material" />
+    <style name="Theme.DeviceDefault.System" />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6ddf364..b67d6e2 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"手机选项"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"紧急呼救"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"此 WLAN 网络无法访问互联网"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"设备会在无法连接到<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"移动数据网络"</item>
+    <item msgid="75483255295529161">"WLAN"</item>
+    <item msgid="6862614801537202646">"蓝牙"</item>
+    <item msgid="5447331121797802871">"以太网"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"未知网络类型"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在准备<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"检查是否有错误"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"检测到新的<xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"始终开启的 VPN 已断开连接"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终开启的 VPN 出现错误"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"点按即可进行配置"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"点按即可进行设置"</string>
     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
     <string name="reset" msgid="2448168080964209908">"重置"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> U 盘"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB存储器"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"流量警告"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"流量消耗提醒"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"点按即可查看使用情况和设置。"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已达到2G-3G流量上限"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已达到4G流量上限"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
       <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"其他"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"这些通知的重要程度由您来设置。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"所有语言"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有国家/地区"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"搜索"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已关闭"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"启用工作资料,包括应用、后台同步和相关功能。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 66b8f95..62bb44a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"手機選項"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"關閉"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,並以電郵傳送給您。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 並未連接互聯網"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"當<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>無法連線至互聯網時,裝置便會切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g>。可能需要支付額外費用。"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"流動數據"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"藍牙"</item>
+    <item msgid="5447331121797802871">"以太網"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明網絡類型"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"已偵測到新<xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可設定"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕按即可設定"</string>
     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇檔案"</string>
     <string name="reset" msgid="2448168080964209908">"重設"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 驅動器"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"資料用量警告"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕按即可查看用量和設定。"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"其他"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"您可以設定這些通知的重要性。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有國家/地區"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已關閉"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"允許使用應用程式、背景同步及相關功能的工作設定檔。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ebf48b7..0500c07 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"電話選項"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"緊急電話"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi 網路沒有網際網路連線"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"裝置會在無法連上 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 時切換至<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"行動數據"</item>
+    <item msgid="75483255295529161">"Wi-Fi"</item>
+    <item msgid="6862614801537202646">"藍牙"</item>
+    <item msgid="5447331121797802871">"乙太網路"</item>
+    <item msgid="8257233890381651999">"VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明的網路類型"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備「<xliff:g id="NAME">%s</xliff:g>」"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"偵測到新的「<xliff:g id="NAME">%s</xliff:g>」"</string>
@@ -1232,8 +1243,9 @@
     <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_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷連線"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可進行設定"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕觸即可進行設定"</string>
     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
     <string name="reset" msgid="2448168080964209908">"重設"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 隨身碟"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"數據用量警告"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"輕觸即可查看用量和設定。"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item>
       <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"其他"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"這些通知的重要性由您決定。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"要允許 <xliff:g id="APP">%1$s</xliff:g> 為 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"所有地區"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Work 模式已關閉"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"啟用 Work 設定檔,包括應用程式、背景同步處理和相關功能。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 7c3c342..849f292 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -214,6 +214,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Okukhethwa kukho kwefoni"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Ukuvala isikrini"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Isimo esiphuthumayo"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
@@ -1076,6 +1077,17 @@
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"I-Wi-Fi ayinakho ukufinyelela kwe-inthanethi"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
+    <string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="5325661434777870353">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ingenakho ukufinyelela kwe-inthanethi. Izindleko zingasebenza."</string>
+    <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2952042958050315394">"idatha yeselula"</item>
+    <item msgid="75483255295529161">"I-Wi-Fi"</item>
+    <item msgid="6862614801537202646">"I-Bluetooth"</item>
+    <item msgid="5447331121797802871">"I-Ethernet"</item>
+    <item msgid="8257233890381651999">"I-VPN"</item>
+  </string-array>
+    <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"uhlobo olungaziwa lwenethiwekhi"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
@@ -1153,7 +1165,6 @@
     <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
-    <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
     <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ilungiselela i-<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ihlolela amaphutha"</string>
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"I-<xliff:g id="NAME">%s</xliff:g> entsha itholiwe"</string>
@@ -1232,8 +1243,9 @@
     <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha inethiwekhi."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"I-VPN ehlala ikhanya iyaxhuma…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"I-VPN ehlala ikhanya ixhunyiwe"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Njalo kuvuliwe i-VPN kunqamukile"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Iphutha le-VPN ehlala ikhanya"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Thinta ukuze umise"</string>
+    <string name="vpn_lockdown_config" msgid="5099330695245008680">"Thepha ukuze usethe"</string>
     <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string>
     <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
@@ -1317,7 +1329,7 @@
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> idrayivu ye-USB"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Hlela"</string>
-    <string name="data_usage_warning_title" msgid="1955638862122232342">"Isexwayiso sokusetshenziswa kwedatha"</string>
+    <string name="data_usage_warning_title" msgid="3620440638180218181">"Izexwayiso zokusetshenziswa kwedatha"</string>
     <string name="data_usage_warning_body" msgid="6660692274311972007">"Thepha ukuze ubuke ukusetshenziswa nezilungiselelo."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G umkhawulo wedatha ufinyelelwe"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G umkhawulo wedatha ufinyelelwe"</string>
@@ -1627,6 +1639,7 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
     </plurals>
+    <string name="default_notification_channel_label" msgid="6950908610709016902">"Okwahlukahlukene"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Usethe ukubaluleka kwalezi zaziso."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukudala umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
@@ -1636,6 +1649,7 @@
     <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string>
     <string name="language_picker_section_all" msgid="3097279199511617537">"Zonke izilimi"</string>
+    <string name="region_picker_section_all" msgid="8966316787153001779">"Zonke izifunda"</string>
     <string name="locale_search_menu" msgid="2560710726687249178">"Sesha"</string>
     <string name="work_mode_off_title" msgid="8954725060677558855">"Imodi yomsebenzi IVALIWE"</string>
     <string name="work_mode_off_message" msgid="3286169091278094476">"Vumela iphrofayela yomsebenzi ukuze isebenze, efaka izinhlelo zokusebenza, ukuvumelanisa kwangemuva, nezici ezisondelene."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9a7fccc..f0a25aa 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2059,6 +2059,8 @@
             <!-- Controller for micro specific layout. -->
             <enum name="micro" value="1" />
         </attr>
+        <!-- @hide Offset when scrolling to a selection. -->
+        <attr name="selectionScrollOffset" format="dimension" />
     </declare-styleable>
 
     <!-- @hide -->
@@ -2334,8 +2336,8 @@
         <!-- Defines whether the vertical scrollbar track should always be drawn. -->
         <attr name="scrollbarAlwaysDrawVerticalTrack" format="boolean" />
 
-        <!-- This attribute is deprecated and will be ignored as of
-             API level 14 ({@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}).
+        <!-- This attribute is ignored in API level 14
+             ({@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}) and higher.
              Using fading edges may introduce noticeable performance
              degradations and should be used only when required by the application's
              visual design. To request fading edges with API level 14 and above,
@@ -2571,7 +2573,7 @@
 
         <!-- Defines the direction of layout drawing. This typically is associated with writing
              direction of the language script used. The possible values are "ltr" for Left-to-Right,
-             "rtl" for Right-to-Left, "locale" and "inherit" from parent view. If there is nothing
+             "rtl" for Right-to-Left, "locale", and "inherit" from parent view. If there is nothing
              to inherit, "locale" is used. "locale" falls back to "en-US". "ltr" is the direction
              used in "en-US". The default for this attribute is "inherit". -->
         <attr name="layoutDirection">
@@ -2585,8 +2587,7 @@
             <enum name="locale" value="3" />
         </attr>
 
-        <!-- Defines the direction of the text. A heuristic is used to determine the resolved text
-              direction of paragraphs. -->
+        <!-- Defines the direction of the text. -->
          <attr name="textDirection" format="integer">
             <!-- Default -->
             <enum name="inherit" value="0" />
@@ -2612,8 +2613,7 @@
             <enum name="firstStrongRtl" value="7" />
         </attr>
 
-        <!-- Defines the alignment of the text. A heuristic is used to determine the resolved
-            text alignment. -->
+        <!-- Defines the alignment of the text. -->
         <attr name="textAlignment" format="integer">
             <!-- Default -->
             <enum name="inherit" value="0" />
@@ -2635,10 +2635,11 @@
             <enum name="viewEnd" value="6" />
         </attr>
 
-        <!-- Controls how this View is important for accessibility which is if it fires
-             accessibility events and if it is reported to accessibility services that
-             query the screen. Note: While not recommended, an accessibility service may
-             decide to ignore this attribute and operate on all views in the view tree. -->
+        <!-- Describes whether or not this view is important for accessibility.
+             If it is important, the view fires accessibility events and is
+             reported to accessibility services that query the screen. Note:
+             While not recommended, an accessibility service may decide to
+             ignore this attribute and operate on all views in the view tree. -->
         <attr name="importantForAccessibility" format="integer">
             <!-- The system determines whether the view is important for accessibility - default
                  (recommended). -->
@@ -4840,6 +4841,11 @@
         <!-- The list year's selected circle color in the list.
              {@deprecated No longer displayed.} -->
         <attr name="yearListSelectorColor" format="color" />
+
+        <!-- @hide Whether this time picker is being displayed within a dialog,
+             in which case it may ignore the requested time picker mode due to
+             space considerations. -->
+        <attr name="dialogMode" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="TwoLineListItem">
@@ -4934,7 +4940,14 @@
     <declare-styleable name="LinearLayout_Layout">
         <attr name="layout_width" />
         <attr name="layout_height" />
+        <!-- Indicates how much of the extra space in the LinearLayout is
+        allocated to the view associated with these LayoutParams. Specify
+        0 if the view should not be stretched. Otherwise the extra pixels
+        will be pro-rated among all views whose weight is greater than 0. -->
         <attr name="layout_weight" format="float" />
+        <!-- Gravity specifies how a component should be placed in its group of cells.
+        The default is {@link android.view.Gravity#TOP}.
+        See {@link android.widget.LinearLayout#setGravity(int)}. -->
         <attr name="layout_gravity" />
     </declare-styleable>
     <declare-styleable name="GridLayout_Layout">
@@ -5168,6 +5181,11 @@
         <!-- The background color state list for the AM/PM selectors.
              {@deprecated Use headerBackground instead.}-->
         <attr name="amPmBackgroundColor" format="color" />
+
+        <!-- @hide Whether this time picker is being displayed within a dialog,
+             in which case it may ignore the requested time picker mode due to
+             space considerations. -->
+        <attr name="dialogMode" />
     </declare-styleable>
 
     <!-- ========================= -->
@@ -5314,6 +5332,21 @@
         <attr name="alpha" />
     </declare-styleable>
 
+    <!-- Drawable used to render according to the animation scale. Esp. when it is 0 due to battery
+         saver mode. It should contain one animatable drawable and one static drawable.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawable">
+    </declare-styleable>
+
+    <!-- Attributes that can be assigned to a AnimationScaleListDrawable item.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawableItem">
+        <!-- Reference to a drawable resource to use for the state. If not
+             given, the drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+    </declare-styleable>
+
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
@@ -5343,7 +5376,10 @@
         <attr name="innerRadius" format="dimension" />
         <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
         <attr name="thickness" format="dimension" />
-        <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
+        <!-- Whether the drawable level value (see
+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the shape.
+             Scaling behavior depends on the shape type. For "ring", the angle is scaled from 0 to
+             360. For all other types, there is no effect. The default value is true. -->
         <attr name="useLevel" />
         <!-- If set, specifies the color to apply to the drawable as a tint. By default,
              no tint is applied. May be a color state list. -->
@@ -5377,28 +5413,37 @@
     <declare-styleable name="GradientDrawableGradient">
         <!-- Start color of the gradient. -->
         <attr name="startColor" format="color" />
-        <!-- Optional center color. For linear gradients, use centerX or centerY
-             to place the center color. -->
+        <!-- Optional center color. For linear gradients, use centerX or centerY to place the center
+             color. -->
         <attr name="centerColor" format="color" />
         <!-- End color of the gradient. -->
         <attr name="endColor" format="color" />
+        <!-- Whether the drawable level value (see
+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the gradient.
+             Scaling behavior varies based on gradient type. For "linear", adjusts the ending
+             position along the gradient's axis of orientation. For "radial", adjusts the outer
+             radius. For "sweep", adjusts the ending angle. The default value is false. -->
         <attr name="useLevel" format="boolean" />
-        <!-- Angle of the gradient. -->
+        <!-- Angle of the gradient, used only with linear gradient. Must be a multiple of 45 in the
+             range [0, 315]. -->
         <attr name="angle" format="float" />
         <!-- Type of gradient. The default type is linear. -->
         <attr name="type">
-            <!-- Linear gradient. -->
+            <!-- Linear gradient extending across the center point. -->
             <enum name="linear" value="0" />
-            <!-- Radial, or circular, gradient. -->
+            <!-- Radial gradient extending from the center point outward. -->
             <enum name="radial" value="1" />
-            <!-- Sweep, or angled or diamond, gradient. -->
+            <!-- Sweep (or angular) gradient sweeping counter-clockwise around the center point. -->
             <enum name="sweep"  value="2" />
         </attr>
-        <!-- X coordinate of the origin of the gradient within the shape. -->
+        <!-- X-position of the center point of the gradient within the shape as a fraction of the
+             width. The default value is 0.5. -->
         <attr name="centerX" format="float|fraction" />
-        <!-- Y coordinate of the origin of the gradient within the shape. -->
+        <!-- Y-position of the center point of the gradient within the shape as a fraction of the
+             height. The default value is 0.5. -->
         <attr name="centerY" format="float|fraction" />
-        <!-- Radius of the gradient, used only with radial gradient. -->
+        <!-- Radius of the gradient, used only with radial gradient. May be an explicit dimension
+             or a fractional value relative to the shape's minimum dimension. -->
         <attr name="gradientRadius" format="float|fraction|dimension" />
     </declare-styleable>
 
@@ -6930,9 +6975,11 @@
         <attr name="icon" />
         <!-- The key to store the Preference value. -->
         <attr name="key" format="string" />
-        <!-- The title for the Preference in a PreferenceActivity screen. -->
+        <!-- The title for the Preference. In API 25 and earlier, this value is read as a
+         plain string with styling information stripped. -->
         <attr name="title" />
-        <!-- The summary for the Preference in a PreferenceActivity screen. -->
+        <!-- The summary for the Preference. In API 25 and earlier, this value is read as a
+         plain string with styling information stripped. -->
         <attr name="summary" />
         <!-- The order for the Preference (lower values are to be ordered first). If this is not
              specified, the default ordering will be alphabetic. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 01cb64d..cad5854 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1305,7 +1305,7 @@
         <attr name="cantSaveState" format="boolean" />
         <attr name="uiOptions" />
         <!-- Declare that your application will be able to deal with RTL (right to left) layouts.
-             If set to  false (default value), your application will not care about RTL layouts. -->
+             The default value is false. -->
         <attr name="supportsRtl" format="boolean" />
         <!-- Declare that this application requires access to restricted accounts of a certain
              type. The default value is null and restricted accounts won\'t be visible to this
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 27ee27b..171f5cb 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -32,4 +32,11 @@
     <color name="accent_device_default_light">@color/accent_material_light</color>
     <color name="accent_device_default_dark">@color/accent_material_dark</color>
     <color name="accent_device_default_50">@color/material_deep_teal_50</color>
+
+    <color name="background_device_default_dark">@color/background_material_dark</color>
+    <color name="background_device_default_light">@color/background_material_light</color>
+    <color name="background_floating_device_default_dark">@color/background_floating_material_dark</color>
+    <color name="background_floating_device_default_light">@color/background_floating_material_light</color>
+    <color name="button_normal_device_default_dark">@color/btn_default_material_dark</color>
+    <color name="button_normal_device_default_light">@color/btn_default_material_light</color>
 </resources>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index a864cf3..92426c6 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -61,7 +61,10 @@
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
-    <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item>
+    <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
+
+    <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item>
+    <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item>
 
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6161494..3d1acdf 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -268,6 +268,18 @@
     <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
     <integer name="config_networkTransitionTimeout">60000</integer>
 
+    <!-- Whether/how to notify the user on network switches. See LingerMonitor.java. -->
+    <integer translatable="false" name="config_networkNotifySwitchType">0</integer>
+
+    <!-- What types of network switches to notify. See LingerMonitor.java. -->
+    <string-array translatable="false" name="config_networkNotifySwitches">
+    </string-array>
+
+    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+         Internet access. Actual device behaviour is controlled by
+         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+
     <!-- List of regexpressions describing the interface (if any) that represent tetherable
          USB interfaces.  If the device doesn't want to support tethering over USB this should
          be empty.  An example would be "usb.*" -->
@@ -1135,6 +1147,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 +1810,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>
@@ -1791,6 +1841,11 @@
          Do not set this to true for production devices. Doing so will cause you to fail CTS. -->
     <bool name="config_disableUsbPermissionDialogs">false</bool>
 
+    <!-- Activity to handle Usb Device connection in USB Host side. Keeping it to null value will
+         lead into handling it inside system using Intent resolution. Non-null contents will have
+         format of package-name/ActivityClassName. -->
+    <string name="config_UsbDeviceConnectionHandling_component" translatable="false">@null</string>
+
     <!-- Minimum span needed to begin a touch scaling gesture.
          If the span is equal to or greater than this size, a scaling gesture
          will begin, where supported. (See android.view.ScaleGestureDetector)
@@ -2166,13 +2221,18 @@
     <!-- Flag specifying whether VT is available on device -->
     <bool name="config_device_vt_available">false</bool>
 
+    <!-- Flag specifying whether the device will use the "allow_hold_in_ims_call" carrier config
+         option.  When false, the device will support holding of IMS calls, regardless of the
+         carrier config setting. -->
+    <bool name="config_device_respects_hold_carrier_config">true</bool>
+
     <!-- Flag specifying whether VT should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
     <bool name="config_carrier_vt_available">false</bool>
 
     <!-- Flag specifying whether WFC over IMS is available on device -->
-    <bool name="config_device_wfc_ims_available">false</bool>
+        <bool name="config_device_wfc_ims_available">false</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
@@ -2211,21 +2271,6 @@
         <item>SUPL_MODE=1</item>
     </string-array>
 
-    <!-- If there is no preload VM number in the sim card, carriers such as
-         Verizon require to load a default vm number from the configurantion.
-         Define config_default_vm_number for this purpose. And there are two
-         optional formats for this configuration as below:
-         (1)<item>voicemail number</item>
-         (2)<item>voicemail number;gid</item>
-         The logic to pick up the correct voicemail number:
-         (1) If the config_default_vm_number array has no gid special item, the last one will be
-         picked
-         (2) If the config_default_vm_number array has gid special item and  it matches the current
-         sim's gid, it will be picked.
-         (3) If the config_default_vm_number array has gid special item but it doesn't match the
-         current sim's gid, the last one without gid will be picked -->
-    <string-array translatable="false" name="config_default_vm_number" />
-
     <!-- Sprint need a 70 ms delay for 3way call -->
     <integer name="config_cdma_3waycall_flash_delay">0</integer>
 
@@ -2308,8 +2353,8 @@
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" />
 
-    <!-- set the system language as value of EF LI/EF PL -->
-    <bool name="config_use_sim_language_file">true</bool>
+    <!-- flag to indicate if EF LI/EF PL should be used for system language -->
+    <bool name="config_use_sim_language_file">false</bool>
 
     <!-- Use ERI text for network name on CDMA LTE -->
     <bool name="config_LTE_eri_for_network_name">true</bool>
@@ -2529,6 +2574,16 @@
     <!-- True if the device supports system navigation keys. -->
     <bool name="config_supportSystemNavigationKeys">false</bool>
 
+    <!-- emergency call number for the emergency affordance -->
+    <string name="config_emergency_call_number" translatable="false">112</string>
+
+    <!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
+         affordances-->
+    <integer-array name="config_emergency_mcc_codes" translatable="false">
+        <item>404</item>
+        <item>405</item>
+    </integer-array>
+
     <!-- Package name for the device provisioning package. -->
     <string name="config_deviceProvisioningPackage"></string>
 
@@ -2547,6 +2602,11 @@
          is installed. -->
     <bool name="config_permissionReviewRequired">false</bool>
 
+    <!-- Default value for android:focusableInTouchMode for some framework scrolling containers.
+         ListView/GridView are notably absent since this is their default anyway.
+         Set to true for watch devices. -->
+    <bool name="config_focusScrollContainersInTouchMode">false</bool>
+
     <string name="config_networkOverLimitComponent" translatable="false">com.android.systemui/com.android.systemui.net.NetworkOverLimitActivity</string>
     <string name="config_dataUsageSummaryComponent" translatable="false">com.android.settings/com.android.settings.Settings$DataUsageSummaryActivity</string>
 
@@ -2554,4 +2614,24 @@
          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>
+
+    <!-- This config is holding calling number conversion map - expected to convert to emergency
+         number. Formats for this config as below:
+         <item>[dialstring1],[dialstring2],[dialstring3]:[replacement]</item>
+
+         E.g. for Taiwan Type Approval, 110 and 119 should be converted to 112.
+         <item>110,119:112</item>
+    -->
+    <string-array translatable="false" name="config_convert_to_emergency_number_map" />
+
+    <!-- An array of packages for which notifications cannot be blocked. -->
+    <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
 </resources>
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index 397635f..29494db 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -34,4 +34,7 @@
 
     <!-- True if preference fragment should clip to padding. -->
     <bool name="config_preferenceFragmentClipToPadding">true</bool>
+
+    <!-- The amount to offset when scrolling to a selection in an AlertDialog -->
+    <dimen name="config_alertDialogSelectionScrollOffset">0dp</dimen>
 </resources>
diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
index a139529..3a1679c 100644
--- a/core/res/res/values/donottranslate.xml
+++ b/core/res/res/values/donottranslate.xml
@@ -26,4 +26,7 @@
     <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string>
     <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.-->
     <string name="system_ui_date_pattern">@string/icu_abbrev_wday_month_day_no_year</string>
+    <!-- @hide DO NOT TRANSLATE Spans within this text are applied to style composing regions
+    within an EditText widget. The text content is ignored and not used. -->
+    <string name="candidates_style" translatable="false"><u>candidates</u></string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c4594e5..cce02f2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -488,6 +488,9 @@
     <!-- TODO: promote to separate string-->
     <string name="global_action_restart" translatable="false">@string/sim_restart_button</string>
 
+    <!-- label for item that starts emergency call -->
+    <string name="global_action_emergency">Emergency</string>
+
     <!-- label for item that generates a bug report in the phone options dialog -->
     <string name="global_action_bug_report">Bug report</string>
 
@@ -2937,6 +2940,27 @@
     <!-- 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>
 
+    <!-- A notification might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
+
+    <!-- A notification might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no Internet access. Charges may apply.</string>
+
+    <!-- A toast might be shown if the device switches to another network type (e.g., cellular data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></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" -->
@@ -3109,8 +3133,6 @@
     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
 
-    <string name="candidates_style"><u>candidates</u></string>
-
     <!-- External media notification strings -->
     <skip />
 
@@ -3313,10 +3335,12 @@
     <string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string>
     <!-- Notification title when connected to lockdown VPN. -->
     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
+    <!-- Notification title when not connected to lockdown VPN. -->
+    <string name="vpn_lockdown_disconnected">Always-on VPN disconnected</string>
     <!-- Notification title when error connecting to lockdown VPN. -->
     <string name="vpn_lockdown_error">Always-on VPN error</string>
     <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
-    <string name="vpn_lockdown_config">Tap to configure</string>
+    <string name="vpn_lockdown_config">Tap to set up</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
@@ -3537,9 +3561,9 @@
     <!-- Button text for the edit menu in input method extract mode. [CHAR LIMIT=16] -->
     <string name="extract_edit_menu_button">Edit</string>
 
-    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
-    <string name="data_usage_warning_title">Data usage warning</string>
-    <!-- Notification body when data usage has exceeded warning threshold. -->
+    <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
+    <string name="data_usage_warning_title">Data usage alert</string>
+    <!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
     <string name="data_usage_warning_body">Tap to view usage and settings.</string>
 
     <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
@@ -4323,6 +4347,8 @@
         <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
     </plurals>
 
+    <string name="default_notification_channel_label">Miscellaneous</string>
+
     <string name="importance_from_user">You set the importance of these notifications.</string>
     <string name="importance_from_person">This is important because of the people involved.</string>
 
@@ -4344,6 +4370,9 @@
     <string name="language_picker_section_suggested">Suggested</string>
     <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] -->
     <string name="language_picker_section_all">All languages</string>
+    <!-- List section subheader for the region picker, containing a list of all regions supported for the selected language.
+    Warning: this is a more 'neutral' term for 'country', not for the sub-divisions of a country. [CHAR LIMIT=30] -->
+    <string name="region_picker_section_all">All regions</string>
 
     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
     <string name="locale_search_menu">Search</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 762cf31..937428b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -649,11 +649,13 @@
     <style name="Widget.ScrollView">
         <item name="scrollbars">vertical</item>
         <item name="fadingEdge">vertical</item>
+        <item name="focusableInTouchMode">@bool/config_focusScrollContainersInTouchMode</item>
     </style>
 
     <style name="Widget.HorizontalScrollView">
         <item name="scrollbars">horizontal</item>
         <item name="fadingEdge">horizontal</item>
+        <item name="focusableInTouchMode">@bool/config_focusScrollContainersInTouchMode</item>
     </style>
 
     <style name="Widget.ListView" parent="Widget.AbsListView">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 90746e5..22bdf7e 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -553,11 +553,7 @@
         <item name="textOff">@string/capital_off</item>
     </style>
 
-    <style name="Widget.Material.BaseButtonBar">
-        <item name="background">?attr/colorBackgroundFloating</item>
-    </style>
-
-    <style name="Widget.Material.ButtonBar" parent="Widget.Material.BaseButtonBar">
+    <style name="Widget.Material.ButtonBar">
         <item name="background">@null</item>
     </style>
 
@@ -1213,6 +1209,7 @@
         <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
         <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
         <item name="controllerType">@integer/config_alertDialogController</item>
+        <item name="selectionScrollOffset">@dimen/config_alertDialogSelectionScrollOffset</item>
     </style>
 
     <style name="AlertDialog.Material.Light" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c2b55b..019a5e8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -347,8 +347,6 @@
   <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
   <java-symbol type="string"  name="config_wifi_framework_sap_2G_channel_list" />
 
-  <java-symbol type="bool" name="editable_voicemailnumber" />
-
   <java-symbol type="bool" name="config_wifi_framework_cellular_handover_enable_user_triggered_adjustment" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_tx_packet_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_rx_packet_threshold" />
@@ -418,6 +416,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 +949,11 @@
   <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="string" name="network_switch_metered" />
+  <java-symbol type="string" name="network_switch_metered_detail" />
+  <java-symbol type="string" name="network_switch_metered_toast" />
+  <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" />
@@ -1405,7 +1409,6 @@
   <java-symbol type="raw" name="color_fade_vert" />
   <java-symbol type="raw" name="color_fade_frag" />
   <java-symbol type="raw" name="accessibility_gestures" />
-  <java-symbol type="raw" name="incognito_mode_start_page" />
   <java-symbol type="raw" name="loaderror" />
   <java-symbol type="raw" name="nodomain" />
 
@@ -1457,6 +1460,7 @@
   <java-symbol type="anim" name="dock_top_exit" />
   <java-symbol type="anim" name="dock_bottom_enter" />
   <java-symbol type="anim" name="dock_bottom_exit" />
+  <java-symbol type="anim" name="dock_bottom_exit_keyguard" />
   <java-symbol type="anim" name="dock_left_enter" />
   <java-symbol type="anim" name="dock_left_exit" />
   <java-symbol type="anim" name="dock_right_enter" />
@@ -1642,6 +1646,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" />
@@ -1743,6 +1750,9 @@
   <java-symbol type="integer" name="config_lowBatteryWarningLevel" />
   <java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
   <java-symbol type="integer" name="config_networkTransitionTimeout" />
+  <java-symbol type="integer" name="config_networkNotifySwitchType" />
+  <java-symbol type="array" name="config_networkNotifySwitches" />
+  <java-symbol type="integer" name="config_networkAvoidBadWifi" />
   <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
   <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
   <java-symbol type="integer" name="config_notificationsBatteryLedOn" />
@@ -1860,12 +1870,14 @@
   <java-symbol type="string" name="usb_ptp_notification_title" />
   <java-symbol type="string" name="usb_midi_notification_title" />
   <java-symbol type="string" name="usb_supplying_notification_title" />
+  <java-symbol type="string" name="config_UsbDeviceConnectionHandling_component" />
   <java-symbol type="string" name="vpn_text" />
   <java-symbol type="string" name="vpn_text_long" />
   <java-symbol type="string" name="vpn_title" />
   <java-symbol type="string" name="vpn_title_long" />
   <java-symbol type="string" name="vpn_lockdown_connecting" />
   <java-symbol type="string" name="vpn_lockdown_connected" />
+  <java-symbol type="string" name="vpn_lockdown_disconnected" />
   <java-symbol type="string" name="vpn_lockdown_error" />
   <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
@@ -1940,6 +1952,7 @@
   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
   <java-symbol type="anim" name="lock_screen_wallpaper_exit" />
   <java-symbol type="anim" name="launch_task_behind_source" />
+  <java-symbol type="anim" name="wallpaper_open_exit" />
 
   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
   <java-symbol type="dimen" name="status_bar_icon_size" />
@@ -2209,6 +2222,7 @@
   <java-symbol type="bool" name="config_carrier_volte_provisioned" />
   <java-symbol type="bool" name="config_carrier_volte_tty_supported" />
   <java-symbol type="bool" name="config_device_vt_available" />
+  <java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
   <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="config_device_wfc_ims_available" />
   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
@@ -2251,7 +2265,6 @@
   <java-symbol type="bool" name="config_auto_attach_data_on_creation" />
   <java-symbol type="attr" name="closeItemLayout" />
   <java-symbol type="layout" name="resolver_different_item_header" />
-  <java-symbol type="array" name="config_default_vm_number" />
   <java-symbol type="integer" name="config_cdma_3waycall_flash_delay"/>
   <java-symbol type="attr" name="windowBackgroundFallback" />
   <java-symbol type="id" name="textSpacerNoButtons" />
@@ -2271,6 +2284,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" />
 
@@ -2453,6 +2468,7 @@
   <java-symbol type="dimen" name="notification_content_margin_top" />
   <java-symbol type="dimen" name="notification_content_margin_bottom" />
   <java-symbol type="dimen" name="notification_header_background_height" />
+  <java-symbol type="string" name="default_notification_channel_label" />
   <java-symbol type="string" name="importance_from_user" />
   <java-symbol type="string" name="importance_from_person" />
 
@@ -2500,6 +2516,7 @@
   <java-symbol type="menu" name="language_selection_list" />
   <java-symbol type="string" name="country_selection_title" />
   <java-symbol type="string" name="language_picker_section_all" />
+  <java-symbol type="string" name="region_picker_section_all" />
   <java-symbol type="string" name="language_picker_section_suggested" />
   <java-symbol type="string" name="language_selection_title" />
   <java-symbol type="string" name="search_language_hint" />
@@ -2658,6 +2675,10 @@
 
   <java-symbol type="string" name="lockscreen_storage_locked" />
 
+  <java-symbol type="string" name="global_action_emergency" />
+  <java-symbol type="string" name="config_emergency_call_number" />
+  <java-symbol type="array" name="config_emergency_mcc_codes" />
+
   <!-- Used for MimeIconUtils. -->
   <java-symbol type="drawable" name="ic_doc_apk" />
   <java-symbol type="drawable" name="ic_doc_audio" />
@@ -2697,4 +2718,13 @@
 
   <java-symbol type="drawable" name="ic_restart" />
 
+  <java-symbol type="drawable" name="emergency_icon" />
+
+  <java-symbol type="array" name="config_convert_to_emergency_number_map" />
+
+  <java-symbol type="array" name="config_nonBlockableNotificationPackages" />
+
+  <!-- Screen-size-dependent modes for picker dialogs. -->
+  <java-symbol type="integer" name="time_picker_mode" />
+  <java-symbol type="integer" name="date_picker_mode" />
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0e98ade..abb0c8f 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -203,45 +203,42 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
-
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+        <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
-    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
          sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen">
+        <item name="windowFullscreen">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
     extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.NoActionBar.Overscan">
+        <item name="windowFullscreen">true</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor">
+        <item name="windowTranslucentStatus">true</item>
+        <item name="windowTranslucentNavigation">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -261,32 +258,29 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+        <item name="colorBackground">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Dialog.MinWidth">
+        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
     for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth">
+        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -307,66 +301,52 @@
 
     <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
-    </style>
+    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="@style/Theme.DeviceDefault" />
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
-    </style>
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.NoActionBar" />
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
-    </style>
+    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="@style/Theme.DeviceDefault.NoActionBar.Fullscreen" />
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
     the window floating, with a transparent background, and turns off dimming behind the window. -->
-    <style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Panel">
+        <item name="windowBackground">@color/transparent</item>
+        <item name="colorBackgroundCacheHint">@null</item>
+        <item name="windowFrame">@null</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="windowAnimationStyle">@null</item>
+        <item name="windowIsFloating">true</item>
+        <item name="backgroundDimEnabled">false</item>
+        <item name="windowIsTranslucent">true</item>
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them. -->
-    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Wallpaper">
+        <item name="windowBackground">@color/transparent</item>
+        <item name="colorBackgroundCacheHint">@null</item>
+        <item name="windowShowWallpaper">true</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them and without an action bar. -->
-    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_dark</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
-        <item name="colorAccent">@color/accent_device_default_dark</item>
+    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar">
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.-->
-    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Material.InputMethod">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.InputMethod">
+        <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
+        <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
+        <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
+        <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -551,53 +531,58 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_light</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+        <item name="colorButtonNormal">@color/button_normal_device_default_light</item>
     </style>
 
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
     inverse color profile. -->
-    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Material.Light.DarkActionBar">
+    <style name="Theme.DeviceDefault.Light.DarkActionBar">
+        <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@style/ThemeOverlay.Material.Dark.ActionBar</item>
+        <item name="popupTheme">@style/ThemeOverlay.Material.Light</item>
+
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Material.Light.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
          This theme sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
+        <item name="windowFullscreen">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
     and extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan">
+        <item name="windowFullscreen">true</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor">
+        <item name="windowTranslucentStatus">true</item>
+        <item name="windowTranslucentNavigation">true</item>
+        <item name="windowContentOverlay">@null</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -617,32 +602,29 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth">
+        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
      <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
     width for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth">
+        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -651,11 +633,6 @@
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
         <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
-
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -664,39 +641,19 @@
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
         <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
-
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
-    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Light" />
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
-    </style>
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Light.NoActionBar" />
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
-        <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_light</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
-    </style>
+    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="@style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
@@ -706,6 +663,9 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -715,6 +675,9 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -722,6 +685,9 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -729,6 +695,9 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
@@ -738,6 +707,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should use Settings theme colors but has
@@ -749,6 +721,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -758,6 +733,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -766,6 +744,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -774,6 +755,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -782,6 +766,9 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- Theme used for the intent picker activity. -->
@@ -800,6 +787,9 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorBackground">@color/background_device_default_light</item>
+        <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
+        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
     </style>
 
     <!-- DeviceDefault theme for the default system theme.  -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index 68f3179..23135dd 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -63,11 +63,6 @@
 
         String password = arguments.getString("password");
 
-        String freqStr = arguments.getString("frequency-band");
-        if (freqStr != null) {
-            setFrequencyBand(freqStr);
-        }
-
         assertTrue("enable Wifi failed", enableWifi());
         WifiInfo wi = mWifiManager.getConnectionInfo();
         logv("%s", wi);
@@ -80,28 +75,6 @@
     }
 
     /**
-     * Set the frequency band and verify that it has been set.
-     */
-    private void setFrequencyBand(String frequencyBandStr) {
-        int frequencyBand = -1;
-        if ("2.4".equals(frequencyBandStr)) {
-            frequencyBand = WifiManager.WIFI_FREQUENCY_BAND_2GHZ;
-        } else if ("5.0".equals(frequencyBandStr)) {
-            frequencyBand = WifiManager.WIFI_FREQUENCY_BAND_5GHZ;
-        } else if ("auto".equals(frequencyBandStr)) {
-            frequencyBand = WifiManager.WIFI_FREQUENCY_BAND_AUTO;
-        } else {
-            fail("Invalid frequency-band");
-        }
-        if (mWifiManager.getFrequencyBand() != frequencyBand) {
-            logv("Set frequency band to %s", frequencyBandStr);
-            mWifiManager.setFrequencyBand(frequencyBand, true);
-        }
-        assertEquals("Specified frequency band does not match operational band",
-                frequencyBand, mWifiManager.getFrequencyBand());
-    }
-
-    /**
      * Get the {@link WifiConfiguration} based on ssid, security, and password.
      */
     private WifiConfiguration getConfig(String ssid, SecurityType securityType, String password) {
diff --git a/core/tests/benchmarks/src/android/os/ParcelBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
index 4bd2d00..6c45ae8 100644
--- a/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
+++ b/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
@@ -20,12 +20,15 @@
 import com.google.caliper.BeforeExperiment;
 
 public class ParcelBenchmark {
+    private static final int INNER_REPS = 1000;
 
     private Parcel mParcel;
 
     @BeforeExperiment
     protected void setUp() {
         mParcel = Parcel.obtain();
+        mParcel.setDataPosition(0);
+        mParcel.setDataCapacity(INNER_REPS * 8);
     }
 
     @AfterExperiment
@@ -36,43 +39,58 @@
 
     public void timeWriteByte(int reps) {
         final byte val = 0xF;
-        for (int i = 0; i < reps; i++) {
-            mParcel.writeByte(val);
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.writeByte(val);
+            }
         }
     }
 
     public void timeReadByte(int reps) {
-        mParcel.setDataCapacity(reps);
-        for (int i = 0; i < reps; i++) {
-            mParcel.readByte();
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.readByte();
+            }
         }
     }
 
     public void timeWriteInt(int reps) {
         final int val = 0xF;
-        for (int i = 0; i < reps; i++) {
-            mParcel.writeInt(val);
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.writeInt(val);
+            }
         }
     }
 
     public void timeReadInt(int reps) {
-        mParcel.setDataCapacity(reps << 2);
-        for (int i = 0; i < reps; i++) {
-            mParcel.readInt();
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.readInt();
+            }
         }
     }
 
     public void timeWriteLong(int reps) {
         final long val = 0xF;
-        for (int i = 0; i < reps; i++) {
-            mParcel.writeLong(val);
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.writeLong(val);
+            }
         }
     }
 
     public void timeReadLong(int reps) {
-        mParcel.setDataCapacity(reps << 3);
-        for (int i = 0; i < reps; i++) {
-            mParcel.readLong();
+        for (int i = 0; i < (reps / INNER_REPS); i++) {
+            mParcel.setDataPosition(0);
+            for (int j = 0; j < INNER_REPS; j++) {
+                mParcel.readLong();
+            }
         }
     }
 }
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 3703b97..4699fd5 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -30,7 +30,7 @@
     guava \
     littlemock \
     android-support-test \
-    mockito-target \
+    mockito-target-minus-junit4 \
     espresso-core \
     ub-uiautomator \
     platform-test-annotations
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 2452cfd..ee78613 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -479,6 +479,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.view.ScaleGesture" android:label="ScaleGesture">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.view.StubbedView" android:label="ViewStub">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1147,6 +1154,8 @@
         </activity>
         <activity android:name="com.android.internal.policy.PhoneWindowActionModeTestActivity">
         </activity>
+        <activity android:name="android.app.EmptyActivity">
+        </activity>
 
         <receiver android:name="android.app.activity.AbortReceiver">
             <intent-filter android:priority="1">
@@ -1320,6 +1329,11 @@
             android:exported="true">
         </activity>
 
+        <activity
+                android:name="android.print.mockservice.AddPrintersActivity"
+                android:exported="true">
+        </activity>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/layout/scale_gesture.xml b/core/tests/coretests/res/layout/scale_gesture.xml
new file mode 100644
index 0000000..05d408d
--- /dev/null
+++ b/core/tests/coretests/res/layout/scale_gesture.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.
+-->
+
+<!-- Demonstrates use of scale gesture detector to perform pinch to zoom.
+     See corresponding Java code. -->
+<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">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        android:id="@+id/article"
+        android:textSize="12sp"/>
+
+</RelativeLayout>
diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml
index abbebda..b105a0f 100644
--- a/core/tests/coretests/res/xml/printservice.xml
+++ b/core/tests/coretests/res/xml/printservice.xml
@@ -17,4 +17,5 @@
 -->
 
 <print-service  xmlns:android="http://schemas.android.com/apk/res/android"
-     android:settingsActivity="android.print.mockservice.SettingsActivity"/>
+     android:settingsActivity="android.print.mockservice.SettingsActivity"
+     android:addPrintersActivity="android.print.mockservice.AddPrintersActivity" />
diff --git a/core/tests/coretests/src/android/app/EmptyActivity.java b/core/tests/coretests/src/android/app/EmptyActivity.java
new file mode 100644
index 0000000..fefd7b7
--- /dev/null
+++ b/core/tests/coretests/src/android/app/EmptyActivity.java
@@ -0,0 +1,21 @@
+/*
+ * 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.app;
+
+public class EmptyActivity extends Activity {
+}
diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
new file mode 100644
index 0000000..1850d57
--- /dev/null
+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNotSame;
+import static junit.framework.TestCase.assertSame;
+
+@RunWith(AndroidJUnit4.class)
+public class LoaderLifecycleTest {
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class);
+    @Test
+    @MediumTest
+    public void loaderIdentityTest() throws Throwable{
+        mActivityRule.runOnUiThread(() -> {
+            final Handler h = new Handler();
+            final FragmentController fc1 = FragmentController.createController(
+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
+
+            fc1.attachHost(null);
+            fc1.dispatchCreate();
+
+            final FragmentManager fm1 = fc1.getFragmentManager();
+
+            final Fragment f1 = new Fragment();
+            fm1.beginTransaction().add(f1, "one").commitNow();
+
+            // Removing and re-adding a fragment completely will destroy its LoaderManager.
+            // Keep the first one here to confirm this later.
+            final LoaderManager lm1 = f1.getLoaderManager();
+
+            // Remove the fragment, add a second one, and re-add the first to
+            // force its internal index to change. The tests below should still remain consistent.
+            final Fragment f2 = new Fragment();
+            fm1.beginTransaction().remove(f1).commitNow();
+            fm1.beginTransaction().add(f2, "two").commitNow();
+            fm1.beginTransaction().add(f1, "one").commitNow();
+
+            // We'll check this to see if we get the same instance back later
+            // as passed through NonConfigurationInstance. If the keys stay consistent
+            // across fragment remove/re-add, this will be consistent.
+            final LoaderManager lm12 = f1.getLoaderManager();
+
+            assertNotSame("fully removed and re-added fragment got same LoaderManager", lm1, lm12);
+
+            fc1.dispatchActivityCreated();
+            fc1.noteStateNotSaved();
+            fc1.execPendingActions();
+            fc1.doLoaderStart();
+            fc1.dispatchStart();
+            fc1.reportLoaderStart();
+            fc1.dispatchResume();
+            fc1.execPendingActions();
+
+            // Bring the state back down to destroyed, simulating an activity restart
+            fc1.dispatchPause();
+            final Parcelable savedState = fc1.saveAllState();
+            fc1.doLoaderStop(true);
+            fc1.dispatchStop();
+            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
+
+            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
+            assertNotNull("loaderNonConfig was null", loaderNonConfig);
+
+            fc1.dispatchDestroy();
+
+            // Create the new controller and restore state
+            final FragmentController fc2 = FragmentController.createController(
+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0));
+
+            final FragmentManager fm2 = fc2.getFragmentManager();
+
+            fc2.attachHost(null);
+            // Make sure nothing blows up on a null here
+            fc2.restoreLoaderNonConfig(null);
+            // for real this time
+            fc2.restoreLoaderNonConfig(loaderNonConfig);
+            fc2.restoreAllState(savedState, nonconf);
+            fc2.dispatchCreate();
+
+
+            fc2.dispatchActivityCreated();
+            fc2.noteStateNotSaved();
+            fc2.execPendingActions();
+            fc2.doLoaderStart();
+            fc2.dispatchStart();
+            fc2.reportLoaderStart();
+            fc2.dispatchResume();
+            fc2.execPendingActions();
+
+            // Test that the fragments are in the configuration we expect
+            final Fragment restoredOne = fm2.findFragmentByTag("one");
+            final LoaderManager lm2 = restoredOne.getLoaderManager();
+
+            assertSame("didn't get same LoaderManager instance back", lm2, lm12);
+
+            // Bring the state back down to destroyed before we finish the test
+            fc2.dispatchPause();
+            fc2.saveAllState();
+            fc2.dispatchStop();
+            fc2.dispatchDestroy();
+        });
+    }
+
+    @Test
+    @MediumTest
+    public void backStackLoaderIdentityTest() throws Throwable{
+        mActivityRule.runOnUiThread(() -> {
+            final Handler h = new Handler();
+            final FragmentHostCallback host1 =
+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
+            final FragmentController fc1 = FragmentController.createController(host1);
+
+            fc1.attachHost(null);
+            fc1.dispatchCreate();
+
+            final FragmentManager fm1 = fc1.getFragmentManager();
+
+            final Fragment f1 = new Fragment();
+            fm1.beginTransaction().add(f1, "one").commitNow();
+
+            final LoaderManager lm1 = f1.getLoaderManager();
+
+            // Put the fragment on the back stack.
+            fm1.beginTransaction().remove(f1).addToBackStack("backentry").commit();
+            fm1.executePendingTransactions();
+
+            fc1.dispatchActivityCreated();
+            fc1.noteStateNotSaved();
+            fc1.execPendingActions();
+            fc1.doLoaderStart();
+            fc1.dispatchStart();
+            fc1.reportLoaderStart();
+            fc1.dispatchResume();
+            fc1.execPendingActions();
+
+            // Bring the state back down to destroyed, simulating an activity restart
+            fc1.dispatchPause();
+            final Parcelable savedState = fc1.saveAllState();
+            fc1.doLoaderStop(true);
+            fc1.dispatchStop();
+            final FragmentManagerNonConfig nonconf = fc1.retainNestedNonConfig();
+
+            final ArrayMap<String, LoaderManager> loaderNonConfig = fc1.retainLoaderNonConfig();
+            assertNotNull("loaderNonConfig was null", loaderNonConfig);
+
+            fc1.dispatchDestroy();
+
+            // Create the new controller and restore state
+            final FragmentHostCallback host2 =
+                    new TestFragmentHostCallback(mActivityRule.getActivity(), h, 0);
+            final FragmentController fc2 = FragmentController.createController(host2);
+
+            final FragmentManager fm2 = fc2.getFragmentManager();
+
+            fc2.attachHost(null);
+            fc2.restoreLoaderNonConfig(loaderNonConfig);
+            fc2.restoreAllState(savedState, nonconf);
+            fc2.dispatchCreate();
+
+
+            fc2.dispatchActivityCreated();
+            fc2.noteStateNotSaved();
+            fc2.execPendingActions();
+            fc2.doLoaderStart();
+            fc2.dispatchStart();
+            fc2.reportLoaderStart();
+            fc2.dispatchResume();
+            fc2.execPendingActions();
+
+            assertNotSame("LoaderManager kept reference to old FragmentHostCallback",
+                    host1, lm1.getFragmentHostCallback());
+            assertSame("LoaderManager did not refrence new FragmentHostCallback",
+                    host2, lm1.getFragmentHostCallback());
+
+            // Test that the fragments are in the configuration we expect
+            final Fragment restoredOne = fm2.findFragmentByTag("one");
+            final LoaderManager lm2 = restoredOne.getLoaderManager();
+
+            assertSame("didn't get same LoaderManager instance back", lm2, lm1);
+
+            // Bring the state back down to destroyed before we finish the test
+            fc2.dispatchPause();
+            fc2.saveAllState();
+            fc2.dispatchStop();
+            fc2.dispatchDestroy();
+        });
+    }
+
+    public class TestFragmentHostCallback extends FragmentHostCallback<LoaderLifecycleTest> {
+        public TestFragmentHostCallback(Context context, Handler handler, int windowAnimations) {
+            super(context, handler, windowAnimations);
+        }
+
+        @Override
+        public LoaderLifecycleTest onGetHost() {
+            return LoaderLifecycleTest.this;
+        }
+    }
+}
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/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index ac5abad..bd90079 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -297,6 +297,20 @@
                 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
     }
 
+    public void testBuildUniqueFile_mimeless() throws Exception {
+        assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
+        new File(mTarget, "test.jpg").createNewFile();
+        assertNameEquals("test (1).jpg", FileUtils.buildUniqueFile(mTarget, "test.jpg"));
+
+        assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, "test"));
+        new File(mTarget, "test").createNewFile();
+        assertNameEquals("test (1)", FileUtils.buildUniqueFile(mTarget, "test"));
+
+        assertNameEquals("test.foo.bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
+        new File(mTarget, "test.foo.bar").createNewFile();
+        assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
+    }
+
     private static void assertNameEquals(String expected, File actual) {
         assertEquals(expected, actual.getName());
     }
diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
index 582bf1a..985fa4f 100644
--- a/core/tests/coretests/src/android/os/OsTests.java
+++ b/core/tests/coretests/src/android/os/OsTests.java
@@ -32,6 +32,7 @@
         suite.addTestSuite(IdleHandlerTest.class);
         suite.addTestSuite(MessageQueueTest.class);
         suite.addTestSuite(MessengerTest.class);
+        suite.addTestSuite(PatternMatcherTest.class);
         suite.addTestSuite(SystemPropertiesTest.class);
 
         return suite;
diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
new file mode 100644
index 0000000..9645ccc
--- /dev/null
+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
@@ -0,0 +1,234 @@
+package android.os;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class PatternMatcherTest extends TestCase{
+
+    @Test
+    public void testAdvancedPatternMatchesAnyToken() {
+        PatternMatcher matcher = new PatternMatcher(".", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertMatches("b", matcher);
+        assertNotMatches("", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesSetToken() {
+        PatternMatcher matcher = new PatternMatcher("[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertNotMatches("b", matcher);
+
+        matcher = new PatternMatcher("[.*+{}\\]\\\\[]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches(".", matcher);
+        assertMatches("*", matcher);
+        assertMatches("+", matcher);
+        assertMatches("{", matcher);
+        assertMatches("}", matcher);
+        assertMatches("]", matcher);
+        assertMatches("\\", matcher);
+        assertMatches("[", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesSetCharacterClassToken() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertMatches("b", matcher);
+        assertNotMatches("A", matcher);
+        assertNotMatches("1", matcher);
+
+        matcher = new PatternMatcher("[a-z][0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a1", matcher);
+        assertNotMatches("1a", matcher);
+        assertNotMatches("aa", matcher);
+
+        matcher = new PatternMatcher("[z-a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertNotMatches("a", matcher);
+        assertNotMatches("z", matcher);
+        assertNotMatches("A", matcher);
+
+        matcher = new PatternMatcher("[^0-9]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertMatches("z", matcher);
+        assertMatches("A", matcher);
+        assertNotMatches("9", matcher);
+        assertNotMatches("5", matcher);
+        assertNotMatches("0", matcher);
+
+        assertPoorlyFormattedPattern("[]a]");
+        matcher = new PatternMatcher("[\\[a]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertMatches("[", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesEscapedCharacters() {
+        PatternMatcher matcher = new PatternMatcher("\\.", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches(".", matcher);
+        assertNotMatches("a", matcher);
+        assertNotMatches("1", matcher);
+
+        matcher = new PatternMatcher("a\\+", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a+", matcher);
+        assertNotMatches("a", matcher);
+        assertNotMatches("aaaaa", matcher);
+
+        matcher = new PatternMatcher("[\\a-\\z]", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertMatches("a", matcher);
+        assertMatches("z", matcher);
+        assertNotMatches("A", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesLiteralTokens() {
+        PatternMatcher matcher = new PatternMatcher("a", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertNotMatches("", matcher);
+        assertMatches("a", matcher);
+        assertNotMatches("z", matcher);
+
+        matcher = new PatternMatcher("az", PatternMatcher.PATTERN_ADVANCED_GLOB);
+        assertNotMatches("", matcher);
+        assertMatches("az", matcher);
+        assertNotMatches("za", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesSetZeroOrMore() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]*", PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertMatches("", matcher);
+        assertMatches("a", matcher);
+        assertMatches("abcdefg", matcher);
+        assertNotMatches("abc1", matcher);
+        assertNotMatches("1abc", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesSetOneOrMore() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]+", PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertNotMatches("", matcher);
+        assertMatches("a", matcher);
+        assertMatches("abcdefg", matcher);
+        assertNotMatches("abc1", matcher);
+        assertNotMatches("1abc", matcher);
+    }
+
+
+    @Test
+    public void testAdvancedPatternMatchesSingleRange() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]{1}",
+                PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertNotMatches("", matcher);
+        assertMatches("a", matcher);
+        assertMatches("z", matcher);
+        assertNotMatches("1", matcher);
+        assertNotMatches("aa", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesFullRange() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]{1,5}",
+                PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertNotMatches("", matcher);
+        assertMatches("a", matcher);
+        assertMatches("zazaz", matcher);
+        assertNotMatches("azazaz", matcher);
+        assertNotMatches("11111", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesPartialRange() {
+        PatternMatcher matcher = new PatternMatcher("[a-z]{3,}",
+                PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertNotMatches("", matcher);
+        assertMatches("aza", matcher);
+        assertMatches("zazaz", matcher);
+        assertMatches("azazazazazaz", matcher);
+        assertNotMatches("aa", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternMatchesComplexPatterns() {
+        PatternMatcher matcher = new PatternMatcher(
+                "/[0-9]{4}/[0-9]{2}/[0-9]{2}/[a-zA-Z0-9_]+\\.html",
+                PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertNotMatches("", matcher);
+        assertMatches("/2016/09/07/got_this_working.html", matcher);
+        assertMatches("/2016/09/07/got_this_working2.html", matcher);
+        assertNotMatches("/2016/09/07/got_this_working2dothtml", matcher);
+        assertNotMatches("/2016/9/7/got_this_working.html", matcher);
+
+        matcher = new PatternMatcher(
+                "/b*a*bar.*",
+                PatternMatcher.PATTERN_ADVANCED_GLOB);
+
+        assertMatches("/babar", matcher);
+        assertMatches("/babarfff", matcher);
+        assertMatches("/bbaabarfff", matcher);
+        assertMatches("/babar?blah", matcher);
+        assertMatches("/baaaabar?blah", matcher);
+        assertNotMatches("?bar", matcher);
+        assertNotMatches("/bar", matcher);
+        assertNotMatches("/baz", matcher);
+        assertNotMatches("/ba/bar", matcher);
+        assertNotMatches("/barf", matcher);
+        assertNotMatches("/", matcher);
+        assertNotMatches("?blah", matcher);
+    }
+
+    @Test
+    public void testAdvancedPatternPoorFormatThrowsIllegalArgumentException() {
+        assertPoorlyFormattedPattern("[a-z");
+        assertPoorlyFormattedPattern("a{,4}");
+        assertPoorlyFormattedPattern("a{0,a}");
+        assertPoorlyFormattedPattern("a{\\1, 2}");
+        assertPoorlyFormattedPattern("[]");
+        assertPoorlyFormattedPattern("a{}");
+        assertPoorlyFormattedPattern("{3,4}");
+        assertPoorlyFormattedPattern("a+{3,4}");
+        assertPoorlyFormattedPattern("*.");
+        assertPoorlyFormattedPattern(".+*");
+        assertPoorlyFormattedPattern("a{3,4");
+        assertPoorlyFormattedPattern("[a");
+        assertPoorlyFormattedPattern("abc\\");
+        assertPoorlyFormattedPattern("+.");
+
+        StringBuilder charSet = new StringBuilder("[");
+        for (int i = 0; i < 1024; i++) {
+            charSet.append('a' + (i % 26));
+        }
+        charSet.append("]");
+        assertPoorlyFormattedPattern(charSet.toString());
+    }
+
+    private void assertMatches(String string, PatternMatcher matcher) {
+        assertTrue("'" + string + "' should match '" + matcher.toString() + "'",
+                matcher.match(string));
+    }
+
+    private void assertNotMatches(String string, PatternMatcher matcher) {
+        assertTrue("'" + string + "' should not match '" + matcher.toString() + "'",
+                !matcher.match(string));
+    }
+
+    private void assertPoorlyFormattedPattern(String format) {
+        try {
+            new PatternMatcher(format, PatternMatcher.PATTERN_ADVANCED_GLOB);
+        } catch (IllegalArgumentException e) {
+            return;// expected
+        }
+
+        fail("'" + format + "' was erroneously created");
+    }
+}
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index 2c2ee8c..8ef8062 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -16,6 +16,9 @@
 
 package android.print;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
@@ -26,173 +29,134 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.os.CancellationSignal;
-import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
-import android.print.PrintAttributes;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintManager;
-import android.print.PrinterId;
 import android.print.mockservice.PrintServiceCallbacks;
 import android.print.mockservice.PrinterDiscoverySessionCallbacks;
 import android.print.mockservice.StubbablePrinterDiscoverySession;
 import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
-import android.test.InstrumentationTestCase;
-import android.util.DisplayMetrics;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.rule.ActivityTestRule;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.mockito.stubbing.Answer;
 
-import java.io.BufferedReader;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.concurrent.TimeoutException;
 
 /**
  * This is the base class for print tests.
  */
-public abstract class BasePrintTest extends InstrumentationTestCase {
-
-    private static final long OPERATION_TIMEOUT = 30000;
+abstract class BasePrintTest {
+    protected static final long OPERATION_TIMEOUT = 30000;
     private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
-    private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
-    private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
-    private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable ";
     private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
 
-    private PrintTestActivity mActivity;
     private android.print.PrintJob mPrintJob;
 
-    private LocaleList mOldLocale;
-
     private CallCounter mStartCallCounter;
     private CallCounter mStartSessionCallCounter;
 
-    private String[] mEnabledImes;
+    private static Instrumentation sInstrumentation;
+    private static UiDevice sUiDevice;
 
-    private String[] getEnabledImes() throws IOException {
-        List<String> imeList = new ArrayList<>();
+    @Rule
+    public ActivityTestRule<PrintTestActivity> mActivityRule =
+            new ActivityTestRule<>(PrintTestActivity.class, false, true);
 
-        ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
-                .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
-        try (BufferedReader reader = new BufferedReader(
-                new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
+    /**
+     * {@link Runnable} that can throw and {@link Exception}
+     */
+    interface Invokable {
+        /**
+         * Execute the invokable
+         *
+         * @throws Exception
+         */
+        void run() throws Exception;
+    }
 
-            String line;
-            while ((line = reader.readLine()) != null) {
-                imeList.add(line);
+    /**
+     * Assert that the invokable throws an expectedException
+     *
+     * @param invokable The {@link Invokable} to run
+     * @param expectedClass The {@link Exception} that is supposed to be thrown
+     */
+    void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
+            throws Exception {
+        try {
+            invokable.run();
+        } catch (Exception e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                throw e;
             }
         }
 
-        String[] imeArray = new String[imeList.size()];
-        imeList.toArray(imeArray);
-
-        return imeArray;
+        throw new AssertionError("No exception thrown");
     }
 
-    private void disableImes() throws Exception {
-        mEnabledImes = getEnabledImes();
-        for (String ime : mEnabledImes) {
-            String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime;
-            runShellCommand(getInstrumentation(), disableImeCommand);
-        }
+    /**
+     * Return the UI device
+     *
+     * @return the UI device
+     */
+    public UiDevice getUiDevice() {
+        return sUiDevice;
     }
 
-    private void enableImes() throws Exception {
-        for (String ime : mEnabledImes) {
-            String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime;
-            runShellCommand(getInstrumentation(), enableImeCommand);
-        }
-        mEnabledImes = null;
+    protected static Instrumentation getInstrumentation() {
+        return sInstrumentation;
     }
 
-    @Override
-    protected void runTest() throws Throwable {
-        // Do nothing if the device does not support printing.
-        if (supportsPrinting()) {
-            super.runTest();
-        }
-    }
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_PRINTING));
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        if (!supportsPrinting()) {
-            return;
-        }
+        sUiDevice = UiDevice.getInstance(sInstrumentation);
 
         // Make sure we start with a clean slate.
         clearPrintSpoolerData();
-        disableImes();
 
         // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
         // Dexmaker is used by mockito.
         System.setProperty("dexmaker.dexcache", getInstrumentation()
                 .getTargetContext().getCacheDir().getPath());
+    }
 
-        // Set to US locale.
-        Resources resources = getInstrumentation().getTargetContext().getResources();
-        Configuration oldConfiguration = resources.getConfiguration();
-        if (!oldConfiguration.getLocales().get(0).equals(Locale.US)) {
-            mOldLocale = oldConfiguration.getLocales();
-            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-            Configuration newConfiguration = new Configuration(oldConfiguration);
-            newConfiguration.setLocale(Locale.US);
-            resources.updateConfiguration(newConfiguration, displayMetrics);
-        }
-
+    @Before
+    public void initCounters() throws Exception {
         // Initialize the latches.
         mStartCallCounter = new CallCounter();
         mStartSessionCallCounter = new CallCounter();
-
-        // Create the activity for the right locale.
-        createActivity();
     }
 
-    @Override
-    public void tearDown() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
-        // Done with the activity.
-        getActivity().finish();
-        enableImes();
-
-        // Restore the locale if needed.
-        if (mOldLocale != null) {
-            Resources resources = getInstrumentation().getTargetContext().getResources();
-            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-            Configuration newConfiguration = new Configuration(resources.getConfiguration());
-            newConfiguration.setLocales(mOldLocale);
-            mOldLocale = null;
-            resources.updateConfiguration(newConfiguration, displayMetrics);
-        }
-
-        // Make sure the spooler is cleaned, this also un-approves all services
-        clearPrintSpoolerData();
-
-        super.tearDown();
+    @After
+    public void exitActivities() throws Exception {
+        // Exit print spooler
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
     }
 
     protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
             final PrintAttributes attributes) {
         // Initiate printing as if coming from the app.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                PrintManager printManager = (PrintManager) getActivity()
-                        .getSystemService(Context.PRINT_SERVICE);
-                mPrintJob = printManager.print("Print job", adapter, attributes);
-            }
+        getInstrumentation().runOnMainSync(() -> {
+            PrintManager printManager = (PrintManager) getActivity()
+                    .getSystemService(Context.PRINT_SERVICE);
+            mPrintJob = printManager.print("Print job", adapter, attributes);
         });
 
         return mPrintJob;
@@ -215,7 +179,7 @@
         waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start.");
     }
 
-    private void waitForCallbackCallCount(CallCounter counter, int count, String message) {
+    private static void waitForCallbackCallCount(CallCounter counter, int count, String message) {
         try {
             counter.waitForCount(count, OPERATION_TIMEOUT);
         } catch (TimeoutException te) {
@@ -224,12 +188,7 @@
     }
 
     protected PrintTestActivity getActivity() {
-        return mActivity;
-    }
-
-    protected void createActivity() {
-        mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
-                PrintTestActivity.class, null);
+        return mActivityRule.getActivity();
     }
 
     public static String runShellCommand(Instrumentation instrumentation, String cmd)
@@ -238,7 +197,7 @@
         byte[] buf = new byte[512];
         int bytesRead;
         FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-        StringBuffer stdout = new StringBuffer();
+        StringBuilder stdout = new StringBuilder();
         while ((bytesRead = fis.read(buf)) != -1) {
             stdout.append(new String(buf, 0, bytesRead));
         }
@@ -246,7 +205,7 @@
         return stdout.toString();
     }
 
-    protected void clearPrintSpoolerData() throws Exception {
+    protected static void clearPrintSpoolerData() throws Exception {
         assertTrue("failed to clear print spooler data",
                 runShellCommand(getInstrumentation(), String.format(
                         "pm clear --user %d %s", CURRENT_USER_ID,
@@ -319,7 +278,7 @@
         return service;
     }
 
-    protected final class CallCounter {
+    private static final class CallCounter {
         private final Object mLock = new Object();
 
         private int mCallCount;
@@ -331,7 +290,7 @@
             }
         }
 
-        public int getCallCount() {
+        int getCallCount() {
             synchronized (mLock) {
                 return mCallCount;
             }
@@ -355,9 +314,4 @@
             }
         }
     }
-
-    protected boolean supportsPrinting() {
-        return getInstrumentation().getContext().getPackageManager()
-                .hasSystemFeature(PackageManager.FEATURE_PRINTING);
-    }
 }
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index d491ec4..2e9c8e7 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -38,17 +38,23 @@
 import android.print.mockservice.PrinterDiscoverySessionCallbacks;
 import android.print.mockservice.StubbablePrinterDiscoverySession;
 
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 /**
  * tests feeding all possible parameters to the IPrintManager Binder.
  */
+@RunWith(AndroidJUnit4.class)
 public class IPrintManagerParametersTest extends BasePrintTest {
 
     private final int BAD_APP_ID = 0xffffffff;
@@ -58,9 +64,7 @@
     private final PrintJobId mBadPrintJobId;
 
     private PrintJob mGoodPrintJob;
-    private PrinterId mBadPrinterId;
     private PrinterId mGoodPrinterId;
-    private ComponentName mGoodComponentName;
     private ComponentName mBadComponentName;
 
     private IPrintManager mIPrintManager;
@@ -93,6 +97,7 @@
             public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
                     CancellationSignal cancellationSignal, LayoutResultCallback callback,
                     Bundle extras) {
+                callback.onLayoutFailed("not implemented");
             }
 
             @Override
@@ -109,54 +114,46 @@
      */
     private PrintServiceCallbacks createMockCallbacks() {
         return createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-                            @Override
-                            public Void answer(InvocationOnMock invocation) {
-                                // Get the session.
-                                StubbablePrinterDiscoverySession session =
-                                        ((PrinterDiscoverySessionCallbacks) invocation
-                                        .getMock()).getSession();
+                invocation -> createMockPrinterDiscoverySessionCallbacks(invocation1 -> {
+                    // Get the session.
+                    StubbablePrinterDiscoverySession session =
+                            ((PrinterDiscoverySessionCallbacks) invocation1
+                            .getMock()).getSession();
 
-                                if (session.getPrinters().isEmpty()) {
-                                    final String PRINTER_NAME = "good printer";
-                                    List<PrinterInfo> printers = new ArrayList<>();
+                    if (session.getPrinters().isEmpty()) {
+                        final String PRINTER_NAME = "good printer";
+                        List<PrinterInfo> printers = new ArrayList<>();
 
-                                    // Add the printer.
-                                    mGoodPrinterId = session.getService()
-                                            .generatePrinterId(PRINTER_NAME);
+                        // Add the printer.
+                        mGoodPrinterId = session.getService()
+                                .generatePrinterId(PRINTER_NAME);
 
-                                    PrinterCapabilitiesInfo capabilities =
-                                            new PrinterCapabilitiesInfo.Builder(mGoodPrinterId)
-                                                    .setMinMargins(
-                                                            new Margins(200, 200, 200, 200))
-                                                    .addMediaSize(MediaSize.ISO_A4, true)
-                                                    .addResolution(new Resolution("300x300",
-                                                            "300x300", 300, 300),
-                                                            true)
-                                                    .setColorModes(
-                                                            PrintAttributes.COLOR_MODE_COLOR,
-                                                            PrintAttributes.COLOR_MODE_COLOR)
-                                                    .build();
+                        PrinterCapabilitiesInfo capabilities =
+                                new PrinterCapabilitiesInfo.Builder(mGoodPrinterId)
+                                        .setMinMargins(
+                                                new Margins(200, 200, 200, 200))
+                                        .addMediaSize(MediaSize.ISO_A4, true)
+                                        .addResolution(new Resolution("300x300",
+                                                "300x300", 300, 300),
+                                                true)
+                                        .setColorModes(
+                                                PrintAttributes.COLOR_MODE_COLOR,
+                                                PrintAttributes.COLOR_MODE_COLOR)
+                                        .build();
 
-                                    PrinterInfo printer = new PrinterInfo.Builder(
-                                            mGoodPrinterId,
-                                            PRINTER_NAME,
-                                            PrinterInfo.STATUS_IDLE)
-                                                    .setCapabilities(capabilities)
-                                                    .build();
-                                    printers.add(printer);
+                        PrinterInfo printer = new PrinterInfo.Builder(
+                                mGoodPrinterId,
+                                PRINTER_NAME,
+                                PrinterInfo.STATUS_IDLE)
+                                        .setCapabilities(capabilities)
+                                        .build();
+                        printers.add(printer);
 
-                                    session.addPrinters(printers);
-                                }
-                                onPrinterDiscoverySessionStartCalled();
-                                return null;
-                            }
-                        }, null, null, null, null, null, null);
+                        session.addPrinters(printers);
                     }
-                },
+                    onPrinterDiscoverySessionStartCalled();
+                    return null;
+                }, null, null, null, null, null, null),
                 null, null);
     }
 
@@ -214,60 +211,28 @@
         waitForPrinterDiscoverySessionStartCallbackCalled();
     }
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
+    /**
+     * Return a printer Id that is not from any print service
+     *
+     * @return The bad printer id.
+     */
+    private PrinterId getBadPrinterId() {
+        return new PrinterId(getActivity().getComponentName(), "dummy printer");
+    }
 
+    @Before
+    public void setUpMockService() throws Exception {
         MockPrintService.setCallbacks(createMockCallbacks());
 
-        mGoodComponentName = getActivity().getComponentName();
-
         mIPrintManager = IPrintManager.Stub
                 .asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
-
-        // Generate dummy printerId which is a valid PrinterId object, but does not correspond to a
-        // printer
-        mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer");
-    }
-
-    /**
-     * {@link Runnable} that can throw and {@link Exception}
-     */
-    private interface Invokable {
-        /**
-         * Execute the invokable
-         *
-         * @throws Exception
-         */
-        void run() throws Exception;
-    }
-
-    /**
-     * Assert that the invokable throws an expectedException
-     *
-     * @param invokable The {@link Invokable} to run
-     * @param expectedClass The {@link Exception} that is supposed to be thrown
-     */
-    public void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
-            throws Exception {
-        try {
-            invokable.run();
-        } catch (Exception e) {
-            if (e.getClass().isAssignableFrom(expectedClass)) {
-                return;
-            } else {
-                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
-                                + e.getClass().getName());
-            }
-        }
-
-        throw new AssertionError("No exception thrown");
     }
 
     /**
      * test IPrintManager.getPrintJobInfo
      */
     @LargeTest
+    @Test
     public void testGetPrintJobInfo() throws Exception {
         startPrinting();
 
@@ -276,12 +241,9 @@
         assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
         assertEquals(null, mIPrintManager.getPrintJobInfo(null, mAppId, mUserId));
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(
+                () -> mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -290,6 +252,7 @@
      * test IPrintManager.getPrintJobInfos
      */
     @LargeTest
+    @Test
     public void testGetPrintJobInfos() throws Exception {
         startPrinting();
 
@@ -304,12 +267,8 @@
         }
         assertTrue(foundPrintJob);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(() -> mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -318,6 +277,7 @@
      * test IPrintManager.print
      */
     @LargeTest
+    @Test
     public void testPrint() throws Exception {
         final String name = "dummy print job";
 
@@ -326,44 +286,23 @@
 
         startPrinting();
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.print(null, adapter, null, mGoodComponentName.getPackageName(),
-                        mAppId, mUserId);
-            }
-        }, IllegalArgumentException.class);
+        assertException(() -> mIPrintManager.print(null, adapter, null,
+                getActivity().getPackageName(), mAppId, mUserId),
+                IllegalArgumentException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.print(name, null, null, mGoodComponentName.getPackageName(),
-                        mAppId, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.print(name, null, null,
+                getActivity().getPackageName(), mAppId, mUserId),
+                NullPointerException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.print(name, adapter, null, null, mAppId, mUserId);
-            }
-        }, IllegalArgumentException.class);
+        assertException(() -> mIPrintManager.print(name, adapter, null, null, mAppId, mUserId),
+                IllegalArgumentException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.print(name, adapter, null, mBadComponentName.getPackageName(),
-                        mAppId, mUserId);
-            }
-        }, IllegalArgumentException.class);
+        assertException(() -> mIPrintManager.print(name, adapter, null,
+                mBadComponentName.getPackageName(), mAppId, mUserId),
+                IllegalArgumentException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.print(name, adapter, null, mGoodComponentName.getPackageName(),
-                        BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(() -> mIPrintManager.print(name, adapter, null,
+                getActivity().getPackageName(), BAD_APP_ID, mUserId), SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -372,6 +311,7 @@
      * test IPrintManager.cancelPrintJob
      */
     @LargeTest
+    @Test
     public void testCancelPrintJob() throws Exception {
         startPrinting();
 
@@ -379,12 +319,9 @@
         mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
         mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(
+                () -> mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
 
@@ -396,6 +333,7 @@
      * test IPrintManager.restartPrintJob
      */
     @LargeTest
+    @Test
     public void testRestartPrintJob() throws Exception {
         startPrinting();
 
@@ -405,12 +343,9 @@
         mIPrintManager.restartPrintJob(mBadPrintJobId, mAppId, mUserId);
         mIPrintManager.restartPrintJob(null, mAppId, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(
+                () -> mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -419,24 +354,18 @@
      * test IPrintManager.addPrintJobStateChangeListener
      */
     @MediumTest
+    @Test
     public void testAddPrintJobStateChangeListener() throws Exception {
         final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
 
         mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId),
+                NullPointerException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(
+                () -> mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -445,6 +374,7 @@
      * test IPrintManager.removePrintJobStateChangeListener
      */
     @MediumTest
+    @Test
     public void testRemovePrintJobStateChangeListener() throws Exception {
         final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
 
@@ -455,12 +385,8 @@
         mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
 
         mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.removePrintJobStateChangeListener(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.removePrintJobStateChangeListener(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -469,17 +395,14 @@
      * test IPrintManager.addPrintServicesChangeListener
      */
     @MediumTest
+    @Test
     public void testAddPrintServicesChangeListener() throws Exception {
         final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
 
         mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.addPrintServicesChangeListener(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.addPrintServicesChangeListener(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -488,6 +411,7 @@
      * test IPrintManager.removePrintServicesChangeListener
      */
     @MediumTest
+    @Test
     public void testRemovePrintServicesChangeListener() throws Exception {
         final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
 
@@ -498,12 +422,8 @@
         mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
 
         mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.removePrintServicesChangeListener(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.removePrintServicesChangeListener(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -512,6 +432,7 @@
      * test IPrintManager.getPrintServices
      */
     @MediumTest
+    @Test
     public void testGetPrintServices() throws Exception {
         List<PrintServiceInfo> printServices = mIPrintManager.getPrintServices(
                 PrintManager.ALL_SERVICES, mUserId);
@@ -520,12 +441,8 @@
         printServices = mIPrintManager.getPrintServices(0, mUserId);
         assertEquals(printServices, null);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId);
-            }
-        }, IllegalArgumentException.class);
+        assertException(() -> mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId),
+                IllegalArgumentException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -534,38 +451,23 @@
      * test IPrintManager.setPrintServiceEnabled
      */
     @MediumTest
+    @Test
     public void testSetPrintServiceEnabled() throws Exception {
         final ComponentName printService = mIPrintManager.getPrintServices(
                 PrintManager.ALL_SERVICES, mUserId).get(0).getComponentName();
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.setPrintServiceEnabled(printService, false, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(() -> mIPrintManager.setPrintServiceEnabled(printService, false, mUserId),
+                SecurityException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.setPrintServiceEnabled(printService, true, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(() -> mIPrintManager.setPrintServiceEnabled(printService, true, mUserId),
+                SecurityException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
-                                mUserId);
-            }
-        }, SecurityException.class);
+        assertException(
+                () -> mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
+                                mUserId), SecurityException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.setPrintServiceEnabled(null, true, mUserId);
-            }
-        }, SecurityException.class);
+        assertException(() -> mIPrintManager.setPrintServiceEnabled(null, true, mUserId),
+                SecurityException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -574,18 +476,16 @@
      * test IPrintManager.addPrintServiceRecommendationsChangeListener
      */
     @MediumTest
+    @Test
     public void testAddPrintServiceRecommendationsChangeListener() throws Exception {
         final IRecommendationsChangeListener listener =
                 createMockIPrintServiceRecommendationsChangeListener();
 
         mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(
+                () -> mIPrintManager.addPrintServiceRecommendationsChangeListener(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -594,6 +494,7 @@
      * test IPrintManager.removePrintServicesChangeListener
      */
     @MediumTest
+    @Test
     public void testRemovePrintServiceRecommendationsChangeListener() throws Exception {
         final IRecommendationsChangeListener listener =
                 createMockIPrintServiceRecommendationsChangeListener();
@@ -605,12 +506,9 @@
         mIPrintManager.removePrintServiceRecommendationsChangeListener(listener, mUserId);
 
         mIPrintManager.addPrintServiceRecommendationsChangeListener(listener, mUserId);
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(
+                () -> mIPrintManager.removePrintServiceRecommendationsChangeListener(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -619,6 +517,7 @@
      * test IPrintManager.getPrintServiceRecommendations
      */
     @MediumTest
+    @Test
     public void testGetPrintServiceRecommendations() throws Exception {
         mIPrintManager.getPrintServiceRecommendations(mUserId);
 
@@ -629,18 +528,15 @@
      * test IPrintManager.createPrinterDiscoverySession
      */
     @MediumTest
+    @Test
     public void testCreatePrinterDiscoverySession() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
         mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
 
         try {
-            assertException(new Invokable() {
-                @Override
-                public void run() throws Exception {
-                    mIPrintManager.createPrinterDiscoverySession(null, mUserId);
-                }
-            }, NullPointerException.class);
+            assertException(() -> mIPrintManager.createPrinterDiscoverySession(null, mUserId),
+                    NullPointerException.class);
 
             // Cannot test bad user Id as these tests are allowed to call across users
         } finally {
@@ -655,6 +551,7 @@
      * test IPrintManager.startPrinterDiscovery
      */
     @LargeTest
+    @Test
     public void testStartPrinterDiscovery() throws Exception {
         startPrinting();
 
@@ -663,7 +560,7 @@
         goodPrinters.add(mGoodPrinterId);
 
         final List<PrinterId> badPrinters = new ArrayList<>();
-        badPrinters.add(mBadPrinterId);
+        badPrinters.add(getBadPrinterId());
 
         final List<PrinterId> emptyPrinters = new ArrayList<>();
 
@@ -677,19 +574,11 @@
         mIPrintManager.startPrinterDiscovery(listener, emptyPrinters, mUserId);
         mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId),
+                NullPointerException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -698,6 +587,7 @@
      * test IPrintManager.stopPrinterDiscovery
      */
     @MediumTest
+    @Test
     public void testStopPrinterDiscovery() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
@@ -708,12 +598,8 @@
         mIPrintManager.stopPrinterDiscovery(listener, mUserId);
 
         mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.stopPrinterDiscovery(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.stopPrinterDiscovery(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -722,6 +608,7 @@
      * test IPrintManager.validatePrinters
      */
     @LargeTest
+    @Test
     public void testValidatePrinters() throws Exception {
         startPrinting();
 
@@ -729,7 +616,7 @@
         goodPrinters.add(mGoodPrinterId);
 
         final List<PrinterId> badPrinters = new ArrayList<>();
-        badPrinters.add(mBadPrinterId);
+        badPrinters.add(getBadPrinterId());
 
         final List<PrinterId> emptyPrinters = new ArrayList<>();
 
@@ -742,19 +629,11 @@
         mIPrintManager.validatePrinters(badPrinters, mUserId);
         mIPrintManager.validatePrinters(emptyPrinters, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.validatePrinters(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.validatePrinters(null, mUserId),
+                NullPointerException.class);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.validatePrinters(nullPrinters, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.validatePrinters(nullPrinters, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -763,20 +642,17 @@
      * test IPrintManager.startPrinterStateTracking
      */
     @LargeTest
+    @Test
     public void testStartPrinterStateTracking() throws Exception {
         startPrinting();
 
         mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
 
         // Bad printers do no cause exceptions
-        mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+        mIPrintManager.startPrinterStateTracking(getBadPrinterId(), mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.startPrinterStateTracking(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.startPrinterStateTracking(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -785,20 +661,17 @@
      * test IPrintManager.getCustomPrinterIcon
      */
     @LargeTest
+    @Test
     public void testGetCustomPrinterIcon() throws Exception {
         startPrinting();
 
         mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
 
         // Bad printers do no cause exceptions
-        mIPrintManager.getCustomPrinterIcon(mBadPrinterId, mUserId);
+        mIPrintManager.getCustomPrinterIcon(getBadPrinterId(), mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.getCustomPrinterIcon(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.getCustomPrinterIcon(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -807,6 +680,7 @@
      * test IPrintManager.stopPrinterStateTracking
      */
     @LargeTest
+    @Test
     public void testStopPrinterStateTracking() throws Exception {
         startPrinting();
 
@@ -817,15 +691,11 @@
         mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
 
         // Bad printers do no cause exceptions
-        mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
-        mIPrintManager.stopPrinterStateTracking(mBadPrinterId, mUserId);
+        mIPrintManager.startPrinterStateTracking(getBadPrinterId(), mUserId);
+        mIPrintManager.stopPrinterStateTracking(getBadPrinterId(), mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.stopPrinterStateTracking(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.stopPrinterStateTracking(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
@@ -834,6 +704,7 @@
      * test IPrintManager.destroyPrinterDiscoverySession
      */
     @MediumTest
+    @Test
     public void testDestroyPrinterDiscoverySession() throws Exception {
         final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
 
@@ -843,12 +714,8 @@
         // Destroying already destroyed session is a no-op
         mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
 
-        assertException(new Invokable() {
-            @Override
-            public void run() throws Exception {
-                mIPrintManager.destroyPrinterDiscoverySession(null, mUserId);
-            }
-        }, NullPointerException.class);
+        assertException(() -> mIPrintManager.destroyPrinterDiscoverySession(null, mUserId),
+                NullPointerException.class);
 
         // Cannot test bad user Id as these tests are allowed to call across users
     }
diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/core/tests/coretests/src/android/print/PrintTestActivity.java
index 86074a6..e9b001f 100644
--- a/core/tests/coretests/src/android/print/PrintTestActivity.java
+++ b/core/tests/coretests/src/android/print/PrintTestActivity.java
@@ -21,7 +21,6 @@
 import android.view.WindowManager;
 
 public class PrintTestActivity extends Activity {
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
diff --git a/core/tests/coretests/src/android/print/WorkflowTest.java b/core/tests/coretests/src/android/print/WorkflowTest.java
new file mode 100644
index 0000000..62d8b97
--- /dev/null
+++ b/core/tests/coretests/src/android/print/WorkflowTest.java
@@ -0,0 +1,454 @@
+/*
+ * 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.print;
+
+import android.graphics.pdf.PdfDocument;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.mockservice.AddPrintersActivity;
+import android.print.mockservice.MockPrintService;
+
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+import android.print.pdf.PrintedPdfDocument;
+import android.support.test.filters.LargeTest;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests for the basic printing workflows
+ */
+@RunWith(Parameterized.class)
+public class WorkflowTest extends BasePrintTest {
+    private static final String LOG_TAG = WorkflowTest.class.getSimpleName();
+
+    private static float sWindowAnimationScaleBefore;
+    private static float sTransitionAnimationScaleBefore;
+    private static float sAnimatiorDurationScaleBefore;
+
+    private PrintAttributes.MediaSize mFirst;
+    private boolean mSelectPrinter;
+    private PrintAttributes.MediaSize mSecond;
+
+    public WorkflowTest(PrintAttributes.MediaSize first, boolean selectPrinter,
+            PrintAttributes.MediaSize second) {
+        mFirst = first;
+        mSelectPrinter = selectPrinter;
+        mSecond = second;
+    }
+
+    interface InterruptableConsumer<T> {
+        void accept(T t) throws InterruptedException;
+    }
+
+    /**
+     * Execute {@code waiter} until {@code condition} is met.
+     *
+     * @param condition Conditions to wait for
+     * @param waiter    Code to execute while waiting
+     */
+    private void waitWithTimeout(Supplier<Boolean> condition, InterruptableConsumer<Long> waiter)
+            throws TimeoutException, InterruptedException {
+        long startTime = System.currentTimeMillis();
+        while (condition.get()) {
+            long timeLeft = OPERATION_TIMEOUT - (System.currentTimeMillis() - startTime);
+            if (timeLeft < 0) {
+                throw new TimeoutException();
+            }
+
+            waiter.accept(timeLeft);
+        }
+    }
+
+    /**
+     * Executes a shell command using shell user identity, and return the standard output in
+     * string.
+     *
+     * @param cmd the command to run
+     *
+     * @return the standard output of the command
+     */
+    private static String runShellCommand(String cmd) throws IOException {
+        try (FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
+                getInstrumentation().getUiAutomation().executeShellCommand(cmd))) {
+            byte[] buf = new byte[64];
+            int bytesRead;
+
+            StringBuilder stdout = new StringBuilder();
+            while ((bytesRead = is.read(buf)) != -1) {
+                stdout.append(new String(buf, 0, bytesRead));
+            }
+
+            return stdout.toString();
+        }
+    }
+
+    @BeforeClass
+    public static void disableAnimations() throws Exception {
+        try {
+            sWindowAnimationScaleBefore = Float.parseFloat(runShellCommand(
+                    "settings get global window_animation_scale"));
+
+            runShellCommand("settings put global window_animation_scale 0");
+        } catch (NumberFormatException e) {
+            sWindowAnimationScaleBefore = Float.NaN;
+        }
+        try {
+            sTransitionAnimationScaleBefore = Float.parseFloat(runShellCommand(
+                    "settings get global transition_animation_scale"));
+
+            runShellCommand("settings put global transition_animation_scale 0");
+        } catch (NumberFormatException e) {
+            sTransitionAnimationScaleBefore = Float.NaN;
+        }
+        try {
+            sAnimatiorDurationScaleBefore = Float.parseFloat(runShellCommand(
+                    "settings get global animator_duration_scale"));
+
+            runShellCommand("settings put global animator_duration_scale 0");
+        } catch (NumberFormatException e) {
+            sAnimatiorDurationScaleBefore = Float.NaN;
+        }
+    }
+
+    @AfterClass
+    public static void enableAnimations() throws Exception {
+        if (sWindowAnimationScaleBefore != Float.NaN) {
+            runShellCommand(
+                    "settings put global window_animation_scale " + sWindowAnimationScaleBefore);
+        }
+        if (sTransitionAnimationScaleBefore != Float.NaN) {
+            runShellCommand(
+                    "settings put global transition_animation_scale " +
+                            sTransitionAnimationScaleBefore);
+        }
+        if (sAnimatiorDurationScaleBefore != Float.NaN) {
+            runShellCommand(
+                    "settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
+        }
+    }
+
+    /** Add a printer with a given name and supported mediasize to a session */
+    private void addPrinter(StubbablePrinterDiscoverySession session,
+            String name, PrintAttributes.MediaSize mediaSize) {
+        PrinterId printerId = session.getService().generatePrinterId(name);
+        List<PrinterInfo> printers = new ArrayList<>(1);
+
+        PrinterCapabilitiesInfo.Builder builder =
+                new PrinterCapabilitiesInfo.Builder(printerId);
+
+        PrinterInfo printerInfo;
+        if (mediaSize != null) {
+            builder.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .addMediaSize(mediaSize, true)
+                    .addResolution(new PrintAttributes.Resolution("300x300", "300x300", 300, 300),
+                            true);
+
+            printerInfo = new PrinterInfo.Builder(printerId, name,
+                    PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+        } else {
+            printerInfo = (new PrinterInfo.Builder(printerId, name,
+                    PrinterInfo.STATUS_IDLE)).build();
+        }
+
+        printers.add(printerInfo);
+        session.addPrinters(printers);
+    }
+
+    /** Find a certain element in the UI and click on it */
+    private void clickOn(UiSelector selector) throws UiObjectNotFoundException {
+        Log.i(LOG_TAG, "Click on " + selector);
+        UiObject view = getUiDevice().findObject(selector);
+        view.click();
+        getUiDevice().waitForIdle();
+    }
+
+    /** Find a certain text in the UI and click on it */
+    private void clickOnText(String text) throws UiObjectNotFoundException {
+        clickOn(new UiSelector().text(text));
+    }
+
+    /** Set the printer in the print activity */
+    private void setPrinter(String printerName) throws UiObjectNotFoundException {
+        clickOn(new UiSelector().resourceId("com.android.printspooler:id/destination_spinner"));
+
+        clickOnText(printerName);
+    }
+
+    /**
+     * Init mock print servic that returns a single printer by default.
+     *
+     * @param sessionRef Where to store the reference to the session once started
+     */
+    private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef,
+            ArrayList<String> trackedPrinters, PrintAttributes.MediaSize mediaSize) {
+        MockPrintService.setCallbacks(createMockPrintServiceCallbacks(
+                inv -> createMockPrinterDiscoverySessionCallbacks(inv2 -> {
+                            synchronized (sessionRef) {
+                                sessionRef[0] = ((PrinterDiscoverySessionCallbacks) inv2.getMock())
+                                        .getSession();
+
+                                addPrinter(sessionRef[0], "1st printer", mediaSize);
+
+                                sessionRef.notifyAll();
+                            }
+                            return null;
+                        },
+                        null, null, inv2 -> {
+                            synchronized (trackedPrinters) {
+                                trackedPrinters
+                                        .add(((PrinterId) inv2.getArguments()[0]).getLocalId());
+                                trackedPrinters.notifyAll();
+                            }
+                            return null;
+                        }, null, inv2 -> {
+                            synchronized (trackedPrinters) {
+                                trackedPrinters
+                                        .remove(((PrinterId) inv2.getArguments()[0]).getLocalId());
+                                trackedPrinters.notifyAll();
+                            }
+                            return null;
+                        }, inv2 -> {
+                            synchronized (sessionRef) {
+                                sessionRef[0] = null;
+                                sessionRef.notifyAll();
+                            }
+                            return null;
+                        }
+                ), null, null));
+    }
+
+    /**
+     * Start print operation that just prints a single empty page
+     *
+     * @param printAttributesRef Where to store the reference to the print attributes once started
+     */
+    private void print(PrintAttributes[] printAttributesRef) {
+        print(new PrintDocumentAdapter() {
+            @Override
+            public void onStart() {
+            }
+
+            @Override
+            public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+                    CancellationSignal cancellationSignal, LayoutResultCallback callback,
+                    Bundle extras) {
+                callback.onLayoutFinished((new PrintDocumentInfo.Builder("doc")).build(),
+                        !newAttributes.equals(printAttributesRef[0]));
+
+                synchronized (printAttributesRef) {
+                    printAttributesRef[0] = newAttributes;
+                    printAttributesRef.notifyAll();
+                }
+            }
+
+            @Override
+            public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+                    CancellationSignal cancellationSignal, WriteResultCallback callback) {
+                try {
+                    try {
+                        PrintedPdfDocument document = new PrintedPdfDocument(getActivity(),
+                                printAttributesRef[0]);
+                        try {
+                            PdfDocument.Page page = document.startPage(0);
+                            document.finishPage(page);
+                            try (FileOutputStream os = new FileOutputStream(
+                                    destination.getFileDescriptor())) {
+                                document.writeTo(os);
+                                os.flush();
+                            }
+                        } finally {
+                            document.close();
+                        }
+                    } finally {
+                        destination.close();
+                    }
+
+                    callback.onWriteFinished(pages);
+                } catch (IOException e) {
+                    callback.onWriteFailed(e.getMessage());
+                }
+            }
+        }, null);
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        ArrayList<Object[]> tests = new ArrayList<>();
+
+        for (PrintAttributes.MediaSize first : new PrintAttributes.MediaSize[]{
+                PrintAttributes.MediaSize.ISO_A0, null}) {
+            for (Boolean selectPrinter : new Boolean[]{true, false}) {
+                for (PrintAttributes.MediaSize second : new PrintAttributes.MediaSize[]{
+                        PrintAttributes.MediaSize.ISO_A1, null}) {
+                    // If we do not use the second printer, no need to try various options
+                    if (!selectPrinter && second == null) {
+                        continue;
+                    }
+                    tests.add(new Object[]{first, selectPrinter, second});
+                }
+            }
+        }
+
+        return tests;
+    }
+
+    @Test
+    @LargeTest
+    public void addAndSelectPrinter() throws Exception {
+        final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
+        final PrintAttributes printAttributes[] = new PrintAttributes[1];
+        ArrayList<String> trackedPrinters = new ArrayList<>();
+
+        Log.i(LOG_TAG, "Running " + mFirst + " " + mSelectPrinter + " " + mSecond);
+
+        setMockPrintServiceCallbacks(session, trackedPrinters, mFirst);
+        print(printAttributes);
+
+        // We are now in the PrintActivity
+        Log.i(LOG_TAG, "Waiting for session");
+        synchronized (session) {
+            waitWithTimeout(() -> session[0] == null, session::wait);
+        }
+
+        setPrinter("1st printer");
+
+        Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+        synchronized (trackedPrinters) {
+            waitWithTimeout(() -> !trackedPrinters.contains("1st printer"), trackedPrinters::wait);
+        }
+
+        if (mFirst != null) {
+            Log.i(LOG_TAG, "Waiting for print attributes to change");
+            synchronized (printAttributes) {
+                waitWithTimeout(
+                        () -> printAttributes[0] == null ||
+                                !printAttributes[0].getMediaSize().equals(
+                                        mFirst), printAttributes::wait);
+            }
+        } else {
+            Log.i(LOG_TAG, "Waiting for error message");
+            assertNotNull(getUiDevice().wait(Until.findObject(
+                    By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+        }
+
+        setPrinter("All printers\u2026");
+
+        // We are now in the SelectPrinterActivity
+        clickOnText("Add printer");
+
+        // We are now in the AddPrinterActivity
+        AddPrintersActivity.addObserver(
+                () -> addPrinter(session[0], "2nd printer", mSecond));
+
+        // This executes the observer registered above
+        clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
+                .resourceId("com.android.printspooler:id/title"));
+
+        getUiDevice().pressBack();
+        AddPrintersActivity.clearObservers();
+
+        if (mSelectPrinter) {
+            // We are now in the SelectPrinterActivity
+            clickOnText("2nd printer");
+        } else {
+            getUiDevice().pressBack();
+        }
+
+        // We are now in the PrintActivity
+        if (mSelectPrinter) {
+            if (mSecond != null) {
+                Log.i(LOG_TAG, "Waiting for print attributes to change");
+                synchronized (printAttributes) {
+                    waitWithTimeout(
+                            () -> printAttributes[0] == null ||
+                                    !printAttributes[0].getMediaSize().equals(
+                                            mSecond), printAttributes::wait);
+                }
+            } else {
+                Log.i(LOG_TAG, "Waiting for error message");
+                assertNotNull(getUiDevice().wait(Until.findObject(
+                        By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+            }
+
+            Log.i(LOG_TAG, "Waiting for 1st printer to be not tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> trackedPrinters.contains("1st printer"),
+                        trackedPrinters::wait);
+            }
+
+            Log.i(LOG_TAG, "Waiting for 2nd printer to be tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> !trackedPrinters.contains("2nd printer"),
+                        trackedPrinters::wait);
+            }
+        } else {
+            Thread.sleep(100);
+
+            if (mFirst != null) {
+                Log.i(LOG_TAG, "Waiting for print attributes to change");
+                synchronized (printAttributes) {
+                    waitWithTimeout(
+                            () -> printAttributes[0] == null ||
+                                    !printAttributes[0].getMediaSize().equals(
+                                            mFirst), printAttributes::wait);
+                }
+            } else {
+                Log.i(LOG_TAG, "Waiting for error message");
+                assertNotNull(getUiDevice().wait(Until.findObject(
+                        By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+            }
+
+            Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+            synchronized (trackedPrinters) {
+                waitWithTimeout(() -> !trackedPrinters.contains("1st printer"),
+                        trackedPrinters::wait);
+            }
+        }
+
+        getUiDevice().pressBack();
+
+        // We are back in the test activity
+        Log.i(LOG_TAG, "Waiting for session to end");
+        synchronized (session) {
+            waitWithTimeout(() -> session[0] != null, session::wait);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java b/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java
new file mode 100644
index 0000000..8f1a9ed
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java
@@ -0,0 +1,52 @@
+/*
+ * 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.print.mockservice;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+
+public class AddPrintersActivity extends Activity {
+    private static final ArrayList<Runnable> sObservers = new ArrayList<>();
+
+    public static void addObserver(@NonNull Runnable observer) {
+        synchronized (sObservers) {
+            sObservers.add(observer);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        synchronized (sObservers) {
+            for (Runnable sObserver : sObservers) {
+                sObserver.run();
+            }
+        }
+
+        finish();
+    }
+
+    public static void clearObservers() {
+        synchronized (sObservers) {
+            sObservers.clear();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
index e132d79..f3a5373 100644
--- a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
 
 package android.print.mockservice;
 
+import android.support.annotation.NonNull;
 import android.os.CancellationSignal;
 import android.print.PrinterId;
 import android.printservice.CustomPrinterIconCallback;
@@ -42,7 +43,7 @@
     }
 
     @Override
-    public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+    public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
         if (mCallbacks != null) {
             mCallbacks.onStartPrinterDiscovery(priorityList);
         }
@@ -56,29 +57,30 @@
     }
 
     @Override
-    public void onValidatePrinters(List<PrinterId> printerIds) {
+    public void onValidatePrinters(@NonNull List<PrinterId> printerIds) {
         if (mCallbacks != null) {
             mCallbacks.onValidatePrinters(printerIds);
         }
     }
 
     @Override
-    public void onStartPrinterStateTracking(PrinterId printerId) {
+    public void onStartPrinterStateTracking(@NonNull PrinterId printerId) {
         if (mCallbacks != null) {
             mCallbacks.onStartPrinterStateTracking(printerId);
         }
     }
 
     @Override
-    public void onRequestCustomPrinterIcon(PrinterId printerId,
-            CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
+    public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+            @NonNull CancellationSignal cancellationSignal,
+            @NonNull CustomPrinterIconCallback callback) {
         if (mCallbacks != null) {
             mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
         }
     }
 
     @Override
-    public void onStopPrinterStateTracking(PrinterId printerId) {
+    public void onStopPrinterStateTracking(@NonNull PrinterId printerId) {
         if (mCallbacks != null) {
             mCallbacks.onStopPrinterStateTracking(printerId);
         }
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
new file mode 100644
index 0000000..9362ed9
--- /dev/null
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.text;
+
+import static android.text.Layout.Alignment.ALIGN_NORMAL;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.text.style.ReplacementSpan;
+import junit.framework.TestCase;
+
+public class DynamicLayoutTest extends TestCase {
+    private static final int WIDTH = 10000;
+
+    public void testGetBlocksAlwaysNeedToBeRedrawn_en() {
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+        final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
+                ALIGN_NORMAL, 0, 0, false);
+
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.append("abcd efg\n");
+        builder.append("hijk lmn\n");
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.delete(0, builder.length());
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+    }
+
+
+    private static class MockReplacementSpan extends ReplacementSpan {
+        @Override
+        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
+            return 10;
+        }
+
+        @Override
+        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+                int y, int bottom, Paint paint) {
+        }
+    }
+
+    public void testGetBlocksAlwaysNeedToBeRedrawn_replacementSpan() {
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+        final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
+                ALIGN_NORMAL, 0, 0, false);
+
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.append("abcd efg\n");
+        builder.append("hijk lmn\n");
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.setSpan(new MockReplacementSpan(), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        assertNotNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+
+        builder.setSpan(new MockReplacementSpan(), 9, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(1));
+
+        builder.delete(9, 13);
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+        assertFalse(layout.getBlocksAlwaysNeedToBeRedrawn().contains(1));
+
+        builder.delete(0, 4);
+        assertFalse(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().isEmpty());
+    }
+
+    public void testGetBlocksAlwaysNeedToBeRedrawn_thai() {
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+        final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
+                ALIGN_NORMAL, 0, 0, false);
+
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.append("\u0E22\u0E34\u0E19\u0E14\u0E35\u0E15\u0E49\u0E2D\u0E19\u0E23\u0E31\u0E1A");
+        builder.append("\u0E2A\u0E39\u0E48");
+        assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+
+        builder.append("\u0E48\u0E48\u0E48\u0E48\u0E48");
+        assertNotNull(layout.getBlocksAlwaysNeedToBeRedrawn());
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+
+        builder.delete(builder.length() -5, builder.length());
+        assertFalse(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
+        assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().isEmpty());
+    }
+}
diff --git a/core/tests/coretests/src/android/view/PinchZoomAction.java b/core/tests/coretests/src/android/view/PinchZoomAction.java
new file mode 100644
index 0000000..78a4b31
--- /dev/null
+++ b/core/tests/coretests/src/android/view/PinchZoomAction.java
@@ -0,0 +1,250 @@
+/*
+ * 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.view;
+
+import static android.support.test.espresso.core.deps.guava.base.Preconditions.checkNotNull;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static org.hamcrest.Matchers.allOf;
+
+import android.os.SystemClock;
+import android.support.test.espresso.InjectEventSecurityException;
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.MotionEvents;
+import android.support.test.espresso.action.Swiper;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.util.HumanReadables;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import javax.annotation.Nullable;
+import org.hamcrest.Matcher;
+
+/**
+ * Pinch and zooms on a View using touch events.
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be displayed on screen
+ * <ul>
+ */
+public class PinchZoomAction implements ViewAction {
+    public static Swiper.Status sendPinchZoomAction(UiController uiController,
+                                                    float[] firstFingerStartCoords,
+                                                    float[] firstFingerEndCoords,
+                                                    float[] secondFingerStartCoords,
+                                                    float[] secondFingerEndCoords,
+                                                    float[] precision) {
+        checkNotNull(uiController);
+        checkNotNull(firstFingerStartCoords);
+        checkNotNull(firstFingerEndCoords);
+        checkNotNull(secondFingerStartCoords);
+        checkNotNull(secondFingerEndCoords);
+        checkNotNull(precision);
+
+        // Specify the touch properties for the finger events.
+        final MotionEvent.PointerProperties pp1 = new MotionEvent.PointerProperties();
+        pp1.id = 0;
+        pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
+        final MotionEvent.PointerProperties pp2 = new MotionEvent.PointerProperties();
+        pp2.id = 1;
+        pp2.toolType = MotionEvent.TOOL_TYPE_FINGER;
+        MotionEvent.PointerProperties[] pointerProperties =
+                new MotionEvent.PointerProperties[]{pp1, pp2};
+
+        // Specify the motion properties of the two touch points.
+        final MotionEvent.PointerCoords pc1 = new MotionEvent.PointerCoords();
+        pc1.x = firstFingerStartCoords[0];
+        pc1.y = firstFingerStartCoords[1];
+        pc1.pressure = 1;
+        pc1.size = 1;
+        final MotionEvent.PointerCoords pc2 = new MotionEvent.PointerCoords();
+        pc2.x = secondFingerStartCoords[0];
+        pc2.y = secondFingerEndCoords[1];
+        pc2.pressure = 1;
+        pc2.size = 1;
+
+        final long startTime = SystemClock.uptimeMillis();
+        long eventTime = startTime;
+        final MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[]{pc1, pc2};
+
+        final MotionEvent firstFingerEvent = MotionEvent.obtain(startTime,
+                eventTime, MotionEvent.ACTION_DOWN, 1, pointerProperties, pointerCoords,
+                0, 0, 1, 1, 0, 0, 0, 0);
+
+        eventTime = SystemClock.uptimeMillis();
+        final MotionEvent secondFingerEvent = MotionEvent.obtain(startTime, eventTime,
+                MotionEvent.ACTION_POINTER_DOWN +
+                        (pp2.id << MotionEvent.ACTION_POINTER_INDEX_SHIFT),
+                2, pointerProperties, pointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
+
+        try {
+            uiController.injectMotionEvent(firstFingerEvent);
+        } catch (InjectEventSecurityException e) {
+            throw new PerformException.Builder()
+                    .withActionDescription("First finger down event")
+                    .withViewDescription("Scale gesture detector")
+                    .withCause(e)
+                    .build();
+        }
+
+        try {
+            uiController.injectMotionEvent(secondFingerEvent);
+        } catch (InjectEventSecurityException e) {
+            throw new PerformException.Builder()
+                    .withActionDescription("Second finger down event")
+                    .withViewDescription("Scale gesture detector")
+                    .withCause(e)
+                    .build();
+        }
+
+        // Specify the coordinates of the two touch points.
+        final float[][] stepsFirstFinger = interpolate(firstFingerStartCoords,
+                firstFingerEndCoords);
+        final float[][] stepsSecondFinger = interpolate(secondFingerStartCoords,
+                secondFingerEndCoords);
+
+        // Loop until the end points of the two fingers are reached.
+        for (int i = 0; i < PINCH_STEP_COUNT; i++) {
+            eventTime = SystemClock.uptimeMillis();
+
+            pc1.x = stepsFirstFinger[i][0];
+            pc1.y = stepsFirstFinger[i][1];
+            pc2.x = stepsSecondFinger[i][0];
+            pc2.y = stepsSecondFinger[i][1];
+
+            final MotionEvent event = MotionEvent.obtain(startTime, eventTime,
+                    MotionEvent.ACTION_MOVE, 2, pointerProperties, pointerCoords,
+                    0, 0, 1, 1, 0, 0, 0, 0);
+
+            try {
+                uiController.injectMotionEvent(event);
+            } catch (InjectEventSecurityException e) {
+                throw new PerformException.Builder()
+                        .withActionDescription("Move event")
+                        .withViewDescription("Scale gesture event")
+                        .withCause(e)
+                        .build();
+            }
+
+           uiController.loopMainThreadForAtLeast(800);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+
+        // Send the up event for the second finger.
+        final MotionEvent secondFingerUpEvent = MotionEvent.obtain(startTime, eventTime,
+                MotionEvent.ACTION_POINTER_UP, 2, pointerProperties, pointerCoords,
+                0, 0, 1, 1, 0, 0, 0, 0);
+        try {
+            uiController.injectMotionEvent(secondFingerUpEvent);
+        } catch (InjectEventSecurityException e) {
+            throw new PerformException.Builder()
+                    .withActionDescription("Second finger up event")
+                    .withViewDescription("Scale gesture detector")
+                    .withCause(e)
+                    .build();
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        // Send the up event for the first finger.
+        final MotionEvent firstFingerUpEvent = MotionEvent.obtain(startTime, eventTime,
+                MotionEvent.ACTION_POINTER_UP, 1, pointerProperties, pointerCoords,
+                0, 0, 1, 1, 0, 0, 0, 0);
+        try {
+            uiController.injectMotionEvent(firstFingerUpEvent);
+        } catch (InjectEventSecurityException e) {
+            throw new PerformException.Builder()
+                    .withActionDescription("First finger up event")
+                    .withViewDescription("Scale gesture detector")
+                    .withCause(e)
+                    .build();
+        }
+        return Swiper.Status.SUCCESS;
+    }
+
+    private static float[][] interpolate(float[] start, float[] end) {
+        float[][] res = new float[PINCH_STEP_COUNT][2];
+
+        for (int i = 0; i < PINCH_STEP_COUNT; i++) {
+            res[i][0] = start[0] + (end[0] - start[0]) * i / (PINCH_STEP_COUNT - 1f);
+            res[i][1] = start[1] + (end[1] - start[1]) * i / (PINCH_STEP_COUNT - 1f);
+        }
+
+        return res;
+    }
+
+    /** The number of move events to send for each pinch. */
+    private static final int PINCH_STEP_COUNT = 10;
+
+    private final Class<? extends View> mViewClass;
+    private final float[] mFirstFingerStartCoords;
+    private final float[] mFirstFingerEndCoords;
+    private final float[] mSecondFingerStartCoords;
+    private final float[] mSecondFingerEndCoords;
+
+    public PinchZoomAction(float[] firstFingerStartCoords,
+                           float[] firstFingerEndCoords,
+                           float[] secondFingerStartCoords,
+                           float[] secondFingerEndCoords,
+                           Class<? extends View> viewClass) {
+        mFirstFingerStartCoords = firstFingerStartCoords;
+        mFirstFingerEndCoords = firstFingerEndCoords;
+        mSecondFingerStartCoords = secondFingerStartCoords;
+        mSecondFingerEndCoords = secondFingerEndCoords;
+        mViewClass = viewClass;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Matcher<View> getConstraints() {
+        return allOf(isCompletelyDisplayed(), isAssignableFrom(mViewClass));
+    }
+
+    @Override
+    public void perform(UiController uiController, View view) {
+        checkNotNull(uiController);
+        checkNotNull(view);
+        Swiper.Status status;
+        final float[] precision = {1.0f, 1.0f, 1.0f, 1.0f};
+
+        try {
+            status = sendPinchZoomAction(uiController, this.mFirstFingerStartCoords,
+                this.mFirstFingerEndCoords, this.mSecondFingerStartCoords,
+                this.mSecondFingerEndCoords, precision);
+        } catch (RuntimeException re) {
+            throw new PerformException.Builder()
+                    .withActionDescription(getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(re)
+                    .build();
+        }
+        if (status == Swiper.Status.FAILURE) {
+            throw new PerformException.Builder()
+                    .withActionDescription(getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(new RuntimeException(getDescription() + " failed"))
+                    .build();
+        }
+    }
+
+    @Override
+    public String getDescription() {
+        return "Pinch Zoom Action";
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ScaleGesture.java b/core/tests/coretests/src/android/view/ScaleGesture.java
new file mode 100644
index 0000000..a954a4a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ScaleGesture.java
@@ -0,0 +1,58 @@
+/*
+* 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.view;
+
+import com.android.frameworks.coretests.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
+import android.widget.TextView;
+
+public class ScaleGesture extends Activity {
+    private ScaleGestureDetector mScaleGestureDetector;
+    private float mFactor;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.scale_gesture);
+        mScaleGestureDetector = new ScaleGestureDetector(this, new OnScaleGestureListener());
+        mFactor = 1.0f;
+    }
+
+    public float getScaleFactor() {
+        return mFactor;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        mScaleGestureDetector.onTouchEvent(event);
+        return true;
+    }
+
+    public class OnScaleGestureListener extends SimpleOnScaleGestureListener {
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            mFactor *= detector.getScaleFactor();
+            return true;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
new file mode 100644
index 0000000..23d0251
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -0,0 +1,91 @@
+/*
+* 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.view;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.DisplayMetrics;
+import android.view.PinchZoomAction;
+import android.view.ScaleGesture;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.Espresso.onView;
+
+public class ScaleGestureDetectorTest extends ActivityInstrumentationTestCase2<ScaleGesture> {
+    private ScaleGesture mScaleGestureActivity;
+
+    public ScaleGestureDetectorTest() {
+        super("com.android.frameworks.coretests", ScaleGesture.class);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        mScaleGestureActivity = getActivity();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testScaleGestureDetector() {
+        // No scaling should have occurred prior to performing pinch zoom action.
+        final float initialScaleFactor = 1.0f;
+        assertEquals(initialScaleFactor, mScaleGestureActivity.getScaleFactor());
+
+        // Specify start and end coordinates, irrespective of device display size.
+        final DisplayMetrics dm = new DisplayMetrics();
+        final WindowManager wm = (WindowManager) (mScaleGestureActivity.getApplicationContext())
+                .getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getMetrics(dm);
+        final int displayWidth = dm.widthPixels;
+        final int displayHeight = dm.heightPixels;
+
+        // Obtain coordinates to perform pinch and zoom from the center, to 75% of the display.
+        final int centerX = displayWidth / 2;
+        final int centerY = displayHeight / 2;
+
+        // Offset center coordinates by one, so that the two starting points are different.
+        final float[] firstFingerStartCoords = new float[] {centerX + 1.0f, centerY - 1.0f};
+        final float[] firstFingerEndCoords =
+        new float[] {0.75f * displayWidth, 0.25f * displayHeight};
+        final float[] secondFingerStartCoords = new float[] {centerX - 1.0f, centerY + 1.0f};
+        final float[] secondFingerEndCoords =
+        new float[] {0.25f * displayWidth, 0.75f * displayHeight};
+
+        onView(withId(R.id.article)).perform(new PinchZoomAction(firstFingerStartCoords,
+                firstFingerEndCoords, secondFingerStartCoords, secondFingerEndCoords,
+                TextView.class));
+
+        // Text should have been 'zoomed', meaning scale factor increased.
+        assertTrue(mScaleGestureActivity.getScaleFactor() > initialScaleFactor);
+    }
+}
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk
new file mode 100644
index 0000000..a6f87ea
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 18
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp_corrupted
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+corrupted_classes2_dex := $(dir $(built_dex))/classes2.dex
+
+$(corrupted_classes2_dex): $(built_dex)
+	$(hide) touch $@
+
+$(LOCAL_BUILT_MODULE): $(corrupted_classes2_dex)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
new file mode 100644
index 0000000..7993c6f
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.framework.multidexlegacycorrupteddex"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="18"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:name="android.support.multidex.MultiDexApplication"
+        android:allowBackup="true"
+        android:label="MultiDexLegacyTestApp_corrupted">
+        <activity
+            android:name="com.android.framework.multidexlegacycorrupteddex.MainActivity"
+            android:label="MultiDexLegacyTestApp_corrupted" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.multidexlegacycorrupteddex"
+                     android:label="Test for MultiDexLegacyTestApp_corrupted" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<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"
+    tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/CorruptedDexTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/CorruptedDexTest.java
new file mode 100644
index 0000000..afef394
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/CorruptedDexTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.multidexlegacycorrupteddex;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacycorrupteddex/android.test.InstrumentationTestRunner
+</code>
+ */
+public class CorruptedDexTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+
+    public CorruptedDexTest() {
+        super(MainActivity.class);
+    }
+
+    /**
+     * Tests that when a {@link ClassNotFoundException} is thrown, the message also contains
+     * something about the suppressed IOException.
+     */
+    public void testSupressedExceptions()
+    {
+        try {
+            Class.forName("notapackage.NotAClass");
+            throw new AssertionError();
+        } catch (ClassNotFoundException e) {
+            // expected
+
+//          This the check we should do but API is not yet available in 19
+//          Throwable[] suppressed = e.getSuppressed();
+//          assertTrue(suppressed.length > 0);
+//          boolean ioFound = false;
+//          for (Throwable throwable : suppressed) {
+//            if (throwable instanceof IOException) {
+//              ioFound = true;
+//              break;
+//            }
+//          }
+//          assertTrue(ioFound);
+
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            PrintStream ps = new PrintStream(baos);
+            e.printStackTrace(ps);
+            ps.close();
+            assertTrue("Exception message should mention IOException but is not: "
+                  + baos.toString(),
+              baos.toString().contains("IOException"));
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/MainActivity.java
new file mode 100644
index 0000000..61ba5b8
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/src/com/android/framework/multidexlegacycorrupteddex/MainActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.framework.multidexlegacycorrupteddex;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+}
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index 6d1ebb4..de962fa 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -14,7 +14,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    mockito-target
+    mockito-target-minus-junit4
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 627f360..e46f166 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -43,7 +43,7 @@
     </permission>
 
     <permission name="android.permission.BLUETOOTH_STACK" >
-        <group gid="net_bt_stack" />
+        <group gid="bluetooth" />
         <group gid="wakelock" />
     </permission>
 
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 117e17b..345ec37 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -350,7 +350,7 @@
     <family lang="und-Zsye">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
     </family>
-    <family>
+    <family lang="und-Zsym">
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
     </family>
     <family>
diff --git a/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg
index 6af4d70..3d1f8ea 100755
--- a/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg
+++ b/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg
Binary files differ
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..59afd81 100644
--- a/docs/html-intl/intl/es/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/es/about/versions/nougat/index.jd
@@ -1,78 +1,62 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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
@@ -82,26 +66,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>
-        Informar un problema
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Consulta las notas de la versión
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Únete a la comunidad de desarrolladores
-        </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">Lo último</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +77,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..1ecf47c 100644
--- a/docs/html-intl/intl/es/index.jd
+++ b/docs/html-intl/intl/es/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/es/preview/download_mp2.jd b/docs/html-intl/intl/es/preview/download_mp2.jd
deleted file mode 100644
index d71d8fd..0000000
--- a/docs/html-intl/intl/es/preview/download_mp2.jd
+++ /dev/null
@@ -1,360 +0,0 @@
-page.title=Descargas
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">Antes de descargar e instalar los componentes del SDK de la versión preliminar de Android, debe aceptar los términos y las condiciones que se describen a continuación.
-</p>
-
-    <h2 class="norule">Términos y condiciones</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-Este es el Contrato de licencia de la versión preliminar del SDK de Android (el “Contrato de licencia”). 1.
-
- Introducción 1.1 Se le otorga la licencia de la versión preliminar del SDK de Android (denominada “Versión preliminar” en este Contrato de licencia y que incluye específicamente los archivos de sistema de Android, las API agrupadas y los archivos de biblioteca de la Versión preliminar, si se encuentran disponibles), sujeto a los términos del Contrato de licencia.
-
- El Contrato de licencia establece una relación legal vinculante entre usted y Google en relación con el uso que usted realice de la Versión preliminar. 1.2 “Android” hace referencia al conjunto de soluciones Android para dispositivos, según se encuentre disponible en el Proyecto de código abierto de Android (Android Open Source Project), que se encuentra en la siguiente URL: http://source.android.com/, y según se actualiza periódicamente. 1.3 “Google” hace referencia a Google Inc., una corporación de Delaware, con sede principal en 1600 Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos. 2.
-
-
-
-
-
- Aceptación del Contrato de licencia 2.1 Para poder utilizar la Versión preliminar, primero debe aceptar el Contrato de licencia.
-
- Si no acepta el Contrato de licencia, no podrá utilizar la Versión preliminar. 2.2 Al hacer clic para aceptar o utilizar la Versión preliminar, por medio del presente, usted acepta los términos del Contrato de licencia. 2.3 Usted no puede utilizar la Versión preliminar ni aceptar el Contrato de licencia si tiene prohibido recibir la Versión preliminar en virtud de las leyes de los Estados Unidos o de otros países, lo que incluye el país donde es residente o desde el que utilizará la Versión preliminar. 2.4 Si usted utilizará la Versión preliminar de forma interna, dentro de su compañía u organización, usted acepta quedar sujeto al Contrato de licencia en representación de su empleador u otra entidad, y expresa y garantiza que tiene plena autoridad legal para vincular a su empleador o a dicha entidad al Contrato de licencia.
-
-
-
-
-
- Si no posee la autoridad exigida, no podrá aceptar el Contrato de licencia ni usar la Versión preliminar en representación de su empleador u otra entidad. 3.
-
- Licencia de la Versión preliminar de Google 3.1 Sujeto a los términos del Contrato de licencia, Google le otorga una licencia libre de regalías, no asignable, no exclusiva, no transferible a terceros, limitada y revocable para utilizar la Versión preliminar, de forma personal o interna dentro de su compañía u organización, únicamente para desarrollar aplicaciones para ejecutar en la plataforma de Android. 3.2 Usted acepta que Google u otros terceros poseen todos los derechos legales, títulos e intereses en relación con la Versión preliminar, incluidos los Derechos de propiedad intelectual que existan en la Versión preliminar.
-
-
-
- Los “Derechos de propiedad intelectual” hacen referencia a todos y cada uno de los derechos en virtud de las leyes de patentes, derechos de autor, secreto comercial y marca comercial, y todos los demás derechos de propiedad. Google se reserva todos los derechos que no se le otorguen expresamente. 3.3 No podrá utilizar la Versión preliminar para ningún otro propósito que no esté expresamente permitido en el Contrato de licencia.
-
- Excepto en la medida que lo exijan las licencias correspondientes de terceros, no podrá: (a) copiar (excepto con fines de copia de seguridad), modificar, adaptar, redistribuir, descompilar, utilizar técnicas de ingeniería inversa, desarmar ni crear trabajos derivados de la Versión preliminar ni de ninguna de sus partes; ni (b) cargar ninguna parte de la Versión preliminar en un teléfono móvil ni en ningún otro dispositivo de hardware (a excepción de una computadora personal), ni podrá combinar ninguna parte de la Versión preliminar con otro software, ni distribuir algún software o dispositivo que incorpore alguna parte de la Versión preliminar. 3.4 Usted acepta que no tomará medidas que pudieran provocar la fragmentación de Android, incluidas, entre otras, la distribución y la participación en la creación o la promoción de un kit de desarrollo de software derivado de la Versión preliminar. 3.5 El uso, la reproducción y la distribución de los componentes de la Versión preliminar con licencia de software de código abierto están regidos exclusivamente por los términos de la licencia de ese software de código abierto y no de este Contrato de licencia.
-
-
-
- Usted acepta mantener la licencia en buenas condiciones con respecto a dichas licencias de software de código abierto en virtud de todos los derechos otorgados y acepta abstenerse de realizar alguna acción que pueda poner fin, suspender o violar dichos derechos. 3.6 Usted acepta que la forma y la naturaleza de la Versión preliminar que proporciona Google pueden cambiar sin brindarle aviso previo y que las versiones futuras de la Versión preliminar pueden ser incompatibles con las aplicaciones desarrolladas en versiones anteriores de la Versión preliminar.
-
- Usted acepta que Google puede (de forma permanente o temporal) dejar de proporcionarles la Versión preliminar (o cualquiera de las características incluidas en ella) a usted o a los usuarios, generalmente, a criterio exclusivo de Google, sin brindarle aviso previo. 3.7 Ninguna declaración de este Contrato de licencia le otorga el derecho de utilizar alguno de los nombres comerciales, las marcas comerciales, las marcas de servicio, los logotipos, los nombres de dominio ni otras características distintivas de marca de Google. 3.8 Usted acepta que no eliminará, ocultará ni alterará ninguno de los avisos de derechos de propiedad (lo que incluye los avisos de marca comercial y derechos de autor) que pudieran estar anexados o incluidos en la Versión preliminar. 4.
-
-
-
-
-
- Uso que usted realiza de la Versión preliminar 4.1 Google acepta que ninguna declaración del Contrato de licencia le concede a Google derecho, título o interés alguno de su parte (o de parte de sus licenciantes), en virtud del Contrato de licencia, con respecto a las aplicaciones de software que usted desarrolle mediante el uso de la Versión preliminar, lo que incluye los derechos de propiedad intelectual que conlleven esas aplicaciones. 4.2 Usted acepta utilizar la Versión preliminar y escribir aplicaciones únicamente conforme a lo que permite (a) este Contrato de licencia y (b) las leyes, regulaciones, o prácticas y pautas generalmente aceptadas pertinentes en las jurisdicciones relevantes (lo que incluye las leyes sobre la exportación de datos o software hacia los Estados Unidos u otros países relevantes y desde ellos). 4.3 Usted acepta que si utiliza la Versión preliminar para desarrollar aplicaciones, protegerá la privacidad y los derechos legales de los usuarios.
-
-
-
-
-
- Si los usuarios le proporcionan sus nombres de usuario, contraseñas u otra información de inicio de sesión o información personal, debe comunicarles a los usuarios que la información se encontrará disponible para su aplicación, y debe proporcionarles a dichos usuarios un aviso de privacidad con protección y validez legal. Si su aplicación almacena información personal o confidencial proporcionada por los usuarios, lo debe hacer de forma segura. Si los usuarios le proporcionan información sobre la cuenta de Google, su aplicación solo puede usar esa información para acceder a la cuenta de Google del usuario siempre que este le haya otorgado permiso para hacerlo y con los fines para los que se lo haya otorgado. 4.4 Usted acepta que no participará en ninguna actividad con la Versión preliminar (lo que incluye el desarrollo o la distribución de una aplicación) que interfiera, interrumpa, dañe o acceda sin autorización a servidores, redes u otras propiedades o servicios de Google o de algún tercero. 4.5 Usted acepta que es el único responsable (y que Google no asume responsabilidades hacia usted ni terceros) de los datos, el contenido o los recursos que usted cree, transmita o muestre a través de Android o las aplicaciones para Android, y de las consecuencias de sus acciones (lo que incluye la pérdida o el daño que Google pudiera sufrir) al hacerlo. 4.6 Usted acepta que es el único responsable (y que Google no asume responsabilidades hacia usted ni terceros) de cualquier incumplimiento de sus obligaciones en virtud de este Contrato de licencia, los contratos aplicables de terceros o los términos del servicio, o cualquier ley o regulación pertinentes, y de las consecuencias (lo que incluye las pérdidas o los daños que pudieran sufrir Google o algún tercero) de dichos incumplimientos. 4.7 La Versión preliminar se encuentra en desarrollo, y sus pruebas y comentarios son una parte importante del proceso de desarrollo.
-
-
-
-
-
-
-
- Al utilizar la Versión preliminar, usted reconoce que la implementación de algunas características aún se encuentra en desarrollo y que no debe confiar en que la Versión preliminar contará con todas las funcionalidades de una versión estable. Usted acepta no distribuir públicamente ni enviar ninguna aplicación que utilice esta Versión preliminar, ya que esta Versión preliminar ya no se admitirá tras el lanzamiento del SDK oficial de Android. 5.
-
- Sus credenciales de desarrollador 5.1 Usted acepta que es responsable de mantener la confidencialidad de toda credencial de desarrollador que Google pudiera otorgarle o que usted pudiera escoger, y que será el único responsable de todas las aplicaciones que se desarrollen con sus credenciales de desarrollador. 6.
-
-
-
- Privacidad e información 6.1 A fin de poder innovar y mejorar de forma continua la Versión preliminar, Google podría recopilar ciertas estadísticas de uso del software, lo que incluye, entre otras características, un identificador único, la dirección IP asociada, el número de versión del software e información sobre las herramientas o los servicios de la Versión preliminar que se estén utilizando y la manera en que se estén utilizando.
-
- Antes de que se recopile esta información, la Versión preliminar se lo notificará y le solicitará su permiso. Si no otorga su permiso, no se recopilará la información. 6.2 Los datos recopilados se analizan en el agregado para mejorar la Versión preliminar y se conservan de acuerdo con la política de privacidad de Google que se encuentra en el sitio http://www.google.com/policies/privacy/. 7.
-
-
-
- Aplicaciones de terceros 7.1 Si utiliza la Versión preliminar para ejecutar aplicaciones desarrolladas por un tercero o que accedan a datos, contenido o recursos proporcionados por un tercero, usted acepta que Google no es responsable de esas aplicaciones, datos, contenido ni recursos.
-
- Usted comprende que todos los datos, contenidos o recursos a los que podría acceder a través de esas aplicaciones de terceros son exclusiva responsabilidad de la persona que los origina y que Google no es responsable de las pérdidas ni los daños que usted pudiera experimentar como consecuencia del uso o acceso de cualquiera de esas aplicaciones, datos, contenido o recursos de terceros. 7.2 Usted debe saber que los datos, el contenido y los recursos que se le presentan a través de esa aplicación de un tercero pueden estar protegidos por derechos de propiedad intelectual que les pertenecen a sus proveedores (o a otras personas o compañías en representación de estos).
-
- No puede modificar, alquilar, arrendar, prestar, vender, distribuir ni crear obras derivadas basadas en esos datos, contenidos o recursos (en su totalidad o en parte), a menos que los propietarios pertinentes le hayan otorgado permiso específicamente para hacerlo. 7.3 Usted acepta que el uso que haga de las aplicaciones, los datos, el contenido o los recursos de ese tercero puede estar sujeto a términos independientes entre usted y el tercero correspondiente. 8.
-
-
-
- Uso de las API de Google 8.1 API de Google 8.1.1 Si utiliza alguna API para recuperar datos de Google, usted acepta que los datos pueden estar protegidos por derechos de propiedad intelectual que le pertenecen a Google o a las partes que proporcionan esos datos (o a otras personas o empresas en representación de estos).
-
-
-
- El uso que realice de cualquiera de esas API puede estar sujeto a términos de servicio adicionales. No puede modificar, alquilar, arrendar, prestar, vender, distribuir ni crear obras derivadas basadas en esos datos (en su totalidad o en parte), a menos que los términos de servicio correspondientes lo permitan. 8.1.2 Si utiliza alguna API para recuperar datos de un usuario de Google, usted acepta y acuerda que solo podrá recuperar datos con el consentimiento explícito del usuario y solo con los fines limitados para los que el usuario le haya otorgado permiso para hacerlo. 9.
-
-
-
- Finalización del Contrato de licencia 9.1 Este Contrato de licencia tendrá vigencia hasta que lo revoquen usted o Google, como se indica a continuación. 9.2 Si desea rescindir el Contrato de licencia, puede hacerlo al interrumpir el uso que realiza de la Versión preliminar y de las credenciales de desarrollador pertinentes. 9.3 Google puede, en cualquier momento, rescindir el Contrato de licencia, con causa o sin ella, después de notificárselo a usted. 9.4 El Contrato de licencia finalizará automáticamente, sin previo aviso ni acción alguna, tras la primera de las siguientes situaciones: (A) cuando Google deje de proporcionar la Versión preliminar o ciertas partes de esta a los usuarios en el país donde usted reside o desde el que utiliza el servicio; y (B) cuando Google emita una versión final del SDK de Android. 9.5 Si el Contrato de licencia se rescinde, se revocará la licencia que usted recibió en virtud de dicho contrato; usted deberá suspender inmediatamente todo uso de la Versión preliminar y las disposiciones de los párrafos 10, 11, 12 y 14 seguirán vigentes indefinidamente. 10.
-
-
-
-
-
-
-
-
-
-
-
-
-
- EXENCIONES DE RESPONSABILIDAD 10.1 USTED COMPRENDE Y ACEPTA EXPRESAMENTE QUE EL USO QUE REALICE DE LA VERSIÓN PRELIMINAR ES BAJO SU PROPIO RIESGO Y QUE LA VERSIÓN PRELIMINAR SE PROPORCIONA “EN LAS CONDICIONES EN LAS QUE SE ENCUENTRA” Y “SUJETA A DISPONIBILIDAD” SIN GARANTÍAS DE NINGÚN TIPO POR PARTE DE GOOGLE. 10.2 EL USO QUE USTED REALICE DE LA VERSIÓN PRELIMINAR Y DE TODO MATERIAL DESCARGADO U OBTENIDO DE ALGUNA OTRA MANERA MEDIANTE EL USO DE LA VERSIÓN PRELIMINAR ES A SU ENTERO RIESGO Y DISCRECIÓN, Y USTED ES EL ÚNICO RESPONSABLE DE CUALQUIER DAÑO QUE PUDIERA SUFRIR SU SISTEMA INFORMÁTICO U OTRO DISPOSITIVO, O DE LA PÉRDIDA DE DATOS COMO CONSECUENCIA DE DICHO USO.
-
-
-
- SIN PERJUICIO DE LO MENCIONADO ANTERIORMENTE, USTED COMPRENDE QUE LA VERSIÓN PRELIMINAR NO ES UNA VERSIÓN ESTABLE, Y PUEDE CONTENER ERRORES, DEFECTOS Y VULNERABILIDADES DE SEGURIDAD QUE PUEDEN PROVOCAR DAÑOS SIGNIFICATIVOS, LO QUE INCLUYE LA PÉRDIDA COMPLETA E IRRECUPERABLE DEL USO DE SU SISTEMA INFORMÁTICO U OTRO DISPOSITIVO. 10.3 GOOGLE TAMBIÉN RECHAZA TODAS LAS GARANTÍAS Y CONDICIONES DE CUALQUIER TIPO, EXPRESAS O IMPLÍCITAS, INCLUIDAS, ENTRE OTRAS, LAS GARANTÍAS Y CONDICIONES DE COMERCIABILIDAD, IDONEIDAD PARA UN FIN DETERMINADO Y NO VIOLACIÓN. 11.
-
-
-
- LIMITACIÓN DE RESPONSABILIDADES 11.1 USTED COMPRENDE Y ACEPTA EXPRESAMENTE QUE GOOGLE, SUS SUBSIDIARIAS Y FILIALES, Y SUS LICENCIANTES NO SERÁN RESPONSABLES ANTE USTED, EN VIRTUD DE NINGUNA TEORÍA DE RESPONSABILIDAD, POR NINGÚN DAÑO DIRECTO, INDIRECTO, INCIDENTAL, ESPECIAL, RESULTANTE NI PUNITIVO EN EL QUE PODRÍA HABER INCURRIDO, LO QUE INCLUYE LA PÉRDIDA DE DATOS, YA SEA QUE SE LE HAYA NOTIFICADO O NO A GOOGLE O A SUS REPRESENTANTES, O SOBRE CUYA POSIBILIDAD ESTOS DEBERÍAN HABER SABIDO. 12.
-
-
-
- Indemnización 12.1 Hasta el grado máximo que permita la ley, usted acepta defender, indemnizar y eximir de responsabilidades a Google, sus filiales y sus respectivos directores, funcionarios, empleados y agentes, de todo tipo de reclamo, acción legal y proceso judicial, así como de las pérdidas, responsabilidades, daños, costos y gastos (incluidos los honorarios razonables de abogados) que surjan o se acumulen (a) del uso que usted realiza de la Versión preliminar, (b) de cualquier aplicación que desarrolle en la Versión preliminar que infrinja algún derecho de propiedad intelectual de cualquier persona, o que difame a cualquier persona o viole sus derechos de publicidad o privacidad, y (c) del incumplimiento por su parte del Contrato de licencia. 13.
-
-
-
- Cambios en el Contrato de licencia 13.1 Google puede realizar cambios en el Contrato de licencia a medida que distribuye nuevas versiones de la Versión preliminar.
-
- Cuando se realicen esos cambios, Google emitirá una nueva versión del Contrato de licencia, que estará disponible en el sitio web donde se ponga a la venta la Versión preliminar. 14.
-
- Términos legales generales 14.1 El Contrato de licencia constituye el contrato legal integral entre usted y Google, y rige el uso que usted realice de la Versión preliminar (a excepción de los servicios que Google pueda proporcionarle en virtud de un contrato por escrito independiente), y reemplaza totalmente cualquier contrato anterior entre usted y Google en relación con la Versión preliminar. 14.2 Usted acepta que, si Google no ejerce ni impone un derecho o recurso legal especificados en el Contrato de licencia (o sobre el que Google tenga beneficios conforme a cualquier ley aplicable), esto no se considerará una renuncia formal a los derechos por parte de Google y Google aún seguirá recibiendo los beneficios de esos derechos o recursos legales. 14.3 Si algún tribunal judicial con jurisdicción para decidir sobre este asunto determina que alguna de las disposiciones de este Contrato de licencia no es válida, se eliminará esa disposición del Contrato de licencia sin que eso afecte la validez del resto del contrato.
-
-
-
-
-
- Las disposiciones restantes del Contrato de licencia continuarán siendo válidas y aplicables. 14.4 Usted reconoce y acepta que cada miembro del grupo de compañías de las que Google es la compañía central serán terceros beneficiarios del Contrato de licencia, y que esas otras empresas tendrán el derecho de imponer directamente cualquier disposición y ampararse en las disposiciones de este Contrato de licencia que les confieran un beneficio (o que confieran derechos a su favor).
-
- Además de esto, ninguna otra persona o compañía serán terceros beneficiarios del Contrato de licencia. 14.5 RESTRICCIONES DE EXPORTACIÓN.
-
- LA VERSIÓN PRELIMINAR ESTÁ SUJETA A LAS LEYES Y REGULACIONES DE EXPORTACIÓN DE LOS ESTADOS UNIDOS. DEBE CUMPLIR CON TODAS LAS LEYES Y REGULACIONES DE EXPORTACIÓN NACIONALES E INTERNACIONALES QUE SE APLIQUEN A LA VERSIÓN PRELIMINAR. ESTAS LEYES INCLUYEN RESTRICCIONES EN RELACIÓN CON LOS DESTINOS, USUARIOS FINALES Y USO FINAL. 14.6 Usted no puede asignar ni transferir el Contrato de licencia sin la aprobación previa por escrito de Google y todo intento de asignación sin dicha aprobación no tendrá validez.
-
- No podrá delegar sus responsabilidades u obligaciones otorgados en virtud del Contrato de licencia sin la aprobación previa por escrito de Google. 14.7 El Contrato de licencia y su relación con Google conforme al Contrato de licencia se regirán por las leyes del estado de California, independientemente de los principios de conflictos entre leyes.
-
- Usted y Google aceptan presentarse ante la jurisdicción exclusiva de los tribunales del condado de Santa Clara, California, para resolver cualquier asunto legal que pudiera surgir del Contrato de licencia. Sin perjuicio de esto, usted acepta que Google aún podrá aplicar reparaciones conforme a mandato judicial (o a un tipo equivalente de desagravio legal) en cualquier jurisdicción.
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">He leído y acepto los términos y las condiciones anteriores.</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>Contenido del documento</h2>
-      <ol>
-        <li><a href="#sdk">SDK de la versión preliminar</a></li>
-        <li><a href="#docs">Documentación para desarrolladores</a></li>
-        <li><a href="#images">Imágenes del sistema de hardware</a></li>
-      </ol>
-
-      <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  El SDK de la versión preliminar de Android M incluye herramientas de desarrollo, archivos de sistema de Android y archivos de biblioteca que lo ayudarán a probar su aplicación y las nuevas API que se incluirán en la próxima versión de la plataforma.
- En este documento, se describe la manera de obtener los componentes que se pueden descargar de la versión preliminar para probar su aplicación.
-
-</p>
-
-
-<h2 id="sdk">SDK de la versión preliminar</h2>
-
-<p>
-  El SDK de la versión preliminar se encuentra disponible para descargarlo a través del <a href="{@docRoot}tools/help/sdk-manager.html">Administrador de SDK de Android</a>. Para obtener más información sobre cómo descargar y configurar el SDK de la versión preliminar, consulte la sección <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Configurar el SDK de la versión preliminar</a>.
-
-</p>
-
-
-<h2 id="docs">Documentación para desarrolladores</h2>
-
-<p>
-  El paquete de descarga de documentación para desarrolladores brinda información detallada de referencia sobre las API y un informe de diferencias de las API para la versión preliminar.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">Imágenes del sistema de hardware</h2>
-
-<p>
-  Estas imágenes del sistema le permiten instalar una versión preliminar de la plataforma en un dispositivo físico para realizar pruebas.
- Al configurar un dispositivo con una de estas imágenes, puede instalar y probar su aplicación para ver cómo funciona en la próxima versión de la plataforma.
- El proceso de instalación de una imagen del sistema en un dispositivo <em>elimina todos los datos del dispositivo</em>, por lo que debe hacer una copia de seguridad de los datos antes de instalar una imagen del sistema.
-
-
-</p>
-
-<p class="warning">
-  <b>Advertencia:</b> Las siguientes imágenes del sistema de Android son versiones preliminares y están sujetas a cambios. El uso que haga de estas imágenes del sistema se rige por el Contrato de licencia de la versión preliminar del SDK de Android.
- Las imágenes del sistema de la versión preliminar de Android no son versiones estables y pueden contener errores y defectos que pueden generar daños en sus sistemas informáticos, dispositivos y datos.
-
- Las imágenes del sistema de la versión preliminar de Android no se someten a las mismas pruebas que el OS de fábrica y podrían hacer que el teléfono, y las aplicaciones y los servicios instalados dejen de funcionar.
-
-
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">Instalar una imagen en un dispositivo</h3>
-
-<p>
-  Si desea utilizar una imagen del dispositivo para realizar pruebas, debe instalarla en un dispositivo compatible. Siga las instrucciones que se ofrecen a continuación para instalar una imagen del sistema:
-
-</p>
-
-<ol>
-  <li>Descargue y descomprima uno de los paquetes de imágenes del sistema que se enumeran aquí.</li>
-  <li>Realice una copia de seguridad de los datos del dispositivo que desee conservar.</li>
-  <li>Siga las instrucciones que se describen en el sitio <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
- para actualizar la imagen en su dispositivo.
-</li>
-</ol>
-
-<p class="note">
-  <strong>Nota:</strong> Cuando haya actualizado un dispositivo de desarrollo con la imagen del sistema de la versión preliminar, se actualizará automáticamente con la próxima versión preliminar a través de actualizaciones OTA.
-
-</p>
-
-<h3 id="revertDevice">Restablecer las especificaciones de fábrica en un dispositivo</h3>
-
-<p>
-  Si desea desinstalar la versión preliminar y restablecer las especificaciones de fábrica en un dispositivo, visite el sitio <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> y descargue la imagen con la que desea actualizar su dispositivo.
-
- Siga las instrucciones que se describen en esa página para actualizar la imagen en su dispositivo.
-
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/es/preview/features/background-optimization.jd b/docs/html-intl/intl/es/preview/features/background-optimization.jd
deleted file mode 100644
index c061a09..0000000
--- a/docs/html-intl/intl/es/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=Optimizaciones en segundo plano
-page.metaDescription=Nuevas restricciones para transmisiones implícitas.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      En este documento
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">Restricciones en CONNECTIVITY_ACTION</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">Programación de trabajos en red en conexiones
-        sin medición de uso</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Control de la conectividad de la red mientras la aplicación
-        se está ejecutando</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">Restricciones en NEW_PICTURE y
-        NEW_VIDEO</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">Nuevos métodos de JobInfo</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">Nuevos métodos de JobParameter</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">Cómo optimizar aún más tu aplicación</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  Los procesos en segundo plano pueden consumir mucha memoria y batería. Por ejemplo, una
-  transmisión implícita puede iniciar muchos procesos en segundo plano registrados para
-  escucharla, aunque esos procesos quizá no desempeñen un trabajo considerable. Esto puede
- afectar de forma significativa tanto el rendimiento del dispositivo como la experiencia de usuario.
-</p>
-
-<p>
-  Para corregir este problema, en Android N se aplican las siguientes
- restricciones:
-</p>
-
-<ul>
-  <li>Las aplicaciones orientadas a la Preview no reciben transmisiones {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} si
- en su manifiesto registran que las reciben. Las aplicaciones que se ejecutan aún pueden
- escuchar {@code CONNECTIVITY_CHANGE} en su subproceso principal mediante el registro de un
- {@link android.content.BroadcastReceiver} con {@link
-  android.content.Context#registerReceiver Context.registerReceiver()}.
-  </li>
-
-  <li>Las aplicaciones no pueden enviar ni recibir transmisiones {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} ni {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Esta optimización
- afecta a todas las aplicaciones, no solo a aquellas orientadas a la Preview.
-  </li>
-</ul>
-
-<p>
-  Si la aplicación utiliza cualquiera de estas intents, debes quitar las dependencias en
- ellas lo antes posible a fin de poder orientar los dispositivos Android N correctamente.
-  El framework de Android ofrece varias soluciones para mitigar la necesidad de
-  estas transmisiones implícitas. Por ejemplo, {@link android.app.job.JobScheduler}
-  y <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> proporcionan mecanismos sólidos para programar operaciones
-  de red cuando se cumplen las condiciones especificadas, como una conexión a una
-  red de uso no medido. Ahora también puedes usar {@link android.app.job.JobScheduler}
-  para reaccionar a cambios en relación con los proveedores de contenido. Los objetos {@link android.app.job.JobInfo}
-  encapsulan los parámetros que usa {@link android.app.job.JobScheduler}
-  para programar el trabajo. Cuando se cumplen las condiciones del trabajo, el sistema
-  ejecuta ese trabajo en el {@link android.app.job.JobService} de tu aplicación.
-</p>
-
-<p>
-  En este documento, aprenderemos cómo usar métodos alternativos, como
-  {@link android.app.job.JobScheduler}, para adaptar tu aplicación a esas nuevas
-  restricciones.
-</p>
-
-<h2 id="connectivity-action">
-  Restricciones en CONNECTIVITY_ACTION
-</h2>
-
-<p>
-  Las aplicaciones orientadas a Android N no reciben transmisiones {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} si en su manifiesto
- registran que las reciben, y los procesos que dependan de esta
- transmisión no se iniciarán. Esto podría ser un problema para aplicaciones que buscan
- escuchar los cambios en la red o realizar múltiples actividades en red cuando el
- dispositivo se conecta a una red sin medición de uso. Ya existen varias soluciones
-  en relación con esta restricción en el framework de Android, pero elegir
-  la correcta depende de lo que quieras lograr con tu aplicación.
-</p>
-
-<p class="note">
-  <strong>Nota:</strong> Un {@link android.content.BroadcastReceiver} registrado con
- {@link android.content.Context#registerReceiver Context.registerReceiver()}
- continúa recibiendo estas transmisiones mientras se ejecuta la aplicación.
-</p>
-
-<h3 id="sched-jobs">
-  Programación de trabajos en red en conexiones sin medición de uso
-</h3>
-
-<p>
-  Cuando uses la clase {@link android.app.job.JobInfo.Builder JobInfo.Builder}
-  para crear tu objeto {@link android.app.job.JobInfo}, aplica el método {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} y pasa {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} como parámetro de trabajo. El siguiente ejemplo de código
-  programa la ejecución de un servicio cuando el dispositivo se conecta a una red sin
-  medición de uso y se está cargando:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  Cuando se cumplan las condiciones para tu trabajo, tu aplicación recibirá un callback para ejecutar
-  el método {@link android.app.job.JobService#onStartJob onStartJob()} en la
-   {@code JobService.class} especificada. Para ver más ejemplos de la implementación de {@link
-  android.app.job.JobScheduler}, consulta la <a href="{@docRoot}samples/JobScheduler/index.html">aplicación de ejemplo JobScheduler</a>.
-</p>
-
-<p>
-  Las aplicaciones que usan servicios de GMSCore y están orientadas a Android 5.0 (API nivel 21)
-  o anterior, pueden usar <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> y especificar {@code Task.NETWORK_STATE_UNMETERED}.
-</p>
-
-<h3 id="monitor-conn">
-  Control de la conectividad de la red mientras la aplicación se está ejecutando
-</h3>
-
-<p>
-  Las aplicaciones que se ejecutan aún pueden escuchar {@code CONNECTIVITY_CHANGE} con un
- {@link android.content.BroadcastReceiver} registrado. No obstante, la API {@link
-  android.net.ConnectivityManager} ofrece un método más robusto para solicitar
- un callback solo cuando se cumplen las condiciones de red especificadas.
-</p>
-
-<p>
-  Los objetos {@link android.net.NetworkRequest} definen los parámetros del
-  callback de la red en términos de {@link android.net.NetworkCapabilities}. Creas
-  objetos {@link android.net.NetworkRequest} con la clase {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder}. {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
-  y luego pasa el objeto {@link android.net.NetworkRequest} al sistema. Cuando
-  se cumplen las condiciones de la red, la aplicación recibe un callback para ejecutar el método
-  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} definido en su clase {@link
-  android.net.ConnectivityManager.NetworkCallback}.
-</p>
-
-<p>
-  La aplicación continuará recibiendo callbacks hasta que la aplicación salga o llame a
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}.
-</p>
-
-<h2 id="media-broadcasts">
-  Restricciones en NEW_PICTURE y NEW_VIDEO
-</h2>
-
-<p>
-  En Android N, las aplicaciones no pueden enviar ni recibir transmisiones {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} ni {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Esta restricción ayuda a
- aliviar el impacto en el rendimiento y la experiencia de usuario cuando varias aplicaciones deben
- activarse para procesar una nueva imagen o video. Android N
- extiende {@link android.app.job.JobInfo} y {@link
-  android.app.job.JobParameters} para proporcionar una solución alternativa.
-</p>
-
-<h3 id="new-jobinfo">
-  Nuevos métodos de JobInfo
-</h3>
-
-<p>
-  Para activar trabajos en los cambios del URI de contenido, Android N extiende
- la API {@link android.app.job.JobInfo} con los siguientes métodos:
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    Encapsula parámetros necesarios para activar un trabajo en cambios del URI de contenido.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    Pasa un objeto {@code TriggerContentUri} a {@link
-    android.app.job.JobInfo}. Un {@link android.database.ContentObserver}
-    controla el URI de contenido encapsulado. Si hay múltiples objetos {@code
-    TriggerContentUri} asociados a un trabajo, el sistema proporciona un
-    callback aunque se informe un cambio en un solo URI de contenido.
-  </dd>
-
-  <dd>
-    Si cambia algún desencadenante del URI determinado, agrega el marcador {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} para
-    activar el trabajo. Este marcador
-    corresponde al parámetro {@code notifyForDescendants} pasado a {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>Nota:</strong> No se puede usar {@code TriggerContentUri()} junto
-  con {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} ni {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}. Para controlar de forma constante la presencia de cambios en el contenido, programa un nuevo
-  {@link android.app.job.JobInfo} antes de que el {@link
-  android.app.job.JobService} de la aplicación termine de administrar la callback más reciente.
-</p>
-
-<p>
-  El siguiente código de ejemplo programa la activación de un trabajo cuando el sistema informe
-  un cambio en el URI de contenido, {@code MEDIA_URI}:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  Cuando el sistema informa un cambio en el(los) URI de contenido especificado(s), tu aplicación
-  recibe un callback y se pasa un objeto {@link android.app.job.JobParameters}
-  al método {@link android.app.job.JobService#onStartJob onStartJob()}
-  en {@code MediaContentJob.class}.
-</p>
-
-<h3 id="new-jobparam">
-  Nuevos métodos de JobParameter
-</h3>
-
-<p>
-  Android N también amplía {@link android.app.job.JobParameters} para
- permitir que tu aplicación reciba información útil sobre qué autoridades de contenido
- y URI activaron el trabajo:
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    Devuelve el arreglo de los URI que activaron el trabajo. Ese arreglo será {@code
-    null} si ningún URI activó el trabajo (por ejemplo, el trabajo
-    se activó debido al cumplimiento de un plazo o por otro motivo), o la cantidad de URI
-    modificados es superior a 50.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    Devuelve el arreglo de cadenas de autoridades de contenido que activaron el trabajo.
-    Si el arreglo devuelto no es {@code null}, usa {@code getTriggeredContentUris()}
-    para recuperar los detalles de los URI que se modificaron.
-  </dd>
-</dl>
-
-<p>
-  El siguiente código de ejemplo anula el método {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} y
-  registra las autoridades de contenido y los URI que activaron el trabajo:
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  Cómo optimizar aún más tu aplicación
-</h2>
-
-<p>
-  Optimizar tus aplicaciones para que se ejecuten en dispositivos con poca memoria o en condiciones de niveles bajos
-  de memoria puede mejorar el rendimiento y la experiencia del usuario. Eliminar
- dependencias en servicios en segundo plano y receptores de transmisiones implícitas
- registrados estadísticamente puede ayudar a que tu aplicación se ejecute mejor en esos dispositivos. Si bien
- Android N toma medidas para reducir algunos de estos problemas, te
- recomendamos que optimices tu aplicación para que pueda ejecutarse sin utilizar esos
- procesos en segundo plano.
-</p>
-
-<p>
-  Android N presenta algunos comandos adicionales de <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> que
- puedes usar para probar el comportamiento de la aplicación con esos procesos en segundo plano deshabilitados:
-</p>
-
-<ul>
-  <li>Para simular condiciones en las que no hay transmisiones implícitas ni servicios en segundo plano
- disponibles, ingresa el siguiente comando:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>Para volver a habilitar las transmisiones implícitas y los servicios en segundo plano, ingresa el
-  siguiente comando:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/es/preview/features/icu4j-framework.jd b/docs/html-intl/intl/es/preview/features/icu4j-framework.jd
deleted file mode 100644
index e87c4dd..0000000
--- a/docs/html-intl/intl/es/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=API de ICU4J en el framework de Android
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>En este documento:</h2>
-<ol>
-    <li><a href="#relation">Relación con ICU4J</a></li>
-    <li><a href="#migration">Migración hacia API de android.icu desde ICU4J</a></li>
-    <li><a href="#licence">Licencias</a></li>
-</ol>
-
-<h2>Consulta también</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">Documentación para ICU4J</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">Últimos estándares compatibles
- con ICU4J</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J es un conjunto de bibliotecas de Java de código abierto y amplio uso que brinda soporte de Unicode
- y de globalización para aplicaciones de software. Android N
- expone un subconjunto de las API de ICU4J en el framework de Android para que los desarrolladores de aplicaciones
- lo usen debajo del paquete {@code android.icu}. Estas API usan
- datos de ubicación que están presentes en el dispositivo. Como resultado, puedes reducir la superficie de APK
- evitando la compilación de las bibliotecas de ICU4J en APK. En lugar de esto, puedes
- llamarlas en el framework. (En este caso, posiblemente debas brindar
- <a href="{@docRoot}google/play/publishing/multiple-apks.html">versiones múltiples
- del APK</a>, de modo que los usuarios que usan versiones de Android inferiores a Android N
- puedan descargar una versión de la aplicación que incluya las bibliotecas de ICU4J).
-</p>
-
-<p>
-  Al principio de este documento, encontrarás información básica sobre el mínimo de niveles de Android API
- necesarios para soportar estas bibliotecas. Más adelante, encontrarás explicaciones sobre qué
- necesitas saber acerca de la implementación de ICU4J específica para Android. Por último,
- encontrarás explicaciones sobre cómo usar las API de ICU4J en el framework de Android.
-</p>
-
-<h2 id="relation">Relación con ICU4J</h2>
-
-<p>
-  Android N expone un subconjunto de las API de ICU4J mediante el
- paquete <code>android.icu</code>, en lugar de <code>com.ibm.icu</code>. El
-framework de Android puede elegir no
- exponer las API de ICU4J por varias razones; por ejemplo, Android N no expone
- algunas API obsoletas o algunas que el equipo de ICU aún no ha declarado como
- estables. A medida que el equipo de ICU deje de usar API en el futuro, Android también las marcará
- como obsoletas, pero las seguirá incluyendo.
-</p>
-
-<p class="table-caption"><strong>Tabla 1.</strong> Versiones de ICU y CLDR usadas
- en Android N.</p>
-<table>
-<tr>
-<th>Nivel de Android API</th>
-<th>Versión de ICU</th>
-<th>Versión de CLDR</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>Debes tener en cuenta lo siguiente:</p>
-
-<ul>
-<li>Las API de ICU4J del framework de Android no incluyen todas las API de ICU4J.</li>
-<li>Los desarrolladores de NDK deben saber que ICU4C de Android no es compatible.</li>
-<li>Las API del framework de Android no reemplazan la compatibilidad de Android para
-<a href="{@docRoot}guide/topics/resources/localization.html">localizar con
-recursos</a>.</li>
-</ul>
-
-<h2 id="migration">Migración hacia el paquete android.icu desde com.ibm.icu</h2>
-
-<p>
-  Si ya estás usando las API de ICU4J en tu aplicación y las
- API de <code>android.icu</code> cumplen con tus requisitos, migrar hacia las
- API del framework implicará que cambies tus importaciones de Java
- de <code>com.ibm.icu</code> a <code>android.icu</code>. Luego, puedes
- quitar tu propia copia de los archivos de ICU4J del APK.
-</p>
-
-<p class="note">
-  <b>Nota</b>: Las API del framework de ICU4J usan el espacio de nombres {@code android.icu}
- en lugar de {@code com.ibm.icu}. El motivo de esto es evitar conflictos de espacio de nombres
- en APK que contienen sus propias bibliotecas de {@code com.ibm.icu}.
-</p>
-
-<h3 id="migrate-from-android">
-  Migración hacia API de android.icu desde otras Android SDK API
-</h3>
-
-<p>
-  Algunas clases de los paquetes de <code>java</code> y de <code>android</code> son
- equivalentes a las clases de ICU4J. Sin embargo, ICU4J a menudo brinda una compatibilidad
- más amplia para estándares e idiomas.
-</p>
-<p>Aquí tienes algunos ejemplos para comenzar:</p>
-<table>
-<tr>
-<th>Clase</th>
-<th>Alternativa</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">Licencias</h2>
-
-<p>
-  ICU4J se presenta bajo la licencia de ICU. Para obtener información más detallada, consulta la <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">Guía de usuario
- de ICU.</a>
-</p>
diff --git a/docs/html-intl/intl/es/preview/features/multilingual-support.jd b/docs/html-intl/intl/es/preview/features/multilingual-support.jd
deleted file mode 100644
index b03777c..0000000
--- a/docs/html-intl/intl/es/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=Idioma y configuración regional
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>En este documento:</h2>
-<ol>
-	  <li><a href="#preN">Desafíos para la resolución de recursos de idioma</a></li>
-    <li><a href="#postN">Mejoras de la estrategia de resolución de recursos</a></li>
-    <li><a href="#design">Diseño de la aplicación para permitir configuraciones regionales
- adicionales</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N brinda un soporte mejorado para los usuarios de diferentes idiomas
-y les permite seleccionar múltiples configuraciones regionales en la configuración. Android N
-brinda esta capacidad expandiendo ampliamente la cantidad de configuraciones regionales compatibles
-y cambiando la forma en que el sistema resuelve los recursos. El nuevo método de resolución
-de recursos es más robusto y está diseñado para ser compatible con APK existentes, pero
-debes tener especial cuidado para detectar cualquier comportamiento inesperado. Por ejemplo, debes
-realizar pruebas para asegurarte de que tu aplicación muestre el idioma esperado de forma predeterminada. Además,
-si tu aplicación permite múltiples idiomas, debes asegurarte de que esta compatibilidad funcione
-como debería. Por último, debes tratar de asegurarte de que tu aplicación administre con facilidad
-los idiomas para los cuales no diseñaste explícitamente la aplicación.</p>
-
-<p>Al inicio de este documento, encontrarás una explicación sobre la estrategia de resolución de recursos anterior a
-Android N. Luego, encontrarás una descripción de la estrategia de resolución de recursos
-mejorada de Android N. Por último, encontrarás una explicación sobre cómo aprovechar
-la cantidad expandida de configuraciones regionales para permitir acceso a más usuarios de diferentes idiomas.</p>
-
-<h2 id="preN">Desafíos para la resolución de recursos de idioma</h2>
-
-<p>Antes de Android N, Android no siempre podía
- hacer coincidir correctamente las configuraciones regionales de la aplicación y del sistema.</p>
-
- <p>Por ejemplo, imagina que tienes la siguiente situación:</p>
- <ul>
- <li>El idioma predeterminado de la aplicación es {@code en_US} (inglés de EE. UU.), y también tiene
- cadenas en español localizadas en archivos de recursos {@code es_ES}
-.</li>
- <li> Se configura un dispositivo en {@code es_MX}. </li>
-
-<p>Cuando el código Java hace referencia a cadenas, el sistema carga
- las cadenas del archivo de recursos ({@code en_US}) predeterminado, incluso si la aplicación tiene
- recursos en español localizados en {@code es_ES}. Esto se debe a que, cuando el sistema
- no puede encontrar una coincidencia exacta, continúa buscando recursos y se quita el
- código del país de la configuración regional. Finalmente, si no se encuentra una coincidencia, el sistema regresa
- a la configuración predeterminada, que es {@code en_US}. </p>
-
-
-<p>El sistema también usaba {@code en_US} de forma predeterminada si el usuario elegía un idioma que
- no era compatible con la aplicación, como el francés. Por ejemplo:</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>Tabla 1.</strong> Resolución de recursos sin una coincidencia de configuración regional exacta.
-</p>
-<table>
-<tbody>
-<tr>
-<th>Configuración del usuario</th>
-<th>Recursos de la aplicación</th>
-<th>Resolución de recursos</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-Predeterminado (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-Intentar fr_CH =&gt; Error<br>
-Intentar fr =&gt; Error<br>
-Usar predeterminado (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>En este ejemplo, el sistema muestra las cadenas en inglés sin
-saber si el usuario comprende este idioma. Este comportamiento es muy común
-hoy en día. Android N debería reducir sustancialmente la frecuencia
-de resultados como este.</p>
-
-<h2 id="postN">Mejoras de la estrategia de resolución de recursos</h2>
-<p>Android N brinda una resolución de recursos más robusta y
-encuentra mejores recursos de forma automática. Sin embargo, para acelerar la resolución y mejorar la
-facilidad de mantenimiento, debes almacenar los recursos en el dialecto primario.
- Por ejemplo, si antes almacenabas los recursos en español en el directorio {@code es-US}
-, pásalos al directorio {@code es-419}, que contiene la variante de Latinoamérica.
- De forma similar, si tienes cadenas de recursos en una carpeta llamada {@code en-GB}, cámbiale
- el nombre a {@code en-001} (inglés internacional), ya que el dialecto primario más común
- para las cadenas en <code>en-GB</code> es {@code en-001}.
- Los siguientes ejemplos explican por qué estas prácticas mejoran el desempeño
- y la confiabilidad de la resolución de recursos.</p>
-
-<h3>Ejemplos de resolución de recursos</h3>
-
-<p>Con Android N, el caso descrito en la <strong>Tabla 1</strong> se resuelve
-de otra forma:</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>Tabla 2.</strong> Una estrategia de resolución mejorada para los casos en que no
-hay una coincidencia de configuración regional exacta.</p>
-<table>
-<tr>
-<th>Configuración del usuario</th>
-<th>Recursos de la aplicación</th>
-<th>Resolución de recursos</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-Predeterminado (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-Intentar fr_CH =&gt; Error<br>
-Intentar fr =&gt; Error<br>
-Intentar secundario de fr =&gt; fr_FR<br>
-Usar fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>Así, los recursos se muestran en francés en lugar de en inglés. Este ejemplo también muestra
- por qué deberías almacenar las cadenas en francés en {@code fr} en lugar de en {@code fr_FR}
- para Android N. Aquí, el procedimiento se basa en hacer coincidir el dialecto primario más cercano,
- lo cual hace que la resolución sea más rápida y más predecible.</p>
-
-<p>Además de esta lógica de resolución mejorada, Android ofrece ahora más
- idiomas de usuario de entre los cuales elegir. Volvamos a ver el ejemplo anterior con el idioma italiano
- especificado como un idioma de usuario adicional, pero sin compatibilidad de la aplicación con el idioma francés.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>Tabla 3.</strong> Resolución de recursos cuando la aplicación solo hace coincidir la
-configuración regional de segunda preferencia del usuario.</p>
-<table>
-<tr>
-<th>Configuración del usuario</th>
-<th>Recursos de la aplicación</th>
-<th>Resolución de recursos</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-Predeterminado (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-Intentar fr_CH =&gt; Error<br>
-Intentar fr =&gt; Error<br>
-Intentar secundario de fr =&gt; Error<br>
-Intentar it_CH =&gt; Error<br>
-Intentar it =&gt; Error<br>
-Intentar secundario de it =&gt; it_IT<br>
-Usar it_IT
-</td>
-
-</tr>
-
-</table>
-<p>El usuario recibe la información en un idioma que comprende, si bien la aplicación no
-es compatible con el idioma francés.</p>
-
-
-<h2 id="design">Diseño de la aplicación para permitir configuraciones regionales adicionales</h2>
-<h3>API LocaleList</h3>
-
-<p>Android N incorpora una nueva API, {@code LocaleList.getDefault()},
-que les permite a las aplicaciones consultar directamente la lista de idiomas que ha especificado el usuario. Esta API
- te permite crear un comportamiento de la aplicación
- más sofisticado y una presentación de contenido más optimizada. Por ejemplo, las búsquedas
- pueden mostrar resultados en múltiples idiomas según la configuración del usuario.  Las aplicaciones de navegadores
- pueden evitar ofrecer la traducción de páginas que están en un idioma que el usuario comprende,
- y las aplicaciones de teclado pueden habilitar automáticamente todos los diseños correctos. </p>
-
-<h3>Formateadores</h3>
-
-<p>Hasta Android 6.0 (API nivel 23), Android solo permitía una o dos
- configuraciones regionales para muchos idiomas comunes
- (en, es, ar, fr, ru). Debido a que había solo unas pocas variantes para cada idioma,
-las aplicaciones podían almacenar algunos números y fechas como cadenas preprogramadas
-en los archivos de recursos.  Sin embargo, con el conjunto ampliado de configuraciones regionales
-compatibles de Android, puede haber diferencias importantes
-en los formatos de fecha, hora, moneda e
-información similar, incluso dentro de una sola configuración regional. Preprogramar los formatos puede generar
-una experiencia confusa para los usuarios.  Por lo tanto, cuando desarrolles aplicaciones para Android,
-asegúrate de usar formateadores en lugar de preprogramar las cadenas de números y fechas.</p>
-
-<p>Un muy buen ejemplo es el árabe. Android N expandió su compatibilidad de
-una configuración regional, {@code ar_EG}, a 27 configuraciones regionales. Estas configuraciones regionales pueden compartir la mayoría de los recursos,
-pero algunas prefieren dígitos ASCII, mientras que otras prefieren dígitos nativos. Por ejemplo,
-cuando desees crear una oración con una variable de dígito, como
-"Elige un PIN de 4 dígitos", usa formateadores como se muestra a continuación:</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/es/preview/features/notification-updates.jd b/docs/html-intl/intl/es/preview/features/notification-updates.jd
deleted file mode 100644
index ff0635e..0000000
--- a/docs/html-intl/intl/es/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,393 +0,0 @@
-page.title=Notificaciones
-page.tags=notifications
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>Este documento incluye lo siguiente:</h2>
-<ol>
-  <li><a href="#direct">Respuesta directa</a></li>
-  <li><a href="#bundle">Notificaciones integradas</a></li>
-  <li><a href="#custom">Vistas personalizadas</a></li>
-  <li><a href="#style">Estilo de mensajería</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N presenta varias API nuevas que permiten a las aplicaciones publicar
-notificaciones altamente visibles e interactivas.</p>
-
-<p>Android N amplía la API de notificación existente {@link android.support.v4.app.RemoteInput}
-para admitir respuestas en línea en teléfonos celulares. Esta función permite a los usuarios
- responder rápidamente desde el panel de notificaciones sin tener que visitar tu aplicación.</p>
-
-<p>
-  Android N también te permite agrupar notificaciones similares para que
-  aparezcan como una sola notificación. Para que esto sea posible, Android N usa el método existente {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()}. Los usuarios pueden expandir cada una de las
-  notificaciones y realizar acciones como responder e ignorar en cada una
-  de ellas, de forma individual desde el panel de notificaciones.
-</p>
-
-<p>Por último, Android N también suma nuevas API que te permiten aprovechar las decoraciones
-del sistema en las vistas de notificación personalizadas de tu aplicación. Estas API ayudan a
-garantizar que las vistas de notificaciones compartan una presentación acorde a las
-plantillas estándar.</p>
-
-<p>En este documento se destacan algunos de los cambios clave que puedes tener en cuenta
- al usar las nuevas funciones de notificación en tus aplicaciones.</p>
-
-<h2 id="direct">Respuesta directa</h2>
-
-<p>Con la función de respuesta directa en Android N, los usuarios pueden responder
-rápidamente mensajes de texto o actualizar listas de tareas directamente dentro de la interfaz de
-notificación. En un dispositivo portátil, la acción de respuesta en línea aparece como un botón adicional
- anexado a la notificación. Cuando un usuario responde mediante el teclado, el sistema adjunta
- la respuesta de texto a la intent
- que especificaste para la acción de notificación y envía la intención a tu
- aplicación para dispositivos portátiles.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>Figura 1.</strong> Android N agrega el botón de acción <strong>Reply</strong>
-.
-</p>
-
-<h3>Adición de acciones de respuesta en línea</h3>
-
-<p>Para crear una acción de notificación que admita respuesta directa:
-</p>
-
-<ol>
-<li>Crea una instancia de {@link android.support.v4.app.RemoteInput.Builder}
-  que puedas agregar a tu acción de
-notificación. El constructor de esta clase acepta una cadena que el sistema usa como clave
- para la inserción de texto. Luego, tu aplicación para dispositivos portátiles usará esa clave para recuperar el texto
-  de la entrada.
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>Adjunta el objeto {@link android.support.v4.app.RemoteInput}
- a una acción usando <code>addRemoteInput()</code>.
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>Aplica la acción a una notificación y emite la notificación.
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> Cuando se active la acción de notificación,
-el sistema le solicitará al usuario que ingrese una respuesta. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Figura 2.</strong> El usuario ingresa texto desde el panel de notificaciones.
-</p>
-
-<h3>
-  Recuperación de entradas del usuario a partir de la respuesta en línea
-</h3>
-
-<p>
-  Para recibir entradas del usuario de la interfaz de notificación a la actividad que
- declaraste en la intent de la acción de respuesta:
-</p>
-
-<ol>
-  <li>Llama a {@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()} pasando la intent de la acción de notificación como
- el parámetro de entrada. Este método devuelve un {@link android.os.Bundle} que
- contiene la respuesta de texto.
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>Consulta el paquete con la clave de resultado (proporcionada al constructor {@link
-  android.support.v4.app.RemoteInput.Builder}). Puedes completar
- este proceso y recuperar el texto de entrada mediante la creación de un método, como en el
- siguiente fragmento de código:
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>Crea y emite otra notificación, utilizando la misma ID de notificación que
- proporcionaste para la notificación anterior. El indicador de progreso
- desaparece de la interfaz de notificación para informarles a los usuarios que la respuesta
- fue exitosa. Al trabajar con esta nueva notificación, usa el contexto que se
- pasa al método {@code onReceive()} del receptor.
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  En el caso de las aplicaciones interactivas, como los chats, podría ser útil incluir
- contexto adicional cuando se administra texto recuperado. Por ejemplo, en estas aplicaciones, se podrían mostrar
- múltiples líneas de historial de chat. Cuando el usuario responde a través de {@link
-  android.support.v4.app.RemoteInput}, puedes actualizar el historial de respuestas
- por medio del método {@code setRemoteInputHistory()}.
-</p>
-
-<p>
-  La notificación se debe actualizar o cancelar luego de que la aplicación haya
- recibido entradas remotas. Cuando el usuario responde a una actualización remota
- por medio de la respuesta directa,
- no canceles la notificación. En cambio, actualiza la notificación para mostrar la respuesta del usuario.
-En el caso de las notificaciones que utilizan {@code MessagingStyle}, debes agregar
-la respuesta como el mensaje más reciente. Cuando se utilizan otras plantillas, puedes
-agregar la respuesta del usuario al historial de entradas remotas.
-</p>
-
-<h2 id="bundle">Notificaciones integradas</h2>
-
-<p>Android N ofrece a los desarrolladores una nueva manera de representar
- una cola de notificaciones: <i>notificaciones integradas</i>. Esto es similar a la función
-  <a href="{@docRoot}training/wearables/notifications/stacks.html">Pilas de
-  notificaciones</a> en Android Wear. Por ejemplo, si tu aplicación crea notificaciones
-  para los mensajes recibidos, cuando se recibe más de un mensaje, agrupa las
- notificaciones en un solo paquete. Puedes
- usar el método existente {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} para agrupar notificaciones similares.</p>
-
-<p>
-  El grupo de notificaciones impone una jerarquía en las notificaciones que lo integran.
-  En la parte superior de esa jerarquía se encuentra una notificación principal que muestra información
-  resumida para el grupo. El usuario puede expandir
-  progresivamente el grupo de notificaciones, y el sistema muestra más información a medida que el
-  usuario continúa indagando. Cuando el usuario expande el paquete, el sistema revela más
-  información para todas sus notificaciones secundarias; cuando el usuario
-  expande una de esas notificaciones, el sistema revela todo su contenido.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Figura 3.</strong> El usuario puede expandir progresivamente el grupo de
- notificaciones.
-</p>
-
-<p class="note">
-  <strong>Nota:</strong> Si la misma aplicación envía cuatro o más notificaciones
- y no se especifica un grupo, el
- sistema las agrupa automáticamente.
-</p>
-
-<p>Para obtener información acerca de cómo agregar notificaciones a un grupo, consulta
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">Agregar
-cada notificación a un grupo</a>.</p>
-
-
-<h3 id="best-practices">Prácticas recomendadas para las notificaciones integradas</h3>
-<p>Esta sección proporciona pautas acerca de cuándo usar grupos de notificaciones en lugar
-de las notificaciones {@link android.app.Notification.InboxStyle InboxStyle}
-que estaban disponibles en versiones anteriores de la
-plataforma Android.</p>
-
-<h3>Cuándo usar notificaciones integradas</h3>
-
-<p>Solo debes usar grupos de notificaciones si se cumplen todas las siguientes condiciones
-para tu caso de uso:</p>
-
-<ul>
-  <li>Las notificaciones secundarias son notificaciones completas y se pueden mostrar
-   individualmente sin la necesidad de un resumen del grupo.</li>
-  <li>El aislamiento de notificaciones secundarias de forma individual tiene un beneficio. Por
-  ejemplo:
-  </li>
-  <ul>
-    <li>Son interactivas, con acciones específicas para cada notificación secundaria.</li>
-    <li>Hay más información sobre la notificación secundaria que el usuario quiere leer.</li>
-  </ul>
-</ul>
-
-<p>Algunos ejemplos de buenos casos de uso para grupos de notificaciones incluyen: una aplicación de mensajería
-que exhiba una lista de mensajes entrantes, o una aplicación de correo electrónico que exhiba una lista de
-correos electrónicos recibidos.</p>
-
-<p>
-Algunos ejemplos de casos en los que se prefiere una sola notificación
- incluyen mensajes individuales de una sola persona, o una lista de
- elementos de texto de una sola línea. Para lograr esto, puedes usar
-({@link android.app.Notification.InboxStyle InboxStyle} o
-{@link android.app.Notification.BigTextStyle BigTextStyle})
-.
-</p>
-
-<h3 id ="post">Visualización de notificaciones integradas</h3>
-
-<p>
-  La aplicación siempre debe publicar un resumen del grupo, aún si el grupo contiene una sola
- notificación secundaria. Si contiene una sola notificación, el sistema suprimirá el resumen y mostrará directamente la
-  notificación secundaria. Esto garantiza
-  que el sistema pueda proporcionar una experiencia uniforme cuando el usuario quita con un gesto de "deslizar" notificaciones
-  secundarias de un grupo.
-</p>
-
-<p class="note">
-  <strong>Nota:</strong> Esta versión de Android N aún no
-  suprime el resumen para los grupos de notificaciones que contienen una sola notificación secundaria. Esta
-  funcionalidad se agregará en una versión posterior de Android N.
-</p>
-
-<h3>Inspección de notificaciones</h3>
-
-<p>Si bien el sistema generalmente muestra las notificaciones secundarias como un grupo, puedes configurarlas
- para que aparezcan temporalmente como
- <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">
- notificaciones emergentes</a>. Esta función es especialmente útil porque permite
-  el acceso inmediato a la notificación secundaria más reciente y a las acciones asociadas a ella.
-</p>
-
-
-<h3>Compatibilidad con versiones anteriores</h3>
-
-<p>
-  Tanto los grupos de notificaciones como las entradas remotas han formado parte de la API {@link
-  android.app.Notification} desde Android 5.0 (API nivel 21) para soportar dispositivos
-  con Android Wear. Si ya compilaste notificaciones con esas API,
-  lo único que debes hacer es verificar que el comportamiento de la aplicación concuerde
-  las pautas antes descritas y considerar la implementación de {@code
-  setRemoteInputHistory()}.
-</p>
-
-<p>
-  Para poder ser compatible con versiones anteriores, están disponibles las mismas API con
-  la clase {@link android.support.v4.app.NotificationCompat}
-  de la biblioteca de soporte, que te permite crear notificaciones que funcionan en versiones de Android
-  anteriores. En dispositivos portátiles y tablets, los usuarios solo ven la notificación de resumen
-  de modo que una aplicación aún debe tener un estilo de bandeja de entrada o una notificación equivalente
-  que represente todo el contenido del grupo. Dado que los dispositivos con Android
-  Wear permiten a los usuarios ver todas las notificaciones secundarias incluso en
-  niveles anteriores de la plataforma, debes crear notificaciones secundarias independientemente del nivel de
-  API.
-</p>
-
-<h2 id="custom"> Vistas personalizadas</h2>
-<p>A partir de la versión Android N, puedes personalizar vistas de notificaciones y
-aún obtener decoraciones del sistema, como encabezados de notificaciones, acciones y diseños
-expandibles.</p>
-
-<p>Para habilitar esta característica, Android N suma las siguientes API para que puedas diseñar tu
-  vista personalizada:</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> Permite diseñar notificaciones que no sean notificaciones
-de medios.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> Permite diseñar notificaciones de medios.</dd>
-</dl>
-
-<p>Para usar esta nueva API, llama al método {@code setStyle()} y pásale
-el estilo de la vista personalizada que hayas elegido.</p>
-
-<p>Este fragmento muestra cómo crear un objeto de notificación personalizada con el método
-{@code DecoratedCustomViewStyle()}.</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">Estilo de mensajería</h2>
-<p>
-  Android N presenta una nueva API para personalizar el estilo de una notificación.
-  Por medio de la clase <code>MessageStyle</code>, puedes modificar varias de las
- etiquetas que aparecen en la notificación, incluidos el título de la conversación,
- mensajes adicionales y la vista de contenido para la notificación.
-</p>
-
-<p>
-  El siguiente fragmento de código demuestra cómo personalizar el estilo
- de una notificación mediante la clase <code>MessageStyle</code>.
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
diff --git a/docs/html-intl/intl/in/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
similarity index 100%
rename from docs/html-intl/intl/in/about/versions/nougat/android-7.0-testing.jd
rename to docs/html-intl/intl/id/about/versions/marshmallow/android-6.0-testing.jd
diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
new file mode 100644
index 0000000..af01cd2
--- /dev/null
+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-changes.jd
@@ -0,0 +1,610 @@
+page.title=Perubahan Perilaku
+page.keywords=pratinjau,sdk,kompatibilitas
+meta.tags="preview", "compatibility"
+page.tags="preview", "developer preview"
+page.image=images/cards/card-n-changes_2x.png
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dalam dokumen ini</h2>
+
+<ol>
+  <li><a href="#perf">Peningkatan Kinerja</a>
+    <ol>
+      <li><a href="#doze">Istirahatkan</a></li>
+      <li><a href="#bg-opt">Optimalisasi Latar Belakang</a></li>
+    </ol>
+  </li>
+  <li><a href="#perm">Perubahan Izin</a>
+  </li>
+  <li><a href="#sharing-files">Berbagi File Antar Aplikasi</a></li>
+  <li><a href="#accessibility">Peningkatan Aksesibilitas</a>
+    <ol>
+      <li><a href="#screen-zoom">Perbesaran Layar</a></li>
+      <li><a href="#vision-settings">Vision Settings di Setup Wizard</a></li>
+    </ol>
+  </li>
+  <li><a href="#ndk">Penautan Aplikasi NDK ke Pustaka Platform</a></li>
+  <li><a href="#afw">Android for Work</a></li>
+  <li><a href="#annotations">Retensi Anotasi</a></li>
+  <li><a href="#other">Poin Penting Lainnya</a></li>
+</ol>
+
+<h2>Lihat Juga</h2>
+<ol>
+  <li><a href="{@docRoot}preview/api-overview.html">
+    Ringkasan Android N API</a></li>
+</ol>
+
+</div>
+</div>
+
+
+<p>
+  Bersama fitur dan kemampuan baru, Android N
+  menyertakan berbagai macam perubahan sistem dan perubahan perilaku API. Dokumen ini
+  menyoroti beberapa perubahan utama yang harus dipahami dan diperhitungkan
+  dalam aplikasi Anda.
+</p>
+
+<p>
+  Jika Anda sebelumnya telah mempublikasikan aplikasi untuk Android, ketahuilah bahwa aplikasi Anda
+  mungkin dipengaruhi oleh perubahan dalam platform.
+</p>
+
+
+<h2 id="perf">Baterai dan Memori</h2>
+
+<p>
+Android N menyertakan perubahan perilaku sistem yang bertujuan untuk meningkatkan daya tahan baterai
+perangkat dan mengurangi penggunaan RAM. Perubahan ini bisa memengaruhi akses aplikasi Anda ke
+sumber daya sistem, termasuk cara aplikasi Anda berinteraksi dengan aplikasi lain melalui
+intent implisit tertentu.
+</p>
+
+<h3 id="doze">Istirahatkan</h3>
+
+<p>
+  Diperkenalkan dalam Android 6.0 (API level 23), Istirahatkan meningkatkan daya tahan baterai dengan
+  menangguhkan aktivitas CPU dan jaringan bila pengguna tidak mencabut perangkat,
+  tidak bergerak, dan layar dinonaktifkan. Android N lebih
+  menyempurnakan Istirahatkan dengan menerapkan subset CPU dan pembatasan jaringan
+  bila perangkat dicabut dan layar dinonaktifkan, namun tidak harus
+  diam, misalnya, bila handset dibawa bepergian di saku pengguna.
+</p>
+
+
+<img src="{@docRoot}images/android-7.0/doze-diagram-1.png" alt="" height="251px" id="figure1" />
+<p class="img-caption">
+  <strong>Gambar 1.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
+  aktivitas sistem level pertama untuk meningkatkan daya tahan baterai.
+</p>
+
+<p>
+  Bila perangkat sedang menggunakan daya baterai, dan layar telah nonaktif selama jangka waktu
+  tertentu, perangkat akan memasuki Istirahatkan dan menerapkan subset pembatasan pertama: Perangkat
+  akan menutup akses jaringan aplikasi, serta menangguhkan pekerjaan dan sinkronisasi. Jika perangkat sedang
+  diam selama jangka waktu tertentu setelah memasuki Istirahatkan, sistem akan menerapkan
+  pembatasan Istirahatkan selebihnya terhadap alarm {@link android.os.PowerManager.WakeLock},
+  {@link android.app.AlarmManager}, GPS, dan pemindaian Wi-Fi. Tidak peduli
+  apakah sebagian atau semua pembatasan Istirahatkan diterapkan, sistem akan membangunkan
+  perangkat selama jeda pemeliharaan singkat, dan selama itu aplikasi diizinkan
+  mengakses jaringan dan bisa mengeksekusi semua pekerjaan/sinkronisasi yang telah ditangguhkan.
+</p>
+
+
+<img src="{@docRoot}images/android-7.0/doze-diagram-2.png" alt="" id="figure2" />
+<p class="img-caption">
+  <strong>Gambar 2.</strong> Ilustrasi tentang cara Istirahatkan menerapkan pembatasan
+  aktivitas sistem level kedua setelah perangkat diam selama jangka waktu tertentu.
+</p>
+
+<p>
+  Perhatikan, mengaktifkan layar atau mencolokkan steker perangkat akan mengeluarkan dari Istirahatkan
+  dan membuang pembatasan pemrosesan ini. Perilaku tambahan ini tidak
+  memengaruhi rekomendasi dan praktik terbaik dalam menyesuaikan aplikasi Anda dengan versi
+  Istirahatkan sebelumnya yang diperkenalkan dalam Android 6.0 (API level 23), seperti yang dibahas di
+  <a href="{@docRoot}training/monitoring-device-state/doze-standby.html">
+  Mengoptimalkan untuk Istirahatkan dan Aplikasi Siaga</a>. Anda tetap harus
+   mengikuti rekomendasi itu, seperti menggunakan Google Cloud Messaging (GCM) untuk
+  mengirim dan menerima pesan, serta mulai merencanakan pembaruan
+  untuk mengakomodasi perilaku Istirahatkan tambahan.
+</p>
+
+
+<h3 id="bg-opt">Project Svelte: Optimalisasi Latar Belakang</h3>
+
+<p>
+  Android N membuang tiga siaran implisit untuk membantu mengoptimalkan
+  penggunaan memori dan konsumsi daya. Perubahan ini penting karena siaran
+  implisit sering memulai aplikasi yang telah didaftarkan untuk mendengarkannya di
+  latar belakang. Membuang siaran ini bisa sangat menguntungkan
+  kinerja perangkat dan pengalaman pengguna.
+</p>
+
+<p>
+  Perangkat seluler seringkali mengalami perubahan konektivitas, seperti saat berpindah
+  antara Wi-Fi dan data seluler. Saat ini, aplikasi bisa memantau perubahan dalam
+  konektivitas dengan mendaftarkan suatu penerima untuk siaran implisit {@link
+  android.net.ConnectivityManager#CONNECTIVITY_ACTION} dalam manifes
+  mereka. Karena banyak aplikasi yang didaftarkan untuk menerima siaran ini, switch  jaringan tunggal
+  bisa menyebabkan semuanya aktif dan memproses siaran tersebut
+  secara bersamaan.
+</p>
+
+<p>
+  Demikian pula, dalam Android versi sebelumnya, aplikasi bisa mendaftar untuk menerima siaran implisit {@link
+  android.hardware.Camera#ACTION_NEW_PICTURE} dan {@link
+  android.hardware.Camera#ACTION_NEW_VIDEO} dari aplikasi lain, seperti
+  Kamera. Bila pengguna mengambil gambar dengan aplikasi Kamera, semua aplikasi ini akan aktif
+  untuk memproses siaran.
+</p>
+
+<p>
+  Untuk meminimalkan masalah ini, Android N menerapkan optimalisasi
+  berikut:
+</p>
+
+<ul>
+  <li>Aplikasi yang menargetkan Android N tidak menerima siaran {@link
+  android.net.ConnectivityManager#CONNECTIVITY_ACTION}, sekalipun
+  memiliki entri manifes untuk meminta pemberitahuan mengenai kejadian ini. Aplikasi
+  yang berjalan tetap bisa mendengarkan {@code CONNECTIVITY_CHANGE} pada thread utama
+  jika mereka meminta pemberitahuan dengan {@link android.content.BroadcastReceiver}.
+  </li>
+
+  <li>Aplikasi tidak bisa mengirim atau menerima siaran {@link
+  android.hardware.Camera#ACTION_NEW_PICTURE} atau {@link
+  android.hardware.Camera#ACTION_NEW_VIDEO}. Optimalisasi ini
+  memengaruhi semua aplikasi, bukan hanya aplikasi yang menargetkan Android N.
+  </li>
+</ul>
+
+<p>Jika aplikasi Anda menggunakan intent ini, Anda harus membuang dependensi padanya
+  secepat mungkin agar Anda bisa menargetkan perangkat Android N dengan benar.
+  Kerangka kerja Android menyediakan beberapa solusi untuk mengurangi kebutuhan akan
+  siaran implisit ini. Misalnya, {@link
+  android.app.job.JobScheduler} API menyediakan mekanisme yang tangguh untuk menjadwalkan
+  operasi jaringan bila kondisi yang ditetapkan, seperti koneksi ke jaringan
+  berbiaya tetap, terpenuhi. Anda juga dapat menggunakan {@link
+  android.app.job.JobScheduler} untuk bereaksi terhadap perubahan pada penyedia materi.
+</p>
+
+<p>
+  Untuk informasi selengkapnya tentang optimalisasi latar belakang di N dan cara menyesuaikan aplikasi Anda,
+  lihat <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
+  Latar Belakang</a>.
+</p>
+
+<h2 id="perm">Perubahan Izin</h2>
+
+<p>
+  Android N menyertakan perubahan pada izin yang bisa memengaruhi aplikasi Anda.
+</p>
+
+<h3 id="permfilesys">Perubahan izin sistem file</h3>
+
+<p>
+  Guna meningkatkan keamanan file privat, direktori privat
+  aplikasi yang menargetkan Android N atau yang lebih tinggi memiliki akses terbatas (<code>0700</code>).
+  Pengaturan ini mencegah kebocoran metadata dari file privat, seperti ukuran
+  atau eksistensi. Perubahan izin ini memiliki beberapa efek samping:
+</p>
+
+<ul>
+  <li>
+    Izin file privat tidak boleh dianggap remeh oleh pemilik,
+    dan usaha untuk melakukannya menggunakan
+    {@link android.content.Context#MODE_WORLD_READABLE} dan/atau
+    {@link android.content.Context#MODE_WORLD_WRITEABLE}, akan memicu sebuah
+    {@link java.lang.SecurityException}.
+    <p class="note">
+      <strong>Catatan:</strong> Seperti sebelumnya, pembatasan ini tidak sepenuhnya diterapkan.
+      Aplikasi mungkin masih memodifikasi izin ke direktori privat mereka menggunakan
+      API asal atau {@link java.io.File File} API. Akan tetapi, kami sangat
+      tidak menyarankan Anda meremehkan izin direktori privat.
+    </p>
+  </li>
+  <li>
+    Meneruskan URI <code>file://</code> di luar domain paket dapat meninggalkan
+    penerima dengan jalur yang tidak bisa di akses. Karena itu, upaya untuk meneruskan URI
+    <code>file://</code> akan memicu
+    <code>FileUriExposedException</code>. Cara yang disarankan adalah
+    materi file privat menggunakan {@link
+    android.support.v4.content.FileProvider}.
+  </li>
+  <li>
+    {@link android.app.DownloadManager} tidak bisa lagi berbagi
+    file yang tersimpan secara privat berdasarkan nama file. Aplikasi lawas dapat mengakibatkan
+    jalur yang tidak dapat diakses saat mengakses {@link
+    android.app.DownloadManager#COLUMN_LOCAL_FILENAME}. Aplikasi yang menargetkan
+    Android N atau yang lebih tinggi akan memicu {@link java.lang.SecurityException} saat
+    berupaya mengakses
+    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}.
+    Aplikasi lawas yang menyetel lokasi unduhan ke lokasi publik dengan
+    menggunakan
+    {@link
+    android.app.DownloadManager.Request#setDestinationInExternalFilesDir
+    DownloadManager.Request.setDestinationInExternalFilesDir()} atau
+    {@link
+    android.app.DownloadManager.Request#setDestinationInExternalPublicDir
+    DownloadManager.Request.setDestinationInExternalPublicDir()}
+    tetap bisa mengakses jalur tersebut di
+    {@link android.app.DownloadManager#COLUMN_LOCAL_FILENAME}, akan tetapi,
+     metode ini sangat tidak disarankan. Cara yang disarankan untuk mengakses file
+    yang diekspos oleh {@link android.app.DownloadManager} adalah menggunakan
+    {@link android.content.ContentResolver#openFileDescriptor
+    ContentResolver.openFileDescriptor()}.
+  </li>
+</ul>
+
+<h2 id="sharing-files">Berbagi File Antar Aplikasi</h2>
+
+<p>
+Untuk aplikasi yang menargetkan Android N, kerangka kerja Android menerapkan
+kebijakan {@link android.os.StrictMode} API yang melarang mengekspos URI {@code file://}
+di luar aplikasi Anda. Jika sebuah intent berisi URI file meninggalkan aplikasi Anda, aplikasi tersebut akan gagal
+dengan pengecualian {@code FileUriExposedException}.
+</p>
+
+<p>
+Untuk berbagi file antar aplikasi, Anda harus mengirim URI {@code content://}
+dan memberikan izin akses sementara pada URI. Cara termudah untuk memberikan izin ini adalah dengan
+menggunakan kelas {@link android.support.v4.content.FileProvider}. Untuk informasi selengkapnya
+mengenai izin dan berbagi file,
+lihat <a href="{@docRoot}training/secure-file-sharing/index.html">Berbagi File</a>.
+</p>
+
+<h2 id="accessibility">Peningkatan Aksesibilitas</h2>
+
+<p>
+  Android N menyertakan perubahan yang bertujuan meningkatkan kegunaan
+  platform untuk pengguna dengan penglihatan yang rendah atau lemah. Perubahan ini umumnya tidak
+  memerlukan perubahan kode dalam aplikasi Anda, akan tetapi Anda harus memeriksa
+  fitur ini dan mengujinya dengan aplikasi untuk menilai kemungkinan dampaknya terhadap pengalaman
+  pengguna.
+</p>
+
+
+<h3 id="screen-zoom">Perbesaran Layar</h3>
+
+<p>
+  Android N memungkinkan pengguna menyetel <strong>Display size</strong> yang akan memperbesar
+  atau memperkecil semua elemen pada layar, sehingga meningkatkan aksesibilitas perangkat
+  bagi pengguna yang kurang melihat. Pengguna tidak bisa memperbesar layar melewati lebar layar
+  minimum <a href="http://developer.android.com/guide/topics/resources/providing-resources.html">
+  sw320dp</a>, yang merupakan lebar Nexus 4, yakni ponsel ukuran sedang pada umumnya.
+</p>
+
+<div class="cols">
+
+<div class="col-6">
+  <img src="{@docRoot}images/android-7.0/screen-zoom-1.png" alt="" height="XXX" id="figure1" />
+</div>
+<div class="col-6">
+  <img src="{@docRoot}images/android-7.0/screen-zoom-2.png" alt="" height="XXX" id="figure1" />
+</div>
+
+</div> <!-- end cols -->
+<p class="img-caption">
+  <strong>Gambar 3.</strong> Layar di sebelah kanan menampilkan efek
+ penambahan Display size perangkat yang menjalankan citra sistem Android N.
+</p>
+
+
+<p>
+  Bila kepadatan perangkat berubah, sistem akan memberi tahu aplikasi yang sedang berjalan dengan
+  cara berikut:
+</p>
+
+<ul>
+  <li>Jika aplikasi menargetkan API level 23 atau yang lebih rendah, sistem secara otomatis akan mematikan
+  semua proses latar belakang. Artinya, jika pengguna beralih dari
+  aplikasi tersebut untuk membuka layar <em>Settings</em> dan mengubah
+  setelan <strong>Display size</strong>, maka sistem akan mematikan aplikasi tersebut dengan cara yang
+  sama dengan saat memori tinggal sedikit. Jika aplikasi memiliki beberapa proses
+  latar depan, sistem akan memberi tahu proses tersebut mengenai perubahan konfigurasi seperti
+ dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
+  Waktu Proses</a>, seolah-olah orientasi perangkat telah berubah.
+  </li>
+
+  <li>Jika sebuah aplikasi menargetkan Android N, semua prosesnya
+  (latar depan dan latar belakang) akan diberi tahu mengenai perubahan konfigurasi seperti
+  dijelaskan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
+  Waktu Proses</a>.
+  </li>
+</ul>
+
+<p>
+  Sebagian besar aplikasi tidak perlu melakukan perubahan untuk mendukung fitur ini, asalkan
+  aplikasi tersebut mengikuti praktik terbaik Android. Hal-hal tertentu yang harus diperiksa:
+</p>
+
+<ul>
+  <li>Uji aplikasi Anda pada perangkat dengan lebar layar <code><a href=
+  "{@docRoot}guide/topics/resources/providing-resources.html">sw320dp</a></code>
+  dan pastikan aplikasi berjalan dengan semestinya.
+  </li>
+
+  <li>Bila konfigurasi perangkat berubah, perbarui informasi cache
+  yang bergantung pada kepadatan, seperti bitmap di cache atau sumber daya yang dimuat dari
+  jaringan. Periksa perubahan konfigurasi bila aplikasi melanjutkan dari status dihentikan
+  sementara.
+    <p class="note">
+      <strong>Catatan:</strong> Catatan: Jika Anda meng-cache data yang bergantung pada konfigurasi, ada
+      baiknya untuk menyertakan metadata yang relevan seperti ukuran layar
+      atau kepadatan piksel yang sesuai untuk data tersebut. Menyimpan metadata ini memungkinkan Anda untuk
+      memutuskan apakah Anda perlu segarkan data cache setelah perubahan
+      konfigurasi.
+    </p>
+  </li>
+
+  <li>Hindari menetapkan dimensi dengan satuan px, karena satuan ini tidak diskalakan dengan
+  kepadatan layar. Sebagai gantinya, tetapkan dimensi dengan satuan <a href="{@docRoot}guide/practices/screens_support.html">piksel yang tidak bergantung kepadatan
+  </a> (<code>dp</code>).
+  </li>
+</ul>
+
+<h3 id="vision-settings">Vision Settings di Setup Wizard</h3>
+
+<p>
+  Android N menyertakan Vision Settings di layar Sambutan, di mana pengguna bisa
+  menyiapkan setelan aksesibilitas berikut pada perangkat baru:
+  <strong>Magnification gesture</strong>, <strong>Font size</strong>,
+  <strong>Display size</strong> dan <strong>TalkBack</strong>. Perubahan ini
+  meningkatkan visibilitas bug terkait dengan setelan layar yang berbeda. Untuk
+  mengurangi dampak fitur ini, Anda harus menguji aplikasi dengan setelan ini
+  diaktifkan. Anda bisa menemukannya pada <strong>Settings &gt;
+  Accessibility</strong>.
+</p>
+
+<h2 id="ndk">Penautan Aplikasi NDK ke Pustaka Platform</h2>
+
+<p>
+  Android N menyertakan perubahan ruang nama untuk mencegah pemuatan API non-publik.
+  Jika menggunakan NDK, Anda hanya boleh menggunakan API publik dari platform
+  Android. Menggunakan API non-publik dalam rilis Android resmi berikutnya
+  bisa menyebabkan aplikasi mogok.
+</p>
+
+<p>
+  Untuk memberi tahu Anda agar menggunakan API non-publik, aplikasi yang berjalan pada perangkat
+  Android N akan menghasilkan kesalahan dalam keluaran logcat bila aplikasi memanggil API non-publik.
+  Kesalahan ini juga ditampilkan di layar perangkat berupa pesan untuk membantu
+  meningkatkan kepedulian terhadap situasi ini. Anda harus memeriksa kode aplikasi untuk
+  membuang penggunaan API platform non-publik dan secara saksama menguji aplikasi Anda menggunakan
+  perangkat pratinjau atau emulator.
+</p>
+
+<p>
+  Jika aplikasi Anda bergantung pada pustaka platform, lihat dokumentasi NDK untuk
+  perbaikan tipikal guna menggantikan API privat umum dengan padanan API publik.
+  Anda mungkin juga menautkan ke pustaka platform tanpa menyadarinya,
+  terutama jika aplikasi Anda menggunakan pustaka yang merupakan bagian dari platform ini (seperti
+  <code>libpng</code>), namun bukan bagian dari NDK. Dalam hal itu, pastikan
+  APK Anda berisi semua file .so yang ingin ditautkan.
+</p>
+
+<p class="caution">
+  <strong>Perhatian:</strong> Beberapa pustaka pihak ketiga mungkin menautkan ke API
+  non-publik. Jika menggunakan pustaka ini, aplikasi Anda bisa mogok saat dijalankan
+  pada rilis resmi Android berikutnya.
+</p>
+
+<p>
+  Aplikasi tidak boleh bergantung pada atau menggunakan pustaka bawaan yang tidak disertakan dalam
+  NDK, karena bisa mengalami perubahan, atau dipindahkan dari satu rilis Android ke
+  rilis lainnya. Peralihan dari OpenSSL ke BoringSSL merupakan satu contoh dari perubahan semacam ini.
+  Selain itu, perangkat yang berbeda bisa menawarkan tingkat kompatibilitas yang berbeda, karena
+   tidak ada persyaratan kompatibilitas untuk pustaka platform yang tidak disertakan
+  dalam NDK. Jika Anda harus mengakses pustaka non-NDK pada perangkat yang lebih lama, jadikan
+  pemuatan bergantung pada level Android API.
+</p>
+
+<p>
+  Untuk membantu Anda mendiagnosis tipe masalah ini ada beberapa contoh kesalahan Java dan NDK
+  yang mungkin Anda temui saat berusaha membangun aplikasi dengan Android N:
+</p>
+
+<p>Contoh kesalahan Java:</p>
+<pre class="no-pretty-print">
+java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
+    is not accessible for the namespace "classloader-namespace"
+</pre>
+
+<p>Contoh kesalahan NDK:</p>
+<pre class="no-pretty-print">
+dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
+</pre>
+
+
+<p>
+  Inilah beberapa perbaikan tipikal untuk aplikasi yang mengalami tipe kesalahan ini:
+</p>
+
+<ul>
+  <li>Penggunaan getJavaVM dan getJNIEnv dari libandroid_runtime.so bisa diganti
+  dengan fungsi JNI standar:
+<pre class="no-pretty-print">
+AndroidRuntime::getJavaVM -&gt; GetJavaVM from &lt;jni.h&gt;
+AndroidRuntime::getJNIEnv -&gt; JavaVM::GetEnv or
+JavaVM::AttachCurrentThread from &lt;jni.h&gt;.
+</pre>
+  </li>
+
+  <li>Penggunaan simbol {@code property_get} dari {@code libcutils.so} bisa
+    diganti dengan {@code alternative __system_property_get} publik.
+   Caranya, gunakan {@code __system_property_get} dengan menyertakan yang berikut:
+<pre>
+#include &lt;sys/system_properties.h&gt;
+</pre>
+  </li>
+
+  <li>Penggunaan simbol {@code SSL_ctrl} dari {@code libcrypto.so} harus
+    diganti dengan aplikasi versi lokal. Misalnya, Anda harus menautkan
+  {@code libcyrpto.a} secara statis dalam file {@code .so} atau menyertakan
+  {@code libcrypto.so} Anda sendiri secara dinamis dari BoringSSL atau OpenSSL dalam aplikasi Anda.
+  </li>
+</ul>
+
+<h2 id="afw">Android for Work</h2>
+<p>
+  Android N berisi perubahan untuk aplikasi yang menargetkan Android for Work, termasuk
+  perubahan pada pemasangan sertifikat, penyetelan ulang sandi, manajemen pengguna
+  tambahan, dan akses ke identifier perangkat. Jika Anda membangun aplikasi untuk
+  lingkungan Android for Work, Anda harus meninjau perubahan ini dan memodifikasi
+  aplikasi sebagaimana mestinya.
+</p>
+
+<ul>
+  <li>Anda harus pasang pemasang sertifikat yang didelegasikan sebelum DPC bisa
+  menyetelnya. Untuk aplikasi profil dan aplikasi pemilik perangkat yang menargetkan N SDK, Anda harus
+  pasang pemasang sertifikat yang didelegasikan sebelum pengontrol kebijakan
+  perangkat (DPC) memanggil
+  <code>DevicePolicyManager.setCertInstallerPackage()</code>. Jika pemasang
+  belum dipasang, sistem akan melontarkan
+  <code>IllegalArgumentException</code>.
+  </li>
+
+  <li>Pembatasan sandi penyetelan ulang untuk admin perangkat sekarang diterapkan ke pemilik
+  profil. Admin perangkat tidak bisa lagi menggunakan
+  {@code DevicePolicyManager.resetPassword()} untuk menghapus sandi atau mengubah
+  sandi yang sudah disetel. Admin perangkat tetap bisa menyetel sandi, namun hanya
+  bila perangkat belum memiliki sandi, PIN, atau pola.
+  </li>
+
+  <li>Pemilik perangkat dan profil bisa mengelola akun meskipun pembatasan
+  telah disetel. Pemilik perangkat dan pemilik profil bisa memanggil Account Management API
+  sekalipun pembatasan pengguna <code>DISALLOW_MODIFY_ACCOUNTS</code> diberlakukan.
+  </li>
+
+  <li>Pemilik perangkat bisa mengelola pengguna tambahan lebih mudah. Bila perangkat
+  berjalan dalam mode pemilik perangkat, maka pembatasan <code>DISALLOW_ADD_USER</code>
+  secara otomatis akan ditetapkan. Ini mencegah pengguna membuat pengguna tambahan yang
+  tidak terkelola. Selain itu, <code>CreateUser()</code> dan
+  <code>createAndInitializeUser()</code> metode tidak digunakan lagi; metode
+  <code>DevicePolicyManager.createAndManageUser()</code> telah menggantikannya.
+  </li>
+
+  <li>Pemilik perangkat bisa mengakses identifier perangkat. Pemilik perangkat bisa mengakses
+  alamat MAC Wi-Fi dari perangkat, menggunakan
+  <code>DevicePolicyManagewr.getWifiMacAddress()</code>. Jika Wi-Fi belum pernah
+  diaktifkan pada perangkat tersebut, metode ini akan mengembalikan nilai {@code null}.
+  </li>
+
+  <li>Setelan Mode Kerja mengontrol akses ke aplikasi kerja. Bila mode kerja tidak aktif, peluncur sistem
+  akan menunjukkan aplikasi kerja tidak tersedia dengan membuat warnanya jadi abu-abu. Mengaktifkan kembali
+ mode kerja akan memulihkan perilaku normal.
+</ul>
+
+<p>
+  Untuk informasi selengkapnya tentang perubahan Android for Work di Android N, lihat
+  <a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.
+</p>
+
+<h2 id="annotations">Retensi Anotasi</h2>
+
+<p>
+Android N memperbaiki bug dengan visibilitas anotasi diabaikan.
+Masalah ini mengaktifkan waktu proses untuk mengakses anotasi yang seharusnya tidak bisa
+dilakukan. Anotasi ini termasuk:
+</p>
+
+<ul>
+   <li>{@code VISIBILITY_BUILD}: Dimaksudkan agar hanya bisa terlihat pada waktu pembuatan.</li>
+   <li>{@code VISIBILITY_SYSTEM}: Dimaksud agar bisa terlihat pada waktu proses, namun hanya pada
+ sistem yang mendasarinya.</li>
+</ul>
+
+<p>
+Jika aplikasi Anda mengandalkan perilaku ini, tambahkan kebijakan retensi untuk anotasi yang harus
+tersedia di waktu proses. Caranya dengan menggunakan {@code @Retention(RetentionPolicy.RUNTIME)}.
+</p>
+
+<h2 id="other">Poin Penting Lainnya</h2>
+
+<ul>
+<li>Bila aplikasi berjalan pada Android N, namun menargetkan level API yang lebih rendah,
+dan pengguna mengubah ukuran tampilan, proses aplikasi akan dimatikan. Aplikasi
+harus dapat menangani skenario ini dengan lancar. Jika tidak, maka akan mogok
+bila pengguna memulihkannya dari Recents.
+
+<p>
+Anda harus menguji aplikasi untuk memastikan
+perilaku ini tidak terjadi.
+Anda bisa melakukannya dengan menyebabkan suatu mogok yang identik
+saat mematikan aplikasi secara manual melalui DDMS.
+</p>
+
+<p>
+Aplikasi yang menargetkan N dan yang di atasnya tidak secara otomatis dimatikan saat perubahan kepadatan;
+akan tetapi, aplikasi tersebut mungkin tetap merespons perubahan konfigurasi dengan buruk.
+</p>
+</li>
+
+<li>
+Aplikasi pada Android N harus mampu menangani perubahan konfigurasi dengan lancar,
+dan tidak boleh mengalami mogok pada start selanjutnya. Anda bisa memverifikasi perilaku aplikasi
+dengan mengubah ukuran font (<strong>Setting</strong> &gt;
+<strong>Display</strong> &gt; <strong>Font size</strong>), kemudian memulihkan
+aplikasi dari Recents.
+</li>
+
+<li>
+Dikarenakan adanya bug di versi Android sebelumnya, sistem tidak menandai penulisan
+  ke soket TCP di thread utama sebagai pelanggaran mode-ketat. Android N memperbaiki bug ini.
+Aplikasi yang menunjukkan perilaku ini kini melontarkan sebuah {@code android.os.NetworkOnMainThreadException}.
+Secara umum, melakukan operasi jaringan di thread utama tidak baik karena operasi ini
+biasanya memiliki latensi tinggi yang menyebabkan ANR dan jank.
+</li>
+
+<li>
+Kelompok metode {@code Debug.startMethodTracing()} kini default ke
+keluaran penyimpanan di direktori paket tertentu di penyimpanan bersama,
+sebagai ganti di level teratas
+kartu SD.  Berarti aplikasi tidak perlu lagi meminta izin {@code WRITE_EXTERNAL_STORAGE} untuk menggunakan API ini.
+</li>
+
+<li>
+Banyak platform API yang kini mulai memeriksa beban besar yang dikirim
+ke seluruh transaksi {@link android.os.Binder}, dan sistem
+kini melontarkan kembali {@code TransactionTooLargeExceptions}
+sebagai {@code RuntimeExceptions}, sebagai ganti logging secara diam-diam atau menyembunyikannya.  Satu contoh
+umum adalah menyimpan terlalu banyak data di
+{@link android.app.Activity#onSaveInstanceState Activity.onSaveInstanceState()},
+yang menyebabkan {@code ActivityThread.StopInfo} melontarkan
+{@code RuntimeException} bila aplikasi Anda menargetkan Android N.
+</li>
+
+<li>
+Jika sebuah aplikasi mengeposkan tugas {@link java.lang.Runnable} ke{@link android.view.View}, dan
+{@link android.view.View}
+tidak terpasang ke jendela, sistem
+akan mengantrekan tugas {@link java.lang.Runnable} dengan {@link android.view.View};
+tugas {@link java.lang.Runnable} tidak akan dieksekusi hingga
+{@link android.view.View} terpasang
+ke jendela. Perilaku ini mengatasi bug berikut:
+<ul>
+   <li>Jika sebuah aplikasi mengeposkan ke {@link android.view.View} dari thread selain thread UI jendela yang dimaksud,
+    maka {@link java.lang.Runnable} mungkin akan menjalankan thread yang salah.
+   </li>
+   <li>Jika tugas {@link java.lang.Runnable} diposkan dari thread selain
+   looper-thread, aplikasi bisa mengekspos tugas {@link java.lang.Runnable}.</li>
+</ul>
+</li>
+
+<li>
+Jika sebuah aplikasi di Android N dengan
+izin{@link android.Manifest.permission#DELETE_PACKAGES DELETE_PACKAGES}
+mencoba menghapus sebuah paket, namun sebuah aplikasi berbeda telah memasang paket itu,
+sistem akan memerlukan konfirmasi pengguna. Dalam skenario ini, aplikasi harus mengharapkan
+{@link android.content.pm.PackageInstaller#STATUS_PENDING_USER_ACTION STATUS_PENDING_USER_ACTION}
+sebagai status kembalian bila memanggil
+{@link android.content.pm.PackageInstaller#uninstall PackageInstaller.uninstall()}.
+</li>
+
+</ul>
+
diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
new file mode 100644
index 0000000..d31c0c0
--- /dev/null
+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0-samples.jd
@@ -0,0 +1,85 @@
+page.title=Contoh
+page.tags="preview", "samples", "android"
+page.image=images/cards/card-n-samples_2x.png
+@jd:body
+
+<p>
+  Contoh kode berikut disediakan untuk Android N. Untuk
+  mengunduh contoh di Android Studio, pilih opsi menu <b>File &gt; Import
+  Samples</b>.
+</p>
+
+<p class="note">
+  <strong>Catatan:</strong> Proyek yang bisa diunduh ini didesain
+   untuk digunakan bersama Gradle dan Android Studio.
+</p>
+
+
+<h3 id="mw">Playground Multi-Jendela</h3>
+<img src="{@docRoot}images/android-7.0/sample-multiwindow.png" style="float: left; padding-right: 0.5em" height="250" width="156" />
+<p>
+  Contoh ini memperagakan cara memanfaatkan antarmuka pengguna
+  multi-jendela bersama aplikasi Anda.
+</p>
+<p>
+  <a href="https://github.com/googlesamples/android-MultiWindowPlayground">
+  Dapatkan di GitHub</a>
+</p>
+
+<div style="clear: both;"></div>
+<h3 id="an">Pemberitahuan Aktif</h3>
+<img src="{@docRoot}images/android-7.0/sample-activenotifications.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
+<p>
+  Ini adalah contoh yang sudah ada sebelumnya, menampilkan layanan sederhana yang mengirimkan
+   pemberitahuan menggunakan NotificationCompat. Setiap percakapan yang belum dibaca dari pengguna
+  dikirimkan sebagai pemberitahuan berbeda.
+</p>
+<p>
+  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
+  yang tersedia di Android N.
+</p>
+<p>
+  <a href="https://github.com/googlesamples/android-ActiveNotifications">
+  Dapatkan di GitHub</a>
+</p>
+
+<div style="clear: both;"></div>
+<h3 id="ms">Layanan Perpesanan</h3>
+<img src="{@docRoot}images/android-7.0/sample-messagingservice.png" style="float: left; padding-right: 0.5em" height="250" width="150" />
+<p>
+  Ini adalah contoh yang telah ada sebelumnya yang memperagakan cara menggunakan
+  NotificationManager untuk memberi tahu jumlah pemberitahuan yang saat ini ditampilkan
+  oleh aplikasi.
+</p>
+<p>
+  Contoh ini telah diperbarui untuk memanfaatkan fitur pemberitahuan baru
+  yang tersedia di Android N.
+</p>
+<p>
+  <a href="https://github.com/googlesamples/android-MessagingService">
+  Dapatkan di GitHub</a>
+</p>
+
+<div style="clear: both;"></div>
+<h3 id="fbe">Direct Boot</h3>
+<img src="{@docRoot}images/android-7.0/sample-directboot.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
+<p>
+  Contoh ini memperagakan cara menyimpan dan mengakses data dalam penyimpanan yang dienkripsi
+  dengan perangkat yang selalu tersedia saat perangkat booting.
+</p>
+<p>
+  <a href="https://github.com/googlesamples/android-DirectBoot">
+  Dapatkan di GitHub</a>
+</p>
+
+<div style="clear: both;"></div>
+<h3 id="sda">Scoped Directory Access</h3>
+<img src="{@docRoot}images/android-7.0/sample-scopeddirectoryaccess.png" style="float: left; padding-right: 0.5em" height="250" width="141" />
+<p>
+  Contoh ini memperagakan cara membaca dan menulis data dari direktori
+  spesifik, sekaligus meminta izin lebih sedikit.
+</p>
+<p>
+  <a href="https://github.com/googlesamples/android-ScopedDirectoryAccess">
+  Dapatkan di GitHub</a>
+</p>
diff --git a/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
new file mode 100644
index 0000000..ff8af12
--- /dev/null
+++ b/docs/html-intl/intl/id/about/versions/nougat/android-7.0.jd
@@ -0,0 +1,1039 @@
+page.title=Android N for Developers
+meta.tags="preview", "androidn"
+page.tags="preview", "developer preview"
+page.image=images/cards/card-n-apis_2x.png
+@jd:body
+
+
+
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Fitur-fitur Utama bagi Pengembang</h2>
+  <ol>
+      <ul style="list-style-type:none;">
+        <li><a href="#multi-window_support">Dukungan Multi-Jendela</a></li>
+        <li><a href="#notification_enhancements">Pemberitahuan</a></li>
+        <li><a href="#jit_aot">Kompilasi JIT/AOT</a></li>
+        <li><a href="#quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</a></li>
+        <li><a href="#doze_on_the_go">Istirahatkan Kapan Saja</a></li>
+        <li><a href="#background_optimizations">Optimalisasi Latar Belakang</a></li>
+        <li><a href="#data_saver">Data Saver</a></li>
+        <li><a href="#vulkan">Vulkan API</a></li>
+        <li><a href="#tile_api">Quick Settings Tile API</a></li>
+        <li><a href="#number-blocking">Pemblokiran Nomor</a></li>
+        <li><a href="#call_screening">Penyaringan Panggilan</a></li>
+        <li><a href="#multi-locale_languages">Lokal dan Bahasa</a></li>
+        <li><a href="#emoji">Emoji Baru</a></li>
+        <li><a href="#icu4">ICU4J API di Android</a></li>
+        <li><a href="#gles_32">OpenGL ES 3.2 API</a></li>
+        <li><a href="#android_tv_recording">Perekaman Android TV</a></li>
+        <li><a href="#android_for_work">Android for Work</a></li>
+        <li><a href="#accessibility_enhancements">Aksesibilitas</a></li>
+        <li><a href="#direct_boot">Direct Boot</a></li>
+        <li><a href="#key_attestation">Key Attestation</a></li>
+        <li><a href="#network_security_config">Network Security Config</a></li>
+        <li><a href="#default_trusted_ca">CA Tepercaya Default</a></li>
+        <li><a href="#apk_signature_v2">APK Signature Scheme V2</a></li>
+        <li><a href="#scoped_directory_access">Scoped Directory Access</a></li>
+        <li><a href="#keyboard_shortcuts_helper">Keyboard Shortcuts Helper</a></li>
+        <li><a href="#sustained_performance_api">Sustained Performance API</a></li>
+        <li><a href="#vr">Dukungan VR</a></li>
+        <li><a href="#print_svc">Penyempurnaan Layanan Cetak</a></li>
+        <li><a href="#virtual_files">File Maya</a></li>
+        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
+      </ol>
+</div>
+</div>
+
+
+
+<p>Android N masih dalam pengembangan aktif, namun Anda bisa mencobanya
+sekarang sebagai bagian dari N Developer Preview. Bagian-bagian di bawah ini akan menyoroti sebagian dari
+fitur baru untuk pengembang. </p>
+
+<p>
+  Pastikan memeriksa <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a> untuk mengetahui selengkapnya tentang
+  bagian-bagian perubahan platform yang bisa memengaruhi aplikasi Anda, lihatlah
+  panduan pengembang untuk mengetahui selengkapnya tentang fitur-fitur utama, dan unduh <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> untuk mengetahui detail tentang
+  API baru.
+</p>
+
+<h2 id="multi-window_support">Dukungan Multi-Jendela</h2>
+
+
+<p>Di Android N, kami memperkenalkan fitur multitasking baru dan yang banyak diminta
+ke dalam platform &mdash; dukungan multi-jendela. </p>
+
+  <p>Pengguna sekarang bisa membuka dua aplikasi sekaligus di layar. </p>
+  <ul>
+  <li>Pada ponsel dan tablet
+yang menjalankan Android N, pengguna bisa menjalankan dua aplikasi secara berdampingan atau
+satu aplikasi di atas yang lain dalam mode layar terbagi. Pengguna bisa mengubah ukuran aplikasi dengan menyeret
+pembagi di antara keduanya. </li>
+
+<li>Pada perangkat Android TV, aplikasi bisa menempatkan dirinya sendiri dalam <a href="{@docRoot}preview/features/picture-in-picture.html">mode
+gambar-dalam-gambar</a>, sehingga aplikasi bisa terus menampilkan materi sementara pengguna menjelajahi atau
+berinteraksi dengan aplikasi lain.</li>
+  </ul>
+
+<div class="col-4of10">
+<img src="{@docRoot}images/android-7.0/mw-portrait.png" alt="" style="height:460px;padding-left:1em;" id="img-split-screen" />
+<p class="img-caption">
+  <strong>Gambar 1.</strong> Aplikasi yang berjalan dalam mode layar terbagi.
+</p>
+
+  </div>
+
+<p>Khususnya pada tablet dan perangkat yang berlayar lebih besar lainnya, dukungan multi-jendela
+memberi Anda cara baru untuk memikat pengguna. Anda bahkan bisa mengaktifkan fitur seret-dan-lepas di
+aplikasi untuk memudahkan pengguna menyeret materi ke dan dari aplikasi &mdash; cara bagus
+untuk menyempurnakan pengalaman pengguna Anda. </p>
+
+<p>Tidak sulit menambahkan dukungan multi-jendela ke aplikasi Anda dan mengonfigurasi cara
+menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
+minimum yang diizinkan aktivitas, sehingga mencegah pengguna mengubah ukuran aktivitas di bawah
+ukuran itu. Anda juga bisa menonaktifkan tampilan multi-jendela untuk aplikasi Anda, yang
+  akan memastikan sistem hanya menampilkan aplikasi dalam mode layar penuh.</p>
+
+<p>
+  Untuk informasi selengkapnya, lihat dokumentasi pengembang <a href="{@docRoot}preview/features/multi-window.html">Dukungan Multi-Jendela</a>.
+
+</p>
+
+<h2 id="notification_enhancements">Penyempurnaan Pemberitahuan</h2>
+
+<p>Di Android N kami telah mengubah desain pemberitahuan agar lebih mudah dan lebih cepat
+digunakan. Beberapa perubahan tersebut antara lain:</p>
+
+<ul>
+  <li>
+    <strong>Pembaruan template</strong>: Kami telah memperbarui template pemberitahuan untuk
+    lebih menekankan citra pahlawan dan avatar. Pengembang akan dapat
+   memanfaatkan template baru dengan penyesuaian kode yang minimal.
+  </li>
+
+  <li>
+    <strong>Penyesuaian gaya pesan</strong>: Anda bisa menyesuaikan lebih banyak
+    label antarmuka pengguna yang berkaitan dengan pemberitahuan Anda menggunakan kelas
+    <code>MessageStyle</code>. Anda bisa mengonfigurasi pesan, judul percakapan,
+    dan tampilan materi.
+  </li>
+
+  <li>
+    <strong>Bundel pemberitahuan</strong>: Sistem bisa mengelompokkan pesan,
+    misalnya menurut topik pesan, dan menampilkan kelompok pesan tersebut. Seorang pengguna bisa
+   bertindak, misalnya Tutup atau Arsipkan, atas pesan yang ditampilkan. Jika Anda sudah
+    mengimplementasikan pemberitahuan untuk Android Wear, Anda akan terbiasa dengan
+    model ini.
+  </li>
+
+  <li>
+    <strong>Balasan Langsung</strong>: Untuk aplikasi komunikasi real-time, sistem
+    Android mendukung balasan inline sehingga pengguna bisa dengan cepat membalas
+    SMS atau pesan teks secara langsung dari dalam antarmuka pemberitahuan.
+  </li>
+
+  <li>
+    <strong>Tampilan khusus</strong>: Dua API baru memungkinkan Anda memanfaatkan dekorasi sistem,
+    misalnya header pemberitahuan dan tindakan, saat menggunakan tampilan
+    khusus dalam pemberitahuan.
+  </li>
+</ul>
+
+<div class="col-4of12">
+  <img src="{@docRoot}images/android-7.0/notifications-1.png" alt="" style="padding:.5em;max-width:226px">
+</div>
+
+<div class="col-4of12">
+  <img src="{@docRoot}images/android-7.0/notifications-3.png" alt="" style="padding:.5em;max-width:226px">
+</div>
+
+<div class="col-4of12">
+  <img src="{@docRoot}images/android-7.0/notifications-2.png" alt="" style="padding:.5em;max-width:226px">
+</div>
+
+
+<p class="img-caption">
+  <strong>Gambar 2.</strong> Bundel pemberitahuan dan balasan langsung.
+</p>
+
+<p>Untuk mengetahui cara mengimplementasikan fitur-fitur
+  baru ini, lihat panduan <a href="{@docRoot}preview/features/notification-updates.html">Pemberitahuan</a>.
+</p>
+
+
+
+<h2 id="jit_aot">Kompilasi JIT/AOT yang dipandu profil</h2>
+
+<p>Di Android N, kami telah menambahkan compiler Just in Time (JIT) dengan pembuatan profil kode ke
+ART, yang memungkinkannya terus meningkatkan kinerja aplikasi Android saat
+dijalankan. Compiler JIT melengkapi compiler Ahead of Time (AOT) pada ART
+dan membantu memperbaiki kinerja waktu proses, menghemat ruang penyimpanan, dan mempercepat
+pembaruan aplikasi serta pembaruan sistem.</p>
+
+<p>Kompilasi yang dipandu profil memungkinkan ART mengelola kompilasi AOT/JIT untuk setiap aplikasi
+sesuai dengan penggunaan sebenarnya, serta kondisi pada perangkat. Misalnya
+,ART menyimpan profil setiap metode terbaik aplikasi dan bisa melakukan kompilasi lebih awal
+serta menyimpan sementara metode-metode tersebut di cache untuk mendapatkan kinerja terbaik. Hal ini membuat bagian lain dari aplikasi
+dibiarkan tidak dikompilasi hingga benar-benar digunakan.</p>
+
+<p>Di samping meningkatkan kinerja bagian-bagian penting aplikasi, kompilasi yang dipandu profil
+membantu mengurangi footprint RAM keseluruhan aplikasi, termasuk biner
+terkait. Fitur ini terutama penting pada perangkat dengan memori minim.</p>
+
+<p>ART mengelola kompilasi yang dipandu profil dengan cara yang meminimalkan dampak terhadap
+baterai perangkat. ART melakukan prakompilasi hanya bila perangkat sedang diam dan
+mengisi daya, sehingga menghemat waktu dan baterai dengan melakukan pekerjaan tersebut di awal.</p>
+
+<h2 id="quick_path_to_app_install">Jalur Cepat untuk Pasang Aplikasi</h2>
+
+<p>Salah satu manfaat paling nyata dari compiler JIT pada ART adalah kecepatan
+pemasnagan aplikasi dan pembaruan sistem. Bahkan aplikasi besar yang membutuhkan beberapa menit untuk
+dioptimalkan dan dipasang di Android 6.0 sekarang bisa dipasang hanya dalam hitungan
+detik. Pembaruan sistem juga lebih cepat, karena tidak ada lagi langkah optimalisasi. </p>
+
+<h2 id="doze_on_the_go">Istirahatkan Kapan Saja...</h2>
+
+<p>Android 6.0 memperkenalkan Istirahatkan, yaitu mode sistem yang menghemat baterai dengan menangguhkan
+aktivitas CPU dan jaringan di aplikasi bila perangkat sedang diam, misalnya saat
+diletakkan di atas meja atau dalam laci. </p>
+
+<p>Sekarang di Android N, Istirahatkan selangkah lebih maju dalam menghemat baterai kapan saja.
+Setiap kali layar mati dalam jangka waktu tertentu dan perangkat tidak terhubung ke sumber daya,
+Istirahatkan akan menerapkan subset pembatasan umum CPU dan jaringan pada aplikasi.
+Artinya pengguna bisa menghemat daya baterai meskipun perangkat dibawa di dalam
+tasnya.</p>
+
+
+<img src="/preview/images/doze-diagram-1.png" alt="" id="figure1" />
+<p class="img-caption">
+  <strong>Gambar 3.</strong> Istirahatkan sekarang menerapkan
+  pembatasan untuk meningkatkan daya tahan baterai bahkan saat perangkat sedang tidak diam.
+</p>
+
+
+<p>Tidak lama setelah layar dimatikan saat perangkat menggunakan daya baterai, Istirahatkan
+akan membatasi akses jaringan serta menangguhkan pekerjaan dan sinkronisasi. Selama jeda
+pemeliharaan, aplikasi diizinkan mengakses jaringan dan menjalankan semua
+pekerjaan/sinkronisasi yang ditangguhkan. Menyalakan layar atau mencolokkan perangkat akan mengeluarkan
+perangkat dari Istirahatkan.</p>
+
+<p>Bila perangkat dalam kondisi diam lagi, dengan layar mati dan menggunakan daya baterai selama
+jangka waktu tertentu, Istirahatkan akan menerapkan pembatasan CPU dan jaringan pada {@link
+android.os.PowerManager.WakeLock}, alarm {@link android.app.AlarmManager}, dan
+pemindaian GPS/Wi-Fi.</p>
+
+<p>Praktik terbaik untuk menyesuaikan aplikasi Anda dengan Istirahatkan adalah sama, baik
+perangkat sedang bergerak maupun diam, jadi jika Anda sudah memperbarui aplikasi untuk
+menjalankan Istirahatkan dengan lancar, berarti Anda sudah siap. Jika belum, mulailah <a href="{@docRoot}training/monitoring-device-state/doze-standby.html#assessing_your_app">menyesuaikan
+aplikasi Anda dengan Istirahatkan</a> sekarang juga.</p>
+
+<h2 id="background_optimizations">Project Svelte: Optimalisasi Latar Belakang</h2>
+
+<p>Project Svelte merupakan upaya berkelanjutan untuk meminimalkan penggunaan RAM oleh sistem dan aplikasi
+di semua jenis perangkat Android dalam ekosistem. Di Android N, Project
+Svelte berfokus pada optimalisasi cara aplikasi berjalan di latar belakang. </p>
+
+<p>Proses latar belakang merupakan bagian terpenting dari sebagian besar aplikasi. Bila ditangani dengan benar, proses
+ini bisa memberikan pengalaman pengguna yang mengagumkan &mdash; segera, cepat, dan sesuai konteks.
+Bila tidak ditangani dengan benar, proses latar belakang bisa menguras RAM (dan
+baterai) yang sebenarnya tidak perlu serta memengaruhi kinerja sistem untuk aplikasi lain. </p>
+
+<p>Sejak Android 5.0, {@link android.app.job.JobScheduler} telah menjadi
+cara yang disukai untuk melakukan pekerjaan latar belakang dengan cara yang baik
+bagi pengguna. Aplikasi bisa menjadwalkan pekerjaan sekaligus memungkinkan sistem mengoptimalkan berdasarkan
+kondisi memori, daya, dan konektivitas. JobScheduler menawarkan kontrol serta
+kemudahan, dan kami ingin semua aplikasi menggunakannya. </p>
+
+<p>
+  Opsi baik lainnya adalah <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
+  <code>GCMNetworkManager</code></a>, bagian dari Google Play Services, yang
+  menawarkan penjadwalan pekerjaan serupa dengan kompatibilitas pada semua versi lawas
+  Android.
+</p>
+
+<p>Kami terus memperluas <code>JobScheduler</code> dan
+<code>GCMNetworkManager</code> untuk memenuhi lebih banyak
+kasus penggunaan Anda &mdash; misalnya, di Android N Anda sekarang bisa menjadwalkan pekerjaan
+latar belakang berdasarkan perubahan di Content Providers. Pada saat yang sama kami mulai
+menghilangkan beberapa pola lama yang bisa mengurangi kinerja sistem,
+terutama pada perangkat yang minim memori.</p>
+
+<p>Di Android N kami membuang tiga siaran implisit yang umum digunakan &mdash;
+ {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}, {@link
+  android.hardware.Camera#ACTION_NEW_PICTURE}, dan {@link
+  android.hardware.Camera#ACTION_NEW_VIDEO} &mdash; karena ketiganya bisa mengaktifkan
+proses latar belakang pada beberapa aplikasi sekaligus serta menguras memori dan baterai. Jika
+aplikasi Anda menerimanya, manfaatkan N Developer Preview untuk
+  beralih ke <code>JobScheduler</code> dan API terkait sebagai gantinya. </p>
+
+<p>
+  Lihat dokumentasi <a href="{@docRoot}preview/features/background-optimization.html">Optimalisasi
+  Latar Belakang</a> untuk mengetahui detailnya.
+</p>
+
+
+<h2 id="data_saver">Data Saver</h2>
+
+<div class="col-5of12" style="margin-right:1.5em;">
+<img src="{@docRoot}images/android-7.0/datasaver.png" style="border:2px solid #ddd">
+
+<p class="img-caption" style="padding-right:2em;">
+  <strong>Gambar 4.</strong> Data Saver di Settings.
+</p>
+  </div>
+
+<p>Selama penggunaan perangkat seluler, biaya paket data seluler biasanya
+  melebihi harga perangkat itu sendiri. Bagi banyak pengguna, data seluler adalah sumber daya
+mahal yang ingin mereka hemat. </p>
+
+<p>Android N memperkenalkan mode Data Saver, layanan sistem baru yang mengurangi
+penggunaan data seluler oleh aplikasi, baik saat roaming, mendekati akhir siklus tagihan,
+atau saat menggunakan paket data prabayar yang kecil. Data Saver memberi pengguna kemampuan mengontrol cara aplikasi
+menggunakan data seluler dan memungkinkan pengembang memberikan layanan yang lebih efisien bila Data
+Saver aktif. </p>
+
+<p>Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
+dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu aplikasi
+untuk menghemat penggunaan data latar depan &mdash; misalnya dengan membatasi
+kecepatan bit untuk streaming, mengurangi kualitas gambar, menangguhkan precaching optimistik,
+dan seterusnya. Pengguna bisa memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota
+bila Data Saver diaktifkan.</p>
+
+<p>Android N memperluas {@link android.net.ConnectivityManager} untuk menyediakan cara pada aplikasi
+untuk <a href="{@docRoot}preview/features/data-saver.html#status">mengambil
+preferensi Data Saver pengguna</a> dan <a href="{@docRoot}preview/features/data-saver.html#monitor-changes">memantau
+perubahan preferensi</a>. Semua aplikasi harus memeriksa apakah pengguna telah mengaktifkan Data
+Saver dan berusaha membatasi penggunaan data latar belakang dan latar depan.</p>
+
+
+<h2 id="vulkan">Vulkan API</h2>
+
+<p>
+  Android N mengintegrasikan <a href="http://www.khronos.org/vulkan" class="external-link">Vulkan™</a>, sebuah API rendering 3D baru, ke dalam platform. Seperti
+  <a href="https://www.khronos.org/opengles/" class="external-link">OpenGL™
+  ES</a>, Vulkan merupakan standar terbuka untuk grafik 3D dan rendering yang dikelola
+  oleh Khronos Group.
+</p>
+
+<p>
+  Vulkan didesain dari nol untuk meminimalkan overhead CPU dalam driver,
+  dan memungkinkan aplikasi Anda mengontrol operasi GPU lebih langsung. Vulkan
+  juga memungkinkan paralelisasi yang lebih baik dengan mengizinkan beberapa thread menjalankan
+  pekerjaan seperti pembuatan buffer perintah sekaligus.
+</p>
+
+<p>
+  Pustaka dan alat pengembangan Vulkan telah dimasukkan ke dalam Android NDK. Ini
+  berisi:
+</p>
+
+<ul>
+  <li>Header
+  </li>
+
+  <li>Layer validasi (pustaka debug)
+  </li>
+
+  <li>SPIR-V shader compiler
+  </li>
+
+  <li>Pustaka kompilasi shader waktu proses SPIR-V
+  </li>
+</ul>
+
+<p>
+  Vulkan hanya tersedia untuk aplikasi pada perangkat dengan perangkat keras yang mendukung Vulkan,
+  seperti Nexus 5X, Nexus 6P, dan Nexus Player. Kami bekerja sama erat dengan mitra
+  agar secepatnya makin banyak perangkat yang dilengkapi Vulkan.
+</p>
+
+<p>
+  Untuk informasi selengkapnya, lihat <a href="{@docRoot}ndk/guides/graphics/index.html">dokumentasi API</a>.
+</p>
+
+<h2 id="tile_api">Quick Settings Tile API</h2>
+
+
+<div style="float:right;max-width:320px">
+<img src="{@docRoot}images/android-7.0/quicksettings.png" style="padding-left:1.5em;">
+
+<p class="img-caption" style="padding-left:2em;">
+  <strong>Gambar 5.</strong> Quick Settings Tile dalam bayangan pemberitahuan.
+</p>
+
+
+  </div><p>Quick Settings adalah cara populer dan mudah untuk mengekspos setelan dan tindakan utama,
+langsung dari bayangan pemberitahuan. Di Android N, kami telah memperluas lingkup
+Quick Settings untuk membuatnya lebih berguna dan praktis lagi. </p>
+
+<p>Kami telah menambahkan ruang lebih banyak untuk petak Quick Settings tambahan, yang bisa
+diakses pengguna di semua bagian area tampilan halaman bernomor dengan mengusap ke kiri atau kanan. Kami juga memberi pengguna
+kontrol untuk mengatur letak dan petak Quick Settings apa yang akan
+ditampilkan &mdash; pengguna bisa menambahkan atau memindahkan petak dengan menyeret dan melepasnya. </p>
+
+<p>Bagi pengembang, Android N juga menambahkan API baru yang memungkinkan Anda mendefinisikan
+  petak Quick Settings untuk memberi akses mudah kepada pengguna ke berbagai kontrol dan tindakan utama dalam aplikasi Anda.</p>
+
+<p>
+  Petak Quick Settings dicadangkan untuk kontrol atau tindakan yang
+  mendesak atau sering digunakan, dan tidak boleh digunakan sebagai pintasan untuk
+ membuka aplikasi.
+</p>
+
+<p>
+  Setelah mendefinisikan petak, Anda bisa menyediakannya kepada pengguna, yang bisa mereka tambahkan
+  ke Quick Settings cukup dengan seret dan lepas.
+</p>
+
+<p>
+  Untuk informasi tentang pembuatan petak aplikasi, lihat dokumentasi untuk
+  <code>android.service.quicksettings.Tile</code> dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
+</p>
+
+
+
+<h2 id="number-blocking">Pemblokiran Nomor</h2>
+
+<p>Android N sekarang mendukung pemblokiran nomor di platform dan menyediakan
+API kerangka kerja agar penyedia layanan bisa mengelola daftar nomor blokir. Aplikasi SMS
+default, aplikasi telepon default, dan aplikasi operator bisa membaca dari dan
+menulis ke daftar nomor blokir. Daftar ini tidak dapat diakses oleh aplikasi lain.</p>
+
+<p>Dengan membuat pemblokiran nomor sebagai fitur standar pada platformnya, Android menyediakan
+cara konsisten bagi aplikasi untuk mendukung pemblokiran nomor di berbagai
+perangkat. Manfaat lain yang bisa diperoleh aplikasi antara lain:</p>
+
+<ul>
+  <li> Nomor yang diblokir untuk panggilan juga akan diblokir untuk SMS
+  <li> Nomor yang diblokir tetap disimpan saat pengaturan ulang dan pada berbagai perangkat melalui fitur Backup &amp;
+Restore.
+  <li> Beberapa aplikasi sekaligus bisa menggunakan daftar nomor blokir yang sama.
+</ul>
+
+<p>Selain itu, dengan integrasi aplikasi operator melalui Android berarti operator bisa
+membaca daftar nomor blokir pada perangkat dan melakukan pemblokiran di sisi layanan
+bagi pengguna tersebut untuk menghentikan panggilan dan SMS yang tidak diinginkan
+agar tidak sampai ke pengguna lewat media apa pun, misalnya VOIP-endpoint atau meneruskan panggilan telepon.</p>
+
+<p>
+  Untuk informasi selengkapnya, lihat <code>android.provider.BlockedNumberContract</code>
+  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
+  API</a> yang bisa diunduh.
+</p>
+
+<h2 id="call_screening">Penyaringan Panggilan</h2>
+
+<p>
+  Android N memungkinkan aplikasi telepon default untuk menyaring panggilan masuk. Aplikasi
+  telepon melakukannya dengan mengimplementasikan <code>CallScreeningService</code> baru,
+  yang memungkinkan aplikasi telepon untuk melakukan sejumlah tindakan berdasarkan
+  {@link android.telecom.Call.Details Call.Details} panggilan masuk, misalnya:
+</p>
+
+<ul>
+  <li> Menolak panggilan masuk
+  <li> Tidak mengizinkan panggilan tersebut disimpan ke log panggilan
+  <li> Tidak menampilkan pemberitahuan untuk panggilan tersebut kepada pengguna
+</ul>
+
+<p>
+  Untuk informasi selengkapnya, lihat <code>android.telecom.CallScreeningService</code>
+  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi
+  API</a> yang bisa diunduh.
+</p>
+
+
+<h2 id="multi-locale_languages">Dukungan Multilokal, Lebih Banyak Bahasa yang Didukung</h2>
+
+
+<p>Android N kini memungkinkan pengguna memilih <strong>banyak lokal</strong> di Settings,
+untuk mendukung kasus penggunaan dwibahasa dengan lebih baik. Aplikasi bisa menggunakan
+API baru untuk mendapatkan lokal pilihan pengguna kemudian menawarkan pengalaman pengguna
+yang lebih canggih untuk pengguna multilokal &mdash; seperti menampilkan hasil telusur dalam
+banyak bahasa dan tidak menawarkan untuk menerjemahkan halaman web dalam bahasa
+yang sudah diketahui pengguna.</p>
+
+<p>Bersama dukungan multilokal, Android N juga memperluas ragam bahasa
+yang tersedia untuk pengguna. Masing-masing ditawarkan lebih dari 25 varian untuk bahasa yang umum
+digunakan seperti Inggris, Spanyol, Prancis, dan Arab. Juga ditambahkan dukungan
+parsial untuk lebih dari 100 bahasa baru.</p>
+
+<p>Aplikasi bisa mendapatkan daftar lokal yang disetel oleh pengguna dengan memanggil
+<code>LocaleList.GetDefault()</code>.  Untuk mendukung jumlah lokal yang diperluas, Android N sedang
+ mengubah cara mengatasi masalah sumber daya. Pastikan Anda menguji dan memverifikasi bahwa aplikasi Anda
+berfungsi seperti yang diharapkan dengan logika resolusi sumber daya baru.</p>
+
+<p>Untuk mengetahui tentang perilaku resolusi sumber daya baru dan praktik terbaik yang
+harus Anda ikuti, lihat <a href="{@docRoot}preview/features/multilingual-support.html">Dukungan Multibahasa</a>.</p>
+
+
+<h2 id="emoji">Emoji Baru</h2>
+
+<p>
+  Android N memperkenalkan emoji tambahan dan fitur terkait emoji termasuk
+  emoji warna kulit dan dukungan untuk pemilih
+  variasi. Jika aplikasi Anda mendukung emoji,
+  ikuti panduan berikut untuk memanfaatkan fitur terkait emoji ini.
+</p>
+
+<ul>
+  <li>
+    <strong>Periksa apakah perangkat berisi emoji sebelum memasukannya.</strong>
+    Untuk memeriksa emoji mana yang terdapat di
+    font sistem, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
+  </li>
+  <li>
+    <strong>Periksa apakah emoji mendukung pemilih variasi.</strong>
+    Pemilih variasi memungkinkan Anda
+    menampilkan emoji tertentu berwarna atau hitam-putih.
+    Pada perangkat seluler, aplikasi akan menghadirkan emoji berwarna daripada hitam-putih. Akan tetapi,
+    jika aplikasi Anda menampilkan emoji sebaris dengan teks, maka harus menggunakan variasi hitam-putih.
+    Untuk menentukan apakah sebuah emoji memiliki variasi, gunakan pemilih variasi.
+    Untuk daftar lengkap dari karakter dengan variasinya, tinjaulah bagian
+    <em>rangkaian variasi emoji</em> pada
+    <a class="external-link" href="http://www.unicode.org/Public/9.0.0/ucd/StandardizedVariants-9.0.0d1.txt">
+      dokumentasi Unicode mengenai variasi</a>.
+  </li>
+  <li>
+    <strong>Periksa apakah emoji mendukung warna kulit.</strong> Android N memungkinkan pengguna memodifikasi
+    warna kulit emoji yang dirender sesuai dengan preferensi mereka. Aplikasi keyboard harus menyediakan indikasi
+    visual untuk emoji yang memiliki beberapa warna kulit dan harus memungkinkan pengguna
+    memilih warna kulit yang mereka sukai. Untuk menentukan apakah emoji sistem memiliki
+    modifier warna kulit, gunakan metode {@link android.graphics.Paint#hasGlyph(String)}.
+ Anda bisa menentukan emoji mana yang menggunakan warna kulit dengan membaca
+    <a class="external-link" href="http://unicode.org/emoji/charts/full-emoji-list.html">
+     dokumentasi Unicode</a>.
+  </li>
+</ul>
+
+
+<h2 id="icu4">ICU4J API di Android</h2>
+
+<p>
+  Android N kini menawarkan subset <a href="http://site.icu-project.org/">ICU4J</a> API dalam kerangka kerja Android pada paket
+  <code>android.icu</code>. Migrasi mudah, dan biasanya hanya perlu
+  mengubah dari ruang nama <code>com.java.icu</code> ke
+  <code>android.icu</code>. Jika Anda sudah menggunakan bundel ICU4J dalam aplikasi,
+  maka beralih ke <code>android.icu</code> API yang disediakan dalam kerangka kerja
+  Android bisa menghasilkan penghematan besar dalam ukuran APK.
+</p>
+
+<p>
+  Untuk mengetahui selengkapnya tentang Android ICU4J API, lihat <a href="{@docRoot}preview/features/icu4j-framework.html">Dukungan ICU4J</a>.
+</p>
+
+
+
+<h2 id="gles_32">OpenGL&trade; ES 3.2 API</h2>
+
+<p>Android N menambahkan antarmuka kerangka kerja dan dukungan platform untuk OpenGL ES 3.2, termasuk:</p>
+
+<ul>
+  <li> Semua ekstensi dari <a class="external-link" href="https://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
+Android Extension Pack</a></a> (AEP) kecuali untuk <code>EXT_texture_sRGB_decode</code>.
+  <li> Floating-point framebuffer untuk HDR dan shading yang ditangguhkan.
+  <li> Panggilan draw BaseVertex agar batching dan streaming jadi lebih baik.
+  <li> Kontrol akses buffer yang tangguh untuk mengurangi overhead WebGL.
+</ul>
+
+<p>API kerangka kerja untuk OpenGL ES 3.2 di Android N dilengkapi dengan kelas
+  <code>GLES32</code>. Saat menggunakan OpenGL ES 3.2, pastikan
+mendeklarasikan persyaratan dalam file manifes Anda, dengan tag <code>&lt;uses-feature&gt;</code> dan
+atribut <code>android:glEsVersion</code>. </p>
+
+<p>Untuk informasi tentang menggunakan OpenGL ES, termasuk cara memeriksa versi
+OpenGL ES yang didukung perangkat saat waktu proses, lihat <a href="{@docRoot}guide/topics/graphics/opengl.html">Panduan OpenGL ES API</a>.</p>
+
+
+<h2 id="android_tv_recording">Perekaman Android TV</h2>
+
+<p>Android N menambahkan kemampuan untuk merekam dan memutar kembali materi dari layanan masukan
+Android TV melalui API perekaman baru.  Karena dibangun dengan API perekaman yang sudah
+ada, layanan masukan TV bisa mengontrol data saluran apa yang bisa direkam, cara menyimpan
+sesi rekaman, dan mengelola interaksi pengguna dengan materi rekaman. </p>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/tv-recording-api.html">API Perekaman Android TV</a>.</p>
+
+
+<h2 id="android_for_work">Android for Work</h2>
+
+<p>Android for Work menambahkan berbagai fitur dan API baru untuk perangkat yang menjalankan Android N.
+Beberapa fitur unggulannya ada di bawah ini &mdash; untuk mengetahui daftar lengkap perubahannya, lihat
+<a href="{@docRoot}preview/features/afw.html">Pembaruan Android for Work</a>.</p>
+
+<h3 id="work_profile_security_challenge">Pertanyaan Keamanan Profil Kerja </h3>
+
+<p>
+  Pemilik profil yang menargetkan N SDK
+  bisa menetapkan pertanyaan keamanan terpisah untuk aplikasi yang berjalan di
+  profil kerja. Pertanyaan kerja ditampilkan bila pengguna mencoba membuka
+  aplikasi kerja apa pun. Jawaban pertanyaan keamanan yang benar akan membuka
+  profil kerja dan mendekripsinya jika diperlukan. Untuk pemilik profil,
+  <code>ACTION_SET_NEW_PASSWORD</code> akan meminta pengguna untuk menetapkan pertanyaan
+  kerja, dan <code>ACTION_SET_NEW_PARENT_PROFILE_PASSWORD</code> meminta
+  pengguna menyetel kunci perangkat.
+</p>
+
+<p>
+  Pemilik profil bisa menyetel kebijakan kode sandi untuk pertanyaan kerja
+  (seperti berapa lama seharusnya PIN, atau apakah sidik jari bisa digunakan
+  untuk membuka kunci profil) menggunakan <code>setPasswordQuality()</code>,
+  <code>setPasswordMinimumLength()</code> dan metode terkait. Pemilik profil
+  juga bisa menyetel kunci perangkat, menggunakan instance <code>DevicePolicyManager</code>
+  yang dikembalikan oleh metode <code>getParentProfileInstance()</code>  baru.
+  Selain itu, pemilik profil bisa menyesuaikan layar kredensial untuk
+ pertanyaan kerja menggunakan metode baru <code>setOrganizationColor()</code> dan
+  <code>setOrganizationName()</code>.
+</p>
+<h3 id="turn_off_work">Menonaktifkan pekerjaan </h3>
+
+<p>Pada perangkat dengan profil kerja, pengguna bisa beralih mode kerja. Bila mode
+kerja dinonaktifkan, profil yang dikelola akan dinonaktifkan untuk sementara, yang akan menonaktifkan aplikasi
+profil kerja, sinkronisasi latar belakang, dan pemberitahuan. Termasuk aplikasi pemilik
+profil. Bila profil kerja dinonaktifkan, sistem akan menampilkan ikon status
+tetap untuk mengingatkan pengguna bahwa mereka tidak bisa meluncurkan aplikasi kerja. Peluncur
+menunjukkan bahwa aplikasi kerja dan widget tidak bisa diakses. </p>
+
+<h3 id="always_on_vpn">Always-On VPN </h3>
+
+<p>Pemilik perangkat dan pemilik profil bisa memastikan bahwa aplikasi kerja selalu menghubungkan
+melalui VPN yang ditetapkan. Sistem secara otomatis akan memulai VPN itu setelah booting
+perangkat.</p>
+
+<p>
+  Metode <code>DevicePolicyManager</code> baru adalah
+  <code>setAlwaysOnVpnPackage()</code> dan
+  <code>getAlwaysOnVpnPackage()</code>.
+</p>
+
+<p>Karena layanan VPN bisa diikat langsung oleh sistem tanpa interaksi
+aplikasi, klien VPN perlu menangani titik masuk baru untuk Always-On VPN. Seperti
+sebelumnya, layanan ditunjukkan ke sistem melalui
+tindakan pencocokan filter intent <code>android.net.VpnService</code>. </p>
+
+<p>
+  Pengguna bisa secara manual menyetel klien Always-On VPN yang mengimplementasikan
+  metode <code>VPNService</code> dalam pengguna utama dengan menggunakan
+  <strong>Settings&gt;More&gt;Vpn</strong>.
+</p>
+
+<h3 id="custom_provisioning">Penyediaan yang disesuaikan</h3>
+
+<p>
+  Aplikasi bisa menyesuaikan alur penyediaan pemilik profil dan pemilik perangkat
+  dengan warna dan logo perusahaan.
+  <code>DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR</code> menyesuaikan
+  warna alur. <code>DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI</code>
+  menyesuaikan alur dengan logo perusahaan.
+</p>
+
+<h2 id="accessibility_enhancements">Penyempurnaan Aksesibilitas</h2>
+
+<p>Android N saat ini menawarkan Vision Settings langsung di layar Sambutan untuk
+persiapan perangkat baru. Ini sangat memudahkan pengguna untuk menemukan dan mengonfigurasi
+fitur aksesibilitas pada perangkat mereka, termasuk isyarat perbesaran, ukuran
+font, ukuran layar, dan TalkBack. </p>
+
+<p>Dengan fitur aksesibilitas yang penempatannya semakin jelas, pengguna Anda
+kemungkinan besar akan mencoba aplikasi dengan fitur-fitur yang diaktifkan itu. Pastikan Anda menguji aplikasi
+lebih dini dengan mengaktifkan dahulu setelan ini. Anda bisa mengaktifkannya dari Settings &gt;
+Accessibility.</p>
+
+<p>Di Android N, layanan aksesibilitas sekarang bisa membantu pengguna yang mengalami gangguan
+motorik untuk menyentuh layar. API baru memungkinkan membangun layanan dengan
+fitur-fitur seperti pelacakan wajah, pelacakan mata, pemindaian titik, dan seterusnya, untuk
+memenuhi kebutuhan para pengguna tersebut.</p>
+
+<p>Untuk informasi selengkapnya, lihat <code>android.accessibilityservice.GestureDescription</code>
+ dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.</p>
+
+
+<h2 id="direct_boot">Direct Boot</h2>
+
+<p>Direct Boot memperbaiki waktu startup perangkat dan memungkinkan aplikasi
+yang telah didaftarkan memiliki fungsionalitas terbatas bahkan setelah boot ulang tak terduga.
+Misalnya, jika perangkat yang dienkripsi melakukan boot ulang selagi pengguna tidur,
+alarm terdaftar, pesan dan panggilan masuk sekarang bisa terus memberi tahu
+pengguna seperti biasa. Ini juga berarti layanan aksesibilitas bisa
+  segera tersedia setelah restart.</p>
+
+<p>Direct Boot memanfaatkan enkripsi berbasis file di Android N
+untuk mengaktifkan kebijakan enkripsi yang telah disesuaikan bagi sistem dan data aplikasi.
+Sistem akan menggunakan penyimpanan yang dienkripsi dengan perangkat untuk data sistem terpilih dan data
+aplikasi yang terdaftar secara eksplisit. Secara default, penyimpanan yang dienkripsi dengan kredensial digunakan untuk semua
+  data sistem lainnya, data pengguna, aplikasi, dan data aplikasi. </p>
+
+<p>Saat booting, sistem dimulai dalam mode terbatas dengan akses
+ke data yang dienkripsi dengan perangkat saja, dan tanpa akses umum ke aplikasi atau data.
+Jika Anda memiliki komponen yang ingin Anda jalankan dalam mode ini, Anda bisa mendaftarkannya
+dengan menyetel flag dalam manifes. Setelah restart, sistem akan mengaktifkan
+komponen terdaftar dengan menyiarkan intent <code>LOCKED_BOOT_COMPLETED</code>.
+ Sistem akan memastikan data aplikasi yang dienkripsi dengan perangkat tersedia
+sebelum membuka kunci. Semua data lainnya tidak tersedia sebelum Pengguna mengonfirmasi
+  kredensial layar kunci mereka untuk mendekripsinya. </p>
+
+Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/direct-boot.html">Direct Boot</a>.</p>
+</p>
+
+
+<h2 id="key_attestation">Key Attestation</h2>
+
+<p>Keystore yang didukung perangkat keras menyediakan metode yang jauh lebih aman untuk membuat, menyimpan,
+dan menggunakan kunci kriptografi pada perangkat Android. Keystore itu melindungi kunci dari
+kernel Linux, potensi kerentanan Android, dan ekstraksi
+dari perangkat yang di-root.</p>
+
+<p>Agar lebih mudah dan lebih aman dalam menggunakan keystore yang didukung perangkat keras,
+Android N memperkenalkan Key Attestation. Aplikasi dan perangkat-nonaktif bisa menggunakan Key
+Attestation untuk menentukan apakah penyandingan kunci RSA atau EC
+didukung perangkat keras, apa properti dari penyandingan kunci, dan batasan
+  apa yang diterapkan terhadap penggunaan dan validitasnya. </p>
+
+<p>Aplikasi dan layanan perangkat-nonaktif bisa meminta informasi tentang penyandingan kunci
+melalui sertifikat pengesahan X.509 yang harus ditandatangani dengan kunci
+pengesahan yang valid. Kunci pengesahan adalah kunci penandatanganan ECDSA yang
+telah diinjeksikan ke dalam keystore yang didukung perangkat keras pada perangkat saat di pabriknya.
+Karena itu, sertifikat pengesahan yang ditandatangani oleh kunci pengesahan yang
+valid akan mengonfirmasi keberadaan keystore yang didukung perangkat keras, bersama
+  detail pasangan kunci dalam keystore itu.</p>
+
+<p>Untuk memastikan perangkat ini menggunakan citra Android resmi yang
+aman dari pabrik, Key Attestation mengharuskan <a class="external-link" href="https://source.android.com/security/verifiedboot/verified-boot.html#bootloader_requirements">bootloader</a> perangkat
+menyediakan informasi berikut pada <a class="external-link" href="https://source.android.com/security/trusty/index.html">Trusted
+Execution Environment (TEE)</a>:</p>
+
+<ul>
+<li>Versi OS dan level patch yang dipasang pada perangkat</li>
+<li>Kunci publik <a href="https://source.android.com/security/verifiedboot/index.html" class="external-link">Verified Boot</a> dan status kunci</li>
+  </ul>
+
+<p>Untuk informasi selengkapnya tentang fitur keystore yang didukung perangkat keras,
+lihat panduan untuk <a href="https://source.android.com/security/keystore/" class="external-link">Keystore yang Didukung Perangkat Keras</a>.</p>
+
+<p>Selain Key Attestation, Android N juga memperkenalkan
+  kunci yang terikat sidik jari yang tidak dipanggil saat pendaftaran sidik jari.</p>
+
+<h2 id="network_security_config">Network Security Config</h2>
+
+<p>Di Android N, aplikasi bisa menyesuaikan perilaku koneksi aman mereka
+(HTTPS, TLS) secara aman, tanpa modifikasi kode, dengan menggunakan
+<em>Network Security Config</em> deklaratif sebagai ganti menggunakan API programatik
+konvensional yang rawan kesalahan (mis. X509TrustManager).</p>
+
+  <p>Fitur yang didukung:</p>
+<ul>
+<li><b>Trust-anchor khusus.</b> Memungkinkan aplikasi menyesuaikan
+Certificate Authorities (CA) mana yang dipercaya untuk koneksi amannya. Misalnya,
+mempercayai sertifikat tertentu yang ditandatangani sendiri atau set CA publik yang dibatasi.
+</li>
+<li><b>Penggantian hanya-debug.</b> Memungkinkan pengembang aplikasi dengan aman men-debug
+koneksi aman aplikasi mereka tanpa menambah risiko pada basis yang sudah
+dipasang.
+</li>
+<li><b>Berhenti dari lalu lintas cleartext.</b> Memungkinkan aplikasi melindungi dirinya sendiri dari
+penggunaan lalu lintas cleartext yang tidak disengaja.</li>
+<li><b>Penyematan sertifikat.</b> Sebuah fitur canggih yang memungkinkan aplikasi
+  membatasi kunci server mana yang dipercaya untuk koneksi aman.</li>
+</ul>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}preview/features/security-config.html">Network Security
+Config</a>.</p>
+
+<h2 id="default_trusted_ca">Certificate Authority Tepercaya Default</h2>
+
+<p>Secara default, aplikasi yang menargetkan Android N hanya mempercayai sertifikat yang disediakan sistem
+dan tidak lagi mempercayai Certificate Authorities (CA) yang ditambahkan pengguna. Aplikasi yang menargetkan Android
+N dan ingin mempercayai CA yang ditambahkan pengguna harus menggunakan
+<a href="{@docRoot}preview/features/security-config.html">Network Security Config</a> untuk
+menetapkan cara mempercayai CA pengguna.</p>
+
+<h2 id="apk_signature_v2">APK Signature Scheme v2</h2>
+
+<p>
+  Android N memperkenalkan APK Signature Scheme v2, sebuah skema penandatanganan aplikasi baru yang
+  menawarkan waktu pasang aplikasi lebih cepat dan lebih banyak perlindungan terhadap perubahan
+ tidak sah pada file APK. Secara default, Android Studio 2.2 dan Android
+  Plugin untuk Gradle 2.2 menandatangani aplikasi Anda menggunakan APK Signature Scheme v2 dan
+  skema penandatanganan tradisional, yang menggunakan penandatanganan JAR.
+</p>
+
+<p>
+  Meskipun kami menyarankan untuk menerapkan APK Signature Scheme v2 pada aplikasi Anda, skema
+  baru ini tidak wajib. Jika aplikasi Anda tidak dibangun dengan benar saat menggunakan APK
+  Signature Scheme v2, Anda bisa menonaktifkan skema baru ini. Proses penonaktifan
+  menyebabkan Android Studio 2.2 dan Android Plugin untuk Gradle 2.2 menandatangani aplikasi Anda
+  menggunakan skema penandatanganan tradisional saja. Untuk menandatangani dengan
+ skema tradisional saja, buka file <code>build.gradle</code> level-modul, kemudian
+  tambahkan baris <code>v2SigningEnabled false</code> ke konfigurasi
+  penandatanganan rilis Anda:
+</p>
+
+<pre>
+  android {
+    ...
+    defaultConfig { ... }
+    signingConfigs {
+      release {
+        storeFile file("myreleasekey.keystore")
+        storePassword "password"
+        keyAlias "MyReleaseKey"
+        keyPassword "password"
+        <strong>v2SigningEnabled false</strong>
+      }
+    }
+  }
+</pre>
+
+<p class="caution"><strong>Perhatian: </strong> Jika Anda menandatangani aplikasi menggunakan APK
+  Signature Scheme v2 dan membuat perubahan lebih jauh pada aplikasi, tanda tangan aplikasi
+  menjadi tidak valid. Untuk alasan ini, gunakan alat seperti <code>zipalign</code>
+  sebelum menandatangani aplikasi Anda menggunakan APK Signature Scheme v2, bukan setelahnya.
+</p>
+
+<p>
+  Untuk informasi selengkapnya, baca dokumen Android Studio yang menjelaskan cara
+  <a href="{@docRoot}studio/publish/app-signing.html#release-mode">
+  menandatangani aplikasi</a> di Android Studio dan cara<a href="{@docRoot}studio/build/build-variants.html#signing"> mengonfigurasi
+  file build untuk menandatangani aplikasi</a> menggunakan Android Plugin untuk Gradle.
+</p>
+
+<h2 id="scoped_directory_access">Scoped Directory Access</h2>
+
+<p>Di Android N, aplikasi bisa menggunakan API baru untuk meminta akses ke direktori <a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">penyimpanan
+eksternal</a> tertentu, termasuk direktori di media lepas-pasang seperti kartu
+SD. API baru ini sangat menyederhanakan cara aplikasi Anda mengakses direktori
+penyimpanan eksternal standar, seperti direktori <code>Pictures</code>. Aplikasi
+seperti aplikasi foto bisa menggunakan API ini sebagai ganti menggunakan
+<code>READ_EXTERNAL_STORAGE</code>, yang memberikan akses ke semua direktori
+penyimpanan, atau Storage Access Framework, yang membuat pengguna mengarah ke
+direktori tersebut.</p>
+
+<p>Selain itu, API baru ini menyederhanakan langkah-langkah yang diambil pengguna untuk memberikan akses
+penyimpanan eksternal ke aplikasi Anda. Bila Anda menggunakan API baru, sistem akan menggunakan UI izin
+sederhana yang memperinci dengan jelas direktori apa yang aksesnya diminta
+oleh aplikasi.</p>
+
+<p>Untuk informasi selengkapnya, lihat dokumentasi pengembang
+<a href="{@docRoot}preview/features/scoped-folder-access.html">Scoped
+Directory Access</a>.</p>
+
+<h2 id="keyboard_shortcuts_helper">Keyboard Shortcuts Helper</h2>
+
+<p>
+Di Android N, pengguna bisa menekan "Alt + /" untuk memunculkan layar <em>Keyboard Shortcuts</em>
+yang menampilkan semua pintasan yang tersedia baik dari sistem maupun dari
+aplikasi yang sedang mendapatkan fokus. Ini diambil secara otomatis dari menu aplikasi
+jika tersedia, namun pengembang bisa menyediakan daftar pintasan yang telah disesuaikan
+untuk layar. Anda bisa melakukannya dengan mengganti metode
+<code>Activity.onProvideKeyboardShortcuts()</code> baru, yang dijelaskan dalam
+<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
+</p>
+
+<p>
+Untuk memunculkan Keyboard Shortcuts Helper dari mana saja di aplikasi Anda,
+panggil {@code Activity.requestKeyboardShortcutsHelper()} untuk aktivitas terkait.
+</p>
+
+<h2 id="sustained_performance_api">Sustained Performance API</h2>
+
+<p>
+Kinerja bisa berfluktuasi secara dramatis untuk aplikasi yang berjalan lama, karena
+sistem melakukan throttle pada mesin sistem-di-chip saat komponen perangkat mencapai
+batas suhunya. Fluktuasi ini memberikan target bergerak bagi pengembang
+aplikasi yang sedang membuat aplikasi berkinerja tinggi dan berjalan lama.
+</p>
+
+<p>
+Untuk menangani batasan ini, Android N menyertakan dukungan untuk
+<em>mode kinerja kontinu</em>, yang memungkinkan OEM memberikan petunjuk mengenai kemampuan kinerja
+perangkat untuk aplikasi yang berjalan lama. Pengembang aplikasi
+bisa menggunakan petunjuk ini untuk menyesuaikan aplikasi agar kinerja perangkat bisa diprediksi
+dan pada level yang konsisten dalam jangka waktu lama.
+</p>
+
+<p>
+Pengembang aplikasi bisa mencoba API baru ini dalam N Developer Preview pada
+perangkat Nexus 6P saja. Untuk menggunakan fitur ini,
+setel flag jendela kinerja kontinu
+yang ingin Anda jalankan dalam mode kinerja kontinu. Setel flag ini menggunakan metode
+{@code Window.setSustainedPerformanceMode()}. Sistem secara otomatis
+akan menonaktifkan mode ini bila jendela tidak lagi mendapatkan fokus.
+</p>
+
+<h2 id="vr">Dukungan VR</h2>
+
+<p>
+Android N menambahkan dukungan platform dan optimalisasi untuk VR Mode baru yang memungkinkan
+pengembang membuat pengalaman VR berkualitas tinggi di seluler bagi para pengguna. Ada banyak perbaikan
+kinerja, termasuk akses ke inti CPU yang eksklusif untuk aplikasi VR.
+Di dalam aplikasi, Anda bisa memanfaatkan pelacakan kepala yang cerdas,
+dan pemberitahuan stereo yang bekerja untuk VR. Hal terpenting adalah Android N menyediakan
+grafis dengan latensi sangat rendah. Untuk informasi selengkapnya tentang membangun aplikasi VR untuk Android N,
+lihat <a href="https://developers.google.com/vr/android/">Google VR SDK untuk Android</a>.
+</p>
+
+
+<h2 id="print_svc">Penyempurnaan Layanan Cetak</h2>
+
+<p>
+  Di Android N, pengembang layanan cetak kini bisa menampilkan informasi tambahan
+  tentang masing-masing printer dan pekerjaan cetak.
+</p>
+
+<p>
+  Saat mendaftarkan masing-masing printer, layanan cetak kini bisa menyetel
+  ikon per printer dalam dua cara:
+</p>
+
+<ul>
+  <li>Anda bisa menyetel ikon dari ID sumber daya dengan memanggil
+  <code>PrinterInfo.Builder.setResourceIconId()</code>
+  </li>
+
+  <li>Anda bisa menampilkan ikon dari jaringan dengan memanggil
+  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, dan menyetel sebuah
+ callback bila ikon diminta menggunakan
+  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
+  </li>
+</ul>
+
+<p>
+  Selain itu, Anda bisa menyediakan aktivitas per printer untuk menampilkan informasi
+  tambahan dengan memanggil <code>PrinterInfo.Builder.setInfoIntent()</code>.
+</p>
+
+<p>
+  Anda bisa menunjukkan kemajuan dan status pekerjaan cetak di
+  pemberitahuan pekerjaan cetak dengan memanggil masing-masing
+  <code>android.printservice.PrintJob.setProgress()</code> dan
+  <code>android.printservice.PrintJob.setStatus()</code>.
+</p>
+
+<p>
+  Untuk informasi selengkapnya tentang metode ini,lihat  dalam <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi  API</a> yang bisa diunduh.
+</p>
+
+<h2 id="framemetrics_api">FrameMetricsListener API</h2>
+
+<p>
+FrameMetricsListener API memungkinkan aplikasi untuk memantau
+kinerja rendering UI. API tersebut menyediakan kemampuan ini dengan mengekspos Pub/Sub API streaming
+untuk mentransfer info frame-timing untuk jendela aplikasi saat ini. Data yang dikembalikan
+setara dengan yang ditampilkan <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
+dumpsys gfxinfo framestats</code>, namun tidak dibatasi pada 120 bingkai.
+</p>
+
+<p>
+Anda bisa menggunakan FrameMetricsListener untuk mengukur kinerja UI
+level interaksi di produksi, tanpa koneksi USB. API
+ini memungkinkan pengumpulan data dengan granularitas lebih tinggi daripada
+{@code adb shell dumpsys gfxinfo}. Granularitas lebih tinggi ini dimungkinkan karena
+sistem bisa mengumpulkan data untuk interaksi tertentu di aplikasi; sistem
+tidak perlu merekam ringkasan global untuk keseluruhan kinerja
+aplikasi, atau mengosongkan status global yang ada. Anda bisa menggunakan kemampuan ini
+untuk mengumpulkan data kinerja dan menangkap regresi di kinerja UI
+untuk kasus penggunaan sungguhan di dalam aplikasi.
+</p>
+
+<p>
+Untuk memantau sebuah jendela, implementasikan metode callback <code>FrameMetricsListener.onMetricsAvailable()</code>
+dan daftarkan di jendela itu. Untuk informasi selengkapnya, lihat
+dokumentasi kelas {@code FrameMetricsListener} di
+<a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi API</a> yang bisa diunduh.
+</p>
+
+<p>
+API menyediakan objek {@code FrameMetrics}, yang berisi data timing yang
+dilaporkan subsistem rendering untuk berbagai tahap pencapaian dalam daur hidup bingkai.
+Metrik yang didukung adalah: {@code UNKNOWN_DELAY_DURATION},
+{@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
+{@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
+{@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
+{@code TOTAL_DURATION}, dan {@code FIRST_DRAW_FRAME}.
+</p>
+
+
+<h2 id="virtual_files">File Maya</h2>
+
+<p>
+  Di versi Android sebelumnya, aplikasi Anda bisa menggunakan Storage Access
+  Framework untuk memungkinkan pengguna memilih file dari akun penyimpanan awan mereka,
+  seperti Google Drive. Akan tetapi, tidak ada cara untuk merepresentasikan file yang
+  tidak memiliki representasi bytecode langsung; setiap file diharuskan menyediakan
+  aliran masukan.
+</p>
+
+<p>
+  Android N menambahkan konsep <em>file maya</em> pada Storage Access
+  Framework. Fitur file maya memungkinkan
+  {@link android.provider.DocumentsProvider} Anda mengembalikan URI dokumen yang bisa
+  digunakan bersama intent {@link android.content.Intent#ACTION_VIEW} sekalipun
+  tidak memiliki representasi bytecode langsung. Android N juga memungkinkan Anda untuk
+  menyediakan format alternatif untuk file pengguna, maya atau dengan cara lain.
+</p>
+
+<p>
+  Untuk mendapatkan URI sebuah dokumen maya di aplikasi Anda, terlebih dahulu Anda membuat
+  {@link android.content.Intent} untuk membuka UI pemilih file. Karena aplikasi
+  tidak bisa membuka file maya secara langsung dengan menggunakan metode
+  {@link android.content.ContentResolver#openInputStream(Uri) openInputStream()},
+   aplikasi Anda tidak akan menerima file maya jika Anda memasukkan kategori
+  {@link android.content.Intent#CATEGORY_OPENABLE}.
+</p>
+
+<p>
+  Setelah pengguna menentukan pilihan, sistem akan memanggil metode
+  {@link android.app.Activity#onActivityResult onActivityResult()}.
+  Aplikasi Anda bisa mengambil URI file maya dan mendapatkan aliran masukan, seperti yang
+  diperagakan dalam cuplikan kode di bawah.
+</p>
+
+<pre>
+  // Other Activity code ...
+
+  final static private int REQUEST_CODE = 64;
+
+  // We listen to the OnActivityResult event to respond to the user's selection.
+  &#64;Override
+  public void onActivityResult(int requestCode, int resultCode,
+    Intent resultData) {
+      try {
+        if (requestCode == REQUEST_CODE &amp;&amp;
+            resultCode == Activity.RESULT_OK) {
+
+            Uri uri = null;
+
+            if (resultData != null) {
+                uri = resultData.getData();
+
+                ContentResolver resolver = getContentResolver();
+
+                // Before attempting to coerce a file into a MIME type,
+                // check to see what alternative MIME types are available to
+                // coerce this file into.
+                String[] streamTypes =
+                  resolver.getStreamTypes(uri, "*/*");
+
+                AssetFileDescriptor descriptor =
+                    resolver.openTypedAssetFileDescriptor(
+                        uri,
+                        streamTypes[0],
+                        null);
+
+                // Retrieve a stream to the virtual file.
+                InputStream inputStream = descriptor.createInputStream();
+            }
+        }
+      } catch (Exception ex) {
+        Log.e("EXCEPTION", "ERROR: ", ex);
+      }
+  }
+</pre>
+
+<p>
+  Untuk informasi selengkapnya tentang mengakses file pengguna, lihat
+  <a href="{@docRoot}guide/topics/providers/document-provider.html">Panduan Storage
+  Access Frameworks</a>.
+</p>
diff --git a/docs/html-intl/intl/id/about/versions/nougat/index.jd b/docs/html-intl/intl/id/about/versions/nougat/index.jd
new file mode 100644
index 0000000..212870a
--- /dev/null
+++ b/docs/html-intl/intl/id/about/versions/nougat/index.jd
@@ -0,0 +1,110 @@
+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
+footer.hide=1
+@jd:body
+
+<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-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
+        <p class="dac-hero-description">
+          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}about/versions/nougat/android-7.0.html">
+          <span class="dac-sprite dac-auto-chevron"></span>
+          Mulai
+        </a>
+      </div>
+      <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></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>
+</section>
+
+
+<div 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">
+      <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://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/dev-community">
+          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
+          Bergabunglah dengan komunitas pengembang
+        </a>
+      </li>
+    </ul>
+  </div><!-- end .wrap -->
+</div><!-- end .dac-actions -->
+
+<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
+  <h2 class="norule">Terbaru</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">
+    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: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>
\ No newline at end of file
diff --git a/docs/html-intl/intl/id/design/get-started/principles.jd b/docs/html-intl/intl/id/design/get-started/principles.jd
new file mode 100644
index 0000000..2a1d194
--- /dev/null
+++ b/docs/html-intl/intl/id/design/get-started/principles.jd
@@ -0,0 +1,307 @@
+page.title=Prinsip Desain Android
+@jd:body
+
+<p>Prinsip desain ini dikembangkan oleh dan untuk Tim Pengalaman Pengguna
+ Android agar selalu mempertimbangkan kepentingan pengguna.
+Untuk pengembang dan desainer Android, mereka terus
+meletakkan dasar pedoman desain yang lebih detail untuk beragam tipe
+perangkat.</p>
+
+<p>
+Perhatikan prinsip-prinsip ini saat Anda menerapkan
+kreativitas dan pemikiran desain sendiri. Menyimpang dengan sengaja.
+</p>
+
+<h2 id="enchant-me">Pikat Saya</h2>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="delight-me">Senangkan saya dengan cara yang mengejutkan</h4>
+<p>Permukaan yang cantik, animasi yang ditempatkan dengan hati-hati, atau efek suara di saat yang tepat sungguh menyenangkan untuk
+dinikmati. Efek yang lembut menimbulkan perasaan serba mudah dan kesadaran bahwa kekuatan yang
+bisa diandalkan ada dalam genggaman.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_delight.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="real-objects-more-fun">Objek sungguhan lebih menyenangkan daripada tombol dan menu</h4>
+<p>Biarkan orang langsung menyentuh dan memanipulasi objek dalam aplikasi Anda. Ini mengurangi upaya kognitif
+yang diperlukan untuk menjalankan tugas sekaligus membuatnya lebih memuaskan secara emosional.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_real_objects.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="make-it-mine">Biarkan saya memilikinya</h4>
+<p>Orang suka menambahkan sentuhan pribadi karena membantu mereka merasa betah dan memegang kendali. Memberikan
+default yang pantas dan indah, tetapi juga mempertimbangkan penyesuaian opsional yang menyenangkan, yang tidak mengganggu
+tugas utama.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_make_it_mine.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="get-to-know-me">Kenali saya</h4>
+<p>Pelajari preferensi orang dari waktu ke waktu. Daripada meminta mereka untuk membuat pilihan yang sama
+berulang-ulang, tempatkan pilihan sebelumnya agar mudah dijangkau.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_get_to_know_me.png">
+
+  </div>
+</div>
+
+<h2 id="simplify-my-life">Sederhanakan Hidup Saya</h2>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="keep-it-brief">Persingkat</h4>
+<p>Gunakan frasa pendek dengan kata-kata sederhana. Orang cenderung melewatkan kalimat-kalimat panjang.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_keep_it_brief.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="pictures-faster-than-words">Gambar lebih cepat dibanding kata-kata</h4>
+<p>Pertimbangkan menggunakan gambar untuk menjelaskan gagasan. Gambar menarik perhatian orang dan bisa jauh lebih efisien
+dibanding kata-kata.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_pictures.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="decide-for-me">Putuskan untuk saya tetapi biarkan saya yang menentukan</h4>
+<p>Gunakan tebakan terbaik Anda dan bertindaklah daripada meminta terlebih dahulu. Terlalu banyak pilihan dan keputusan membuat orang
+tidak suka. Untuk berjaga-jaga jika Anda salah, izinkan 'pembatalan'.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_decide_for_me.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="only-show-when-i-need-it">Cukup tunjukkan yang saya perlukan ketika saya memerlukannya</h4>
+<p>Orang merasa kewalahan ketika melihat terlalu banyak hal sekaligus. Uraikan tugas dan informasi menjadi potongan-potongan
+kecil yang mudah dicerna. Sembunyikan opsi yang tidak perlu pada saat ini, dan ajari orang sambil jalan.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_information_when_need_it.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="always-know-where-i-am">Saya harus selalu tahu di mana saya berada</h4>
+<p>Beri orang kepercayaan diri bahwa mereka tahu di mana berada. Buat agar tempat-tempat dalam aplikasi Anda terlihat berbeda dan
+gunakan transisi untuk menunjukkan hubungan antar layar. Berikan umpan balik tentang tugas yang sedang berlangsung.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_navigation.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="never-lose-my-stuff">Jangan sekali-kali menghilangkan milik saya</h4>
+<p>Simpan apa yang telah susah-payah dibuat orang dan biarkan mereka mengaksesnya dari mana saja. Ingat pengaturan,
+sentuhan pribadi, dan kreasi lintas ponsel, tablet, dan komputer. Itu membuat pemutakhiran menjadi
+hal termudah di dunia.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_never_lose_stuff.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="looks-same-should-act-same">Jika terlihat sama, seharusnya fungsinya sama</h4>
+<p>Bantu orang merasakan perbedaan fungsional dengan membuat mereka terlihat berbeda daripada mirip.
+Hindari mode, yaitu tempat yang terlihat mirip tetapi berbeda fungsinya pada input yang sama.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_looks_same.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="interrupt-only-if-important">Sela saya jika penting saja</h4>
+<p>Layaknya asisten pribadi yang baik, lindungi orang dari detail yang tidak penting. Orang ingin tetap
+fokus, dan kecuali jika memang penting dan sensitif waktu, interupsi bisa melelahkan dan menjengkelkan.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_important_interruption.png">
+
+  </div>
+</div>
+
+<h2 id="make-me-amazing">Buat Saya Terpesona</h2>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="give-me-tricks">Beri saya trik yang efektif di mana saja</h4>
+<p>Orang merasa senang ketika mereka memahami sendiri sesuatu. Jadikan aplikasi Anda lebih mudah dipelajari dengan
+memanfaatkan pola visual dan memori otot dari aplikasi Android lainnya. Misalnya, gerakan menggeser
+dapat menjadi pintasan navigasi yang bagus.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_tricks.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="its-not-my-fault">Bukan salah saya</h4>
+<p>Bersikap ramahlah dalam meminta orang untuk melakukan koreksi. Mereka ingin merasa pintar ketika menggunakan
+aplikasi Anda. Jika terjadi kesalahan, berikan petunjuk perbaikan yang jelas tetapi lepaskan mereka dari detail teknis.
+Jika Anda dapat memperbaikinya secara diam-diam, tentu lebih baik.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_error.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="sprinkle-encouragement">Berikan dorongan</h4>
+<p>Uraikan tugas-tugas rumit menjadi langkah-langkah kecil yang dapat dilakukan dengan mudah. Beri umpan balik tentang tindakan,
+meskipun hanya sesuatu yang sederhana.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_sprinkle_encouragement.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="do-heavy-lifting-for-me">Lakukan pekerjaan yang sulit untuk saya</h4>
+<p>Buatlah pemula merasa seperti ahli dengan memungkinkan mereka untuk melakukan hal-hal yang mereka pikir tidak akan bisa.
+Misalnya, pintasan yang menggabungkan beberapa efek foto dapat membuat foto amatir terlihat mengagumkan hanya
+dalam beberapa langkah.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_heavy_lifting.png">
+
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="cols">
+  <div class="col-7">
+
+<h4 id="make-important-things-fast">Percepat hal penting</h4>
+<p>Tidak semua tindakan itu sama. Putuskan apa yang terpenting dalam aplikasi Anda dan permudah untuk menemukannya serta
+cepat untuk digunakan, seperti tombol rana pada kamera, atau tombol jeda pada pemutar musik.</p>
+
+  </div>
+  <div class="col-6">
+
+    <img src="{@docRoot}design/media/principles_make_important_fast.png">
+
+  </div>
+</div>
diff --git a/docs/html-intl/intl/id/design/material/index.jd b/docs/html-intl/intl/id/design/material/index.jd
new file mode 100644
index 0000000..0cb4dbc
--- /dev/null
+++ b/docs/html-intl/intl/id/design/material/index.jd
@@ -0,0 +1,186 @@
+page.title=Material Design for Android
+page.tags=Material,design
+page.type=design
+page.image=images/cards/design-material-for-android_2x.jpg
+
+@jd:body
+
+<!-- developer docs box -->
+<a class="notice-developers right" href="{@docRoot}training/material/index.html">
+  <div>
+    <h3>Dokumen Pengembang</h3>
+    <p>Membuat Aplikasi dengan Desain Bahan</p>
+  </div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=p4gmvHyuZzw">
+<div>
+    <h3>Video</h3>
+    <p>Pengantar Desain Bahan</p>
+</div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=YaG_ljfzeUw">
+<div>
+    <h3>Video</h3>
+    <p>Kertas dan Tinta: Bahan Penting</p>
+</div>
+</a>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=XOcCOBe8PTc">
+<div>
+    <h3>Video</h3>
+    <p>Desain Bahan di Aplikasi Google I/O</p>
+</div>
+</a>
+
+
+
+<p itemprop="description">Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan
+interaksi lintas platform dan perangkat. Android kini menyertakan dukungan untuk
+aplikasi desain bahan. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan yang didefinisikan
+dalam <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a> dan gunakan
+komponen dan fungsionalitas baru yang tersedia di Android 5.0 (API level 21) ke atas.</p>
+
+<p>Android menyediakan elemen berikut untuk membangun aplikasi desain bahan:</p>
+
+<ul>
+  <li>Tema baru</li>
+  <li>Widget baru untuk tampilan yang kompleks</li>
+  <li>API baru untuk animasi dan bayangan custom</li>
+</ul>
+
+<p>Untuk informasi selengkapnya tentang mengimplementasikan desain bahan pada Android, lihat
+<a href="{@docRoot}training/material/index.html">Membuat Aplikasi dengan Desain Bahan</a>.</p>
+
+
+<h3>Tema Bahan</h3>
+
+<p>Tema bahan menyediakan gaya baru untuk aplikasi Anda, widget sistem yang memungkinkan Anda mengatur
+palet warnanya, dan animasi default untuk umpan balik sentuh dan transisi aktivitas.</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238" />
+  <div style="width:140px;margin:0 auto">
+  <p style="margin-top:8px">Tema bahan gelap</p>
+  </div>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238" />
+  <div style="width:140px;margin:0 auto">
+  <p style="margin-top:8px">Tema bahan terang</p>
+  </div>
+</div>
+<br style="clear:left"/>
+</div>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/theme.html">Menggunakan Tema
+Bahan</a>.</p>
+
+
+<h3>Daftar dan Kartu</h3>
+
+<p>Android menyediakan dua widget baru untuk menampilkan kartu dan daftar dengan gaya desain bahan
+dan animasi:</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+  <img src="{@docRoot}design/material/images/list_mail.png" width="500" height="426" />
+  <p>Widget <code>RecyclerView</code> baru adalah versi <code>ListView</code>
+ yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.</p>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+  <img src="{@docRoot}design/material/images/card_travel.png" width="500" height="426" />
+  <p>Widget <code>CardView</code> baru memungkinkan Anda menampilkan potongan informasi penting dalam
+  kartu yang memiliki tampilan dan cara kerja yang konsisten.</p>
+</div>
+<br style="clear:left"/>
+</div>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
+dan Kartu</a>.</p>
+
+
+<h3>Bayangan Tampilan</h3>
+
+<p>Selain properti X dan Y, tampilan di Android kini memiliki
+properti Z. Properti baru ini mewakili ketinggian tampilan, yang menentukan:</p>
+
+<ul>
+<li>Ukuran bayangan: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar.</li>
+<li>Urutan penggambaran: tampilan dengan nilai Z lebih tinggi muncul di atas tampilan lainnya.</li>
+</ul>
+
+<div style="width:290px;margin-left:35px;float:right">
+  <div class="framed-nexus5-port-span-5">
+  <video class="play-on-hover" autoplay>
+    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4"/>
+    <source src="{@docRoot}design/videos/ContactsAnim.webm"/>
+    <source src="{@docRoot}design/videos/ContactsAnim.ogv"/>
+  </video>
+  </div>
+  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+    <em>Untuk memutar ulang film, klik layar perangkat</em>
+  </div>
+</div>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
+Bayangan dan Memangkas Tampilan</a>.</p>
+
+
+<h3>Animasi</h3>
+
+<p>API animasi baru memungkinkan Anda membuat animasi custom untuk umpan balik sentuh dalam kontrol UI,
+perubahan status tampilan, dan transisi aktivitas.</p>
+
+<p>API ini memungkinkan Anda:</p>
+
+<ul>
+<li style="margin-bottom:15px">
+Merespons kejadian sentuh dalam tampilan Anda dengan animasi <strong>umpan balik sentuh</strong>.
+</li>
+<li style="margin-bottom:15px">
+Menyembunyikan dan memperlihatkan tampilan dengan animasi <strong>membuka melingkar</strong>.
+</li>
+<li style="margin-bottom:15px">
+Peralihan antar aktivitas dengan animasi <strong>transisi aktivitas</strong> custom.
+</li>
+<li style="margin-bottom:15px">
+Membuat animasi yang lebih alami dengan <strong>gerak melengkung</strong>.
+</li>
+<li style="margin-bottom:15px">
+Menganimasikan perubahan dalam satu atau beberapa properti tampilan dengan animasi <strong>perubahan status tampilan</strong>.
+</li>
+<li style="margin-bottom:15px">
+Menampilkan animasi di <strong>drawable daftar status</strong> di antara perubahan status tampilan.
+</li>
+</ul>
+
+<p>Animasi umpan balik sentuh dimasukkan ke dalam beberapa tampilan standar, misalnya tombol. API baru
+ini memungkinkan Anda menyesuaikan animasi ini dan menambahkannya ke tampilan custom Anda.</p>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi
+Custom</a>.</p>
+
+
+<h3>Drawable</h3>
+
+<p>Kemampuan baru untuk drawable ini membantu Anda mengimplementasikan aplikasi desain bahan:</p>
+
+<ul>
+<li><strong>Drawable vektor</strong> bisa diubah skalanya tanpa kehilangan definisi dan cocok
+untuk ikon satu-warna dalam-aplikasi.</li>
+<li><strong>Pewarnaan drawable</strong> memungkinkan Anda mendefinisikan bitmap sebagai alpha-mask dan mewarnainya
+saat runtime.</li>
+<li><strong>Ekstraksi warna</strong> memungkinkan Anda mengekstrak warna mencolok secara otomatis dari
+gambar bitmap.</li>
+</ul>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/drawables.html">Bekerja dengan
+Drawable</a>.</p>
diff --git a/docs/html-intl/intl/id/design/patterns/compatibility.jd b/docs/html-intl/intl/id/design/patterns/compatibility.jd
new file mode 100644
index 0000000..cafaac4
--- /dev/null
+++ b/docs/html-intl/intl/id/design/patterns/compatibility.jd
@@ -0,0 +1,70 @@
+page.title=Kompatibilitas Mundur
+page.tags="support"
+page.metaDescription=Catatan tentang bagaimana Android 4.x menyesuaikan UI yang didesain untuk perangkat keras dan versi OS yang lebih lama.
+@jd:body
+
+<a class="notice-developers" href="{@docRoot}training/basics/supporting-devices/index.html">
+  <div>
+    <h3>Dokumen Pengembang</h3>
+    <p>Mendukung Perangkat Berbeda</p>
+  </div>
+</a>
+
+<p>Perubahan signifikan dalam Android 3.0 meliputi:</p>
+<ul>
+<li>Dihilangkannya tombol perangkat keras navigasi (Back, Menu, Search, Home) untuk membantu menangani navigasi
+  melalui kontrol maya (Back, Home, Recents).</li>
+<li>Pola yang tangguh untuk penggunaan menu pada action-bar.</li>
+</ul>
+<p>Android 4.0 membawa perubahan ini untuk tablet dengan platform ponsel.</p>
+
+<h2 id="older-hardware">Menyesuaikan Android 4.0 dengan Perangkat Keras dan Aplikasi yang Lebih Lama</h2>
+
+<div class="cols">
+  <div class="col-6">
+
+<h4>Ponsel dengan kontrol navigasi virtual</h4>
+<p>Aplikasi Android yang ditulis untuk Android 3.0 dan yang lebih baru menampilkan tindakan dalam action-bar. Tindakan yang tidak
+muat dalam action-bar atau tidak cukup penting untuk ditampilkan di tingkat atas akan muncul dalam
+action-overflow.</p>
+<p>Pengguna mengakses action-overflow dengan menyentuhnya dalam action-bar.</p>
+
+  </div>
+  <div class="col-7">
+
+    <img src="{@docRoot}design/media/compatibility_virtual_nav.png">
+
+  </div>
+</div>
+
+<div class="cols">
+  <div class="col-6">
+
+<h4>Ponsel dengan tombol navigasi fisik</h4>
+<p>Ponsel Android dengan tombol perangkat keras navigasi biasa tidak menampilkan baris navigasi virtual di
+bagian bawah layar. Sebagai gantinya, action-overflow tersedia dari tombol perangkat keras menu. Popup
+tindakan yang dihasilkan memiliki gaya yang sama dengan contoh sebelumnya, tetapi ditampilkan di bagian bawah layar.</p>
+
+  </div>
+  <div class="col-7">
+
+    <img src="{@docRoot}design/media/compatibility_physical_buttons.png">
+
+  </div>
+</div>
+
+<div class="cols">
+  <div class="col-6">
+
+<h4>Aplikasi lama pada ponsel dengan kontrol navigasi virtual</h4>
+<p>Bila Anda menjalankan aplikasi yang dibuat untuk Android 2.3 atau yang lebih lama pada ponsel
+dengan kontrol navigasi virtual, sebuah kontrol action-overflow akan muncul di sebelah kanan baris navigasi virtual. Anda
+dapat menyentuh kontrol itu untuk menampilkan tindakan aplikasi dalam gaya menu Android biasa.</p>
+
+  </div>
+  <div class="col-7">
+
+    <img src="{@docRoot}design/media/compatibility_legacy_apps.png">
+
+  </div>
+</div>
diff --git a/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
new file mode 100644
index 0000000..d22e924
--- /dev/null
+++ b/docs/html-intl/intl/id/design/patterns/confirming-acknowledging.jd
@@ -0,0 +1,70 @@
+page.title=Mengonfirmasi &amp; Mengakui
+page.tags=dialog,toast,notification
+@jd:body
+
+<p>Dalam beberapa situasi, bila pengguna memanggil suatu tindakan dalam aplikasi Anda, ada baiknya <em>mengonfirmasi</em> atau <em>mengakui</em> tindakan itu melalui teks.</p>
+
+<div class="cols">
+  <div class="col-6">
+    <img src="{@docRoot}design/media/confirm_ack_confirming.png">
+    <p><strong>Mengonfirmasi</strong> adalah meminta pengguna untuk memverifikasi bahwa mereka benar-benar ingin melanjutkan tindakan yang baru saja mereka panggil. Dalam beberapa kasus, konfirmasi ditampilkan bersama-sama dengan peringatan atau informasi penting yang terkait dengan tindakan yang perlu mereka pertimbangkan.</p>
+  </div>
+  <div class="col-6">
+    <img src="{@docRoot}design/media/confirm_ack_acknowledge.png">
+    <p><strong>Mengakui</strong> adalah menampilkan teks untuk memberi tahu pengguna bahwa tindakan yang baru mereka panggil sudah dilakukan. Ini menghilangkan ketidakpastian tentang operasi implisit yang dilakukan sistem. Dalam beberapa kasus, pengakuan ditampilkan bersama dengan opsi untuk membatalkan tindakan.</p>
+  </div>
+</div>
+
+<p>Berkomunikasi pada pengguna dengan cara ini bisa membantu mengurangi ketidakpastian tentang hal-hal yang sudah atau akan terjadi. Mengonfirmasi atau mengakui juga dapat mencegah pengguna melakukan kesalahan yang akan mereka sesali.</p>
+
+<h2>Kapan Harus Mengonfirmasi atau Mengakui Tindakan Pengguna</h2>
+<p>Tidak semua tindakan memerlukan konfirmasi atau pengakuan. Gunakan bagan alur ini untuk memandu keputusan desain Anda.</p>
+<img src="{@docRoot}design/media/confirm_ack_flowchart.png">
+
+<h2>Mengonfirmasi</h2>
+<div class="cols">
+  <div class="col-6">
+    <h4>Contoh: Google Play Books</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_books.png">
+    <p>Dalam contoh ini, pengguna telah meminta untuk menghapus sebuah buku dari perpustakaan Google Play mereka. Sebuah <a href="{@docRoot}design/building-blocks/dialogs.html#alerts">peringatan</a> muncul untuk mengonfirmasi tindakan ini karena perlu dipahami bahwa buku tersebut tidak akan tersedia lagi dari perangkat apa pun.</p>
+    <p>Saat membuat dialog konfirmasi, buat judul bermakna dengan mencerminkan tindakan yang diminta.</p>
+  </div>
+  <div class="col-7">
+    <h4>Contoh: Android Beam</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_beam.png">
+    <p>Konfirmasi tidak harus ditampilkan dalam peringatan dengan dua tombol. Setelah menjalankan Android Beam, pengguna diminta untuk menyentuh konten yang akan dibagikan (dalam contoh ini, sebuah foto). Jika mereka memutuskan untuk tidak melanjutkan, mereka tinggal memindahkan ponsel.</p>
+  </div>
+</div>
+
+<h2>Mengakui</h2>
+<div class="cols">
+  <div class="col-6">
+    <h4>Contoh: Draf Gmail batal yang disimpan</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_draftsave.png">
+    <p>Dalam contoh ini, jika pengguna menyusuri ke belakang atau ke atas dari layar pembuatan email di Gmail, sesuatu yang tak diharapkan bisa terjadi: draf saat itu akan disimpan secara otomatis. Pengakuan dalam bentuk pemberitahuan akan lebih jelas. Ini menghilang setelah beberapa detik.</p>
+    <p>Pembatalan tidak cocok di sini karena penyimpanan dilakukan oleh aplikasi, bukan pengguna. Cepat dan mudah untuk melanjutkan penulisan pesan dengan menyusuri daftar draf.</p>
+
+  </div>
+  <div class="col-6">
+    <h4>Contoh: Percakapan Gmail dihapus</h4>
+    <img src="{@docRoot}design/media/confirm_ack_draft_deleted.png">
+    <p>Setelah pengguna menghapus percakapan dari daftar dalam Gmail, sebuah pengakuan muncul tanpa opsi pembatalan. Pengakuan tetap ada sampai pengguna melakukan tindakan yang tidak berkaitan, seperti menggulir daftar.</p>
+  </div>
+</div>
+
+<h2>Tidak ada Konfirmasi atau Pengakuan</h2>
+<div class="cols">
+  <div class="col-6">
+    <h4>Contoh: memberikan +1</h4>
+    <img style="padding: 33px 0 30px;" src="{@docRoot}design/media/confirm_ack_ex_plus1.png">
+    <p><strong>Konfirmasi tidak diperlukan</strong>. Jika pengguna telah memberikan +1 secara tidak sengaja, tidak masalah. Mereka cukup menyentuh kembali tombol itu untuk membatalkan tindakan.</p>
+    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan melihat tombol +1 memantul dan berubah merah. Itu tanda yang sangat jelas.</p>
+  </div>
+  <div class="col-7">
+    <h4>Contoh: Menghapus aplikasi dari Layar Beranda</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_removeapp.png">
+    <p><strong>Konfirmasi tidak diperlukan</strong>. Ini adalah tindakan yang disengaja: pengguna harus menyeret dan meletakkan sebuah item di atas target yang relatif besar dan terpisah. Karena itu, kecil kemungkinan terjadi ketidaksengajaan. Tetapi jika pengguna menyesali keputusan itu, maka hanya perlu beberapa detik untuk mengembalikannya lagi.</p>
+    <p><strong>Pengakuan tidak diperlukan</strong>. Pengguna akan mengetahui bahwa aplikasi itu tidak ada di Layar Beranda karena mereka menghilangkannya dengan cara menyeretnya.</p>
+
+  </div>
+</div>
diff --git a/docs/html-intl/intl/id/design/patterns/navigation.jd b/docs/html-intl/intl/id/design/patterns/navigation.jd
new file mode 100644
index 0000000..4915700
--- /dev/null
+++ b/docs/html-intl/intl/id/design/patterns/navigation.jd
@@ -0,0 +1,213 @@
+page.title=Navigasi dengan Back dan Up
+page.tags="navigation","activity","task","up navigation","back navigation"
+page.image=/design/media/navigation_between_siblings_gmail.png
+@jd:body
+
+<a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
+  <div>
+    <h3>Dokumen Pengembang</h3>
+    <p>Mengimplementasikan Navigasi yang Efektif</p>
+  </div>
+</a>
+
+<p itemprop="description">Navigasi yang konsisten merupakan komponen penting dari keseluruhan pengalaman pengguna. Hampir tidak ada yang lebih membingungkan
+pengguna selain navigasi dasar yang perilakunya tidak konsisten dan tidak sesuai harapan. Android 3.0
+memperkenalkan perubahan besar dalam perilaku navigasi global. Mengikuti dengan saksama
+panduan untuk Back dan Up akan membuat navigasi aplikasi Anda dapat diprediksi dan dapat diandalkan pengguna.</p>
+<p>Android 2.3 dan versi sebelumnya mengandalkan tombol <em>Back</em> sistem untuk mendukung navigasi dalam
+aplikasi. Dengan diperkenalkannya action-bar dalam Android 3.0, mekanisme navigasi kedua muncul:
+tombol <em>Up</em>, yang terdiri dari ikon aplikasi dan tanda panah yang menunjuk ke kiri.</p>
+
+<img src="{@docRoot}design/media/navigation_with_back_and_up.png">
+
+<h2 id="up-vs-back">Up vs. Back</h2>
+
+<p>Tombol Up digunakan untuk berpindah dalam aplikasi berdasarkan hubungan hierarki
+antar layar. Misalnya, jika layar A menampilkan daftar item, dan memilih sebuah item akan membuka
+layar B (yang menampilkan item tersebut secara lebih detail), maka layar B akan menawarkan tombol Up untuk
+kembali ke layar A.</p>
+<p>Jika suatu layar merupakan yang teratas dalam aplikasi (yaitu layar Home aplikasi), maka tidak perlu menampilkan tombol
+Up.</p>
+
+<p>Tombol Back sistem digunakan untuk berpindah, dalam urutan kronologis terbalik, melalui riwayat
+layar yang baru dibuka oleh pengguna. Biasanya ini berdasarkan hubungan sementara
+antar layar, dan bukan hierarki aplikasi.</p>
+
+<p>Bila layar yang dilihat sebelumnya juga merupakan induk hierarki dari layar yang sekarang, menekan tombol
+Back akan sama hasilnya dengan menekan tombol Up&mdash;ini adalah kejadian
+biasa. Akan tetapi, berbeda dengan tombol Up, yang memastikan pengguna tetap berada dalam aplikasi Anda, tombol Back
+dapat mengembalikan pengguna ke layar Home, atau bahkan ke aplikasi lain.</p>
+
+<img src="{@docRoot}design/media/navigation_up_vs_back_gmail.png">
+
+<p>Tombol Back juga mendukung beberapa perilaku yang tidak terkait langsung dengan navigasi antar layar:
+</p>
+<ul>
+<li>Menghilangkan jendela mengambang (dialog, popup)</li>
+<li>Menghilangkan action-bar kontekstual, dan menghapus sorotan dari item yang dipilih</li>
+<li>Menyembunyikan keyboard di layar (IME)</li>
+</ul>
+<h2 id="within-app">Navigasi Dalam Aplikasi Anda</h2>
+
+<h4>Berpindah ke layar yang memiliki beberapa titik masuk</h4>
+<p>Kadang-kadang layar tidak memiliki posisi pasti dalam hierarki aplikasi, dan bisa dimasuki
+dari berbagai titik masuk&mdash;seperti layar pengaturan yang dapat dibuka dari layar lain
+dalam aplikasi Anda. Dalam hal ini, tombol Up akan memilih untuk kembali ke layar pengarah, yang cara kerjanya
+sama dengan tombol Back.</p>
+<h4>Mengubah tampilan dalam layar</h4>
+<p>Mengubah opsi tampilan untuk layar tidak mengubah perilaku Up atau Back: layar tetap
+berada di tempat yang sama dalam hierarki aplikasi, dan tidak dibuat riwayat navigasi yang baru.</p>
+<p>Contoh perubahan tampilan tersebut adalah:</p>
+<ul>
+<li>Mengganti tampilan menggunakan tab dan/atau geser kiri dan kanan</li>
+<li>Mengubah tampilan menggunakan tarik-turun (alias tab turun)</li>
+<li>Memfilter daftar</li>
+<li>Menyortir daftar</li>
+<li>Mengubah karakteristik tampilan (seperti zoom)</li>
+</ul>
+<h4>Berpindah antar layar yang seinduk</h4>
+<p>Bila aplikasi Anda mendukung navigasi dari daftar item ke tampilan detail salah satu item tersebut, aplikasi
+juga sering diharapkan mendukung navigasi langsung dari item itu ke item sebelumnya atau
+sesudahnya dalam daftar. Misalnya, dalam Gmail, begitu mudah untuk bergeser ke kiri atau kanan dari sebuah percakapan
+untuk melihat percakapan yang lebih baru atau lebih lama dalam Inbox yang sama. Sama seperti saat mengubah tampilan dalam layar, navigasi
+ini tidak mengubah perilaku Up atau Back.</p>
+
+<img src="{@docRoot}design/media/navigation_between_siblings_gmail.png">
+
+<p>Akan tetapi, pengecualian khusus terhadap hal ini terjadi saat menjelajah di antara tampilan detail terkait yang tidak disatukan
+oleh daftar yang merujuknya&mdash;misalnya, saat menjelajahi Play Store di antara aplikasi dari
+pengembang yang sama, atau album dari artis yang sama. Dalam hal ini, mengikuti setiap tautan akan membuat
+riwayat, sehingga tombol Back akan menyusuri setiap layar yang dilihat sebelumnya. Tombol Up akan terus
+melewatkan semua layar terkait ini dan berpindah ke layar kontainer yang terakhir dilihat.</p>
+
+<img src="{@docRoot}design/media/navigation_between_siblings_market1.png">
+
+<p>Anda dapat menjadikan perilaku tombol Up lebih cerdas lagi berdasarkan pengetahuan Anda tentang tampilan
+detail. Dengan memperluas contoh Play Store dari atas, bayangkan pengguna yang telah berpindah dari Buku
+terakhir yang dilihat ke detail untuk adaptasi Film. Dalam hal itu, tombol Up dapat kembali ke kontainer
+(Movies) yang sebelumnya belum dilalui pengguna.</p>
+
+<img src="{@docRoot}design/media/navigation_between_siblings_market2.png">
+
+<h2 id="into-your-app">Navigasi ke Aplikasi Anda melalui Widget dan Pemberitahuan Layar Home</h2>
+
+<p>Anda bisa menggunakan widget atau pemberitahuan layar Home untuk membantu pengguna berpindah langsung ke layar
+jauh dalam hierarki aplikasi Anda. Misalnya, widget Inbox dan pemberitahuan pesan baru di Gmail dapat
+melewatkan layar Inbox, dan membawa pengguna langsung ke tampilan percakapan.</p>
+
+<p>Untuk kedua kasus ini, tangani tombol Up sebagai berikut:</p>
+
+<ul>
+<li><em>Jika layar tujuan biasanya dicapai dari satu layar tertentu dalam aplikasi
+Anda</em>, tombol Up akan mengarahkannya ke layar itu.</li>
+<li><em>Jika tidak</em>, tombol Up akan mengarahkan ke layar teratas ("Home") dari aplikasi Anda.</li>
+</ul>
+
+<p>Dalam hal tombol Back, Anda harus membuat navigasi lebih bisa diprediksi dengan menyisipkan ke dalam
+back-stack tugas path navigasi naik lengkap menuju layar teratas aplikasi. Ini memungkinkan pengguna
+yang lupa cara masuk ke aplikasi Anda untuk berpindah ke layar teratas aplikasi sebelum
+keluar.</p>
+
+<p>Sebagai contoh, widget layar Home di Gmail memiliki tombol untuk menuju langsung ke layar
+Compose. Tombol Up atau Back dari layar Compose akan membawa pengguna ke Inbox, dan dari sana tombol
+Back berlanjut ke Home.</p>
+
+<img src="{@docRoot}design/media/navigation_from_outside_back.png">
+
+<h4>Pemberitahuan tidak langsung</h4>
+
+<p>Jika aplikasi Anda perlu menampilkan informasi tentang beberapa kejadian sekaligus, aplikasi dapat menggunakan
+pemberitahuan tunggal yang mengarahkan pengguna ke layar antara. Layar ini merangkum semua
+kejadian tersebut, dan menyediakan path bagi pengguna untuk menjelajah ke dalam aplikasi. Pemberitahuan dengan gaya seperti ini
+disebut <em>pemberitahuan tidak langsung</em>.</p>
+
+<p>Berbeda dengan pemberitahuan standar (langsung), menekan tombol Back dari
+layar antara pada pemberitahuan tidak langsung akan mengembalikan pengguna ke titik pemicu pemberitahuan tersebut&mdash;tidak ada
+layar tambahan yang disisipkan ke dalam back-stack. Setelah pengguna melanjutkan ke dalam aplikasi dari
+layar antara, tombol Up dan Back akan berperilaku seperti pada pemberitahuan standar, sebagaimana dijelaskan di atas:
+menyusuri ke dalam aplikasi dan bukan kembali ke layar antara.</p>
+
+<p>Misalnya, anggaplah seorang pengguna di Gmail menerima pemberitahuan tidak langsung dari Kalender. Menyentuh
+pemberitahuan ini akan membuka layar antara, yang menampilkan pengingat beberapa macam
+kejadian. Menyentuh Back dari layar antara akan mengembalikan pengguna ke Gmail. Menyentuh kejadian
+tertentu akan membawa pengguna dari layar antara ke aplikasi Kalender lengkap untuk menampilkan detail
+kejadian. Dari detail kejadian, tombol Up dan Back akan mengarahkan ke tampilan Kalender tingkat atas.</p>
+
+<img src="{@docRoot}design/media/navigation_indirect_notification.png">
+
+<h4>Pemberitahuan pop-up</h4>
+
+<p><em>Pemberitahuan pop-up</em> akan melewatkan laci pemberitahuan, bukan muncul secara langsung di
+hadapan pengguna. Ini jarang digunakan, dan <strong>harus dicadangkan untuk peristiwa yang memerlukan respons tepat waktu
+dan diperlukan interupsi dari konteks pengguna</strong>. Misalnya,
+Talk menggunakan gaya ini untuk memberi tahu pengguna tentang ajakan dari teman untuk bergabung dalam chatting video, karena
+ajakan ini akan kedaluwarsa secara otomatis setelah beberapa detik.</p>
+
+<p>Dalam hal perilaku navigasi, pemberitahuan pop-up sangat mirip perilaku pemberitahuan
+tidak langsung pada layar antara. Tombol Back akan menghilangkan pemberitahuan pop-up. Jika pengguna berpindah
+dari pop-up ke aplikasi yang memberi tahu, tombol Up dan Back akan mengikuti aturan pemberitahuan standar,
+berpindah dalam aplikasi.</p>
+
+<img src="{@docRoot}design/media/navigation_popup_notification.png">
+
+<h2 id="between-apps">Navigasi Antar Aplikasi</h2>
+
+<p>Salah satu kekuatan dasar sistem Android adalah kemampuan aplikasi untuk saling
+mengaktifkan, sehingga pengguna dapat berpindah langsung dari satu aplikasi ke aplikasi lainnya. Misalnya, sebuah
+aplikasi yang perlu mengambil foto dapat mengaktifkan aplikasi Kamera, yang akan mengembalikan foto
+ke aplikasi perujuk. Ini sangat menguntungkan pengembang, yang bisa dengan mudah memanfaatkan
+kode dari aplikasi lain, maupun pengguna, yang menikmati pengalaman konsisten untuk tindakan yang biasa
+dilakukan.</p>
+
+<p>Untuk memahami navigasi antar aplikasi, maka perlu memahami perilaku kerangka kerja Android
+yang akan dibahas di bawah ini.</p>
+
+<h4>Aktivitas, tugas, dan intent</h4>
+
+<p>Dalam Android, <strong>aktivitas</strong> adalah komponen aplikasi yang mendefinisikan layar
+informasi dan semua tindakan terkait yang dapat dilakukan pengguna. Aplikasi Anda adalah kumpulan
+aktivitas, yang terdiri dari aktivitas yang Anda buat dan aktivitas yang Anda gunakan ulang dari aplikasi lain.</p>
+
+<p><strong>Tugas</strong> adalah urutan aktivitas yang diikuti pengguna untuk mencapai tujuan.
+Tugas tunggal dapat memanfaatkan aktivitas dari satu aplikasi saja, atau dapat memanfaatkan aktivitas dari sejumlah
+aplikasi berbeda.</p>
+
+<p><strong>Intent</strong> adalah mekanisme bagi satu aplikasi untuk memberi isyarat minta bantuan
+aplikasi lain dalam menjalankan suatu tindakan. Aktivitas aplikasi dapat menunjukkan intent
+ apa saja yang dapat diresponsnya. Untuk intent umum seperti "Share", pengguna mungkin telah menginstal beberapa aplikasi
+yang dapat memenuhi permintaan itu.</p>
+
+<h4>Contoh: berpindah antar aplikasi untuk mendukung berbagi</h4>
+
+<p>Untuk memahami cara kerja sama aktivitas, tugas, dan intent, perhatikan bagaimana sebuah aplikasi memungkinkan pengguna
+untuk berbagi konten dengan menggunakan aplikasi lain. Misalnya, membuka aplikasi Play Store dari Home akan memulai
+Task A baru (lihat gambar di bawah). Setelah menyusuri Play Store dan menyentuh buku yang dipromosikan
+untuk melihat detailnya, pengguna tetap berada dalam tugas yang sama, memperluasnya dengan menambahkan aktivitas. Memicu
+tindakan Share akan memberi tahu pengguna dengan dialog berisi daftar aktivitas (dari aplikasi berbeda)
+yang telah terdaftar untuk menangani intent Share.</p>
+
+<img src="{@docRoot}design/media/navigation_between_apps_inward.png">
+
+<p>Bila pengguna memilih untuk berbagi melalui Gmail, aktivitas penulisan di Gmail akan ditambahkan sebagai kelanjutan dari
+Task A&mdash;tidak ada tugas baru yang dibuat. Jika Gmail sedang menjalankan tugasnya di latar belakang, maka
+tidak akan terpengaruh.</p>
+
+<p>Dari aktivitas penulisan, mengirim pesan atau menyentuh tombol Back akan mengembalikan pengguna ke
+aktivitas detail buku tersebut. Penyentuhan tombol Back berikutnya akan terus mengarahkan kembali melalui Play
+Store, sampai akhirnya tiba di Home.</p>
+
+<img src="{@docRoot}design/media/navigation_between_apps_back.png">
+
+<p>Akan tetapi, dengan menyentuh tombol Up dari aktivitas penulisan, pengguna menunjukkan keinginan untuk tetap berada di
+Gmail. Aktivitas daftar percakapan Gmail muncul, Task B yang baru akan dibuat untuk itu. Tugas baru
+selalu terkait ke Home, maka menyentuh tombol Back dari daftar percakapan akan mengembalikan ke sana.</p>
+
+<img src="{@docRoot}design/media/navigation_between_apps_up.png">
+
+<p>Task A tetap berjalan di latar belakang, dan pengguna nanti dapat kembali ke sana (misalnya, melalui layar
+Recents). Jika Gmail sedang menjalankan tugasnya di latar belakang, maka itu akan digantikan
+dengan Task B&mdash;konteks sebelumnya akan diabaikan demi tujuan baru pengguna.</p>
+
+<p>Jika register aplikasi Anda menangani intent dengan aktivitas yang jauh di dalam hierarki aplikasi,
+lihat <a href="#into-your-app">Navigasi Aplikasi Anda melalui Widget Layar Home dan
+Pemberitahuan</a> untuk panduan mengenai cara menetapkan navigasi Up.</p>
diff --git a/docs/html-intl/intl/id/guide/components/activities.jd b/docs/html-intl/intl/id/guide/components/activities.jd
new file mode 100644
index 0000000..bbc061c
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/activities.jd
@@ -0,0 +1,756 @@
+page.title=Aktivitas
+page.tags=aktivitas,intent
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#Creating">Membuat Aktivitas</a>
+    <ol>
+      <li><a href="#UI">Mengimplementasikan antarmuka pengguna</a></li>
+      <li><a href="#Declaring">Mendeklarasikan aktivitas dalam manifes</a></li>
+    </ol>
+  </li>
+  <li><a href="#StartingAnActivity">Memulai Aktivitas</a>
+    <ol>
+      <li><a href="#StartingAnActivityForResult">Memulai aktivitas agar berhasil</a></li>
+    </ol>
+  </li>
+  <li><a href="#ShuttingDown">Mematikan Aktivitas</a></li>
+  <li><a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>
+    <ol>
+      <li><a href="#ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
+      <li><a href="#SavingActivityState">Menyimpan status aktivitas</a></li>
+      <li><a href="#ConfigurationChanges">Menangani perubahan konfigurasi</a></li>
+      <li><a href="#CoordinatingActivities">Mengoordinasikan aktivitas</a></li>
+    </ol>
+  </li>
+</ol>
+
+<h2>Kelas-kelas utama</h2>
+<ol>
+  <li>{@link android.app.Activity}</li>
+</ol>
+
+<h2>Lihat juga</h2>
+<ol>
+  <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan
+Back-Stack</a></li>
+</ol>
+
+</div>
+</div>
+
+
+
+<p>{@link android.app.Activity} adalah sebuah komponen aplikasi yang menyediakan layar yang digunakan
+pengguna untuk berinteraksi guna melakukan sesuatu, misalnya memilih nomor telepon, mengambil foto, mengirim email, atau
+menampilkan peta. Tiap aktivitas diberi sebuah jendela untuk menggambar antarmuka penggunanya. Jendela ini
+biasanya mengisi layar, namun mungkin lebih kecil daripada layar dan mengambang di atas
+jendela lain.</p>
+
+<p> Sebuah aplikasi biasanya terdiri atas beberapa aktivitas yang terikat secara longgar
+satu sama lain. Biasanya, satu aktivitas dalam aplikasi ditetapkan sebagai aktivitas "utama", yang
+ditampilkan kepada pengguna saat membuka aplikasi untuk pertama kali. Tiap
+aktivitas kemudian bisa memulai aktivitas lain untuk melakukan berbagai tindakan. Tiap kali
+aktivitas baru dimulai, aktivitas sebelumnya akan dihentikan, namun sistem mempertahankan aktivitas
+dalam sebuah tumpukan ("back-stack"). Bila sebuah aktivitas baru dimulai, aktivitas itu akan didorong ke atas back-stack dan
+mengambil fokus pengguna. Back-stack mematuhi mekanisme dasar tumpukan "masuk terakhir, keluar pertama",
+jadi, bila pengguna selesai dengan aktivitas saat ini dan menekan tombol <em>Back</em>, aktivitas
+akan dikeluarkan dari tumpukan (dan dimusnahkan) dan aktivitas sebelumnya akan dilanjutkan. (Back-stack
+dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas
+dan Back-Stack</a>.)</p>
+
+<p>Bila aktivitas dihentikan karena ada aktivitas baru yang dimulai, aktivitas lama akan diberi tahu tentang perubahan status ini
+melalui metode callback daur hidupnya.
+Ada beberapa metode callback yang mungkin diterima aktivitas, karena sebuah perubahan dalam
+statusnya&mdash;apakah sistem sedang membuatnya, menghentikannya, melanjutkannya, atau menghapuskannya&mdash;dan
+masing-masing callback memberi Anda kesempatan melakukan pekerjaan tertentu yang
+sesuai untuk perubahan status itu. Misalnya, bila dihentikan, aktivitas Anda harus melepas
+objek besar, seperti koneksi jaringan atau database. Bila aktivitas dilanjutkan, Anda bisa
+memperoleh kembali sumber daya yang diperlukan dan melanjutkan tindakan yang terputus. Transisi status ini
+semuanya bagian dari daur hidup aktivitas.</p>
+
+<p>Bagian selebihnya dari dokumen ini membahas dasar-dasar cara membuat dan menggunakan aktivitas,
+yang meliputi satu pembahasan lengkap tentang cara kerja daur hidup aktivitas, sehingga Anda bisa dengan benar mengelola
+transisi di antara berbagai status aktivitas.</p>
+
+
+
+<h2 id="Creating">Membuat Aktivitas</h2>
+
+<p>Untuk membuat sebuah aktivitas, Anda harus membuat subkelas {@link android.app.Activity} (atau
+subkelasnya yang ada). Dalam subkelas itu, Anda perlu mengimplementasikan metode-metode callback yang
+dipanggil sistem saat aktivitas bertransisi di antara berbagai status daur hidupnya, misalnya saat
+aktivitas sedang dibuat, dihentikan, dilanjutkan, atau dimusnahkan. Dua metode callback
+terpenting adalah:</p>
+
+<dl>
+  <dt>{@link android.app.Activity#onCreate onCreate()}</dt>
+  <dd>Anda harus mengimplementasikan metode ini. Sistem memanggilnya saat membuat
+    aktivitas Anda. Dalam implementasi, Anda harus menginisialisasi komponen-komponen esensial
+aktivitas.
+    Yang terpenting, inilah tempat Anda harus memanggil {@link android.app.Activity#setContentView
+    setContentView()} untuk mendefinisikan layout untuk antarmuka pengguna aktivitas.</dd>
+  <dt>{@link android.app.Activity#onPause onPause()}</dt>
+  <dd>Sistem memanggil metode ini sebagai pertanda pertama bahwa pengguna sedang meninggalkan
+aktivitas Anda (walau itu tidak selalu berarti aktivitas sedang dimusnahkan). Inilah biasanya tempat Anda
+harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
+pengguna mungkin tidak kembali).</dd>
+</dl>
+
+<p>Ada beberapa metode callback daur hidup lainnya yang harus Anda gunakan untuk memberikan
+pengalaman pengguna yang mengalir di antara aktivitas dan menangani interupsi tidak terduga yang menyebabkan aktivitas Anda
+dihentikan dan bahkan dimusnahkan. Semua metode callback daur hidup akan dibahas nanti, di
+bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a>.</p>
+
+
+
+<h3 id="UI">Mengimplementasikan antarmuka pengguna</h3>
+
+<p> Antarmuka pengguna aktivitas disediakan oleh hierarki objek&mdash;tampilan yang diturunkan
+dari kelas {@link android.view.View}.  Tiap tampilan mengontrol sebuah ruang persegi panjang tertentu
+dalam jendela aktivitas dan bisa merespons interaksi pengguna. Misalnya, sebuah tampilan mungkin berupa sebuah
+tombol yang mengawali suatu tindakan bila pengguna menyentuhnya.</p>
+
+<p>Android menyediakan sejumlah tampilan siap-dibuat yang bisa Anda gunakan untuk mendesain dan mengatur
+layout. "Widget" adalah tampilan yang menyediakan elemen-elemen visual (dan interaktif) untuk layar,
+misalnya tombol, bidang teks, kotak cek, atau sekadar sebuah gambar. "Layout" adalah tampilan yang diturunkan dari {@link
+android.view.ViewGroup} yang memberikan sebuah model layout unik untuk tampilan anaknya, misalnya
+layout linier, layout grid, atau layout relatif. Anda juga bisa mensubkelaskan kelas-kelas {@link android.view.View} dan
+{@link android.view.ViewGroup} (atau subkelas yang ada) untuk membuat widget dan
+layout Anda sendiri dan menerapkannya ke layout aktivitas Anda.</p>
+
+<p>Cara paling umum untuk mendefinisikan layout dengan menggunakan tampilan adalah dengan file layout XML yang disimpan dalam
+sumber daya aplikasi Anda. Dengan cara ini, Anda bisa memelihara desain antarmuka pengguna Anda secara terpisah dari
+kode yang mendefinisikan perilaku aktivitas. Anda bisa mengatur layout sebagai UI
+aktivitas Anda dengan {@link android.app.Activity#setContentView(int) setContentView()}, dengan meneruskan
+ID sumber daya untuk layout itu. Akan tetapi, Anda juga bisa membuat {@link android.view.View} baru dalam
+kode aktivitas dan membuat hierarki tampilan dengan menyisipkan {@link
+android.view.View} baru ke dalam {@link android.view.ViewGroup}, kemudian menggunakan layout itu dengan meneruskan akar
+{@link android.view.ViewGroup} ke {@link android.app.Activity#setContentView(View)
+setContentView()}.</p>
+
+<p>Untuk informasi tentang cara membuat antarmuka pengguna, lihat dokumentasi <a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
+
+
+
+<h3 id="Declaring">Mendeklarasikan aktivitas dalam manifes</h3>
+
+<p>Anda harus mendeklarasikan aktivitas dalam file manifes agar file itu
+bisa diakses oleh sistem. Untuk mendeklarasikan aktivitas, bukalah file manifes Anda dan tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+sebagai anak elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
+. Misalnya:</p>
+
+<pre>
+&lt;manifest ... &gt;
+  &lt;application ... &gt;
+      &lt;activity android:name=".ExampleActivity" /&gt;
+      ...
+  &lt;/application ... &gt;
+  ...
+&lt;/manifest &gt;
+</pre>
+
+<p>Ada beberapa atribut lain yang bisa Anda sertakan dalam elemen ini, untuk mendefinisikan properti
+misalnya label untuk aktivitas, ikon untuk aktivitas, atau tema untuk memberi gaya ke
+UI aktivitas. Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">{@code android:name}</a>
+ adalah satu-satunya atribut yang diperlukan&mdash;atribut ini menetapkan nama kelas aktivitas. Setelah
+Anda mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
+sebagian fungsionalitas, misalnya pintasan aplikasi (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
+That Cannot Change</a>).</p>
+
+<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+untuk informasi selengkapnya tentang cara mendeklarasikan aktivitas Anda dalam manifes.</p>
+
+
+<h4>Menggunakan filter intent</h4>
+
+<p>Elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a> juga bisa menetapkan berbagai filter intent&mdash;dengan menggunakan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> &mdash;untuk mendeklarasikan cara komponen aplikasi lain
+mengaktifkannya.</p>
+
+<p>Bila Anda membuat aplikasi baru dengan Android SDK Tools, aktivitas stub
+yang dibuat untuk Anda secara otomatis menyertakan filter intent yang mendeklarasikan respons
+aktivitas pada tindakan "main" (utama) dan harus diletakkan dalam kategori "launcher"). Filter intent
+terlihat seperti ini:</p>
+
+<pre>
+&lt;activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.MAIN" /&gt;
+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+    &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p>Elemen <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> menetapkan bahwa ini adalah titik masuk "main" ke aplikasi. Elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> menetapkan bahwa aktivitas ini harus tercantum dalam launcher aplikasi
+sistem (untuk memungkinkan pengguna meluncurkan aktivitas ini).</p>
+
+<p>Jika Anda bermaksud agar aplikasi dimuat dengan sendirinya dan tidak memperbolehkan aplikasi lain
+mengaktifkan aktivitasnya, maka Anda tidak memerlukan filter intent lain. Hanya satu aktivitas yang boleh
+memiliki tindakan "main" dan kategori "launcher", seperti dalam contoh sebelumnya. Aktivitas yang
+tidak ingin Anda sediakan untuk aplikasi lain tidak boleh memiliki filter intent dan Anda bisa
+memulai sendiri aktivitas dengan menggunakan intent secara eksplisit (seperti dibahas di bagian berikut).</p>
+
+<p>Akan tetapi, jika ingin aktivitas Anda merespons intent implisit yang dikirim dari
+aplikasi lain (dan aplikasi Anda sendiri), maka Anda harus mendefinisikan filter intent tambahan untuk
+aktivitas. Untuk masing-masing tipe intent yang ingin direspons, Anda harus menyertakan sebuah <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> yang menyertakan elemen
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> dan, opsional, sebuah elemen <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> dan/atau elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
+&lt;data&gt;}</a>. Elemen-elemen ini menetapkan tipe intent yang bisa
+direspons oleh aktivitas Anda.</p>
+
+<p>Untuk informasi selengkapnya tentang cara aktivitas Anda merespons intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
+</p>
+
+
+
+<h2 id="StartingAnActivity">Memulai Aktivitas</h2>
+
+<p>Anda bisa memulai aktivitas lain dengan memanggil {@link android.app.Activity#startActivity
+  startActivity()}, dengan meneruskan sebuah {@link android.content.Intent} yang menjelaskan aktivitas
+  yang ingin Anda mulai. Intent menetapkan aktivitas persis yang ingin Anda mulai atau menjelaskan
+  tipe tindakan yang ingin Anda lakukan (dan sistem akan memilih aktivitas yang sesuai untuk Anda,
+yang bahkan
+  bisa berasal dari aplikasi berbeda). Intent juga bisa membawa sejumlah kecil data untuk
+  digunakan oleh aktivitas yang dimulai.</p>
+
+<p>Saat bekerja dalam aplikasi sendiri, Anda nanti akan sering meluncurkan aktivitas yang dikenal saja.
+ Anda bisa melakukannya dengan membuat intent yang mendefinisikan secara eksplisit aktivitas yang ingin Anda mulai,
+dengan menggunakan nama kelas. Misalnya, beginilah cara satu aktivitas memulai aktivitas lain bernama {@code
+SignInActivity}:</p>
+
+<pre>
+Intent intent = new Intent(this, SignInActivity.class);
+startActivity(intent);
+</pre>
+
+<p>Akan tetapi, aplikasi Anda mungkin juga perlu melakukan beberapa tindakan, misalnya mengirim email,
+  pesan teks, atau pembaruan status, dengan menggunakan data dari aktivitas Anda. Dalam hal ini, aplikasi Anda mungkin
+ tidak memiliki aktivitasnya sendiri untuk melakukan tindakan tersebut, sehingga Anda bisa memanfaatkan aktivitas
+  yang disediakan oleh aplikasi lain pada perangkat, yang bisa melakukan tindakan itu untuk Anda. Inilah saatnya
+intent benar-benar berharga&mdash;Anda bisa membuat intent yang menjelaskan tindakan yang ingin
+dilakukan dan sistem
+  akan meluncurkan aktivitas yang tepat dari aplikasi lain. Jika ada
+  beberapa aktivitas yang bisa menangani intent itu, pengguna bisa memilih aktivitas yang akan digunakan. Misalnya,
+  jika Anda ingin memperbolehkan pengguna mengirim pesan email, Anda bisa membuat
+  intent berikut:</p>
+
+<pre>
+Intent intent = new Intent(Intent.ACTION_SEND);
+intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
+startActivity(intent);
+</pre>
+
+<p>Ekstra {@link android.content.Intent#EXTRA_EMAIL} yang ditambahkan ke intent adalah sebuah larik string
+  alamat email yang menjadi tujuan pengiriman email. Bila aplikasi email merespons intent ini,
+ aplikasi itu akan membaca larik string yang disediakan dalam ekstra dan meletakkannya dalam bidang "to"
+  pada formulir penulisan email. Dalam situasi ini, aktivitas aplikasi email dimulai dan bila
+  pengguna selesai, aktivitas Anda akan dilanjutkan.</p>
+
+
+
+
+<h3 id="StartingAnActivityForResult">Memulai aktivitas agar berhasil</h3>
+
+<p>Kadang-kadang, Anda mungkin ingin menerima hasil dari aktivitas yang Anda mulai. Dalam hal itu,
+  mulailah aktivitas dengan memanggil {@link android.app.Activity#startActivityForResult
+  startActivityForResult()} (sebagai ganti {@link android.app.Activity#startActivity
+  startActivity()}). Untuk menerima hasil dari
+aktivitas selanjutnya nanti, implementasikan metode callback {@link android.app.Activity#onActivityResult onActivityResult()}
+. Bila aktivitas selanjutnya selesai, aktivitas akan mengembalikan hasil dalam {@link
+android.content.Intent} kepada metode {@link android.app.Activity#onActivityResult onActivityResult()}
+Anda.</p>
+
+<p>Misalnya, mungkin Anda ingin pengguna mengambil salah satu kontaknya, sehingga aktivitas Anda bisa
+melakukan sesuatu dengan informasi dalam kontak itu. Begini caranya membuat intent tersebut dan
+menangani hasilnya:</p>
+
+<pre>
+private void pickContact() {
+    // Create an intent to "pick" a contact, as defined by the content provider URI
+    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
+    startActivityForResult(intent, PICK_CONTACT_REQUEST);
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
+    if (resultCode == Activity.RESULT_OK &amp;&amp; requestCode == PICK_CONTACT_REQUEST) {
+        // Perform a query to the contact's content provider for the contact's name
+        Cursor cursor = getContentResolver().query(data.getData(),
+        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
+        if (cursor.moveToFirst()) { // True if the cursor is not empty
+            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
+            String name = cursor.getString(columnIndex);
+            // Do something with the selected contact's name...
+        }
+    }
+}
+</pre>
+
+<p>Contoh ini menunjukkan logika dasar yang harus Anda gunakan dalam metode {@link
+android.app.Activity#onActivityResult onActivityResult()} Anda untuk menangani
+hasil aktivitas. Syarat pertama memeriksa apakah permintaan berhasil&mdash;jika ya, maka
+ {@code resultCode} akan berupa {@link android.app.Activity#RESULT_OK}&mdash;dan apakah permintaan
+yang direspons hasil ini dikenal&mdash;dalam hal ini, {@code requestCode} cocok dengan
+parameter kedua yang dikirim dengan {@link android.app.Activity#startActivityForResult
+startActivityForResult()}. Dari sana, kode akan menangani hasil aktivitas dengan membuat query
+data yang dihasilkan dalam{@link android.content.Intent} (parameter {@code data}).</p>
+
+<p>Yang terjadi adalah {@link
+android.content.ContentResolver} melakukan query terhadap penyedia konten, yang menghasilkan
+{@link android.database.Cursor} yang memperbolehkan data query dibaca. Untuk informasi selengkapnya, lihat dokumen
+<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
+
+<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
+Intent</a>.</p>
+
+
+<h2 id="ShuttingDown">Mematikan Aktivitas</h2>
+
+<p>Anda bisa mematikan aktivitas dengan memanggil metode {@link android.app.Activity#finish
+finish()}-nya. Anda juga bisa mematikan aktivitas terpisah yang sebelumnya Anda mulai dengan memanggil
+{@link android.app.Activity#finishActivity finishActivity()}.</p>
+
+<p class="note"><strong>Catatan:</strong> Pada umumnya, Anda tidak boleh secara eksplisit mengakhiri aktivitas
+dengan menggunakan metode-metode ini. Seperti yang dibahas di bagian berikut tentang daur hidup aktivitas,
+sistem Android mengelola hidup aktivitas untuk Anda, sehingga Anda tidak perlu menyelesaikan sendiri
+aktivitas tersebut. Memanggil metode-metode ini bisa berpengaruh negatif pada pengalaman
+pengguna yang diharapkan dan hanya boleh digunakan bila Anda benar-benar tidak ingin pengguna kembali ke
+instance aktivitas ini.</p>
+
+
+<h2 id="Lifecycle">Mengelola Daur Hidup Aktivitas</h2>
+
+<p>Mengelola daur hidup aktivitas dengan mengimplementasikan metode-metode callback sangat
+penting untuk mengembangkan
+aplikasi yang kuat dan fleksibel. Daur hidup aktivitas dipengaruhi langsung oleh kaitannya dengan
+aktivitas lain, tugasnya, serta back-stack.</p>
+
+<p>Pada dasarnya, sebuah aktivitas bisa berada dalam tiga status:</p>
+
+<dl>
+  <dt><i>Dilanjutkan</i></dt>
+    <dd>Aktivitas berada di latar depan layar dan mendapatkan fokus pengguna. (Status ini
+kadang-kadang disebut juga dengan "running" (berjalan).)</dd>
+
+  <dt><i>Dihentikan sementara</i></dt>
+    <dd>Aktivitas lain berada di latar depan dan mendapat fokus, namun aktivitas ini masih terlihat. Yakni,
+aktivitas lain terlihat di atas aplikasi ini dan aktivitas itu setengah transparan atau tidak
+menuutpi seluruh layar. Aktivitas yang dihentikan sementara adalah benar-benar hidup (objek {@link android.app.Activity}
+dipertahankan dalam memori, objek itu memelihara semua informasi status dan anggota, dan tetap dikaitkan dengan
+window manager), namun bisa dimatikan oleh sistem dalam situasi memori sangat rendah.</dd>
+
+  <dt><i>Dihentikan</i></dt>
+    <dd>Aktivitas ditutupi sepenuhnya oleh aktivitas lain (aktivitas sekarang berada di
+"latar belakang"). Aktivitas yang dihentikan juga masih hidup (objek {@link android.app.Activity}
+dipertahankan dalam memori, objek itu menjaga semua informasi status dan anggota, namun <em>tidak</em>
+dikaitkan dengan window manager). Akan tetapi, aktivitas tidak lagi terlihat bagi pengguna dan
+bisa dimatikan oleh sistem bila memori diperlukan di lain.</dd>
+</dl>
+
+<p>Jika aktivitas dihentikan sementara atau dihentikan, sistem bisa mengeluarkannya dari memori baik dengan memintanya agar
+diakhiri (memanggil metode {@link android.app.Activity#finish finish()}-nya), atau sekadar mematikan
+prosesnya.  Bila dibuka lagi (setelah diakhiri atau dimatikan), aktivitas harus dibuat dari
+awal.</p>
+
+
+
+<h3 id="ImplementingLifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
+
+<p>Saat bertransisi ke dalam dan ke luar berbagai status yang dijelaskan di atas, aktivitas diberi tahu
+melalui berbagai metode callback. Semua metode callback adalah sangkutan yang
+bisa Anda kesampingkan untuk melakukan pekerjaan yang sesuai saat status aktivitas Anda berubah. Aktivitas skeleton
+berikut menyertakan setiap metode daur hidup mendasar:</p>
+
+
+<pre>
+public class ExampleActivity extends Activity {
+    &#64;Override
+    public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // The activity is being created.
+    }
+    &#64;Override
+    protected void {@link android.app.Activity#onStart onStart()} {
+        super.onStart();
+        // The activity is about to become visible.
+    }
+    &#64;Override
+    protected void {@link android.app.Activity#onResume onResume()} {
+        super.onResume();
+        // The activity has become visible (it is now "resumed").
+    }
+    &#64;Override
+    protected void {@link android.app.Activity#onPause onPause()} {
+        super.onPause();
+        // Another activity is taking focus (this activity is about to be "paused").
+    }
+    &#64;Override
+    protected void {@link android.app.Activity#onStop onStop()} {
+        super.onStop();
+        // The activity is no longer visible (it is now "stopped")
+    }
+    &#64;Override
+    protected void {@link android.app.Activity#onDestroy onDestroy()} {
+        super.onDestroy();
+        // The activity is about to be destroyed.
+    }
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Implementasi Anda terhadap metode-metode daur hidup ini harus
+selalu memanggil implementasi superkelas sebelum melakukan pekerjaan apa pun, seperti yang ditampilkan dalam contoh-contoh di atas.</p>
+
+<p>Bersama-sama, semua metode ini mendefinisikan seluruh daur hidup sebuah aktivitas. Dengan mengimplementasikan
+metode-metode ini, Anda bisa memantau tiga loop tersarang (nested loop) dalam daur hidup aktivitas: </p>
+
+<ul>
+<li><b>Seluruh masa hidup</b> aktivitas berlangsung antara panggilan ke {@link
+android.app.Activity#onCreate onCreate()} dan panggilan ke {@link
+android.app.Activity#onDestroy}. Aktivitas Anda harus melakukan penyiapan
+status "global" (misalnya mendefinisikan layout) dalam {@link android.app.Activity#onCreate onCreate()}, dan
+melepas semua sisa sumber daya dalam {@link android.app.Activity#onDestroy}. Misalnya, jika
+aktivitas Anda memiliki sebuah thread yang berjalan di latar belakang untuk mengunduh data dari jaringan, aktivitas itu bisa membuat
+thread itu dalam {@link android.app.Activity#onCreate onCreate()} kemudian menghentikan thread dalam {@link
+android.app.Activity#onDestroy}.</li>
+
+<li><p><b>Masa pakai terlihat</b> (visible lifetime) aktivitas berlangsung antara panggilan ke {@link
+android.app.Activity#onStart onStart()} dan panggilan ke {@link
+android.app.Activity#onStop onStop()}. Selama ini, pengguna bisa melihat aktivitas
+pada layar dan berinteraksi dengannya. Misalnya, {@link android.app.Activity#onStop onStop()} dipanggil
+bila sebuah aktivitas baru dimulai dan aktivitas ini tidak lagi terlihat. Di antara dua metode ini, Anda bisa
+memelihara sumber daya yang diperlukan untuk menampilkan aktivitas kepada pengguna. Misalnya, Anda bisa mendaftarkan sebuah
+{@link android.content.BroadcastReceiver} dalam {@link
+android.app.Activity#onStart onStart()} untuk memantau perubahan yang berdampak pada UI Anda, dan mencabut pendaftarannya
+dalam {@link android.app.Activity#onStop onStop()} bila pengguna tidak bisa lagi melihat apa yang sedang Anda
+tampilkan. Sistem bisa memanggil {@link android.app.Activity#onStart onStart()} dan {@link
+android.app.Activity#onStop onStop()} beberapa kali selama masa pakai aktivitas, sambil
+aktivitas berganti-ganti antara terlihat dan tersembunyi bagi pengguna.</p></li>
+
+<li><p><b>Masa pakai latar depan</b> aktivitas berlangsung antara panggilan ke {@link
+android.app.Activity#onResume onResume()} dan panggilan ke {@link android.app.Activity#onPause
+onPause()}. Selama waktu ini, aktivitas berada di depan semua aktivitas lain pada layar dan mendapatkan
+fokus input pengguna.  Aktivitas bisa sering bertransisi ke dalam dan ke luar latar depan&mdash;misalnya,
+ {@link android.app.Activity#onPause onPause()} dipanggil bila perangkat masuk ke mode tidur atau
+bila dialog muncul. Karena status ini bisa sering bertransisi, kode dalam dua metode ini harus
+cukup ringan untuk menghindari transisi lamban yang membuat pengguna menunggu.</p></li>
+</ul>
+
+<p>Gambar 1 mengilustrasikan loop dan path yang mungkin diambil sebuah aktivitas di antara status-status.
+Persegi panjang mewakili metode callback yang bisa Anda implementasikan untuk melakukan operasi saat
+aktivitas bertransisi di antara status. <p>
+
+<img src="{@docRoot}images/activity_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup aktivitas.</p>
+
+<p>Metode-metode callback daur hidup yang sama tercantum dalam tabel 1, yang menjelaskan setiap metode callback
+secara lebih detail dan menentukan lokasinya masing-masing dalam
+daur hidup aktivitas keseluruhan, termasuk apakah sistem bisa mematikan aktivitas setelah
+metode callback selesai.</p>
+
+<p class="table-caption"><strong>Tabel 1.</strong> Rangkuman metode callback
+daur hidup aktivitas.</p>
+
+<table border="2" width="85%" frame="hsides" rules="rows">
+<colgroup align="left" span="3"></colgroup>
+<colgroup align="left"></colgroup>
+<colgroup align="center"></colgroup>
+<colgroup align="center"></colgroup>
+
+<thead>
+<tr><th colspan="3">Metode</th> <th>Keterangan</th> <th>Bisa dimatikan setelahnya?</th> <th>Berikutnya</th></tr>
+</thead>
+
+<tbody>
+<tr>
+  <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
+  <td>Dipanggil saat aktivitas pertama kali dibuat.
+      Di sinilah Anda harus melakukan semua persiapan statis normal &mdash;
+      membuat tampilan, mengikat data ke daftar, dan sebagainya.  Metode ini diberi
+      sebuah objek Bundle yang berisi status aktivitas sebelumnya, jika
+      status itu tertangkap (lihat <a href="#actstate">Menyimpan Status Aktivitas</a>,
+      nanti).
+      <p>Selalu diikuti oleh {@code onStart()}.</p></td>
+  <td align="center">Tidak</td>
+      <td align="center">{@code onStart()}</td>
+</tr>
+
+<tr>
+   <td rowspan="5" style="border-left: none; border-right: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
+   <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
+onRestart()}</code></td>
+   <td>Dipanggil setelah aktivitas dihentikan, tepat sebelum
+       dimulai lagi.
+       <p>Selalu diikuti oleh {@code onStart()}</p></td>
+   <td align="center">Tidak</td>
+   <td align="center">{@code onStart()}</td>
+</tr>
+
+<tr>
+   <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td>
+   <td>Dipanggil tepat sebelum aktivitas menjadi terlihat bagi pengguna.
+       <p>Diikuti oleh {@code onResume()} jika aktivitas maju
+       ke latar depan, atau {@code onStop()} jika menjadi tersembunyi.</p></td>
+    <td align="center">Tidak</td>
+    <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
+</tr>
+
+<tr>
+   <td rowspan="2" style="border-left: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
+   <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
+   <td>Dipanggil tepat sebelum aktivitas mulai
+       berinteraksi dengan pengguna.  Pada titik ini, aktivitas berada di
+       puncak tumpukan aktivitas, dengan input pengguna menuju kepadanya.
+       <p>Selalu diikuti oleh {@code onPause()}.</p></td>
+   <td align="center">Tidak</td>
+   <td align="center">{@code onPause()}</td>
+</tr>
+
+<tr>
+   <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td>
+   <td>Dipanggil bila sistem akan memulai pelanjutan
+       aktivitas lain.  Metode ini biasanya digunakan untuk menerapkan (commit) perubahan yang tidak tersimpan pada
+       data persisten, menghentikan animasi dan hal-hal lain yang mungkin menghabiskan
+       CPU, dan sebagainya.  Metode ini harus melakukan apa saja yang dilakukannya dengan sangat cepat, karena
+       aktivitas berikutnya tidak akan dilanjutkan hingga aktivitas ini kembali.
+       <p>Diikuti oleh {@code onResume()} jika aktivitas
+       kembali ke depan, atau oleh {@code onStop()} jika menjadi
+       tidak terlihat bagi pengguna.</td>
+   <td align="center"><strong style="color:#800000">Ya</strong></td>
+   <td align="center">{@code onResume()} <br/>atau<br/> {@code onStop()}</td>
+</tr>
+
+<tr>
+   <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td>
+   <td>Dipanggil bila aktivitas tidak lagi terlihat bagi pengguna.  Hal ini
+       bisa terjadi karena aktivitas sedang dimusnahkan, atau karena aktivitas lain
+       (aktivitas yang ada atau yang baru) telah dilanjutkan dan sedang menutupinya.
+       <p>Diikuti oleh {@code onRestart()} jika
+       aktivitas kembali untuk berinteraksi dengan pengguna, atau oleh
+       {@code onDestroy()} jika aktivitas ini akan menghilang.</p></td>
+   <td align="center"><strong style="color:#800000">Ya</strong></td>
+   <td align="center">{@code onRestart()} <br/>atau<br/> {@code onDestroy()}</td>
+</tr>
+
+<tr>
+   <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy
+onDestroy()}</code></td>
+   <td>Dipanggil sebelum aktivitas dimusnahkan.  Inilah panggilan terakhir
+       yang akan diterima aktivitas.  Metode ini bisa dipanggil karena
+       aktivitas selesai (seseorang memanggil <code>{@link android.app.Activity#finish
+       finish()}</code> padanya), atau karena sistem memusnahkan sementara
+       instance aktivitas ini untuk menghemat tempat.  Anda bisa membedakan
+       kedua skenario ini dengan metode <code>{@link
+       android.app.Activity#isFinishing isFinishing()}</code>.</td>
+   <td align="center"><strong style="color:#800000">Ya</strong></td>
+   <td align="center"><em>tidak ada</em></td>
+</tr>
+</tbody>
+</table>
+
+<p>Kolom berlabel "Bisa dimatikan setelahnya?" menunjukkan apakah sistem bisa
+atau tidak mematikan proses yang menjadi host aktivitas kapan saja <em>setelah metode kembali</em>, tanpa
+menjalankan baris lain pada kode aktivitas.  Tiga metode ini ditandai "ya": ({@link
+android.app.Activity#onPause
+onPause()}, {@link android.app.Activity#onStop onStop()}, dan {@link android.app.Activity#onDestroy
+onDestroy()}). Karena {@link android.app.Activity#onPause onPause()} adalah yang pertama
+dari tiga, begitu aktivitas dibuat, {@link android.app.Activity#onPause onPause()} adalah
+metode terakhir yang dipastikan akan dipanggil sebelum proses <em>bisa</em> dimatikan&mdash;jika
+sistem harus memulihkan memori dalam keadaan darurat, maka {@link
+android.app.Activity#onStop onStop()} dan {@link android.app.Activity#onDestroy onDestroy()} mungkin
+tidak dipanggil. Karena itu, Anda harus menggunakan {@link android.app.Activity#onPause onPause()} untuk menulis
+data persisten yang penting (misalnya hasil edit pengguna) ke penyimpanan. Akan tetapi, Anda harus selektif dalam hal
+informasi yang harus dipertahankan selama {@link android.app.Activity#onPause onPause()}, karena setiap
+prosedur pemblokiran dalam metode ini akan memblokir transisi ke aktivitas berikutnya dan memperlambat
+pengalaman pengguna.</p>
+
+<p> Metode-metode yang ditandai "Tidak" dalam kolom <b>Bisa dimatikan</b> melindungi proses yang menjadi host
+aktivitas dari dimatikan sejak saat metode dipanggil.  Jadi, aktivitas bisa dimatikan
+sejak {@link android.app.Activity#onPause onPause()} kembali hingga waktu
+{@link android.app.Activity#onResume onResume()} dipanggil. Aktivitas tidak akan lagi bisa dimatikan hingga
+{@link android.app.Activity#onPause onPause()} dipanggil lagi dan kembali. </p>
+
+<p class="note"><strong>Catatan:</strong> Aktivitas yang tidak "bisa dimatikan" secara teknis oleh
+definisi dalam tabel 1 masih bisa dimatikan oleh sistem&mdash;namun itu hany terjadi dalam
+situasi ekstrem bila tidak ada jalan lain. Kapan aktivitas bisa dimatikan
+akan dibahas selengkapnya dalam dokumen <a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan
+Threading</a>.</p>
+
+
+<h3 id="SavingActivityState">Menyimpan status aktivitas</h3>
+
+<p>Pengantar untuk <a href="#Lifecycle">Mengelola Daur Hidup Aktivitas</a> secara ringkas menyebutkan
+bahwa
+bila aktivitas dihentikan sementara atau dihentikan, status aktivitas akan dipertahankan. Hal itu terjadi karena
+objek {@link android.app.Activity} masih ditahan dalam memori saat aktivitas dihentikan sementara atau
+dihentikan&mdash;semua informasi tentang anggota dan statusnya saat ini masih hidup. Jadi, setiap perubahan
+yang dibuat pengguna dalam aktivitas akan dipertahankan sehingga bila aktivitas kembali ke
+latar depan (bila "dilanjutkan"), perubahan itu masih ada.</p>
+
+<p>Akan tetapi, bila sistem memusnahkan aktivitas untuk memulihkan memori, objek {@link
+android.app.Activity} akan dimusnahkan, sehingga sistem tidak bisa sekadar melanjutkan aktivitas dengan status
+tidak berubah. Sebagai gantinya, sistem harus membuat ulang objek {@link android.app.Activity} jika pengguna
+menyusuri kembali ke aktivitas tersebut. Namun, pengguna tidak menyadari
+bahwa sistem memusnahkan aktivitas dan membuatnya kembali dan, karena itu, mungkin
+mengharapkan aktivitas untuk sama persis dengan sebelumnya. Dalam situasi ini, Anda bisa memastikan bahwa
+informasi penting tentang status aktivitas tetap terjaga dengan mengimplementasikan
+metode callback tambahan yang memungkinkan Anda menyimpan informasi tentang status aktivitas: {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()}.</p>
+
+<p>Sistem memanggil {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
+sebelum membuat aktivitas rawan terhadap pemusnahan. Sistem meneruskan ke metode ini
+sebuah {@link android.os.Bundle} tempat Anda bisa menyimpan
+informasi status tentang aktivitas sebagai pasangan nama-nilai, dengan menggunakan metode-metode misalnya {@link
+android.os.Bundle#putString putString()} dan {@link
+android.os.Bundle#putInt putInt()}. Kemudian, jika sistem mematikan proses aplikasi Anda
+dan pengguna menyusuri kembali ke aktivitas tersebut, sistem akan membuat kembali aktivitas dan meneruskan
+{@link android.os.Bundle} ke {@link android.app.Activity#onCreate onCreate()} maupun {@link
+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Dengan menggunakan salah satu
+metode ini, Anda bisa mengekstrak status tersimpan dari {@link android.os.Bundle} dan memulihkan
+status aktivitas. Jika tidak ada informasi status untuk dipulihkan, maka {@link
+android.os.Bundle} yang diteruskan kepada adalah Anda null (yang akan terjadi bila aktivitas dibuat untuk
+pertama kali).</p>
+
+<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" />
+<p class="img-caption"><strong>Gambar 2.</strong> Ada dua cara yang bisa digunakan aktivitas untuk kembali ke fokus pengguna
+dengan status tetap: aktivitas dimusnahkan, kemudian dibuat kembali, dan aktivitas harus memulihkan
+status yang disimpan sebelumnya, atau aktivitas dihentikan, kemudian dilanjutkan dengan status aktivitas
+tetap.</p>
+
+<p class="note"><strong>Catatan:</strong> Tidak ada jaminan bahwa {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} akan dipanggil sebelum
+aktivitas Anda dimusnahkan, karena bisa saja terjadi aktivitas tidak perlu menyimpan status
+(misalnya saat pengguna meninggalkan aktivitas Anda dengan menggunakan tombol <em>Back</em>, karena pengguna menutup aktivitas
+secara eksplisit
+). Jika sistem memanggil {@link android.app.Activity#onSaveInstanceState
+onSaveInstanceState()}, ini akan dilakukan sebelum {@link
+android.app.Activity#onStop onStop()} dan mungkin sebelum {@link android.app.Activity#onPause
+onPause()}.</p>
+
+<p>Akan tetapi, sekalipun Anda tidak melakukan apa-apa dan tidak mengimplementasikan {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()}, beberapa status aktivitas
+akan dipulihkan oleh implementasi default {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} dalam kelas {@link android.app.Activity}. Khususnya,
+implementasi default akan memanggil metode {@link
+android.view.View#onSaveInstanceState onSaveInstanceState()} yang sesuai untuk setiap {@link
+android.view.View} dalam layout, yang memungkinkan setiap tampilan untuk memberi informasi tentang dirinya
+yang harus disimpan. Hampir setiap widget dalam kerangka kerja Android mengimplementasikan metode ini
+sebagaimana mestinya, sehingga setiap perubahan yang terlihat pada UI akan disimpan dan dipulihkan secara otomatis bila
+aktivitas Anda dibuat kembali. Misalnya, widget {@link android.widget.EditText} menyimpan teks apa saja
+yang dimasukkan oleh pengguna dan widget {@link android.widget.CheckBox} menyimpan baik teks itu diperiksa maupun
+tidak. Satu-satunya pekerjaan yang Anda perlukan adalah memberikan ID unik (dengan atribut <a href="{@docRoot}guide/topics/resources/layout-resource.html#idvalue">{@code android:id}</a>
+) untuk masing-masing widget yang ingin disimpan statusnya. Jika widget tidak memiliki ID, maka sistem
+tidak bisa menyimpan statusnya.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<p>Anda juga bisa menghentikan secara eksplisit sebuah tampilan dalam layout Anda agar tidak menyimpan statusnya dengan mengatur atribut
+{@link android.R.attr#saveEnabled android:saveEnabled} ke {@code "false"} atau dengan memanggil
+metode {@link android.view.View#setSaveEnabled setSaveEnabled()}. Biasanya, Anda tidak boleh
+menonaktifkannya, namun Anda boleh melakukannya jika ingin memulihkan status UI aktivitas secara berbeda.</p>
+</div>
+</div>
+
+<p>Walaupun implementasi default {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} menyimpan informasi yang berguna tentang
+UI aktivitas, Anda mungkin masih perlu mengesampingkannya untuk menyimpan informasi tambahan.
+Misalnya, Anda mungkin perlu menyimpan nilai-nilai anggota yang berubah selama masa pakai aktivitas (yang
+mungkin berkorelasi dengan nilai-nilai yang dipulihkan dalam UI, namun anggota-anggota yang menyimpan nilai-nilai UI itu tidak
+dipulihkan, secara default).</p>
+
+<p>Karena implementasi default {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} membantu menyimpan status UI, jika
+Anda mengesampingkan metode ini untuk menyimpan informasi tambahan status, Anda harus selalu memanggil
+implementasi superkelas {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
+sebelum melakukan pekerjaan apa pun. Demikian pula, Anda juga harus memanggil implementasi superkelas {@link
+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} jika Anda mengesampingkannya, sehingga
+implementasi default bisa memulihkan status tampilan.</p>
+
+<p class="note"><strong>Catatan:</strong> Karena {@link android.app.Activity#onSaveInstanceState
+onSaveInstanceState()} tidak dijamin
+akan dipanggil, Anda harus menggunakannya hanya untuk mencatat status aktivitas sementara (transient) (status
+UI)&mdash;Anda tidak boleh menggunakannya untuk menyimpan data persisten.  Sebagai gantinya, Anda harus menggunakan {@link
+android.app.Activity#onPause onPause()} untuk menyimpan data persisten (misalnya data yang harus disimpan
+ke database) saat pengguna meninggalkan aktivitas.</p>
+
+<p>Salah satu cara yang baik untuk menguji kemampuan aplikasi dalam memulihkan statusnya adalah cukup dengan memutar
+perangkat sehingga orientasi layarnya berubah. Bila orientasi layar berubah, sistem
+akan memusnahkan dan membuat kembali aktivitas untuk menerapkan sumber daya alternatif yang mungkin tersedia
+untuk konfigurasi layar baru. Karena alasan ini saja, sangat penting bahwa aktivitas Anda
+memulihkan statusnya secara lengkap saat dibuat kembali, karena pengguna memutar layar secara rutin saat
+menggunakan aplikasi.</p>
+
+
+<h3 id="ConfigurationChanges">Menangani perubahan konfigurasi</h3>
+
+<p>Sebagian konfigurasi perangkat bisa berubah saat runtime (misalnya orientasi layar, ketersediaan keyboard
+, dan bahasa). Bila terjadi perubahan demikian, Android akan membuat kembali aktivitas yang berjalan
+(sistem akan memanggil {@link android.app.Activity#onDestroy}, kemudian segera memanggil {@link
+android.app.Activity#onCreate onCreate()}). Perilaku ini
+didesain untuk membantu aplikasi Anda menyesuaikan diri dengan konfigurasi baru dengan cara memuat ulang
+aplikasi Anda secara otomatis dengan sumber daya alternatif yang telah Anda sediakan (misalnya layout yang berbeda untuk
+layar orientasi dan ukuran yang berbeda).</p>
+
+<p>Jika Anda mendesain aktivitas dengan benar untuk menangani restart karena perubahan orientasi layar dan
+memulihkan status aktivitas seperti yang dijelaskan di atas, aplikasi Anda akan lebih tahan terhadap
+kejadian tidak terduga lainnya dalam daur hidup aktivitas.</p>
+
+<p>Cara terbaik menangani restart tersebut adalah
+  menyimpan dan memulihkan status aktivitas Anda dengan menggunakan {@link
+  android.app.Activity#onSaveInstanceState onSaveInstanceState()} dan {@link
+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (atau {@link
+android.app.Activity#onCreate onCreate()}), seperti yang dibahas di bagian sebelumnya.</p>
+
+<p>Untuk informasi selengkapnya tentang konfigurasi perubahan yang terjadi saat program berjalan dan cara menanganinya
+, bacalah panduan untuk <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani
+Perubahan Runtime</a>.</p>
+
+
+
+<h3 id="CoordinatingActivities">Mengoordinasikan aktivitas</h3>
+
+ <p>Bila suatu aktivitas memulai aktivitas lain, keduanya akan mengalami transisi daur hidup. Aktivitas pertama
+akan berhenti sementara dan berhenti sama sekali (walau tidak akan berhenti jika masih terlihat di latar belakang), saat
+aktivitas lain dibuat. Jika aktivitas-aktivitas ini berbagi data yang disimpan ke disk atau di tempat lain, Anda perlu
+memahami bahwa aktivitas pertama tidak dihentikan sepenuhnya sebelum aktivitas kedua dibuat.
+Sebagai gantinya, proses akan memulai aktivitas kedua secara tumpang tindih dengan proses penghentian
+aktivitas pertama.</p>
+
+<p>Urutan callback daur hidup didefinisikan dengan baik, khususnya bila kedua aktivitas berada dalam
+proses yang sama dan salah satunya memulai yang lain. Berikut ini adalah urutan operasi yang terjadi bila Aktivitas
+A memulai Aktivitas B: </p>
+
+<ol>
+<li>Metode {@link android.app.Activity#onPause onPause()} Aktivitas A berjalan.</li>
+
+<li>Metode-metode {@link android.app.Activity#onCreate onCreate()}, {@link
+android.app.Activity#onStart onStart()}, dan {@link android.app.Activity#onResume onResume()}
+Aktivitas B berjalan secara berurutan. (Aktivitas B sekarang mendapatkan fokus pengguna.)</li>
+
+<li>Kemudian, jika Aktivitas A tidak lagi terlihat di layar, metode {@link
+android.app.Activity#onStop onStop()}-nya akan dijalankan.</li>
+</ol>
+
+ <p>Urutan callback daur hidup yang bisa diramalkan ini memungkinkan Anda mengelola transisi
+informasi dari satu aktivitas ke aktivitas lainnya. Misalnya, jika Anda harus menulis ke database saat
+aktivitas pertama berhenti agar aktivitas berikutnya bisa membacanya, maka Anda harus menulis ke
+database selama {@link android.app.Activity#onPause onPause()} sebagai ganti selama {@link
+android.app.Activity#onStop onStop()}.</p>
+
+<!--
+<h2>Beginner's Path</h2>
+
+<p>For more information about how Android maintains a history of activities and
+enables user multitasking, continue with the <b><a
+href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back
+Stack</a></b> document.</p>
+-->
diff --git a/docs/html-intl/intl/id/guide/components/bound-services.jd b/docs/html-intl/intl/id/guide/components/bound-services.jd
new file mode 100644
index 0000000..6e5e65a
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/bound-services.jd
@@ -0,0 +1,658 @@
+page.title=Layanan Terikat
+parent.title=Layanan
+parent.link=services.html
+@jd:body
+
+
+<div id="qv-wrapper">
+<ol id="qv">
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#Basics">Dasar-Dasar</a></li>
+  <li><a href="#Creating">Membuat Layanan Terikat</a>
+    <ol>
+      <li><a href="#Binder">Memperluas kelas Binder</a></li>
+      <li><a href="#Messenger">Menggunakan Messenger</a></li>
+    </ol>
+  </li>
+  <li><a href="#Binding">Mengikat ke Layanan</a></li>
+  <li><a href="#Lifecycle">Mengelola Daur Hidup Layanan Terikat</a></li>
+</ol>
+
+<h2>Kelas-kelas utama</h2>
+<ol>
+  <li>{@link android.app.Service}</li>
+  <li>{@link android.content.ServiceConnection}</li>
+  <li>{@link android.os.IBinder}</li>
+</ol>
+
+<h2>Contoh</h2>
+<ol>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
+      RemoteService}</a></li>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
+      LocalService}</a></li>
+</ol>
+
+<h2>Lihat juga</h2>
+<ol>
+  <li><a href="{@docRoot}guide/components/services.html">Layanan</a></li>
+</ol>
+</div>
+
+
+<p>Layanan terikat adalah server di antarmuka klien-server. Layanan terikat memungkinkan komponen-komponen
+(seperti aktivitas) untuk diikat ke layanan, mengirim permintaan, menerima respons, dan bahkan melakukan
+komunikasi antarproses (IPC). Layanan terikat biasanya hidup hanya saat melayani
+komponen aplikasi lain dan tidak berjalan di latar belakang terus-menerus.</p>
+
+<p>Dokumen ini menampilkan cara membuat layanan terikat, termasuk cara mengikat
+ke layanan dari komponen aplikasi lain. Akan tetapi, Anda juga harus mengacu dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a> untuk
+informasi tambahan tentang layanan secara umum, seperti cara menyampaikan pemberitahuan dari layanan, mengatur
+layanan agar berjalan di latar depan, dan lain-lain.</p>
+
+
+<h2 id="Basics">Dasar-Dasar</h2>
+
+<p>Layanan terikat adalah implementasi kelas {@link android.app.Service} yang memungkinkan
+aplikasi lain diikat padanya dan berinteraksi dengannya. Untuk menyediakan pengikatan bagi sebuah
+layanan, Anda harus mengimplementasikan metode callback {@link android.app.Service#onBind onBind()}. Metode ini
+menghasilkan objek {@link android.os.IBinder} yang mendefinisikan antarmuka pemprograman yang
+bisa digunakan klien untuk berinteraksi dengan layanan.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h3>Mengikat ke Layanan yang Sudah Dimulai</h3>
+
+<p>Seperti dibahas dalam dokumen <a href="{@docRoot}guide/components/services.html">Layanan</a>
+, Anda bisa membuat layanan yang dimulai sekaligus diikat. Yakni, layanan bisa
+dimulai dengan memanggil {@link android.content.Context#startService startService()}, yang memungkinkan
+layanan berjalan terus-menerus, dan juga membolehkan klien untuk mengikat ke layanan dengan memanggil {@link
+android.content.Context#bindService bindService()}.
+  <p>Jika Anda mengizinkan layanan dimulai dan diikat, lalu ketika layanan telah
+dimulai, sistem <em>tidak</em> menghapus layanan ketika semua klien melepas ikatan. Sebagai gantinya, Anda harus
+menghentikan layanan secara eksplisit, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
+android.content.Context#stopService stopService()}.</p>
+
+<p>Walaupun Anda biasanya harus mengimplementasikan {@link android.app.Service#onBind onBind()}
+<em>atau</em> {@link android.app.Service#onStartCommand onStartCommand()}, kadang-kadang perlu
+mengimplementasikan keduanya. Misalnya, sebuah pemutar musik bisa merasakan manfaatnya karena layanannya boleh berjalan
+terus-menerus dan juga menyediakan pengikatan. Dengan cara ini, sebuah aktivitas bisa memulai layanan untuk memutar beberapa
+lagu dan musik terus dimainkan sekalipun pengguna meninggalkan aplikasi. Lalu, bila pengguna
+kembali ke aplikasi, aktivitas bisa mengikat ke layanan untuk mendapatkan kembali kontrol atas pemutaran.</p>
+
+<p>Pastikan membaca bagian tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan
+Terikat</a>, untuk informasi selengkapnya tentang daur hidup layanan saat menambahkan pengikatan ke
+layanan yang sudah dimulai.</p>
+</div>
+</div>
+
+<p>Klien bisa mengikat ke layanan dengan memanggil {@link android.content.Context#bindService
+bindService()}. Bila itu dilakukan, klien harus menyediakan implementasi {@link
+android.content.ServiceConnection}, yang memantau koneksi dengan layanan. Metode {@link
+android.content.Context#bindService bindService()} kembali dengan serta-merta tanpa sebuah nilai, namun
+bila sistem Android membuat koneksi antara klien
+dan layanan, sistem akan memanggil {@link
+android.content.ServiceConnection#onServiceConnected onServiceConnected()} pada {@link
+android.content.ServiceConnection} untuk mengirim {@link android.os.IBinder} yang
+bisa digunakan klien untuk berkomunikasi dengan layanan.</p>
+
+<p>Beberapa klien bisa terhubung ke layanan dengan serentak. Akan tetapi, sistem akan memanggil metode
+{@link android.app.Service#onBind onBind()} layanan Anda untuk mengambil {@link android.os.IBinder} hanya
+bila klien pertama mengikat. Sistem lalu memberikan {@link android.os.IBinder} yang sama ke setiap
+klien tambahan yang mengikat, tanpa memanggil {@link android.app.Service#onBind onBind()} lagi.</p>
+
+<p>Bila klien terakhir melepas ikatan dari layanan, sistem akan menghapus layanan (kecuali jika
+layanan juga dimulai oleh {@link android.content.Context#startService startService()}).</p>
+
+<p>Bila Anda mengimplementasikan layanan terikat, yang terpenting adalah mendefinisikan antarmuka
+yang dihasilkan metode callback {@link android.app.Service#onBind onBind()} Anda. Ada sedikit
+cara mendefinisikan antarmuka {@link android.os.IBinder} layanan Anda dan bagian berikut
+akan membahas masing-masing teknik.</p>
+
+
+
+<h2 id="Creating">Membuat Layanan Terikat</h2>
+
+<p>Saat membuat layanan yang menyediakan pengikatan, Anda harus menyediakan {@link android.os.IBinder}
+yang menyediakan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan. Ada
+tiga cara untuk mendefinisikan antarmuka:</p>
+
+<dl>
+  <dt><a href="#Binder">Memperluas kelas Binder</a></dt>
+  <dd>Jika layanan Anda bersifat privat untuk aplikasi Anda sendiri dan berjalan dalam proses yang sama dengan klien
+(biasanya), Anda harus membuat antarmuka dengan memperluas kelas {@link android.os.Binder}
+dan menghasilkan instance dari
+{@link android.app.Service#onBind onBind()}. Klien akan menerima {@link android.os.Binder} dan
+bisa menggunakannya untuk mengakses langsung metode publik yang tersedia dalam implementasi {@link android.os.Binder}
+atau bahkan {@link android.app.Service}.
+  <p>Inilah teknik yang lebih disukai bila layanan Anda sekadar pekerja latar belakang untuk aplikasi Anda
+sendiri. Satu-satunya alasan tidak membuat antarmuka dengan cara ini adalah karena
+layanan Anda akan digunakan oleh aplikasi lain atau pada proses-proses terpisah.</dd>
+
+  <dt><a href="#Messenger">Menggunakan Messenger</a></dt>
+  <dd>Jika antarmuka Anda perlu bekerja lintas proses, Anda bisa membuat
+antarmuka untuk layanan dengan {@link android.os.Messenger}. Dengan cara ini, layanan
+mendefinisikan {@link android.os.Handler} yang akan merespons aneka tipe objek {@link
+android.os.Message}. {@link android.os.Handler}
+ini adalah dasar bagi {@link android.os.Messenger} yang nanti bisa berbagi {@link android.os.IBinder}
+dengan klien, sehingga memungkinkan klien mengirim perintah ke layanan dengan menggunakan objek {@link
+android.os.Message}. Selain itu, klien bisa mendefinisikan sendiri {@link android.os.Messenger}
+sehingga layanan bisa mengirim balik pesan.
+  <p>Inilah cara termudah melakukan komunikasi antarproses (IPC), karena {@link
+android.os.Messenger} akan mengantre semua permintaan ke dalam satu thread sehingga Anda tidak perlu mendesain
+layanan agar thread-safe.</p>
+  </dd>
+
+  <dt>Menggunakan AIDL</dt>
+  <dd>AIDL (Android Interface Definition Language) melakukan semua pekerjaan untuk mengurai objek menjadi
+primitif yang bisa dipahami dan diarahkan oleh sistem operasi ke berbagai proses untuk melakukan
+IPC. Teknik sebelumnya, dengan menggunakan {@link android.os.Messenger}, sebenarnya berdasarkan AIDL sebagai
+struktur yang mendasarinya. Seperti disebutkan di atas, {@link android.os.Messenger} membuat antrean
+semua permintaan klien dalam satu thread, sehingga layanan akan menerima permintaan satu per satu. Akan tetapi,
+jika ingin layanan Anda menangani beberapa permintaan sekaligus, Anda bisa menggunakan AIDL
+secara langsung. Dalam hal ini, layanan Anda harus mampu multi-thread dan dibuat thread-safe.
+  <p>Untuk menggunakan AIDL secara langsung, Anda harus
+membuat file {@code .aidl} yang mendefinisikan antarmuka pemrograman. Alat Android SDK menggunakan
+file ini untuk menghasilkan kelas abstrak yang mengimplementasikan antarmuka dan menangani IPC, yang nanti
+bisa Anda perluas dalam layanan.</p>
+  </dd>
+</dl>
+
+  <p class="note"><strong>Catatan:</strong> Umumnya aplikasi <strong>tidak boleh</strong> menggunakan AIDL untuk
+membuat layanan terikat, karena hal itu mungkin memerlukan kemampuan multi-thread dan
+bisa mengakibatkan implementasi yang lebih rumit. Dengan demikian, AIDL tidak cocok untuk sebagian besar aplikasi
+dan dokumen ini tidak membahas cara menggunakannya untuk layanan Anda. Jika Anda yakin perlu
+menggunakan AIDL secara langsung, lihat dokumen <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
+.</p>
+
+
+
+
+<h3 id="Binder">Memperluas kelas Binder</h3>
+
+<p>Jika layanan Anda hanya digunakan oleh aplikasi lokal dan tidak perlu bekerja lintas proses,
+maka Anda bisa mengimplementasikan kelas {@link android.os.Binder} Anda sendiri yang memberi klien Anda
+akses langsung ke metode publik dalam layanan.</p>
+
+<p class="note"><strong>Catatan:</strong> Hal ini hanya berhasil jika klien dan layanan berada dalam
+aplikasi dan proses yang sama, suatu kondisi yang paling umum. Misalnya, cara ini sangat cocok untuk sebuah aplikasi musik
+yang perlu mengikat aktivitas ke layanannya sendiri, yakni memutar musik di
+latar belakang.</p>
+
+<p>Berikut cara menyiapkannya:</p>
+<ol>
+  <li>Dalam layanan Anda, buat sebuah instance {@link android.os.Binder} yang:
+    <ul>
+      <li>berisi metode publik yang bisa dipanggil klien</li>
+      <li>menghasilkan instance {@link android.app.Service} saat ini, yang memiliki metode publik yang
+bisa dipanggil klien</li>
+      <li>atau, menghasilkan instance kelas lain yang host-nya di layanan dengan metode publik yang
+bisa dipanggil klien</li>
+    </ul>
+  <li>Hasilkan instance {@link android.os.Binder} ini dari metode callback {@link
+android.app.Service#onBind onBind()}.</li>
+  <li>Di klien, terima {@link android.os.Binder} dari metode callback {@link
+android.content.ServiceConnection#onServiceConnected onServiceConnected()} dan
+buat panggilan ke layanan terikat dengan menggunakan metode yang disediakan.</li>
+</ol>
+
+<p class="note"><strong>Catatan:</strong> Alasan layanan dan klien harus berada dalam aplikasi yang sama
+adalah agar klien bisa mengkonversi objek yang dihasilkan dan memanggil API-nya dengan benar. Layanan
+dan klien juga harus berada dalam proses yang sama, karena teknik ini tidak melakukan
+pengarahan (marshalling) apa pun untuk lintas proses.</p>
+
+<p>Misalnya, berikut ini adalah layanan yang memberi klien akses ke metode-metode dalam layanan melalui
+implementasi {@link android.os.Binder}:</p>
+
+<pre>
+public class LocalService extends Service {
+    // Binder given to clients
+    private final IBinder mBinder = new LocalBinder();
+    // Random number generator
+    private final Random mGenerator = new Random();
+
+    /**
+     * Class used for the client Binder.  Because we know this service always
+     * runs in the same process as its clients, we don't need to deal with IPC.
+     */
+    public class LocalBinder extends Binder {
+        LocalService getService() {
+            // Return this instance of LocalService so clients can call public methods
+            return LocalService.this;
+        }
+    }
+
+    &#64;Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /** method for clients */
+    public int getRandomNumber() {
+      return mGenerator.nextInt(100);
+    }
+}
+</pre>
+
+<p>{@code LocalBinder} menyediakan {@code getService()} metode bagi klien untuk mengambil
+instance {@code LocalService} saat ini. Cara ini memungkinkan klien memanggil metode publik dalam
+layanan. Misalnya, klien bisa memanggil {@code getRandomNumber()} dari layanan.</p>
+
+<p>Berikut ini adalah aktivitas yang mengikat ke {@code LocalService} dan memanggil {@code getRandomNumber()}
+bila tombol diklik:</p>
+
+<pre>
+public class BindingActivity extends Activity {
+    LocalService mService;
+    boolean mBound = false;
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    &#64;Override
+    protected void onStart() {
+        super.onStart();
+        // Bind to LocalService
+        Intent intent = new Intent(this, LocalService.class);
+        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    &#64;Override
+    protected void onStop() {
+        super.onStop();
+        // Unbind from the service
+        if (mBound) {
+            unbindService(mConnection);
+            mBound = false;
+        }
+    }
+
+    /** Called when a button is clicked (the button in the layout file attaches to
+      * this method with the android:onClick attribute) */
+    public void onButtonClick(View v) {
+        if (mBound) {
+            // Call a method from the LocalService.
+            // However, if this call were something that might hang, then this request should
+            // occur in a separate thread to avoid slowing down the activity performance.
+            int num = mService.getRandomNumber();
+            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
+        }
+    }
+
+    /** Defines callbacks for service binding, passed to bindService() */
+    private ServiceConnection mConnection = new ServiceConnection() {
+
+        &#64;Override
+        public void onServiceConnected(ComponentName className,
+                IBinder service) {
+            // We've bound to LocalService, cast the IBinder and get LocalService instance
+            LocalBinder binder = (LocalBinder) service;
+            mService = binder.getService();
+            mBound = true;
+        }
+
+        &#64;Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            mBound = false;
+        }
+    };
+}
+</pre>
+
+<p>Contoh di atas menampilkan cara klien mengikat ke layanan dengan menggunakan implementasi
+{@link android.content.ServiceConnection} dan callback {@link
+android.content.ServiceConnection#onServiceConnected onServiceConnected()}. Bagian
+berikut menyediakan informasi selengkapnya tentang proses pengikatan ke layanan.</p>
+
+<p class="note"><strong>Catatan:</strong> Contoh di atas tidak secara eksplisit melepas ikatan dari layanan,
+namun semua klien harus melepas ikatan pada waktu yang tepat (seperti saat aktivitas sedang jeda).</p>
+
+<p>Untuk contoh kode selengkapnya, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
+LocalService.java}</a> dan kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
+LocalServiceActivities.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
+
+
+
+
+
+<h3 id="Messenger">Menggunakan Messenger</h3>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h4>Dibandingkan dengan AIDL</h4>
+  <p>Bila Anda perlu melakukan IPC, menggunakan {@link android.os.Messenger} untuk antarmuka
+lebih sederhana daripada mengimplementasikannya dengan AIDL, karena {@link android.os.Messenger} mengantre
+semua panggilan ke layanan, sementara antarmuka AIDL murni mengirim permintaan serentak ke
+layanan, yang nanti harus menangani multi-threading.</p>
+  <p>Untuk sebagian besar aplikasi, layanan tidak perlu melakukan multi-threading, jadi dengan menggunakan {@link
+android.os.Messenger} memungkinkan layanan menangani panggilan satu per satu. Jika
+layanan harus multi-thread, Anda harus menggunakan <a href="{@docRoot}guide/components/aidl.html">AIDL</a> untuk mendefinisikan antarmuka.</p>
+</div>
+</div>
+
+<p>Jika layanan perlu berkomunikasi dengan proses jauh, Anda bisa menggunakan
+{@link android.os.Messenger} untuk menyediakan antarmuka bagi layanan Anda. Teknik ini memungkinkan
+Anda melakukan komunikasi antarproses (IPC) tanpa harus menggunakan AIDL.</p>
+
+<p>Berikut ini rangkuman cara menggunakan {@link android.os.Messenger}:</p>
+
+<ul>
+  <li>Layanan mengimplementasikan {@link android.os.Handler} yang menerima callback untuk tiap
+panggilan dari klien.</li>
+  <li>{@link android.os.Handler} digunakan untuk membuat objek {@link android.os.Messenger}
+(yang merupakan acuan ke {@link android.os.Handler}).</li>
+  <li>{@link android.os.Messenger} membuat {@link android.os.IBinder} yang
+dikembalikan layanan ke klien dari {@link android.app.Service#onBind onBind()}.</li>
+  <li>Klien menggunakan {@link android.os.IBinder} untuk membuat instance {@link android.os.Messenger}
+(yang mengacu {@link android.os.Handler} layanan), yang digunakan klien untuk mengirim
+objek {@link android.os.Message} ke layanan.</li>
+  <li>Layanan menerima setiap {@link android.os.Message} dalam {@link
+android.os.Handler}&mdash;secara spesifik, dalam metode {@link android.os.Handler#handleMessage
+handleMessage()}.</li>
+</ul>
+
+
+<p>Dengan cara ini, tidak ada "metode" untuk dipanggil klien pada layanan. Sebagai gantinya,
+klien mengirim "pesan" (objek-objek {@link android.os.Message}) yang diterima layanan dalam
+{@link android.os.Handler}-nya.</p>
+
+<p>Berikut ini contoh layanan sederhana yang menggunakan antarmuka {@link android.os.Messenger}:</p>
+
+<pre>
+public class MessengerService extends Service {
+    /** Command to the service to display a message */
+    static final int MSG_SAY_HELLO = 1;
+
+    /**
+     * Handler of incoming messages from clients.
+     */
+    class IncomingHandler extends Handler {
+        &#64;Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SAY_HELLO:
+                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    }
+
+    /**
+     * Target we publish for clients to send messages to IncomingHandler.
+     */
+    final Messenger mMessenger = new Messenger(new IncomingHandler());
+
+    /**
+     * When binding to the service, we return an interface to our messenger
+     * for sending messages to the service.
+     */
+    &#64;Override
+    public IBinder onBind(Intent intent) {
+        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
+        return mMessenger.getBinder();
+    }
+}
+</pre>
+
+<p>Perhatikan bahwa metode {@link android.os.Handler#handleMessage handleMessage()} dalam
+{@link android.os.Handler} adalah tempat layanan menerima {@link android.os.Message}
+yang masuk dan memutuskan aksi yang harus dilakukan, berdasarkan anggota {@link android.os.Message#what}.</p>
+
+<p>Klien tinggal membuat {@link android.os.Messenger} berdasarkan {@link
+android.os.IBinder} yang dihasilkan layanan dan mengirim pesan menggunakan {@link
+android.os.Messenger#send send()}. Misalnya, berikut ini adalah aktivitas sederhana yang mengikat ke
+layanan dan mengirim pesan {@code MSG_SAY_HELLO} ke layanan:</p>
+
+<pre>
+public class ActivityMessenger extends Activity {
+    /** Messenger for communicating with the service. */
+    Messenger mService = null;
+
+    /** Flag indicating whether we have called bind on the service. */
+    boolean mBound;
+
+    /**
+     * Class for interacting with the main interface of the service.
+     */
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            // This is called when the connection with the service has been
+            // established, giving us the object we can use to
+            // interact with the service.  We are communicating with the
+            // service using a Messenger, so here we get a client-side
+            // representation of that from the raw IBinder object.
+            mService = new Messenger(service);
+            mBound = true;
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            // This is called when the connection with the service has been
+            // unexpectedly disconnected -- that is, its process crashed.
+            mService = null;
+            mBound = false;
+        }
+    };
+
+    public void sayHello(View v) {
+        if (!mBound) return;
+        // Create and send a message to the service, using a supported 'what' value
+        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
+        try {
+            mService.send(msg);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+    &#64;Override
+    protected void onStart() {
+        super.onStart();
+        // Bind to the service
+        bindService(new Intent(this, MessengerService.class), mConnection,
+            Context.BIND_AUTO_CREATE);
+    }
+
+    &#64;Override
+    protected void onStop() {
+        super.onStop();
+        // Unbind from the service
+        if (mBound) {
+            unbindService(mConnection);
+            mBound = false;
+        }
+    }
+}
+</pre>
+
+<p>Perhatikan bahwa contoh ini tidak menampilkan cara layanan merespons klien. Jika ingin
+layanan merespons, Anda juga perlu membuat {@link android.os.Messenger} di klien. Lalu
+saat menerima callback {@link android.content.ServiceConnection#onServiceConnected
+onServiceConnected()}, klien akan mengirim {@link android.os.Message} ke layanan yang berisi
+{@link android.os.Messenger} klien dalam parameter {@link android.os.Message#replyTo}
+metode {@link android.os.Messenger#send send()}.</p>
+
+<p>Anda bisa melihat contoh cara menyediakan pertukaran pesan dua arah dalam contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
+MessengerService.java}</a> (layanan) dan <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
+MessengerServiceActivities.java}</a> (klien).</p>
+
+
+
+
+
+<h2 id="Binding">Mengikat ke Layanan</h2>
+
+<p>Komponen-komponen aplikasi (klien) bisa mengikat ke layanan dengan memanggil
+{@link android.content.Context#bindService bindService()}. Sistem Android
+lalu memanggil metode {@link android.app.Service#onBind
+onBind()} layanan, yang menghasilkan {@link android.os.IBinder} untuk berinteraksi dengan layanan.</p>
+
+<p>Pengikatan ini bersifat asinkron. {@link android.content.Context#bindService
+bindService()} segera kembali dan <em>tidak</em> mengembalikan {@link android.os.IBinder} ke
+klien. Untuk menerima {@link android.os.IBinder}, klien harus membuat instance {@link
+android.content.ServiceConnection} dan meneruskannya ke {@link android.content.Context#bindService
+bindService()}. {@link android.content.ServiceConnection} berisi metode callback yang
+dipanggil sistem untuk mengirim {@link android.os.IBinder}.</p>
+
+<p class="note"><strong>Catatan:</strong> Hanya aktivitas, layanan, dan penyedia konten yang bisa mengikat
+ke layanan yang&mdash;Anda <strong>tidak bisa</strong> ikat ke layanan dari penerima siaran.</p>
+
+<p>Jadi, untuk mengikat ke layanan dari klien, Anda harus: </p>
+<ol>
+  <li>Mengimplementasikan {@link android.content.ServiceConnection}.
+    <p>Implementasi Anda harus mengesampingkan dua metode callback:</p>
+    <dl>
+      <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt>
+        <dd>Sistem memanggil ini untuk mengirim {@link android.os.IBinder} yang dihasilkan oleh
+metode {@link android.app.Service#onBind onBind()} layanan.</dd>
+      <dt>{@link android.content.ServiceConnection#onServiceDisconnected
+onServiceDisconnected()}</dt>
+        <dd>Sistem Android memanggil ini bila koneksi ke layanan putus
+tanpa terduga, seperti ketika layanan mengalami crash atau dimatikan. Ini <em>tidak</em> dipanggil ketika
+klien melepas ikatan.</dd>
+    </dl>
+  </li>
+  <li>Panggil {@link
+android.content.Context#bindService bindService()}, dengan meneruskan implementasi {@link
+android.content.ServiceConnection}. </li>
+  <li>Bila sistem memanggil metode callback {@link android.content.ServiceConnection#onServiceConnected
+onServiceConnected()}, Anda bisa mulai membuat panggilan ke layanan, dengan menggunakan
+metode yang didefinisikan oleh antarmuka.</li>
+  <li>Untuk memutus koneksi dari layanan, panggil {@link
+android.content.Context#unbindService unbindService()}.
+    <p>Bila telah dimusnahkan (destroyed), klien Anda akan melepas ikatan dari layanan, namun Anda harus selalu melepas ikatan
+bila sudah selesai berinteraksi dengan layanan atau bila aktivitas Anda sedang jeda sehingga layanan bisa
+dimatikan saat tidak sedang digunakan. (Waktu yang tepat untuk mengikat dan melepas ikatan dibahas
+selengkapnya di bawah ini.)</p>
+  </li>
+</ol>
+
+<p>Misalnya, cuplikan berikut menghubungkan klien ke layanan yang dibuat di atas dengan
+<a href="#Binder">memperluas kelas Binder</a>, sehingga tinggal mengkonversi
+{@link android.os.IBinder} yang dihasilkan ke kelas {@code LocalService} dan meminta instance {@code
+LocalService}:</p>
+
+<pre>
+LocalService mService;
+private ServiceConnection mConnection = new ServiceConnection() {
+    // Called when the connection with the service is established
+    public void onServiceConnected(ComponentName className, IBinder service) {
+        // Because we have bound to an explicit
+        // service that is running in our own process, we can
+        // cast its IBinder to a concrete class and directly access it.
+        LocalBinder binder = (LocalBinder) service;
+        mService = binder.getService();
+        mBound = true;
+    }
+
+    // Called when the connection with the service disconnects unexpectedly
+    public void onServiceDisconnected(ComponentName className) {
+        Log.e(TAG, "onServiceDisconnected");
+        mBound = false;
+    }
+};
+</pre>
+
+<p>Dengan {@link android.content.ServiceConnection} ini, klien bisa mengikat ke layanan dengan meneruskannya
+ke {@link android.content.Context#bindService bindService()}. Misalnya:</p>
+
+<pre>
+Intent intent = new Intent(this, LocalService.class);
+bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+</pre>
+
+<ul>
+  <li>Parameter pertama {@link android.content.Context#bindService bindService()} adalah sebuah
+{@link android.content.Intent} yang secara eksplisit menyebutkan layanan yang akan diikat (walaupun intent
+boleh implisit).</li>
+<li>Parameter kedua adalah objek {@link android.content.ServiceConnection}.</li>
+<li>Parameter ketiga adalah tanda (flag) yang menunjukkan opsi pengikatan. Tanda ini biasanya harus {@link
+android.content.Context#BIND_AUTO_CREATE} agar dapat membuat layanan jika belum hidup.
+Nilai-nilai lain yang memungkinkan adalah {@link android.content.Context#BIND_DEBUG_UNBIND}
+dan {@link android.content.Context#BIND_NOT_FOREGROUND}, atau {@code 0} untuk tidak satu pun.</li>
+</ul>
+
+
+<h3>Catatan tambahan</h3>
+
+<p>Berikut ini beberapa catatan penting tentang mengikat ke layanan:</p>
+<ul>
+  <li>Anda harus selalu menjebak eksepsi {@link android.os.DeadObjectException}, yang dilontarkan
+bila koneksi terputus. Inilah satu-satunya eksepsi yang dilontarkan oleh metode jauh.</li>
+  <li>Objek adalah acuan yang dihitung lintas proses. </li>
+  <li>Anda biasanya harus memasangkan pengikatan dan pelepasan ikatan selama
+memasangkan momen membuat dan menghapus daur hidup klien. Misalnya:
+    <ul>
+      <li>Jika Anda hanya perlu berinteraksi dengan layanan saat aktivitas terlihat, Anda
+harus mengikat selama {@link android.app.Activity#onStart onStart()} dan melepas ikatan selama {@link
+android.app.Activity#onStop onStop()}.</li>
+      <li>Jika Anda ingin aktivitas menerima tanggapan bahkan saat dihentikan di
+latar belakang, Anda bisa mengikat selama {@link android.app.Activity#onCreate onCreate()} dan melepas ikatan
+selama {@link android.app.Activity#onDestroy onDestroy()}. Berhati-hatilah karena hal ini menyiratkan aktivitas
+Anda perlu menggunakan layanan selama dijalankan (sekalipun di latar belakang), jadi jika
+layanan berada dalam proses lain, Anda meningkatkan bobot proses dan semakin besar
+kemungkinan sistem akan mematikannya.</li>
+    </ul>
+    <p class="note"><strong>Catatan:</strong> Anda biasanya <strong>tidak</strong> boleh mengikat dan melepas ikatan
+selama {@link android.app.Activity#onResume onResume()} aktivitas Anda dan {@link
+android.app.Activity#onPause onPause()}, karena callback ini terjadi pada setiap transisi daur hidup
+dan Anda harus menjaga pemrosesan yang terjadi pada transisi ini tetap minim. Juga, jika
+banyak aktivitas dalam aplikasi Anda mengikat ke layanan yang sama dan ada transisi antara
+dua aktivitas, layanan bisa dimusnahkan dan dibuat lagi sambil aktivitas saat ini melepas ikatan
+(selama jeda) sebelum aktivitas berikutnya mengikat (selama lanjutkan). (Transisi aktivitas ini untuk cara
+aktivitas mengoordinasikan daur hidupnya dijelaskan dalam dokumen <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Aktivitas</a>
+.)</p>
+</ul>
+
+<p>Untuk contoh kode selengkapnya, yang menampilkan cara mengikat ke layanan, lihat kelas <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
+RemoteService.java}</a> dalam <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
+
+
+
+
+
+<h2 id="Lifecycle">Mengelola Daur Hidup Layanan Terikat</h2>
+
+<p>Bila layanan dilepas ikatannya dari semua klien, sistem Android akan menghapusnya (kecuali jika layanan juga
+dimulai dengan {@link android.app.Service#onStartCommand onStartCommand()}). Dengan demikian, Anda tidak harus
+mengelola daur hidup layanan jika layanan itu murni sebuah layanan
+terikat&mdash;yang dikelola sistem Android untuk Anda berdasarkan apakah layanan terikat ke klien atau tidak.</p>
+
+<p>Akan tetapi, Jika Anda memilih untuk mengimplementasikan metode callback {@link android.app.Service#onStartCommand
+onStartCommand()}, maka Anda harus menghentikan layanan secara eksplisit, karena layanan
+sekarang dianggap telah <em>dimulai</em>. Dalam hal ini, layanan akan berjalan hingga layanan
+menghentikan dirinya sendiri dengan {@link android.app.Service#stopSelf()} atau panggilan komponen lain {@link
+android.content.Context#stopService stopService()}, terlepas dari apakah layanan terikat ke
+klien atau tidak.</p>
+
+<p>Selain itu, jika layanan Anda telah dimulai dan menerima pengikatan, maka saat sistem memanggil
+metode {@link android.app.Service#onUnbind onUnbind()}, Anda bisa memilih untuk mengembalikan
+{@code true} jika ingin menerima panggilan ke {@link android.app.Service#onRebind
+onRebind()} bila nanti klien mengikat ke layanan (sebagai ganti menerima panggilan ke {@link
+android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind
+onRebind()} akan menghasilkan void, namun klien tetap menerima {@link android.os.IBinder} dalam callback
+{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}.
+Di bawah ini adalah gambar 1 yang mengilustrasikan logika untuk jenis daur hidup ini.</p>
+
+
+<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Daur hidup untuk layanan yang dimulai
+dan juga memungkinkan pengikatan.</p>
+
+
+<p>Untuk informasi selengkapnya tentang daur hidup layanan yang telah dimulai, lihat dokumen <a href="{@docRoot}guide/components/services.html#Lifecycle">Layanan</a>.</p>
+
+
+
+
diff --git a/docs/html-intl/intl/id/guide/components/fragments.jd b/docs/html-intl/intl/id/guide/components/fragments.jd
new file mode 100644
index 0000000..9f7199c
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/fragments.jd
@@ -0,0 +1,812 @@
+page.title=Fragmen
+parent.title=Aktivitas
+parent.link=activities.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#Design">Filosofi Desain</a></li>
+    <li><a href="#Creating">Membuat Fragmen</a>
+      <ol>
+        <li><a href="#UI">Menambahkan antarmuka pengguna</a></li>
+        <li><a href="#Adding">Menambahkan fragmen ke aktivitas</a></li>
+      </ol>
+    </li>
+    <li><a href="#Managing">Mengelola Fragmen</a></li>
+    <li><a href="#Transactions">Melakukan Transaksi Fragmen</a></li>
+    <li><a href="#CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</a>
+      <ol>
+        <li><a href="#EventCallbacks">Membuat callback kejadian pada aktivitas</a></li>
+        <li><a href="#ActionBar">Menambahkan item ke Action-Bar</a></li>
+      </ol>
+    </li>
+    <li><a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>
+      <ol>
+        <li><a href="#CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</a></li>
+      </ol>
+    </li>
+    <li><a href="#Example">Contoh</a></li>
+  </ol>
+
+  <h2>Kelas-kelas utama</h2>
+  <ol>
+    <li>{@link android.app.Fragment}</li>
+    <li>{@link android.app.FragmentManager}</li>
+    <li>{@link android.app.FragmentTransaction}</li>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="{@docRoot}training/basics/fragments/index.html">Membangun UI Dinamis dengan Fragmen</a></li>
+    <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet
+dan Handset</a></li>
+  </ol>
+</div>
+</div>
+
+<p>{@link android.app.Fragment} mewakili perilaku atau bagian dari antarmuka pengguna dalam
+{@link android.app.Activity}. Anda bisa mengombinasikan beberapa fragmen dalam satu aktivitas untuk membangun UI
+multipanel dan menggunakan kembali sebuah fragmen dalam beberapa aktivitas. Anda bisa menganggap fragmen sebagai bagian
+modular dari aktivitas, yang memiliki daur hidup sendiri, menerima kejadian input sendiri, dan
+yang bisa Anda tambahkan atau hapus saat aktivitas berjalan (semacam "sub aktivitas" yang
+bisa digunakan kembali dalam aktivitas berbeda).</p>
+
+<p>Fragmen harus selalu tertanam dalam aktivitas dan daur hidup fragmen secara langsung
+dipengaruhi oleh daur hidup aktivitas host-nya. Misalnya, saat aktivitas dihentikan sementara,
+semua fragmen di dalamnya juga dihentikan sementara, dan bila aktivitas dimusnahkan, semua fragmen juga demikian. Akan tetapi, saat
+aktivitas berjalan (dalam <a href="{@docRoot}guide/components/activities.html#Lifecycle">status daur hidup</a> <em>dilanjutkan</em>, Anda bisa
+memanipulasi setiap fragmen secara terpisah, seperti menambah atau menghapusnya. Saat melakukan transaksi
+fragmen, Anda juga bisa menambahkannya ke back-stack yang dikelola oleh aktivitas
+&mdash;setiap entri back-stack merupakan record transaksi fragmen yang
+terjadi. Dengan back-stack pengguna dapat membalikkan transaksi fragmen (mengarah mundur),
+dengan menekan tombol <em>Back</em>.</p>
+
+<p>Bila Anda menambahkan fragmen sebagai bagian dari layout aktivitas, fragmen itu berada dalam {@link
+android.view.ViewGroup} di hierarki tampilan aktivitas tersebut dan fragmen mendefinisikan
+layout
+tampilannya sendiri. Anda bisa menyisipkan fragmen ke dalam layout aktivitas dengan mendeklarasikan fragmen dalam file layout aktivitas
+, sebagai elemen {@code &lt;fragment&gt;}, atau dari kode aplikasi dengan menambahkannya ke
+ {@link android.view.ViewGroup} yang ada. Akan tetapi, fragmen tidak harus menjadi bagian dari
+layout aktivitas; Anda juga bisa menggunakan fragmen tanpa UI-nya sendiri sebagai pekerja tak terlihat untuk
+aktivitas tersebut.</p>
+
+<p>Dokumen ini menjelaskan cara membangun aplikasi menggunakan fragmen, termasuk
+cara fragmen mempertahankan statusnya bila ditambahkan ke back-stack aktivitas, berbagi
+kejadian dengan aktivitas, dan fragmen lain dalam aktivitas, berkontribusi pada action-bar
+aktivitas, dan lainnya.</p>
+
+
+<h2 id="Design">Filosofi Desain</h2>
+
+<p>Android memperkenalkan fragmen di Android 3.0 (API level 11), terutama untuk mendukung desain UI yang lebih
+dinamis dan fleksibel pada layar besar, seperti tablet. Karena
+layar tablet jauh lebih besar daripada layar handset, maka lebih banyak ruang untuk mengombinasikan dan
+bertukar komponen UI. Fragmen memungkinkan desain seperti itu tanpa perlu mengelola perubahan
+kompleks pada hierarki tampilan. Dengan membagi layout aktivitas menjadi beberapa fragmen, Anda bisa
+mengubah penampilan aktivitas saat runtime dan mempertahankan perubahan itu di back-stack
+yang dikelola oleh aktivitas.</p>
+
+<p>Misalnya, aplikasi berita bisa menggunakan satu fragmen untuk menampilkan daftar artikel di
+sebelah kiri dan fragmen lainnya untuk menampilkan artikel di sebelah kanan&mdash;kedua fragmen ini muncul di satu
+aktivitas, berdampingan, dan masing-masing fragmen memiliki serangkaian metode callback daur hidup dan menangani kejadian input
+penggunanya sendiri. Sehingga, sebagai ganti menggunakan satu aktivitas untuk memilih
+artikel dan aktivitas lainnya untuk membaca artikel, pengguna bisa memilih artikel dan membaca semuanya dalam
+aktivitas yang sama, sebagaimana diilustrasikan dalam layout tablet pada gambar 1.</p>
+
+<p>Anda harus mendesain masing-masing fragmen sebagai komponen aktivitas modular dan bisa digunakan kembali. Yakni, karena
+setiap fragmen mendefinisikan layoutnya dan perilakunya dengan callback daur hidupnya sendiri, Anda bisa memasukkan
+satu fragmen dalam banyak aktivitas, sehingga Anda harus mendesainnya untuk digunakan kembali dan mencegah
+memanipulasi satu fragmen dari fragmen lain secara langsung. Ini terutama penting karena dengan
+fragmen modular Anda bisa mengubah kombinasi fragmen untuk ukuran layar berbeda. Saat mendesain aplikasi
+untuk mendukung tablet maupun handset, Anda bisa menggunakan kembali fragmen dalam
+konfigurasi layout berbeda untuk mengoptimalkan pengalaman pengguna berdasarkan ruang layar yang tersedia. Misalnya
+, pada handset, fragmen mungkin perlu dipisahkan untuk menyediakan UI panel tunggal
+bila lebih dari satu yang tidak cocok dalam aktivitas yang sama.</p>
+
+<img src="{@docRoot}images/fundamentals/fragments.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Contoh cara dua modul UI yang didefinisikan oleh
+ fragmen bisa digabungkan ke dalam satu aktivitas untuk desain tablet, namun dipisahkan untuk
+desain handset.</p>
+
+<p>Misalnya&mdash;untuk melanjutkan contoh aplikasi berita&mdash; aplikasi bisa menanamkan
+dua fragmen dalam <em>Aktivitas A</em>, saat berjalan pada perangkat berukuran tablet. Akan tetapi, pada
+layar berukuran handset, ruang untuk kedua fragmen tidak cukup, sehingga <em>Aktivitas A</em> hanya
+menyertakan fragmen untuk daftar artikel, dan saat pengguna memilih artikel,
+<em>Aktivitas B</em> akan dimulai, termasuk fragmen kedua untuk membaca artikel. Sehingga, aplikasi mendukung
+tablet dan handset dengan menggunakan kembali fragmen dalam kombinasi berbeda, seperti diilustrasikan dalam
+gambar 1.</p>
+
+<p>Untuk informasi selengkapnya tentang mendesain aplikasi menggunakan kombinasi fragmen berbeda
+untuk konfigurasi layar berbeda, lihat panduan untuk <a href="{@docRoot}guide/practices/tablets-and-handsets.html">Mendukung Tablet dan Handset</a>.</p>
+
+
+
+<h2 id="Creating">Membuat Fragmen</h2>
+
+<div class="figure" style="width:327px">
+<img src="{@docRoot}images/fragment_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup fragmen (saat
+ aktivitasnya berjalan).</p>
+</div>
+
+<p>Untuk membuat fragmen, Anda harus membuat subkelas {@link android.app.Fragment} (atau
+subkelasnya yang ada). Kelas {@link android.app.Fragment} memiliki kode yang mirip seperti
+{@link android.app.Activity}. Kelas ini memiliki metode callback yang serupa dengan aktivitas, seperti
+ {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()},
+{@link android.app.Fragment#onPause onPause()}, dan {@link android.app.Fragment#onStop onStop()}. Sebenarnya
+, jika Anda mengkonversi aplikasi Android saat ini untuk menggunakan fragmen, Anda mungkin cukup memindahkan
+kode dari metode callback aktivitas ke masing-masing metode callback
+fragmen.</p>
+
+<p>Biasanya, Anda harus mengimplementasikan setidaknya metode daur hidup berikut ini:</p>
+
+<dl>
+  <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
+  <dd>Sistem akan memanggilnya saat membuat fragmen. Dalam implementasi, Anda harus
+menginisialisasi komponen penting dari fragmen yang ingin dipertahankan saat fragmen
+dihentikan sementara atau dihentikan, kemudian dilanjutkan.</dd>
+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+  <dd>Sistem akan memanggilnya saat fragmen menggambar antarmuka penggunanya
+untuk yang pertama kali. Untuk menggambar UI fragmen, Anda harus mengembalikan {@link android.view.View} dari metode
+ini yang menjadi akar layout fragmen. Hasil yang dikembalikan bisa berupa null jika
+fragmen tidak menyediakan UI.</dd>
+  <dt>{@link android.app.Activity#onPause onPause()}</dt>
+  <dd>Sistem akan memanggil metode ini sebagai indikasi pertama bahwa pengguna sedang meninggalkan
+fragmen Anda (walau itu tidak selalu berarti fragmen sedang dimusnahkan). Inilah biasanya tempat Anda
+harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena
+pengguna mungkin tidak kembali).</dd>
+</dl>
+
+<p>Kebanyakan aplikasi harus mengimplementasikan setidaknya tiga metode ini untuk setiap fragmen, namun ada
+beberapa metode callback lain yang juga harus Anda gunakan untuk menangani berbagai tahap
+daur hidup fragmen. Semua metode callback daur hidup akan dibahas secara lebih detail, di bagian
+tentang <a href="#Lifecycle">Menangani Daur Hidup Fragmen</a>.</p>
+
+
+<p>Ada juga beberapa subkelas yang mungkin ingin diperpanjang, sebagai ganti kelas basis {@link
+android.app.Fragment}:</p>
+
+<dl>
+  <dt>{@link android.app.DialogFragment}</dt>
+  <dd>Menampilkan dialog mengambang. Penggunaan kelas ini untuk membuat dialog merupakan alternatif yang baik dari
+penggunaan metode helper dialog di kelas {@link android.app.Activity}, karena Anda bisa
+menyatukan dialog fragmen ke dalam back-stack fragmen yang dikelola oleh aktivitas,
+sehingga pengguna bisa kembali ke fragmen yang ditinggalkan.</dd>
+
+  <dt>{@link android.app.ListFragment}</dt>
+  <dd>Menampilkan daftar item yang dikelola oleh adaptor (seperti {@link
+android.widget.SimpleCursorAdapter}), serupa dengan {@link android.app.ListActivity}. Menampilkan
+beberapa metode pengelolaan daftar tampilan seperti callback {@link
+android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} untuk
+menangani kejadian klik.</dd>
+
+  <dt>{@link android.preference.PreferenceFragment}</dt>
+  <dd>Menampilkan hierarki objek {@link android.preference.Preference} sebagai daftar, serupa dengan
+{@link android.preference.PreferenceActivity}. Hal ini berguna saat membuat aktivitas
+"pengaturan" untuk aplikasi Anda.</dd>
+</dl>
+
+
+<h3 id="UI">Menambahkan antarmuka pengguna</h3>
+
+<p>Fragmen biasanya digunakan sebagai bagian dari antarmuka pengguna aktivitas dan menyumbangkan
+layoutnya sendiri ke aktivitas.</p>
+
+<p>Untuk menyediakan layout fragmen, Anda harus mengimplementasikan metode callback {@link
+android.app.Fragment#onCreateView onCreateView()}, yang dipanggil sistem Android
+bila tiba saatnya fragmen menggambar layoutnya. Implementasi Anda atas metode ini harus mengembalikan
+{@link android.view.View} yang menjadi akar layout fragmen.</p>
+
+<p class="note"><strong>Catatan:</strong> Jika fragmen adalah subkelas {@link
+android.app.ListFragment}, implementasi default akan mengembalikan {@link android.widget.ListView} dari
+{@link android.app.Fragment#onCreateView onCreateView()}, sehingga Anda tidak perlu mengimplementasikannya.</p>
+
+<p>Untuk mengembalikan layout dari {@link
+android.app.Fragment#onCreateView onCreateView()}, Anda bisa memekarkannya dari <a href="{@docRoot}guide/topics/resources/layout-resource.html">sumber daya layout</a> yang didefinisikan di XML. Untuk
+membantu melakukannya, {@link android.app.Fragment#onCreateView onCreateView()} menyediakan objek
+{@link android.view.LayoutInflater}.</p>
+
+<p>Misalnya, ini adalah subkelas {@link android.app.Fragment} yang memuat layout dari file
+{@code example_fragment.xml}:</p>
+
+<pre>
+public static class ExampleFragment extends Fragment {
+    &#64;Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        return inflater.inflate(R.layout.example_fragment, container, false);
+    }
+}
+</pre>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h3>Membuat layout</h3>
+  <p>Dalam contoh di atas, {@code R.layout.example_fragment} merupakan acuan ke sumber daya layout
+bernama {@code example_fragment.xml} yang tersimpan dalam sumber daya aplikasi. Untuk informasi tentang cara
+membuat layout di XML, lihat dokumentasi
+<a href="{@docRoot}guide/topics/ui/index.html">Antarmuka Pengguna</a>.</p>
+</div>
+</div>
+
+<p>Parameter {@code container} yang diteruskan ke {@link android.app.Fragment#onCreateView
+onCreateView()} adalah induk {@link android.view.ViewGroup} (dari layout aktivitas) tempat
+layout fragmen
+akan disisipkan. Parameter {@code savedInstanceState} adalah {@link android.os.Bundle} yang
+menyediakan data tentang instance fragmen sebelumnya, jika fragmen dilanjutkan
+(status pemulihan dibahas selengkapnya di bagian tentang <a href="#Lifecycle">Menangani
+Daur Hidup Fragmen</a>).</p>
+
+<p>Metode {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} membutuhkan
+tiga argumen:</p>
+<ul>
+  <li>ID sumber daya layout yang ingin dimekarkan.</li>
+  <li>{@link android.view.ViewGroup} akan menjadi induk dari layout yang dimekarkan. {@code
+container} perlu diteruskan agar sistem menerapkan parameter layout ke tampilan akar layout
+yang dimekarkan, yang ditetapkan dalam tampilan induk yang akan dituju.</li>
+  <li>Boolean yang menunjukkan apakah layout akan dimekarkan harus ditempelkan pada {@link
+android.view.ViewGroup} (parameter kedua) selama pemekaran. (Dalam hal ini, ini
+salah karena sistem sudah memasukkan layout yang dimekarkan ke dalam {@code
+container}&mdash;meneruskan benar akan membuat tampilan grup yang berlebihan dalam layout akhir.)</li>
+</ul>
+
+<p>Anda kini telah melihat cara membuat fragmen yang menyediakan layout. Berikutnya, Anda perlu menambahkan
+fragmen ke aktivitas.</p>
+
+
+
+<h3 id="Adding">Menambahkan fragmen ke aktivitas</h3>
+
+<p>Biasanya, fragmen berkontribusi pada sebagian UI ke aktivitas host, yang ditanamkan sebagai
+bagian dari hierarki tampilan keseluruhan aktivitas. Ada dua cara untuk menambahkan fragmen ke layout
+aktivitas:</p>
+
+<ul>
+  <li><b>Deklarasikan fragmen dalam file layout aktivitas.</b>
+<p>Dalam hal ini, Anda bisa
+menetapkan properti layout fragmen seakan-akan sebuah tampilan. Misalnya, berikut ini adalah file
+layout untuk aktivitas dengan dua fragmen:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+    &lt;fragment android:name="com.example.news.ArticleListFragment"
+            android:id="@+id/list"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" /&gt;
+    &lt;fragment android:name="com.example.news.ArticleReaderFragment"
+            android:id="@+id/viewer"
+            android:layout_weight="2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" /&gt;
+&lt;/LinearLayout&gt;
+</pre>
+  <p>Atribut {@code android:name} dalam {@code &lt;fragment&gt;} menetapkan kelas {@link
+android.app.Fragment} untuk dibuat instance-nya dalam layout.</p>
+
+<p>Saat sistem membuat layout aktivitas, sistem membuat instance setiap fragmen sebagaimana yang ditetapkan dalam layout
+dan memanggil metode {@link android.app.Fragment#onCreateView onCreateView()} masing-masing,
+untuk mengambil setiap fragmen. Sistem akan menyisipkan {@link android.view.View} yang dikembalikan langsung oleh fragmen,
+ menggantikan elemen {@code &lt;fragment&gt;}.</p>
+
+<div class="note">
+  <p><strong>Catatan:</strong> Setiap fragmen memerlukan identifier
+unik yang bisa digunakan sistem untuk memulihkan fragmen jika aktivitas dimulai kembali (dan identifier yang bisa digunakan menangkap
+fragmen untuk melakukan transaksi, seperti menghapusnya). Ada tiga cara untuk memberikan
+ID bagi fragmen:</p>
+  <ul>
+    <li>Memberikan atribut {@code android:id} bersama ID unik.</li>
+    <li>Memberikan atribut {@code android:tag} bersama string unik.</li>
+    <li>Jika Anda tidak memberikan dua hal tersebut, sistem akan menggunakan ID
+tampilan kontainer.</li>
+  </ul>
+</div>
+  </li>
+
+  <li><b>Atau, secara programatis tambahkan fragmen ke {@link android.view.ViewGroup} yang ada.</b>
+<p>Kapan saja saat aktivitas berjalan, Anda bisa menambahkan fragmen ke layout aktivitas. Anda
+cukup menetapkan {@link
+android.view.ViewGroup} di tempat memasukkan fragmen.</p>
+  <p>Untuk membuat transaksi fragmen dalam aktivitas (seperti menambah, menghapus, atau mengganti
+fragmen), Anda harus menggunakan API dari {@link android.app.FragmentTransaction}. Anda bisa mengambil instance
+ {@link android.app.FragmentTransaction} dari {@link android.app.Activity} seperti ini:</p>
+
+<pre>
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
+</pre>
+
+<p>Selanjutnya Anda bisa menambahkan fragmen menggunakan metode {@link
+android.app.FragmentTransaction#add(int,Fragment) add()}, dengan menetapkan fragmen yang akan ditambahkan dan
+tampilan tempat menyisipkannya. Misalnya:</p>
+
+<pre>
+ExampleFragment fragment = new ExampleFragment();
+fragmentTransaction.add(R.id.fragment_container, fragment);
+fragmentTransaction.commit();
+</pre>
+
+  <p>Argumen pertama yang diteruskan ke {@link android.app.FragmentTransaction#add(int,Fragment) add()}
+ adalah {@link android.view.ViewGroup} tempat fragmen harus dimasukkan, yang ditetapkan oleh
+ID sumber daya, dan parameter kedua merupakan fragmen yang akan ditambahkan.</p>
+  <p>Setelah membuat perubahan dengan
+{@link android.app.FragmentTransaction}, Anda harus
+ memanggil {@link android.app.FragmentTransaction#commit} untuk menerapkan perubahan.</p>
+  </li>
+</ul>
+
+
+<h4 id="AddingWithoutUI">Menambahkan fragmen tanpa UI</h4>
+
+<p>Contoh di atas menampilkan cara menambahkan fragmen ke aktivitas untuk menyediakan UI. Akan tetapi,
+Anda juga bisa menggunakan fragmen untuk menyediakan perilaku latar belakang bagi aktivitas tanpa menampilkan UI
+tambahan.</p>
+
+<p>Untuk menambahkan fragmen tanpa UI, tambahkan fragmen dari aktivitas menggunakan {@link
+android.app.FragmentTransaction#add(Fragment,String)} (dengan menyediakan string unik "tag" untuk fragmen
+, bukan ID tampilan). Ini akan menambahkan fragmen, namun, karena tidak dikaitkan dengan tampilan
+dalam layout aktivitas, ini tidak akan menerima panggilan ke {@link
+android.app.Fragment#onCreateView onCreateView()}. Jadi Anda tidak perlu mengimplementasikan metode itu.</p>
+
+<p>Menyediakan tag string untuk fragmen tidak hanya untuk fragmen non-UI&mdash;Anda juga bisa
+menyediakan tag string untuk fragmen yang memiliki UI&mdash;namun jika fragmen tidak memiliki UI
+, maka tag string adalah satu-satunya cara untuk mengidentifikasinya. Jika Anda ingin mendapatkan fragmen dari
+aktivitas nantinya, Anda perlu menggunakan {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()}.</p>
+
+<p>Untuk contoh aktivitas yang menggunakan fragmen sebagai pekerja latar belakang, tanpa UI, lihat sampel {@code
+FragmentRetainInstance.java}, yang disertakan dalam sampel SDK (tersedia melalui
+Android SDK Manager) dan terletak di sistem Anda sebagai
+<code>&lt;sdk_root&gt;/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java</code>.</p>
+
+
+
+<h2 id="Managing">Mengelola Fragmen</h2>
+
+<p>Untuk mengelola fragmen dalam aktivitas, Anda perlu menggunakan {@link android.app.FragmentManager}. Untuk
+mendapatkannya, panggil {@link android.app.Activity#getFragmentManager()} dari aktivitas Anda.</p>
+
+<p>Beberapa hal yang dapat Anda lakukan dengan {@link android.app.FragmentManager} antara lain:</p>
+
+<ul>
+  <li>Dapatkan fragmen yang ada di aktivitas dengan {@link
+android.app.FragmentManager#findFragmentById findFragmentById()} (untuk fragmen yang menyediakan UI dalam
+layout aktivitas) atau {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()} (untuk fragmen yang menyediakan atau tidak menyediakan UI).</li>
+  <li>Tarik fragmen dari back-stack, dengan {@link
+android.app.FragmentManager#popBackStack()} (mensimulasikan perintah <em>Back</em> oleh pengguna).</li>
+  <li>Daftarkan listener untuk perubahan pada back-stack, dengan {@link
+android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li>
+</ul>
+
+<p>Untuk informasi selengkapnya tentang metode ini dan hal lainnya, lihat dokumentasi kelas {@link
+android.app.FragmentManager}.</p>
+
+<p>Seperti yang ditunjukkan di bagian sebelumnya, Anda juga bisa menggunakan {@link android.app.FragmentManager}
+untuk membuka {@link android.app.FragmentTransaction}, sehingga Anda bisa melakukan transaksi, seperti
+menambah dan menghapus fragmen.</p>
+
+
+<h2 id="Transactions">Melakukan Transaksi Fragmen</h2>
+
+<p>Fitur menarik terkait penggunaan fragmen di aktivitas adalah kemampuan menambah, menghapus, mengganti,
+dan melakukan tindakan lain dengannya, sebagai respons atas interaksi pengguna. Setiap set perubahan
+yang Anda lakukan untuk aktivitas disebut transaksi dan Anda bisa melakukan transaksi menggunakan API di {@link
+android.app.FragmentTransaction}. Anda juga bisa menyimpan setiap transaksi ke back-stack yang dikelola
+aktivitas, sehingga pengguna bisa mengarah mundur melalui perubahan fragmen (mirip mengarah
+mundur melalui aktivitas).</p>
+
+<p>Anda bisa mengambil instance {@link android.app.FragmentTransaction} dari {@link
+android.app.FragmentManager} seperti ini:</p>
+
+<pre>
+FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
+FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};
+</pre>
+
+<p>Setiap transaksi merupakan serangkaian perubahan yang ingin dilakukan pada waktu yang sama. Anda bisa
+mengatur semua perubahan yang ingin dilakukan untuk transaksi mana saja menggunakan metode seperti {@link
+android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()},
+dan {@link android.app.FragmentTransaction#replace replace()}. Kemudian, untuk menerapkan transaksi
+pada aktivitas, Anda harus memanggil {@link android.app.FragmentTransaction#commit()}.</p>
+</dl>
+
+<p>Akan tetapi, sebelum memanggil {@link
+android.app.FragmentTransaction#commit()}, Anda mungkin perlu memanggil {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, untuk menambahkan transaksi
+ke back-stack dari transaksi fragmen. Back-stack ini dikelola oleh aktivitas dan memungkinkan
+pengguna kembali ke status fragmen sebelumnya, dengan menekan tombol <em>Back</em>.</p>
+
+<p>Misalnya, berikut ini cara mengganti satu fragmen dengan yang fragmen yang lain, dan mempertahankan
+status sebelumnya di back-stack:</p>
+
+<pre>
+// Create new fragment and transaction
+Fragment newFragment = new ExampleFragment();
+FragmentTransaction transaction = getFragmentManager().beginTransaction();
+
+// Replace whatever is in the fragment_container view with this fragment,
+// and add the transaction to the back stack
+transaction.replace(R.id.fragment_container, newFragment);
+transaction.addToBackStack(null);
+
+// Commit the transaction
+transaction.commit();
+</pre>
+
+<p>Dalam contoh ini, {@code newFragment} menggantikan fragmen apa saja (jika ada) yang saat ini berada dalam
+kontainer layout yang diidentifikasi oleh ID {@code R.id.fragment_container}. Dengan memanggil @link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, transaksi yang diganti
+disimpan ke back-stack sehingga pengguna bisa membalikkan transaksi dan mengembalikan fragmen
+sebelumnya dengan menekan tombol <em>Back</em>.</p>
+
+<p>Jika Anda menambahkan beberapa perubahan pada transaksi (seperti {@link
+android.app.FragmentTransaction#add add()} atau {@link android.app.FragmentTransaction#remove
+remove()}) dan panggil {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()}, maka semua perubahan akan diterapkan
+sebelum Anda memanggil {@link android.app.FragmentTransaction#commit commit()} akan ditambahkan ke
+back-stack sebagai satu transaksi dan tombol <em>Back</em> akan membalikannya semua.</p>
+
+<p>Urutan menambahkan perubahan pada {@link android.app.FragmentTransaction} tidak berpengaruh,
+kecuali:</p>
+<ul>
+  <li>Anda harus memanggil {@link android.app.FragmentTransaction#commit()} paling akhir</li>
+  <li>Jika Anda menambahkan beberapa fragmen ke kontainer yang sama, maka
+urutan penambahannya akan menentukan urutan munculnya dalam hierarki tampilan</li>
+</ul>
+
+<p>Jika Anda tidak memanggil {@link android.app.FragmentTransaction#addToBackStack(String)
+addToBackStack()} saat melakukan transaksi yang menghapus fragmen, maka fragmen itu
+akan dimusnahkan bila transaksi diikat dan pengguna tidak bisa mengarah kembali ke sana. Sedangkan, jika
+Anda memanggil {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} saat
+menghapus fragmen, maka fragmen itu akan <em>dihentikan</em> dan akan dilanjutkan jika pengguna mengarah
+kembali.</p>
+
+<p class="note"><strong>Tip:</strong> Untuk setiap transaksi fragmen, Anda bisa menerapkan animasi
+transisi, dengan memanggil {@link android.app.FragmentTransaction#setTransition setTransition()} sebelum
+mengikatnya.</p>
+
+<p>Memanggil {@link android.app.FragmentTransaction#commit()} tidak akan langsung menjalankan
+transaksi. Namun sebuah jadwal akan dibuat untuk dijalankan pada thread UI aktivitas (thread "utama")
+begitu thread bisa melakukannya. Akan tetapi, jika perlu Anda bisa memanggil {@link
+android.app.FragmentManager#executePendingTransactions()} dari thread UI untuk segera
+mengeksekusi transaksi yang diserahkan oleh {@link android.app.FragmentTransaction#commit()}. Hal itu
+biasanya tidak perlu kecuali jika transaksi merupakan dependensi bagi pekerjaan dalam thread lain.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Anda bisa mengikat transaksi menggunakan {@link
+android.app.FragmentTransaction#commit commit()} hanya sebelum aktivitas <a href="{@docRoot}guide/components/activities.html#SavingActivityState">menyimpan
+statusnya</a> (saat pengguna meninggalkan aktivitas). Jika Anda mencoba mengikatnya setelah itu,
+eksepsi akan dilontarkan. Ini karena status setelah pengikatan bisa hilang jika aktivitas
+perlu dipulihkan. Untuk situasi yang memperbolehkan Anda meniadakan pengikatan (commit), gunakan {@link
+android.app.FragmentTransaction#commitAllowingStateLoss()}.</p>
+
+
+
+
+<h2 id="CommunicatingWithActivity">Berkomunikasi dengan Aktivitas</h2>
+
+<p>Meskipun {@link android.app.Fragment} diimplementasikan sebagai objek yang tidak bergantung pada
+{@link android.app.Activity} dan bisa digunakan dalam banyak aktivitas, instance tertentu
+dari fragmen secara langsung terkait dengan aktivitas yang dimuatnya.</p>
+
+<p>Khususnya, fragmen bisa mengakses instance {@link android.app.Activity} dengan {@link
+android.app.Fragment#getActivity()} dan dengan mudah melakukan tugas-tugas seperti mencari tampilan dalam
+ layout aktivitas:</p>
+
+<pre>
+View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
+</pre>
+
+<p>Demikian pula, aktivitas Anda bisa memanggil metode di fragmen dengan meminta acuan ke
+{@link android.app.Fragment} dari {@link android.app.FragmentManager}, menggunakan {@link
+android.app.FragmentManager#findFragmentById findFragmentById()} atau {@link
+android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. Misalnya:</p>
+
+<pre>
+ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
+</pre>
+
+
+<h3 id="EventCallbacks">Membuat callback kejadian pada aktivitas</h3>
+
+<p>Dalam beberapa kasus, Anda mungkin perlu fragmen untuk berbagi kejadian dengan aktivitas. Cara yang baik untuk melakukannya
+adalah mendefinisikan antarmuka callback di dalam fragmen dan mengharuskan aktivitas host
+mengimplementasikannya. Saat aktivitas menerima callback melalui antarmuka, aktivitas akan bisa berbagi informasi itu
+dengan fragmen lain dalam layout jika perlu.</p>
+
+<p>Misalnya, jika sebuah aplikasi berita memiliki dua fragmen dalam aktivitas&mdash;satu untuk menampilkan daftar
+artikel (fragmen A) dan satu lagi untuk menampilkan artikel (fragmen B)&mdash;maka fragmen A harus
+memberi tahu aktivitas bila item daftar dipilih sehingga aktivitas bisa memberi tahu fragmen B untuk menampilkan artikel. Dalam
+hal ini, antarmuka {@code OnArticleSelectedListener} dideklarasikan di dalam fragmen A:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    ...
+    // Container Activity must implement this interface
+    public interface OnArticleSelectedListener {
+        public void onArticleSelected(Uri articleUri);
+    }
+    ...
+}
+</pre>
+
+<p>Selanjutnya aktivitas yang menjadi host fragmen akan mengimplementasikan antarmuka {@code OnArticleSelectedListener}
+ dan
+mengesampingkan {@code onArticleSelected()} untuk memberi tahu fragmen B mengenai kejadian dari fragmen A. Untuk memastikan
+bahwa aktivitas host mengimplementasikan antarmuka ini, metode callback fragmen A {@link
+android.app.Fragment#onAttach onAttach()} (yang dipanggil sistem saat menambahkan
+fragmen ke aktivitas) membuat instance {@code OnArticleSelectedListener} dengan
+membuat {@link android.app.Activity} yang diteruskan ke {@link android.app.Fragment#onAttach
+onAttach()}:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    OnArticleSelectedListener mListener;
+    ...
+    &#64;Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mListener = (OnArticleSelectedListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
+        }
+    }
+    ...
+}
+</pre>
+
+<p>Jika aktivitas belum mengimplementasikan antarmuka, maka fragmen akan melontarkan
+{@link java.lang.ClassCastException}.
+Jika berhasil, anggota {@code mListener} yang menyimpan acuan ke implementasi aktivitas
+{@code OnArticleSelectedListener}, sehingga fragmen A bisa berbagi kejadian dengan aktivitas, dengan memanggil metode
+yang didefinisikan oleh antarmuka {@code OnArticleSelectedListener}. Misalnya, jika fragmen A adalah
+ekstensi dari {@link android.app.ListFragment}, maka setiap kali
+pengguna mengklik item daftar, sistem akan memanggil {@link android.app.ListFragment#onListItemClick
+onListItemClick()} di fragmen, yang selanjutnya memanggil {@code onArticleSelected()} untuk berbagi
+kejadian dengan aktivitas:</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+    OnArticleSelectedListener mListener;
+    ...
+    &#64;Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        // Append the clicked item's row ID with the content provider Uri
+        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
+        // Send the event and Uri to the host activity
+        mListener.onArticleSelected(noteUri);
+    }
+    ...
+}
+</pre>
+
+<p>Parameter {@code id} yang diteruskan ke {@link
+android.app.ListFragment#onListItemClick onListItemClick()} merupakan ID baris dari item yang diklik,
+yang digunakan aktivitas (atau fragmen lain) untuk mengambil artikel dari {@link
+android.content.ContentProvider} aplikasi.</p>
+
+<p><!--To see a complete implementation of this kind of callback interface, see the <a
+href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->Informasi selengkapnya tentang
+menggunakan penyedia konten tersedia dalam dokumen <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
+
+
+
+<h3 id="ActionBar">Menambahkan item ke Action-Bar</h3>
+
+<p>Fragmen Anda bisa menyumbangkan item menu ke <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Menu Opsi</a> aktivitas (dan, konsekuensinya, <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>) dengan mengimplementasikan
+{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. Agar
+metode ini bisa menerima panggilan, Anda harus memanggil {@link
+android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} selama {@link
+android.app.Fragment#onCreate(Bundle) onCreate()}, untuk menunjukkan bahwa fragmen
+ingin menambahkan item ke Menu Opsi (jika tidak, fragmen tidak akan menerima panggilan ke
+{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).</p>
+
+<p>Setiap item yang selanjutnya Anda tambahkan ke Menu Opsi dari fragmen akan ditambahkan ke item menu
+yang ada. Fragmen juga menerima callback ke {@link
+android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} bila item menu
+dipilih.</p>
+
+<p>Anda juga bisa mendaftarkan tampilan dalam layout fragmen untuk menyediakan menu konteks dengan memanggil {@link
+android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. Bila pengguna
+membuka menu konteks, fragmen akan menerima panggilan ke {@link
+android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo)
+onCreateContextMenu()}. Bila pengguna memilih item, fragmen akan menerima panggilan ke @link
+android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
+
+<p class="note"><strong>Catatan:</strong> Walaupun fragmen menerima callback pada item yang dipilih
+untuk setiap item menu yang ditambahkannya, aktivitaslah yang pertama kali menerima masing-masing callback saat pengguna
+memilih item menu. Jika implementasi aktivitas dari callback bila-item-dipilih,
+tidak menangani item yang dipilih, maka kejadian akan diteruskan ke callback fragmen. Ini berlaku
+untuk Menu Opsi dan menu konteks.</p>
+
+<p>Untuk informasi selengkapnya tentang menu, lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html">Menu</a> dan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>.</p>
+
+
+
+
+<h2 id="Lifecycle">Menangani Daur Hidup Fragmen</h2>
+
+<div class="figure" style="width:350px">
+<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Gambar 3.</strong> Efek daur hidup aktivitas pada daur hidup
+fragmen.</p>
+</div>
+
+<p>Mengelola daur hidup fragmen mirip sekali dengan mengelola daur hidup aktivitas. Seperti
+aktivitas, fragmen bisa berada dalam tiga status:</p>
+
+<dl>
+  <dt><i>Dilanjutkan</i></dt>
+    <dd>Fragmen terlihat dalam aktivitas yang berjalan.</dd>
+
+  <dt><i>Dihentikan sementara</i></dt>
+    <dd>Aktivitas lain berada di latar depan dan memiliki fokus, namun aktivitas tempat fragmen berada
+masih terlihat (aktivitas latar depan sebagian terlihat atau tidak menutupi
+seluruh layar).</dd>
+
+  <dt><i>Dihentikan</i></dt>
+    <dd>Fragmen tidak terlihat. Aktivitas host telah dihentikan atau
+fragmen telah dihapus dari aktivitas namun ditambahkan ke back-stack. Fragmen yang dihentikan
+masih hidup (semua status dan informasi anggota masih disimpan oleh sistem). Akan tetapi, fragmen
+tidak terlihat lagi oleh pengguna dan akan dimatikan jika aktivitas dimatikan.</dd>
+</dl>
+
+<p>Seperti halnya aktivitas, Anda bisa mempertahankan status fragmen menggunakan {@link
+android.os.Bundle}, jika proses aktivitas dimatikan dan Anda harus memulihkan status
+fragmen bila aktivitas dibuat kembali. Anda bisa menyimpan status selama callback {@link
+android.app.Fragment#onSaveInstanceState onSaveInstanceState()} fragmen dan memulihkannya selama
+{@link android.app.Fragment#onCreate onCreate()}, {@link
+android.app.Fragment#onCreateView onCreateView()}, atau {@link
+android.app.Fragment#onActivityCreated onActivityCreated()}. Untuk informasi selengkapnya tentang menyimpan
+status, lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
+.</p>
+
+<p>Perbedaan paling signifikan dalam daur hidup antara aktivitas dan fragmen ada
+pada cara penyimpanannya dalam back-stack masing-masing. Aktivitas ditempatkan ke back-stack aktivitas
+yang dikelola oleh sistem saat dihentikan, secara default (sehingga pengguna bisa mengarah kembali
+ke aktivitas dengan tombol <em>Back</em>, seperti yang dibahas dalam <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tugas dan Back-Stack</a>).
+Akan tetapi, fragmen yang ditempatkan ke back-stack dikelola oleh aktivitas host hanya saat
+Anda secara eksplisit meminta agar instance disimpan dengan memanggil {@link
+android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} selama transaksi yang
+menghapus fragmen.</p>
+
+<p>Jika tidak, pengelolaan daur hidup fragmen mirip sekali dengan mengelola daur hidup
+aktivitas. Jadi, praktik yang sama untuk <a href="{@docRoot}guide/components/activities.html#Lifecycle">mengelola daur hidup
+aktivitas</a> juga berlaku untuk fragmen. Namun yang perlu juga Anda pahami adalah bagaimana hidup
+aktivitas memengaruhi hidup fragmen.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Jika Anda memerlukan objek {@link android.content.Context}
+ dalam {@link android.app.Fragment}, Anda bisa memanggil {@link android.app.Fragment#getActivity()}.
+Akan tetapi, berhati-hatilah memanggil {@link android.app.Fragment#getActivity()} hanya bila fragmen
+terkait dengan aktivitas. Bila fragmen belum terkait, atau terlepas selama akhir daur
+hidupnya, {@link android.app.Fragment#getActivity()} akan kembali nol.</p>
+
+
+<h3 id="CoordinatingWithActivity">Mengoordinasi dengan daur hidup aktivitas</h3>
+
+<p>Daur hidup aktivitas tempat fragmen berada akan memengaruhi langsung siklus hidup
+fragmen sedemikian rupa sehingga setiap callback daur hidup aktivitas menghasilkan callback yang sama untuk masing-masing
+fragmen. Misalnya, bila aktivitas menerima {@link android.app.Activity#onPause}, masing-masing
+fragmen dalam aktivitas akan menerima {@link android.app.Fragment#onPause}.</p>
+
+<p>Namun fragmen memiliki beberapa callback daur hidup ekstra, yang menangani interaksi
+unik dengan aktivitas untuk melakukan tindakan seperti membangun dan memusnahkan UI fragmen. Metode callback
+tambahan ini adalah:</p>
+
+<dl>
+  <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
+    <dd>Dipanggil bila fragmen telah dikaitkan dengan aktivitas ({@link
+android.app.Activity} diteruskan di sini).</dd>
+  <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+    <dd>Dipanggil untuk membuat hierarki tampilan yang dikaitkan dengan fragmen.</dd>
+  <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
+    <dd>Dipanggil bila metode {@link android.app.Activity#onCreate
+onCreate()} aktivitas telah dikembalikan.</dd>
+  <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt>
+    <dd>Dipanggil bila hierarki tampilan yang terkait dengan fragmen dihapus.</dd>
+  <dt>{@link android.app.Fragment#onDetach onDetach()}</dt>
+    <dd>Dipanggil bila fragmen diputuskan dari aktivitas.</dd>
+</dl>
+
+<p>Aliran daur hidup fragmen, karena dipengaruhi oleh aktivitas host-nya, diilustrasikan oleh
+gambar 3. Dalam gambar ini, Anda bisa melihat bagaimana setiap status aktivitas menentukan
+metode callback mana yang mungkin diterima fragmen. Misalnya, saat aktivitas menerima call back {@link
+android.app.Activity#onCreate onCreate()}, fragmen dalam aktivitas akan menerima tidak lebih
+dari callback {@link android.app.Fragment#onActivityCreated onActivityCreated()}.</p>
+
+<p>Setelah status aktivitas diteruskan kembali, Anda bisa bebas menambah dan menghapus fragmen untuk
+aktivitas tersebut. Sehingga, hanya saat aktivitas berada dalam status dilanjutkan, daur hidup fragmen bisa
+berubah secara independen.</p>
+
+<p>Akan tetapi, saat aktivitas meninggalkan status dilanjutkan, fragmen akan kembali didorong
+melalui daur hidupnya oleh aktivitas.</p>
+
+
+
+
+<h2 id="Example">Contoh</h2>
+
+<p>Untuk merangkum semua yang telah dibahas dalam dokumen ini, berikut ini contoh aktivitas
+yang menggunakan dua fragmen untuk membuat layout dua panel. Aktivitas di bawah ini menyertakan satu fragmen untuk
+menampilkan daftar putar Shakespeare dan fragmen lainnya menampilkan rangkuman pemutaran bila dipilih dari
+daftar. Aktivitas ini juga menunjukkan cara menyediakan konfigurasi fragmen berbeda,
+berdasarkan konfigurasi layar.</p>
+
+<p class="note"><strong>Catatan:</strong> Kode sumber lengkap untuk aktivitas ini tersedia di
+<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code
+FragmentLayout.java}</a>.</p>
+
+<p>Aktivitas utama akan menerapkan layout seperti biasa, selama {@link
+android.app.Activity#onCreate onCreate()}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}
+
+<p>Layout yang diterapkan adalah {@code fragment_layout.xml}:</p>
+
+{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}
+
+<p>Dengan layout ini, sistem akan membuat instance {@code TitlesFragment} (yang mencantumkan
+judul) segera setelah aktivitas memuat layout, sementara {@link android.widget.FrameLayout}
+ (lokasi penempatan fragmen untuk menampilkan rangkuman pemutaran) menempati ruang di sisi kanan
+layar, namun pada awalnya masih kosong. Seperti yang akan Anda lihat di bawah ini, sampai pengguna memilih item
+dari daftar maka fragmen baru akan ditempatkan ke dalam {@link android.widget.FrameLayout}.</p>
+
+<p>Akan tetapi, tidak semua konfigurasi layar cukup lebar untuk menampilkan
+daftar putar dan rangkuman secara berdampingan. Sehingga, layout di atas hanya digunakan untuk konfigurasi
+layar mendatar, dengan menyimpannya di {@code res/layout-land/fragment_layout.xml}.</p>
+
+<p>Sehingga, bila layar berada dalam orientasi tegak, sistem akan menerapkan layout berikut, yang
+tersimpan di {@code res/layout/fragment_layout.xml}:</p>
+
+{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout}
+
+<p>Layout ini hanya menyertakan {@code TitlesFragment}. Ini artinya saat perangkat berada dalam
+orientasi tegak, hanya judul daftar putar yang terlihat. Jadi, saat pengguna mengklik item
+daftar dalam konfigurasi ini, aplikasi akan memulai aktivitas baru untuk menampilkan rangkuman,
+sebagai ganti pemuatan fragmen kedua.</p>
+
+<p>Berikutnya, Anda bisa melihat bagaimana hal ini dilakukan dalam kelas fragmen. Pertama adalah {@code
+TitlesFragment}, yang menampilkan judul daftar putar Shakespeare. Fragmen ini membuat ekstensi {@link
+android.app.ListFragment} dan mengandalkannya itu untuk menangani sebagian besar pekerjaan tampilan daftar.</p>
+
+<p>Saat Anda memeriksa kode ini, perhatikan bahwa ada dua kemungkinan perilaku saat pengguna mengklik
+item daftar: bergantung pada layout mana yang aktif, bisa membuat dan menampilkan fragmen
+baru untuk menampilkan detail dalam aktivitas yang sama (menambahkan fragmen ke {@link
+android.widget.FrameLayout}), atau memulai aktivitas baru (tempat fragmen ditampilkan).</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}
+
+<p>Fragmen kedua, {@code DetailsFragment} menampilkan rangkuman pemutaran untuk item yang dipilih dari
+daftar dari {@code TitlesFragment}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}
+
+<p>Ingatlah dari kelas {@code TitlesFragment}, bahwa, jika pengguna mengklik item daftar dan
+layout saat ini <em>tidak</em> menyertakan tampilan {@code R.id.details} (yaitu tempat
+{@code DetailsFragment} berada), maka aplikasi memulai aktivitas {@code DetailsActivity}
+untuk menampilkan konten item.</p>
+
+<p>Berikut ini adalah {@code DetailsActivity}, yang hanya menanamkan {@code DetailsFragment} untuk menampilkan rangkuman pemutaran
+yang dipilih saat layar dalam orientasi tegak:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java
+details_activity}
+
+<p>Perhatikan bahwa aktivitas ini selesai sendiri jika konfigurasi mendatar, sehingga aktivitas utama
+bisa mengambil alih dan menampilkan {@code DetailsFragment} bersama {@code TitlesFragment}.
+Ini bisa terjadi jika pengguna memulai {@code DetailsActivity} saat dalam orientasi tegak, namun kemudian
+memutarnya menjadi mendatar (yang akan memulai lagi aktivitas saat ini).</p>
+
+
+<p>Untuk contoh lainnya mengenai penggunaan fragmen (dan file sumber lengkap untuk contoh ini),
+lihat aplikasi contoh Demo API yang tersedia di <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">
+ApiDemos</a> (bisa diunduh dari <a href="{@docRoot}resources/samples/get.html">Komponen contoh SDK</a>).</p>
+
+
diff --git a/docs/html-intl/intl/id/guide/components/fundamentals.jd b/docs/html-intl/intl/id/guide/components/fundamentals.jd
new file mode 100644
index 0000000..2c925e9
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/fundamentals.jd
@@ -0,0 +1,480 @@
+page.title=Dasar-Dasar Aplikasi
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+<li><a href="#Components">Komponen Aplikasi</a>
+  <ol>
+    <li><a href="#ActivatingComponents">Mengaktifkan komponen</a></li>
+  </ol>
+</li>
+<li><a href="#Manifest">File Manifes</a>
+  <ol>
+    <li><a href="#DeclaringComponents">Mendeklarasikan komponen</a></li>
+    <li><a href="#DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</a></li>
+  </ol>
+</li>
+<li><a href="#Resources">Sumber Daya Aplikasi</a></li>
+</ol>
+</div>
+</div>
+
+<p>Aplikasi Android ditulis dalam bahasa pemrograman Java. Android SDK Tools mengkompilasi
+kode Anda&mdash;bersama data dan file sumber daya &mdash;ke dalam APK: <i>Paket Android</i>,
+yaitu file arsip berekstensi {@code .apk}. Satu file APK berisi semua konten
+aplikasi Android dan merupakan file yang digunakan perangkat berbasis Android untuk menginstal aplikasi.</p>
+
+<p>Setelah diinstal di perangkat, setiap aplikasi Android tinggal di sandbox keamanannya sendiri: </p>
+
+<ul>
+ <li>Sistem operasi Android merupakan sistem Linux multi-pengguna yang di dalamnya setiap
+aplikasi adalah pengguna berbeda.</li>
+
+<li>Secara default, sistem menetapkan ID pengguna Linux unik kepada setiap aplikasi (ID ini hanya
+ digunakan oleh sistem dan tidak diketahui aplikasi). Sistem menetapkan izin
+bagi semua file dalam aplikasi sehingga hanya ID pengguna yang diizinkan yang bisa mengaksesnya. </li>
+
+<li>Setiap proses memiliki mesin virtual (VM) sendiri, sehingga kode aplikasi yang berjalan secara terisolasi dari
+aplikasi lainnya.</li>
+
+<li>Secara default, setiap aplikasi berjalan dalam proses Linux-nya sendiri. Android memulai proses
+bila ada komponen aplikasi yang perlu dijalankan, kemudian mematikan proses bila tidak lagi diperlukan
+atau bila sistem harus memulihkan memori untuk digunakan aplikasi lain.</li>
+</ul>
+
+<p>Dengan cara ini, sistem Android mengimplementasikan <em>prinsip privilese minim</em>. Ini berarti,
+secara default aplikasi hanya memiliki akses ke komponen yang diperlukannya untuk melakukan pekerjaannya dan
+tidak lebih dari itu. Hal ini menghasilkan lingkungan yang sangat aman sehingga aplikasi tidak bisa mengakses bagian
+sistem bila tidak diberi izin.</p>
+
+<p>Akan tetapi, ada beberapa cara bagi aplikasi untuk berbagi data dengan aplikasi lain dan bagi aplikasi
+untuk mengakses layanan sistem:</p>
+
+<ul>
+  <li>Dua aplikasi bisa diatur untuk menggunakan ID pengguna Linux yang sama,
+dalam hal ini keduanya bisa saling mengakses file masing-masing.  Untuk menghemat sumber daya sistem, aplikasi dengan ID
+pengguna yang sama juga bisa diatur agar berjalan dalam proses Linux yang sama dan menggunakan VM yang sama (
+aplikasi juga harus ditandatangani dengan sertifikat yang sama).</li>
+  <li>Aplikasi bisa meminta izin akses ke data perangkat seperti kontak
+pengguna, pesan SMS, penyimpanan lepas-pasang (kartu SD), kamera, Bluetooth, dan lainnya. Semua
+izin aplikasi harus diberikan oleh pengguna saat menginstal.</li>
+</ul>
+
+<p>Hal tersebut mencakup dasar-dasar tentang cara aplikasi Android berada di dalam sistem. Bagian dokumen
+selanjutnya memperkenalkan Anda pada:</p>
+<ul>
+  <li>Komponen kerangka kerja inti yang mendefinisikan aplikasi.</li>
+  <li>File manifes tempat Anda mendeklarasikan komponen dan fitur yang diperlukan perangkat
+untuk aplikasi.</li>
+  <li>Sumber daya yang terpisah dari kode aplikasi dan memungkinkan
+aplikasi mengoptimalkan perilakunya untuk beragam konfigurasi perangkat.</li>
+</ul>
+
+
+
+<h2 id="Components">Komponen Aplikasi</h2>
+
+<p>Komponen aplikasi adalah blok pembangun penting dari aplikasi Android.
+Setiap komponen merupakan titik berbeda yang digunakan sistem untuk memasuki aplikasi. Tidak semua komponen
+merupakan titik masuk sebenarnya bagi pengguna dan sebagian saling bergantung, namun masing-masing komponen tersedia
+sebagai kesatuan sendiri dan memainkan peran tertentu&mdash;masing-masing merupakan
+blok pembangun unik yang mendefinisikan perilaku aplikasi secara keseluruhan.</p>
+
+<p>Ada empat macam tipe komponen aplikasi. Setiap tipe memiliki kegunaan tersendiri
+dan daur hidupnya sendiri yang mendefinisikan cara komponen dibuat dan dimusnahkan.</p>
+
+<p>Berikut ini empat tipe komponen aplikasi:</p>
+
+<dl>
+
+<dt><b>Aktivitas</b></dt>
+
+<dd>Sebuah <i>aktivitas</i> mewakili satu layar dengan antarmuka pengguna. Misalnya,
+aplikasi email mungkin memiliki satu aktivitas yang menampilkan daftar email
+baru, aktivitas lain untuk menulis email, dan aktivitas satunya lagi untuk membaca email. Walaupun
+semua aktivitas bekerja sama untuk membentuk pengalaman pengguna yang kohesif dalam aplikasi email,
+masing-masing tidak saling bergantung. Karenanya, aplikasi berbeda bisa memulai
+salah satu aktivitas ini (jika aplikasi email mengizinkannya). Misalnya, aplikasi kamera bisa memulai
+aktivitas dalam aplikasi email yang membuat email baru agar pengguna bisa berbagi gambar.
+
+<p>Aktivitas diimplementasikan sebagai subkelas {@link android.app.Activity} dan Anda bisa mengetahui selengkapnya
+tentang hal ini dalam panduan pengembang <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
+.</p>
+</dd>
+
+
+<dt><b>Layanan</b></dt>
+
+<dd>Sebuah <i>layanan</i> adalah komponen yang berjalan di latar belakang untuk melakukan
+operasi yang berjalan lama atau untuk melakukan pekerjaan bagi proses jarak jauh. Layanan
+tidak menyediakan antarmuka pengguna. Misalnya, sebuah layanan bisa memutar musik di latar belakang sementara
+pengguna berada dalam aplikasi lain, atau layanan bisa menarik data lewat jaringan tanpa
+memblokir interaksi pengguna dengan aktivitas. Komponen lain, seperti aktivitas, bisa memulai
+layanan dan membiarkannya berjalan atau mengikat layanan untuk berinteraksi dengannya.
+
+<p>Layanan diimplementasikan sebagai subkelas {@link android.app.Service} dan Anda bisa mengetahui selengkapnya
+tentang hal ini dalam panduan
+pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
+</dd>
+
+
+<dt><b>Penyedia konten</b></dt>
+
+<dd>Sebuah <i>penyedia konten</i> mengelola seperangkat data-bersama aplikasi. Anda bisa menyimpan data
+dalam sistem file, database SQLite, di web, atau lokasi penyimpanan permanen lainnya
+yang bisa diakses aplikasi. Melalui penyedia konten, aplikasi lain bisa melakukan query atau bahkan
+memodifikasi data (jika penyedia konten mengizinkannya). Misalnya, sistem Android menyediakan penyedia
+konten yang mengelola informasi kontak pengguna. Karenanya, setiap aplikasi
+dengan izin yang sesuai bisa melakukan query mengenai bagian dari penyedia konten (seperti {@link
+android.provider.ContactsContract.Data}) untuk membaca dan menulis informasi tentang orang tertentu.
+
+<p>Penyedia konten juga berguna untuk membaca dan menulis data privat ke aplikasi Anda
+dan tidak dibagikan. Misalnya, aplikasi contoh <a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> menggunakan
+penyedia konten untuk menyimpan catatan.</p>
+
+<p>Penyedia konten diimplementasikan sebagai subkelas {@link android.content.ContentProvider}
+dan harus mengimplementasikan seperangkat standar API yang memungkinkan aplikasi
+lain melakukan transaksi. Untuk informasi selengkapnya, lihat panduan pengembang
+<a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
+</dd>
+
+
+<dt><b>Penerima siaran</b></dt>
+
+<dd>Sebuah <i>penerima siaran</i> adalah komponen yang merespons pengumuman siaran dalam lingkup
+sistem.  Banyak siaran yang berasal dari sistem&mdash;misalnya, siaran yang mengumumkan bahwa
+layar telah dimatikan, baterai lemah, atau gambar telah direkam.
+Aplikasi juga bisa memulai siaran&mdash;misalnya untuk menginformasikan ke
+aplikasi lain bahwa sebagian data telah diunduh ke perangkat dan bisa digunakan aplikasi lain tersebut. Walaupun penerima
+siaran tidak menampilkan antarmuka pengguna, penerima bisa <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">membuat pemberitahuan baris status</a>
+untuk memberi tahu pengguna kapan kejadian siaran dilakukan. Meskipun penerima siaran umumnya cuma menjadi
+"gerbang" untuk komponen lain dan dimaksudkan untuk melakukan pekerjaan dalam jumlah sangat minim. Misalnya
+, penerima siaran bisa menjalankan layanan untuk melakukan beberapa pekerjaan berdasarkan kejadian.
+
+<p>Penerima siaran diimplementasikan sebagai subkelas {@link android.content.BroadcastReceiver}
+dan setiap siaran dikirim sebagai objek {@link android.content.Intent}. Untuk informasi selengkapnya,
+lihat kelas {@link android.content.BroadcastReceiver}.</p>
+</dd>
+
+</dl>
+
+
+
+<p>Aspek unik dari desain sistem Android adalah aplikasi mana pun bisa memulai
+komponen aplikasi lain. Misalnya, jika Anda menginginkan pengguna mengambil
+foto dengan kamera perangkat, bisa saja aplikasi lain yang melakukannya dan aplikasi
+Anda bisa menggunakannya, sebagai ganti mengembangkan aktivitas sendiri untuk mengambil foto. Anda tidak
+harus menyatukan atau bahkan menautkan ke kode dari aplikasi kamera.
+Sebagai gantinya, Anda tinggal memulai aktivitas di aplikasi kamera yang akan mengambil
+foto. Bila selesai, foto akan dikembalikan ke aplikasi sehingga Anda bisa menggunakannya. Bagi pengguna,
+kamera seakan menjadi bagian dari aplikasi Anda.</p>
+
+<p>Saat sistem memulai komponen, sistem akan memulai proses untuk aplikasi itu (jika
+belum berjalan) dan membuat instance kelas yang diperlukan untuk komponen. Misalnya, jika aplikasi Anda
+memulai aktivitas dalam aplikasi kamera yang mengambil foto, aktivitas itu akan
+berjalan dalam proses yang dimiliki oleh aplikasi kamera, bukan dalam proses aplikasi Anda.
+Karenanya, tidak seperti aplikasi di sebagian besar sistem lain, aplikasi Android tidak memiliki titik
+masuk tunggal (misalnya tidak ada fungsi {@code main()}).</p>
+
+<p>Karena sistem menjalankan setiap aplikasi dalam proses terpisah dengan izin file yang
+membatasi akses ke aplikasi lain, aplikasi Anda tidak bisa langsung mengaktifkan komponen dari aplikasi lain. Akan tetapi, sistem
+Android bisa melakukannya. Jadi, untuk mengaktifkan
+komponen dalam aplikasi lain, Anda harus mengirim pesan ke sistem yang menetapkan <em>intent</em> Anda untuk memulai
+komponen tertentu. Selanjutnya sistem akan mengaktifkan komponen untuk Anda.</p>
+
+
+<h3 id="ActivatingComponents">Mengaktifkan Komponen</h3>
+
+<p>Tiga dari empat tipe komponen&mdash;aktivitas, layanan, dan
+penerima siaran&mdash;diaktifkan oleh pesan asinkron yang disebut <em>intent</em>.
+Intent saling mengikat setiap komponen saat runtime (Anda bisa menganggapnya
+sebagai pembawa pesan yang meminta tindakan dari komponen lain), baik komponen itu milik aplikasi Anda
+atau milik aplikasi lain.</p>
+
+<p>Intent dibuat dengan objek {@link android.content.Intent}, yang mendefinisikan pesan untuk
+mengaktifkan komponen tertentu atau komponen <em>tipe</em> komponen tertentu&mdash;masing-masing intent
+bisa eksplisit atau implisit.</p>
+
+<p>Untuk aktivitas dan layanan, intent mendefinisikan tindakan yang akan dilakukan (misalnya, untuk "melihat" atau
+"mengirim" sesuatu) dan mungkin menetapkan URI data untuk ditindaklanjuti (salah satu hal yang mungkin perlu diketahui
+oleh komponen yang akan dimulai). Misalnya, intent mungkin menyampaikan permintaan suatu
+aktivitas untuk menampilkan gambar atau membuka halaman web. Dalam beberapa kasus, Anda bisa memulai
+aktivitas untuk menerima hasil, dalam hal ini, aktivitas juga akan mengembalikan hasil
+dalam {@link android.content.Intent} (misalnya Anda bisa mengeluarkan intent agar
+pengguna bisa memilih kontak pribadi dan memintanya dikembalikan kepada Anda&mdash;intent yang dikembalikan menyertakan URI yang
+menunjuk ke kontak yang dipilih).</p>
+
+<p>Untuk penerima siaran, intent hanya mendefinisikan
+pengumuman yang sedang disiarkan (misalnya, siaran untuk menunjukkan baterai perangkat hampir habis
+hanya menyertakan string tindakan yang menunjukkan "baterai hampir habis").</p>
+
+<p>Tipe komponen lainnya dan penyedia konten, tidak diaktifkan oleh intent. Melainkan
+diaktifkan saat ditargetkan oleh permintaan dari {@link android.content.ContentResolver}. Resolver
+konten menangani semua transaksi langsung dengan penyedia konten sehingga komponen yang melakukan
+transaksi dengan penyedia tidak perlu dan sebagai gantinya memanggil metode pada objek {@link
+android.content.ContentResolver}. Ini membuat lapisan abstraksi antara penyedia
+konten dan komponen yang meminta informasi (demi keamanan).</p>
+
+<p>Ada beberapa metode terpisah untuk mengaktifkan masing-masing tipe komponen:</p>
+<ul>
+  <li>Anda bisa memulai aktivitas (atau memberinya pekerjaan baru) dengan
+meneruskan {@link android.content.Intent} ke {@link android.content.Context#startActivity
+startActivity()} atau {@link android.app.Activity#startActivityForResult startActivityForResult()}
+(bila Anda ingin aktivitas mengembalikan hasil).</li>
+  <li>Anda bisa memulai layanan (atau memberikan instruksi baru ke layanan yang sedang berlangsung) dengan
+meneruskan {@link android.content.Intent} ke {@link android.content.Context#startService
+startService()}. Atau Anda bisa mengikat ke layanan dengan meneruskan {@link android.content.Intent} ke
+{@link android.content.Context#bindService bindService()}.</li>
+  <li>Anda bisa memulai siaran dengan meneruskan {@link android.content.Intent} ke metode seperti
+{@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link
+android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, atau {@link
+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</li>
+  <li>Anda bisa melakukan query ke penyedia konten dengan memanggil {@link
+android.content.ContentProvider#query query()} pada {@link android.content.ContentResolver}.</li>
+</ul>
+
+<p>Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter
+ Intent</a>. Informasi selengkapnya tentang mengaktifkan komponen
+tertentu juga tersedia dalam dokumen berikut: <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>, <a href="{@docRoot}guide/components/services.html">Layanan</a>, {@link
+android.content.BroadcastReceiver} dan <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Konten</a>.</p>
+
+
+<h2 id="Manifest">File Manifes</h2>
+
+<p>Sebelum sistem Android bisa memulai komponen aplikasi, sistem harus mengetahui
+keberadaan komponen dengan membaca file {@code AndroidManifest.xml} aplikasi (file
+"manifes"). Aplikasi Anda harus mendeklarasikan semua komponennya dalam file ini, yang harus menjadi akar
+dari direktori proyek aplikasi.</p>
+
+<p>Manifes melakukan banyak hal selain mendeklarasikan komponen aplikasi,
+seperti:</p>
+<ul>
+  <li>Mengidentifikasi izin pengguna yang diperlukan aplikasi, seperti akses Internet atau
+akses-baca ke kontak pengguna.</li>
+  <li>Mendeklarasikan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a>
+ minimum yang diperlukan aplikasi, berdasarkan API yang digunakan aplikasi.</li>
+  <li>Mendeklarasikan fitur perangkat keras dan perangkat lunak yang diperlukan aplikasi, seperti kamera,
+layanan Bluetooth, atau layar multisentuh.</li>
+  <li>Pustaka API aplikasi perlu ditautkan (selain
+API kerangka kerja Android), seperti pustaka
+<a href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google Maps.</a></li>
+  <li>Dan lainnya</li>
+</ul>
+
+
+<h3 id="DeclaringComponents">Mendeklarasikan komponen</h3>
+
+<p>Tugas utama manifes adalah menginformasikan komponen aplikasi pada sistem. Misalnya,
+file manifes bisa mendeklarasikan aktivitas sebagai berikut: </p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;manifest ... &gt;
+    &lt;application android:icon="@drawable/app_icon.png" ... &gt;
+        &lt;activity android:name="com.example.project.ExampleActivity"
+                  android:label="@string/example_label" ... &gt;
+        &lt;/activity&gt;
+        ...
+    &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>Dalam elemen <code><a
+href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+, atribut {@code android:icon} menunjuk ke sumber daya untuk ikon yang mengidentifikasi
+aplikasi.</p>
+
+<p>Dalam elemen <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
+atribut {@code android:name} menetapkan nama kelas yang sepenuhnya memenuhi syarat subkelas {@link
+android.app.Activity} dan atribut {@code android:label} menetapkan string yang akan
+digunakan sebagai label yang terlihat oleh pengguna untuk aktivitas tersebut.</p>
+
+<p>Anda harus mendeklarasikan semua komponen aplikasi dengan cara ini:</p>
+<ul>
+  <li>Elemen <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> untuk
+aktivitas</li>
+  <li>Elemen <code><a
+href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> untuk
+layanan</li>
+  <li>Elemen <code><a
+href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code> untuk
+penerima siaran</li>
+  <li>Elemen <code><a
+href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> untuk
+penyedia konten</li>
+</ul>
+
+<p>Aktivitas, layanan, dan penyedia konten yang Anda sertakan dalam kode sumber, namun tidak
+dideklarasikan dalam manifes, tidak akan terlihat pada sistem dan, akibatnya, tidak pernah bisa berjalan.  Akan tetapi,
+penerima siaran
+bisa dideklarasikan dalam manifes atau dibuat secara dinamis dalam kode (sebagai objek
+{@link android.content.BroadcastReceiver}) dan didaftarkan pada sistem dengan memanggil
+{@link android.content.Context#registerReceiver registerReceiver()}.</p>
+
+<p>Untuk informasi selengkapnya tentang cara menstrukturkan file manifes untuk aplikasi Anda,
+lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">File AndroidManifest.xml</a>. </p>
+
+
+
+<h3 id="DeclaringComponentCapabilities">Mendeklarasikan kemampuan komponen</h3>
+
+<p>Seperti telah dibahas di atas, dalam <a href="#ActivatingComponents">Mengaktifkan Komponen</a>, Anda bisa menggunakan
+{@link android.content.Intent} untuk memulai aktivitas, layanan, dan penerima siaran. Anda bisa
+melakukannya dengan menamai komponen sasaran secara eksplisit (menggunakan nama kelas komponen) dalam intent. Akan tetapi,
+kemampuan intent sebenarnya ada pada konsep <em>intent implisit</em>. Intent implisit
+cuma menjelaskan tipe tindakan yang akan dilakukan (dan, secara opsional, data tempat Anda ingin
+melakukan tindakan) dan memungkinkan sistem untuk menemukan komponen pada perangkat yang bisa melakukan
+tindakan tersebut dan memulainya. Jika ada banyak komponen yang bisa melakukan tindakan yang dijelaskan oleh intent,
+maka pengguna bisa memilih komponen yang akan digunakan.</p>
+
+<p>Cara sistem mengidentifikasi komponen yang bisa merespons intent adalah dengan membandingkan
+intent yang diterima dengan <i>filter intent</i> yang disediakan dalam file manifes aplikasi lainnya pada
+perangkat.</p>
+
+<p>Bila mendeklarasikan aktivitas dalam manifes aplikasi, secara opsional Anda bisa menyertakan
+filter intent yang mendeklarasikan kemampuan aktivitas agar bisa merespons intent dari
+aplikasi lain. Anda bisa mendeklarasikan filter intent untuk komponen dengan
+menambahkan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> sebagai anak elemen deklarasi komponen.</p>
+
+<p>Misalnya, jika Anda telah membangun aplikasi email dengan aktivitas untuk menulis email baru, Anda bisa
+mendeklarasikan filter intent untuk merespons intent "kirim" (untuk mengirim email baru) seperti ini:</p>
+<pre>
+&lt;manifest ... >
+    ...
+    &lt;application ... &gt;
+        &lt;activity android:name="com.example.project.ComposeEmailActivity">
+            &lt;intent-filter>
+                &lt;action android:name="android.intent.action.SEND" />
+                &lt;data android:type="*/*" />
+                &lt;category android:name="android.intent.category.DEFAULT" />
+            &lt;/intent-filter>
+        &lt;/activity>
+    &lt;/application&gt;
+&lt;/manifest>
+</pre>
+
+<p>Kemudian, jika aplikasi lain membuat intent dengan tindakan {@link
+android.content.Intent#ACTION_SEND} dan meneruskannya ke {@link android.app.Activity#startActivity
+startActivity()}, sistem bisa memulai aktivitas Anda agar pengguna bisa menulis draf dan mengirim
+email.</p>
+
+<p>Untuk informasi selengkapnya tentang membuat filter intent, lihat dokumen <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
+</p>
+
+
+
+<h3 id="DeclaringRequirements">Mendeklarasikan kebutuhan aplikasi</h3>
+
+<p>Ada berbagai macam perangkat yang didukung oleh Android dan tidak
+semuanya menyediakan fitur dan kemampuan yang sama. Agar aplikasi Anda tidak dihapus pada perangkat yang tidak memiliki
+fitur yang diperlukan aplikasi, Anda harus jelas mendefinisikan profil mengenai
+tipe perangkat yang didukung aplikasi dengan mendeklarasikan kebutuhan perangkat dan perangkat lunak dalam file
+manifes. Kebanyakan deklarasi ini hanya bersifat informasi dan sistem tidak
+membacanya, namun layanan eksternal seperti Google Play akan membacanya untuk menyediakan
+penyaringan bagi pengguna saat mereka mencari aplikasi dari perangkat.</p>
+
+<p>Misalnya, jika aplikasi memerlukan kamera dan menggunakan API yang disediakan dalam Android 2.1 (<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API Level</a> 7)
+, Anda harus mendeklarasikannya sebagai kebutuhan dalam file manifes seperti ini:</p>
+
+<pre>
+&lt;manifest ... >
+    &lt;uses-feature android:name="android.hardware.camera.any"
+                  android:required="true" />
+    &lt;uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
+    ...
+&lt;/manifest>
+</pre>
+
+<p>Sekarang, perangkat yang <em>tidak</em> memiliki kamera dan menggunakan
+Android versi <em>lebih rendah</em> dari 2.1 tidak bisa menginstal aplikasi Anda dari Google Play.</p>
+
+<p>Akan tetapi, bisa juga mendeklarasikan bahwa aplikasi Anda menggunakan kamera, namun tidak
+<em>mengharuskannya</em>. Dalam hal itu, aplikasi Anda harus mengatur atribut <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a>
+ ke {@code "false"} dan memeriksa saat runtime apakah
+perangkat memiliki kamera dan menonaktifkan setiap fitur kamera yang sesuai.</p>
+
+<p>Informasi selengkapnya tentang cara mengelola kompatibilitas aplikasi dengan
+perangkat yang berbeda disediakan dalam dokumen
+<a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>.</p>
+
+
+
+<h2 id="Resources">Sumber Daya Aplikasi</h2>
+
+<p>Aplikasi Android tidak hanya terdiri dari kode&mdash;Aplikasi memerlukan sumber daya yang
+terpisah dari kode sumber, seperti gambar, file audio, dan apa saja yang berkaitan dengan
+presentasi visual dari aplikasi. Misalnya, Anda harus mendefinisikan animasi, menu, gaya, warna,
+dan layout antarmuka pengguna aktivitas dengan file XML. Penggunaan sumber daya aplikasi
+mempermudah pembaruan berbagai karakteristik aplikasi Anda tanpa memodifikasi kode dan&mdash;dengan menyediakan
+seperangkat sumber daya alternatif&mdash;memungkinkan Anda mengoptimalkan aplikasi untuk berbagai konfigurasi
+perangkat berbeda (seperti bahasa dan ukuran layar yang berbeda).</p>
+
+<p>Untuk setiap sumber daya yang Anda sertakan dalam proyek Android, alat bawaan SDK akan mendefinisikan ID integer
+unik, yang bisa Anda gunakan untuk mengacu sumber daya dari kode aplikasi atau dari sumber daya lainnya yang
+didefinisikan dalam XML. Misalnya, jika aplikasi berisi file gambar bernama {@code
+logo.png} (disimpan dalam direktori {@code res/drawable/}), alat SDK akan menghasilkan ID sumber daya
+bernama {@code R.drawable.logo}, yang bisa Anda gunakan untuk mengacu gambar dan memasukkannya dalam
+antarmuka pengguna.</p>
+
+<p>Salah satu aspek paling penting dari penyediaan sumber daya yang terpisah dari
+kode sumber adalah kemampuan Anda menyediakan sumber daya alternatif untuk konfigurasi perangkat
+yang berbeda. Misalnya, dengan mendefinisikan string UI dalam XML, Anda bisa menerjemahkan string ke dalam
+bahasa lain dan menyimpan string itu dalam file terpisah. Kemudian, berdasarkan <em>qualifier</em>
+bahasa yang ditambahkan ke nama direktori sumber daya (seperti {@code res/values-fr/} untuk nilai
+string Prancis) dan pengaturan bahasa pengguna, sistem Android akan menerapkan string bahasa yang sesuai
+untuk UI Anda.</p>
+
+<p>Android mendukung banyak <em>qualifier</em> berbeda untuk sumber daya alternatif Anda. Qualifier
+adalah string pendek yang Anda sertakan dalam nama direktori sumber
+daya untuk mendefinisikan konfigurasi perangkat yang harus digunakan sumber daya tersebut. Contoh lainnya,
+Anda harus sering membuat layout berbeda untuk aktivitas, bergantung pada
+orientasi layar dan ukuran perangkat. Misalnya, saat layar perangkat dalam orientasi
+tegak, Anda mungkin ingin layout tombolnya vertikal, tetapi saat layar dalam orientasi
+mendatar, tombolnya harus sejajar horizontal. Untuk mengubah layout
+sesuai orientasi, Anda bisa mendefinisikan dua layout berbeda dan menerapkan qualifier yang
+tepat untuk setiap nama direktori layout. Kemudian, sistem secara otomatis menerapkan
+layout yang tepat sesuai dengan orientasi perangkat saat ini.</p>
+
+<p>Untuk informasi selengkapnya tentang berbagai jenis sumber daya yang bisa disertakan dalam aplikasi dan cara
+membuat sumber daya alternatif untuk konfigurasi perangkat berbeda, bacalah <a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a>.</p>
+
+
+
+<div class="next-docs">
+<div class="col-6">
+  <h2 class="norule">Teruskan membaca tentang:</h2>
+  <dl>
+    <dt><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
+    </dt>
+    <dd>Informasi tentang cara menggunakan API {@link android.content.Intent} untuk
+ mengaktifkan komponen aplikasi, seperti aktivitas dan layanan, dan cara menyediakan komponen aplikasi
+ untuk digunakan oleh aplikasi lain.</dd>
+    <dt><a href="{@docRoot}guide/components/activities.html">Aktivitas</a></dt>
+    <dd>Informasi tentang cara membuat instance kelas {@link android.app.Activity},
+yang menyediakan layar tersendiri dalam aplikasi bersama antarmuka pengguna.</dd>
+    <dt><a href="{@docRoot}guide/topics/resources/providing-resources.html">Menyediakan Sumber Daya</a></dt>
+    <dd>Informasi tentang cara aplikasi Android disusun untuk memisahkan sumber daya aplikasi dari
+kode aplikasi, termasuk cara Anda bisa menyediakan sumber daya alternatif untuk
+konfigurasi perangkat tertentu.
+    </dd>
+  </dl>
+</div>
+<div class="col-6">
+  <h2 class="norule">Anda juga mungkin tertarik dengan:</h2>
+  <dl>
+    <dt><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a></dt>
+    <dd>Informasi tentang cara kerja Android pada berbagai tipe perangkat dan
+pengenalan mengenai cara mengoptimalkan aplikasi untuk setiap perangkat atau membatasi ketersediaan aplikasi Anda untuk
+perangkat berbeda.</dd>
+    <dt><a href="{@docRoot}guide/topics/security/permissions.html">Izin Sistem</a></dt>
+    <dd>Informasi tentang cara Android membatasi akses aplikasi pada API tertentu dengan sistem izin
+yang mengharuskan persetujuan pengguna agar aplikasi dapat menggunakan API tersebut.</dd>
+  </dl>
+</div>
+</div>
+
diff --git a/docs/html-intl/intl/id/guide/components/index.jd b/docs/html-intl/intl/id/guide/components/index.jd
new file mode 100644
index 0000000..de40b22
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/index.jd
@@ -0,0 +1,57 @@
+page.title=Komponen Aplikasi
+page.landing=true
+page.landing.intro=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
+page.metaDescription=Kerangka kerja aplikasi Android memungkinkan Anda membuat aplikasi yang kaya dan inovatif menggunakan seperangkat komponen yang dapat digunakan kembali. Bagian ini menjelaskan cara membangun komponen yang mendefinisikan blok pembangun aplikasi Anda dan cara menghubungkannya bersama menggunakan intent.
+page.landing.image=images/develop/app_components.png
+page.image=images/develop/app_components.png
+
+@jd:body
+
+<div class="landing-docs">
+
+  <div class="col-6">
+    <h3>Artikel Blog</h3>
+
+    <a href="http://android-developers.blogspot.com/2012/05/using-dialogfragments.html">
+      <h4>Menggunakan DialogFragments</h4>
+      <p>Dalam posting ini, saya akan menunjukkan cara menggunakan DialogFragments dengan pustaka dukungan v4 (untuk kompatibilitas mundur pada perangkat sebelum Honeycomb) untuk menunjukkan dialog edit sederhana dan mengembalikan hasil ke Aktivitas pemanggil menggunakan antarmuka.</p>
+    </a>
+
+    <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
+      <h4>Fragmen Untuk Semua</h4>
+      <p>Hari ini kami telah merilis pustaka statis yang memperlihatkan API Fragment yang sama (serta LoaderManager baru dan beberapa kelas lain) agar aplikasi yang kompatibel dengan Android 1.6 atau yang lebih baru bisa menggunakan fragmen untuk membuat antarmuka pengguna yang kompatibel dengan tablet. </p>
+    </a>
+
+    <a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">
+      <h4>Multithreading untuk Kinerja</h4>
+      <p>Praktik yang baik dalam membuat aplikasi yang responsif adalah memastikan thread UI utama Anda
+melakukan pekerjaan minimum. Setiap tugas yang berpotensi lama dan dapat membuat aplikasi mogok harus
+ditangani di thread berbeda.</p>
+    </a>
+  </div>
+
+  <div class="col-6">
+    <h3>Pelatihan</h3>
+
+    <a href="http://developer.android.com/training/basics/activity-lifecycle/index.html">
+      <h4>Mengelola Daur Hidup Aktivitas</h4>
+      <p>Bagian ini menjelaskan pentingnya metode callback daur hidup yang diterima setiap instance Aktivitas
+dan cara menggunakannya sehingga aktivitas Anda melakukan yang diharapkan pengguna dan tidak menghabiskan sumber daya sistem
+saat aktivitas tidak membutuhkannya.</p>
+    </a>
+
+    <a href="http://developer.android.com/training/basics/fragments/index.html">
+      <h4>Membangun UI Dinamis dengan Fragmen</h4>
+      <p>Bagian ini menunjukkan kepada Anda cara membuat pengalaman pengguna yang dinamis dengan fragmen dan mengoptimalkan
+pengalaman pengguna aplikasi Anda dengan berbagai ukuran layar, sekaligus terus mendukung
+perangkat yang menjalankan versi sebelumnya, sesudah versi Android 1.6.</p>
+    </a>
+
+    <a href="http://developer.android.com/training/sharing/index.html">
+      <h4>Berbagi Konten</h4>
+      <p>Bagian ini membahas beberapa cara umum untuk mengirim dan menerima konten antar
+aplikasi menggunakan API Intent dan objek ActionProvider.</p>
+    </a>
+  </div>
+
+</div>
diff --git a/docs/html-intl/intl/id/guide/components/intents-filters.jd b/docs/html-intl/intl/id/guide/components/intents-filters.jd
new file mode 100644
index 0000000..8e89b5d
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/intents-filters.jd
@@ -0,0 +1,899 @@
+page.title=Intent dan Filter Intent
+page.tags="IntentFilter"
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#Types">Tipe Intent</a></li>
+  <li><a href="#Building">Membangun Intent</a>
+    <ol>
+      <li><a href="#ExampleExplicit">Contoh intent eksplisit</a></li>
+      <li><a href="#ExampleSend">Contoh intent implisit</a></li>
+      <li><a href="#ForceChooser">Memaksakan pemilih aplikasi</a></li>
+    </ol>
+  </li>
+  <li><a href="#Receiving">Menerima Intent Implisit</a>
+    <ol>
+      <li><a href="#ExampleFilters">Contoh filter</a></li>
+    </ol>
+  </li>
+  <li><a href="#PendingIntent">Menggunakan Intent Tertunda</a></li>
+  <li><a href="#Resolution">Resolusi Intent</a>
+    <ol>
+      <li><a href="#ActionTest">Pengujian tindakan</a></li>
+      <li><a href="#CategoryTest">Pengujian kategori</a></li>
+      <li><a href="#DataTest">Pengujian data</a></li>
+      <li><a href="#imatch">Pencocokan intent</a></li>
+    </ol>
+  </li>
+</ol>
+
+<h2>Lihat juga</h2>
+<ol>
+<li><a href="{@docRoot}training/basics/intents/index.html">Berinteraksi dengan Aplikasi Lain</a></li>
+<li><a href="{@docRoot}training/sharing/index.html">Berbagi Konten</a></li>
+</ol>
+
+</div>
+</div>
+
+
+
+
+<p>{@link android.content.Intent} merupakan objek pertukaran pesan yang bisa Anda gunakan untuk meminta tindakan
+dari <a href="{@docRoot}guide/components/fundamentals.html#Components">komponen aplikasi</a> lain.
+Walaupun intent memudahkan komunikasi antarkomponen dalam beberapa cara, ada tiga
+kasus-penggunaan dasar:</p>
+
+<ul>
+<li><b>Untuk memulai aktivitas:</b>
+<p>{@link android.app.Activity} menyatakan satu layar dalam aplikasi. Anda bisa memulai instance
+baru {@link android.app.Activity} dengan meneruskan {@link android.content.Intent}
+ke {@link android.content.Context#startActivity startActivity()}. {@link android.content.Intent}
+menjelaskan aktivitas yang akan dimulai dan membawa data yang diperlukan.</p>
+
+<p>Jika Anda ingin menerima hasil dari aktivitas bila selesai,
+panggil {@link android.app.Activity#startActivityForResult
+startActivityForResult()}. Aktivitas Anda menerima hasil
+sebagai objek {@link android.content.Intent} terpisah dalam callback {@link
+android.app.Activity#onActivityResult onActivityResult()} aktivitas Anda.
+Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/activities.html">Aktivitas</a>.</p></li>
+
+<li><b>Untuk memulai layanan:</b>
+<p>{@link android.app.Service} adalah komponen yang melakukan operasi di latar belakang
+tanpa antarmuka pengguna. Anda bisa memulai layanan untuk melakukan operasi satu-kali
+(misalnya mengunduh file) dengan meneruskan {@link android.content.Intent}
+ke {@link android.content.Context#startService startService()}. {@link android.content.Intent}
+menjelaskan layanan yang akan dimulai dan membawa data yang diperlukan.</p>
+
+<p>Jika layanan didesain dengan antarmuka pengguna klien-server, Anda bisa mengikat ke layanan
+dari komponen lain dengan meneruskan {@link android.content.Intent} ke {@link
+android.content.Context#bindService bindService()}</code>. Untuk informasi selengkapnya, lihat panduan <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p></li>
+
+<li><b>Untuk mengirim siaran:</b>
+<p>Siaran adalah pesan yang bisa diterima aplikasi apa saja. Sistem menyampaikan beragam siaran
+untuk kejadian sistem, misalnya saat sistem booting atau saat perangkat mulai mengisi daya.
+Anda bisa mengirim siaran ke aplikasi lain dengan meneruskan {@link android.content.Intent}
+ke {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()},
+{@link android.content.Context#sendOrderedBroadcast(Intent, String)
+sendOrderedBroadcast()}, atau {@link
+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
+</li>
+</ul>
+
+
+
+
+<h2 id="Types">Tipe Intent</h2>
+
+<p>Ada dua tipe intent:</p>
+
+<ul>
+<li><b>Intent eksplisit</b> menetapkan komponen untuk memulai dengan nama (
+nama kelas yang sepenuhnya memenuhi syarat). Anda biasanya akan menggunakan intent eksplisit untuk memulai sebuah komponen
+dalam aplikasi sendiri, karena Anda mengetahui nama kelas dari aktivitas atau layanan yang ingin dimulai.
+Misalnya, mulai aktivitas baru sebagai respons terhadap tindakan pengguna atau mulai layanan untuk mengunduh
+file di latar belakang.</li>
+
+<li><b>Intent implisit</b> tidak menetapkan komponen tertentu, melainkan mendeklarasikan tindakan umum
+yang dilakukan, yang memungkinkan komponen aplikasi lain untuk menanganinya. Misalnya, jika Anda ingin
+menampilkan sebuah lokasi di peta pada pengguna, Anda bisa menggunakan intent implisit untuk meminta aplikasi lain
+yang mampu untuk menunjukkan lokasi yang telah ditetapkan di peta tersebut.</li>
+</ul>
+
+<p>Saat Anda membuat intent eksplisit untuk memulai aktivitas atau layanan, sistem akan segera
+memulai komponen aplikasi yang telah ditetapkan dalam objek {@link android.content.Intent}.</p>
+
+<div class="figure" style="width:446px">
+<img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi yang menggambarkan cara intent implisit
+disampaikan melalui sistem untuk memulai aktivitas lain: <b>[1]</b> <em>Aktivitas A</em> membuat sebuah
+{@link android.content.Intent} dengan keterangan tindakan dan meneruskannya ke {@link
+android.content.Context#startActivity startActivity()}. <b>[2]</b> Sistem Android akan mencari semua
+aplikasi untuk filter intent yang cocok dengan intent tersebut. Bila cocok, <b>[3]</b> sistem akan
+memulai aktivitas mencocokkan (<em>Aktivitas B</em>) dengan memanggil metode {@link
+android.app.Activity#onCreate onCreate()} dan meneruskannya ke {@link android.content.Intent}.
+</p>
+</div>
+
+<p>Bila Anda membuat intent implisit, sistem Android akan menemukan komponen yang sesuai untuk memulai
+dengan membandingkan konten intent dengan <em>filter intent</em> yang dideklarasikan dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> aplikasi lain di
+perangkat. Jika intent cocok dengan filter intent, sistem akan memulai komponen tersebut dan mengiriminya
+objek {@link android.content.Intent}. Jika banyak filter intent yang kompatibel, sistem
+menampilkan dialog sehingga pengguna bisa memilih aplikasi yang akan digunakan.</p>
+
+<p>Filter intent adalah ekspresi dalam file manifes aplikasi yang
+menetapkan tipe intent yang akan diterima
+komponen. Misalnya, dengan mendeklarasikan intent filter untuk aktivitas,
+Anda akan memungkinkan aplikasi lain untuk langsung memulai aktivitas Anda dengan intent tertentu.
+Demikian pula, jika Anda <em>tidak</em> mendeklarasikan filter intent untuk suatu aktivitas, maka aktivitas tersebut hanya bisa dimulai
+dengan intent eksplisit.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Untuk memastikan aplikasi Anda aman, selalu gunakan intent
+eksplisit saat memulai {@link android.app.Service} dan jangan
+mendeklarasikan filter intent untuk layanan. Menggunakan intent implisit untuk memulai layanan akan menimbulkan
+bahaya keamanan karena Anda tidak bisa memastikan layanan apa yang akan merespons intent,
+dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dari Android 5.0 (API level 21), sistem
+melontarkan eksepsi jika Anda memanggil {@link android.content.Context#bindService bindService()}
+dengan intent implisit.</p>
+
+
+
+
+
+<h2 id="Building">Membangun Intent</h2>
+
+<p>Objek {@link android.content.Intent} membawa informasi yang digunakan sistem Android
+untuk menentukan komponen mana yang akan dimulai (misalnya nama persis dari suatu komponen atau kategori
+komponen yang seharusnya menerima intent), ditambah informasi yang digunakan komponen penerima untuk
+melakukan tindakan dengan benar (misalnya tindakan yang harus dilakukan dan data yang harus diolah).</p>
+
+
+<p>Informasi utama yang dimuat dalam {@link android.content.Intent} adalah sebagai berikut:</p>
+
+<dl>
+
+<dt><b>Nama komponen</b></dt>
+<dd>Nama komponen yang akan dimulai.
+
+<p>Ini opsional, namun merupakan bagian informasi penting yang membuat intent
+menjadi <b>eksplisit</b>, yaitu intent harus dikirim hanya ke komponen aplikasi
+yang didefinisikan oleh nama komponen. Tanpa nama komponen, intent menjadi <b>implisit</b> dan
+sistem akan memutuskan komponen mana yang harus menerima intent berdasarkan informasi intent lain
+(misalnya tindakan, data, dan kategori&mdash;yang dijelaskan di bawah ini). Jadi jika Anda ingin memulai komponen
+tertentu dalam aplikasi, Anda harus menetapkan nama komponen tersebut.</p>
+
+<p class="note"><strong>Catatan:</strong> Saat memulai {@link android.app.Service}, Anda harus
+<strong>selalu menetapkan nama komponen</strong>. Jika tidak, maka Anda tidak bisa memastikan layanan apa
+yang akan merespons intent tersebut, dan pengguna tidak bisa melihat layanan mana yang dimulai.</p>
+
+<p>Bidang {@link android.content.Intent} ini adalah objek
+{@link android.content.ComponentName}, yang bisa Anda tetapkan menggunakan
+nama kelas yang sepenuhnya memenuhi syarat dari komponen target, termasuk nama paket aplikasi. Misalnya,
+{@code com.example.ExampleActivity}. Anda bisa mengatur nama komponen dengan {@link
+android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
+setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, atau dengan konstruktor
+{@link android.content.Intent}.</p>
+
+</dd>
+
+<p><dt><b>Tindakan</b></dt>
+<dd>String yang menetapkan tindakan generik untuk dilakukan (misalnya <em>lihat</em> atau <em>pilih</em>).
+
+<p>Dalam hal intent siaran, ini adalah tindakan yang terjadi dan dilaporkan.
+Tindakan ini sangat menentukan bagaimana keseluruhan intent disusun&mdash;terutama
+apa yang dimuat dalam data dan ekstra.
+
+<p>Anda bisa menetapkan tindakan sendiri yang akan digunakan oleh intent dalam aplikasi Anda (atau digunakan oleh aplikasi
+lain untuk memanggil komponen dalam aplikasi Anda), namun Anda harus menggunakan konstanta tindakan
+yang didefinisikan oleh kelas {@link android.content.Intent} atau kelas kerangka kerja lain. Berikut ini adalah beberapa
+tindakan umum untuk memulai sebuah aktivitas:</p>
+
+<dl>
+<dt>{@link android.content.Intent#ACTION_VIEW}</dt>
+   <dd>Gunakan tindakan ini dalam intent dengan {@link
+   android.content.Context#startActivity startActivity()} saat Anda memiliki beberapa informasi yang
+ bisa ditampilkan aktivitas kepada pengguna, misalnya foto yang bisa dilihat dalam aplikasi galeri, atau alamat
+ yang bisa dilihat dalam aplikasi peta.</dd>
+
+<dt>{@link android.content.Intent#ACTION_SEND}</dt>
+   <dd>Juga dikenal dengan intent "berbagi", Anda harus menggunakannya dalam intent dengan {@link
+   android.content.Context#startActivity startActivity()} bila Anda memiliki data yang bisa digunakan pengguna untuk
+ berbagi melalui aplikasi lain, misalnya aplikasi email atau aplikasi jaringan sosial.</dd>
+</dl>
+
+<p>Lihat referensi kelas {@link android.content.Intent} untuk konstanta
+selengkapnya yang mendefinisikan tindakan generik.  Tindakan lain yang didefinisikan
+di tempat lain dalam kerangka kerja Android, misalnya dalam {@link android.provider.Settings} untuk tindakan
+yang membuka layar tertentu dalam aplikasi Settings di sistem.</p>
+
+<p>Anda bisa menetapkan tindakan untuk sebuah intent dengan {@link android.content.Intent#setAction
+setAction()} atau dengan konstruktor {@link android.content.Intent}.</p>
+
+<p>Jika mendefinisikan tindakan Anda sendiri, pastikan untuk memasukkan nama paket aplikasi Anda
+sebagai awalan. Misalnya:</p>
+<pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
+</dd>
+
+<dt><b>Data</b></dt>
+<dd>URI (objek {@link android.net.Uri}) yang mengacu data untuk diolah dan/atau
+tipe MIME dari data tersebut. Tipe data yang disediakan umumnya didikte oleh tindakan intent.
+Misalnya, jika tindakan merupakan {@link android.content.Intent#ACTION_EDIT}, data harus berisi
+URI dari dokumen untuk diedit.
+
+<p>Saat membuat intent,
+seringkali tipe data (tipe MIME-nya) selain URI perlu ditetapkan.
+Misalnya, aktivitas yang mampu menampilkan gambar mungkin tidak mampu
+memutar file audio, walaupun format URI mungkin serupa.
+Jadi menetapkan tipe MIME data Anda akan membantu sistem
+Android menemukan komponen terbaik untuk diterima intent.
+Akan tetapi, tipe MIME seringkali bisa diambil dari URI&mdash;terutama saat datanya merupakan URI
+{@code content:}, yang menunjukkan data tersebut berada di perangkat dan dikontrol oleh
+{@link android.content.ContentProvider}, yang membuat data tipe MIME terlihat di sistem.</p>
+
+<p>Untuk mengatur data URI saja, panggil {@link android.content.Intent#setData setData()}.
+Untuk mengatur tipe MIME saja, panggil {@link android.content.Intent#setType setType()}. Jika perlu, Anda
+bisa mengatur keduanya secara eksplisit dengan {@link
+android.content.Intent#setDataAndType setDataAndType()}.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Jika ingin mengatur tipe URI dan MIME,
+<strong>jangan</strong> panggil {@link android.content.Intent#setData setData()} dan
+{@link android.content.Intent#setType setType()} karena mereka saling menghapuskan nilai satu sama lain.
+Selalu gunakan {@link android.content.Intent#setDataAndType setDataAndType()} untuk mengatur
+tipe URI maupun MIME.</p>
+</dd>
+
+<p><dt><b>Kategori</b></dt>
+<dd>String yang berisi informasi tambahan tentang jenis komponen
+yang harus menangani intent.  Keterangan kategori dalam jumlah berapa pun bisa
+dimasukkan dalam intent, namun sebagian besar intent tidak memerlukan kategori.
+Berikut ini adalah beberapa kategori umum:
+
+<dl>
+<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
+  <dd>Aktivitas target memungkinkannya dimulai oleh browser web untuk menampilkan data
+yang diacu oleh tautan&mdash;misalnya gambar atau pesan e-mail.
+  </dd>
+<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
+  <dd>Aktivitas tersebut adalah aktivitas awal dari sebuah tugas dan dicantumkan dalam
+       launcher aplikasi sistem.
+  </dd>
+</dl>
+
+<p>Lihat keterangan kelas {@link android.content.Intent} untuk mengetahui daftar lengkap
+kategori.</p>
+
+<p>Anda bisa menetapkan kategori dengan {@link android.content.Intent#addCategory addCategory()}.</p>
+</dd>
+</dl>
+
+
+<p>Properti yang tercantum di atas (nama komponen, tindakan, data, dan kategori) menyatakan
+karakteristik yang mendefinisikan intent. Dengan membaca properti ini, sistem Android
+mampu memutuskan komponen aplikasi yang harus dimulainya.</p>
+
+<p>Akan tetapi, intent bisa membawa informasi tambahan yang tidak memengaruhi
+cara intent ditetapkan pada komponen aplikasi. Intent juga bisa menyediakan:</p>
+
+<dl>
+<dt><b>Ekstra</b></dt>
+<dd>Pasangan nilai-kunci yang membawa informasi yang diperlukan untuk menghasilkan tindakan yang diminta.
+Seperti halnya beberapa tindakan menggunakan jenis tertentu URI data, beberapa tindakan juga menggunakan ekstra tertentu.
+
+<p>Anda bisa menambahkan data ekstra dengan beragam metode {@link android.content.Intent#putExtra putExtra()},
+masing-masing menerima dua parameter: nama kunci dan nilainya.
+Anda juga bisa membuat objek {@link android.os.Bundle} dengan semua data ekstra, kemudian memasukkan
+{@link android.os.Bundle} dalam {@link android.content.Intent} dengan {@link
+android.content.Intent#putExtras putExtras()}.</p>
+
+<p>Misalnya, saat membuat intent yang akan dikirimkan bersama email
+{@link android.content.Intent#ACTION_SEND}, Anda bisa menetapkan penerima "kepada" dengan kunci
+{@link android.content.Intent#EXTRA_EMAIL}, dan menetapkan "subjek" dengan kunci
+{@link android.content.Intent#EXTRA_SUBJECT}.</p>
+
+<p>Kelas {@link android.content.Intent} menetapkan beberapa konstanta {@code EXTRA_*}
+untuk tipe data standar. Jika Anda ingin mendeklarasikan kunci ekstra sendiri (untuk intent yang
+diterima aplikasi Anda), pastikan untuk memasukkan nama paket aplikasi
+sebagai awalan. Misalnya:</p>
+<pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
+</dd>
+
+<dt><b>Flag</b></dt>
+<dd>Flag didefinisikan dalam kelas {@link android.content.Intent} yang berfungsi sebagai metadata untuk
+intent. Flag menginstruksikan cara meluncurkan aktivitas (misalnya,
+<a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> mana yang harus dimiliki suatu aktivitas
+) dan cara memperlakukannya setelah diluncurkan (misalnya, apakah aktivitas tersebut masuk ke dalam daftar aktivitas
+terbaru) pada sistem Android.
+
+<p>Untuk informasi selengkapnya, lihat metode {@link android.content.Intent#setFlags setFlags()} .</p>
+</dd>
+
+</dl>
+
+
+
+
+<h3 id="ExampleExplicit">Contoh intent eksplisit</h3>
+
+<p>Intent eksplisit adalah intent yang Anda gunakan untuk meluncurkan komponen aplikasi tertentu, seperti
+aktivitas tertentu atau layanan dalam aplikasi Anda. Untuk membuat intent eksplisit, definisikan
+nama komponen untuk objek {@link android.content.Intent} &mdash;semua
+properti intent lain bersifat opsional.</p>
+
+<p>Misalnya, jika Anda ingin membangun layanan dalam aplikasi Anda, bernama {@code DownloadService},
+yang didesain untuk mengunduh file dari web, Anda bisa memulainya dengan kode berikut ini:</p>
+
+<pre>
+// Executed in an Activity, so 'this' is the {@link android.content.Context}
+// The fileUrl is a string URL, such as "http://www.example.com/image.png"
+Intent downloadIntent = new Intent(this, DownloadService.class);
+downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl));
+startService(downloadIntent);
+</pre>
+
+<p>Konstruktor {@link android.content.Intent#Intent(Context,Class)}
+ menyediakan {@link android.content.Context} aplikasi dan
+objek {@link java.lang.Class} pada komponen. Dengan demikian,
+intent ini memulai secara eksplisit kelas {@code DownloadService} dalam aplikasi.</p>
+
+<p>Untuk informasi selengkapnya tentang membangun dan memulai layanan, lihat panduan
+<a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
+
+
+
+
+<h3 id="ExampleSend">Contoh intent implisit</h3>
+
+<p>Intent implisit menetapkan tindakan yang bisa memanggil aplikasi pada perangkat yang mampu
+melakukan tindakan. Menggunakan intent implisit berguna bila aplikasi Anda tidak bisa melakukan
+tindakan, namun aplikasi lain mungkin bisa melakukannya dan Anda ingin pengguna untuk memilih aplikasi mana yang ingin digunakan.</p>
+
+<p>Misalnya, jika memiliki konten yang Anda ingin agar pengguna berbagi konten itu dengan orang lain, buatlah intent
+dengan tindakan {@link android.content.Intent#ACTION_SEND}
+dan tambahkan ekstra yang menetapkan konten yang akan dibagikan. Bila Anda memanggil
+{@link android.content.Context#startActivity startActivity()} dengan intent tersebut, pengguna bisa
+memilih aplikasi yang akan digunakan untuk berbagi konten.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Ada kemungkinan pengguna tidak memiliki <em>suatu</em>
+aplikasi yang menangani intent implisit yang Anda kirimkan ke {@link android.content.Context#startActivity
+startActivity()}. Jika itu terjadi, panggilan akan gagal dan aplikasi Anda akan crash. Untuk memeriksa
+apakah aktivitas bisa menerima intent, panggil {@link android.content.Intent#resolveActivity
+resolveActivity()} pada objek {@link android.content.Intent} Anda. Jika hasilnya bukan nol,
+berarti setidaknya ada satu aplikasi yang bisa menangani intent tersebut dan aman untuk memanggil
+{@link android.content.Context#startActivity startActivity()}. Jika hasilnya nol,
+Anda tidak boleh menggunakan intent tersebut dan, jika memungkinkan, Anda harus menonaktifkan fitur yang mengeluarkan
+intent tersebut.</p>
+
+
+<pre>
+// Create the text message with a string
+Intent sendIntent = new Intent();
+sendIntent.setAction(Intent.ACTION_SEND);
+sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
+sendIntent.setType("text/plain");
+
+// Verify that the intent will resolve to an activity
+if (sendIntent.resolveActivity(getPackageManager()) != null) {
+    startActivity(sendIntent);
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Dalam hal ini, URI tidak digunakan, namun tipe data intent
+dideklarasikan untuk menetapkan konten yang dibawa oleh ekstra.</p>
+
+
+<p>Saat {@link android.content.Context#startActivity startActivity()} dipanggil, sistem akan
+memeriksa semua aplikasi yang terinstal untuk menentukan aplikasi mana yang bisa menangani intent jenis ini (
+intent dengan tindakan {@link android.content.Intent#ACTION_SEND} dan yang membawa data
+"teks/polos"). Jika hanya ada satu aplikasi yang bisa menanganinya, aplikasi tersebut akan langsung terbuka dan diberi
+intent tersebut. Jika banyak aktivitas menerima intent, sistem akan
+menampilkan dialog sehingga pengguna bisa memilih aplikasi mana yang digunakan.</p>
+
+
+<div class="figure" style="width:200px">
+  <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="">
+  <p class="img-caption"><strong>Gambar 2.</strong> Dialog pemilih.</p>
+</div>
+
+<h3 id="ForceChooser">Memaksakan pemilih aplikasi</h3>
+
+<p>Bila ada lebih dari satu aplikasi yang merespons intent implisit Anda,
+pengguna bisa memilih aplikasi mana yang digunakan dan membuat aplikasi tersebut pilihan default untuk
+tindakan tersebut. Ini sangat membantu saat melakukan tindakan di mana pengguna
+mungkin ingin menggunakan aplikasi yang sama untuk seterusnya, seperti saat membuka halaman web (pengguna
+biasanya memilih hanya satu browser web).</p>
+
+<p>Akan tetapi, jika ada banyak aplikasi yang bisa merespons intent tersebut dan pengguna mungkin ingin menggunakan aplikasi
+yang berbeda untuk setiap kalinya, Anda harus menampilkan dialog pemilih secara eksplisit. Dialog pemilih akan meminta
+pengguna memilih aplikasi yang akan digunakan untuk tindakan tertentu setiap kali (pengguna tidak bisa memilih aplikasi default untuk
+tindakan tersebut). Misalnya, saat aplikasi Anda melakukan "berbagi" dengan tindakan {@link
+android.content.Intent#ACTION_SEND}, pengguna mungkin ingin berbagi menggunakan aplikasi berbeda sesuai
+dengan situasi mereka saat itu, jadi Anda harus selalu menggunakan dialog pemilih, seperti yang ditampilkan dalam gambar 2.</p>
+
+
+
+
+<p>Untuk menampilkan pemilih, buatlah {@link android.content.Intent} menggunakan {@link
+android.content.Intent#createChooser createChooser()} dan teruskan ke {@link
+android.app.Activity#startActivity startActivity()}. Misalnya:</p>
+
+<pre>
+Intent sendIntent = new Intent(Intent.ACTION_SEND);
+...
+
+// Always use string resources for UI text.
+// This says something like "Share this photo with"
+String title = getResources().getString(R.string.chooser_title);
+// Create intent to show the chooser dialog
+Intent chooser = Intent.createChooser(sendIntent, title);
+
+// Verify the original intent will resolve to at least one activity
+if (sendIntent.resolveActivity(getPackageManager()) != null) {
+    startActivity(chooser);
+}
+</pre>
+
+<p>Ini menampilkan dialog dengan daftar aplikasi yang merespons intent yang diteruskan ke metode {@link
+android.content.Intent#createChooser createChooser()} dan menggunakan teks yang disediakan sebagai
+judul dialog.</p>
+
+
+
+
+
+
+
+
+
+<h2 id="Receiving">Menerima Intent Implisit</h2>
+
+<p>Untuk mengiklankan intent implisit yang bisa diterima aplikasi Anda, deklarasikan satu atau beberapa filter intent untuk
+tiap komponen aplikasi dengan elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
+dalam <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">file manifes</a> Anda.
+Tiap filter intent menetapkan tipe intent yang diterimanya berdasarkan tindakan intent,
+data, dan kategori. Sistem akan mengirim intent implisit ke komponen aplikasi Anda hanya jika
+intent tersebut bisa diteruskan melalui salah satu filter intent.</p>
+
+<p class="note"><strong>Catatan:</strong> Intent eksplisit selalu dikirimkan ke targetnya,
+apa pun filter intent yang dideklarasikan komponen.</p>
+
+<p>Komponen aplikasi harus mendeklarasikan filter terpisah untuk setiap pekerjaan unik yang bisa dilakukannya.
+Misalnya, satu aktivitas dalam aplikasi galeri gambar bisa memiliki dua filter: satu filter
+untuk melihat gambar, dan filter lainnya untuk mengedit gambar. Bila aktivitas dimulai,
+aktivitas akan memeriksa {@link android.content.Intent} dan menentukan cara berperilaku berdasarkan informasi
+dalam {@link android.content.Intent} (misalnya menampilkan kontrol editor atau tidak).</p>
+
+<p>Tiap filter intent didefinisikan oleh elemen <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
+dalam file manifes aplikasi, yang tersarang dalam komponen aplikasi terkait (seperti
+elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+). Di dalam <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>,
+Anda bisa menetapkan tipe intent yang akan diterima dengan menggunakan salah satu atau beberapa
+dari tiga elemen ini:</p>
+
+<dl>
+<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a></dt>
+  <dd>Mendeklarasikan tindakan intent yang diterima, dalam atribut {@code name}. Nilai
+  haruslah nilai string literal dari tindakan, bukan konstanta kelas.</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a></dt>
+  <dd>Mendeklarasikan tipe data yang diterima, menggunakan salah satu atau beberapa atribut yang menetapkan beragam
+  aspek URI data (<code>scheme</code>, <code>host</code>, <code>port</code>,
+  <code>path</code>, dll.) dan tipe MIME.</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a></dt>
+  <dd>Mendeklarasikan kategori intent yang diterima, dalam atribut {@code name}. Nilai
+  haruslah nilai string literal dari tindakan, bukan konstanta kelas.
+
+  <p class="note"><strong>Catatan:</strong> Untuk menerima intent implisit, Anda
+  <strong>harus menyertakan</strong> kategori
+{@link android.content.Intent#CATEGORY_DEFAULT} dalam filter intent. Metode
+  {@link android.app.Activity#startActivity startActivity()}dan
+  {@link android.app.Activity#startActivityForResult startActivityForResult()} memperlakukan semua intent
+  seolah-olah mendeklarasikan kategori {@link android.content.Intent#CATEGORY_DEFAULT}.
+  Jika tidak mendeklarasikan kategori ini dalam filter intent Anda, tidak ada intent implisit yang ditetapkan untuk
+ aktivitas Anda.</p>
+  </dd>
+</dl>
+
+<p>Misalnya, ini adalah deklarasi aktivitas dengan filter intent yang diterima intent
+{@link android.content.Intent#ACTION_SEND} bila tipe data berupa teks:</p>
+
+<pre>
+&lt;activity android:name="ShareActivity">
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SEND"/>
+        &lt;category android:name="android.intent.category.DEFAULT"/>
+        &lt;data android:mimeType="text/plain"/>
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p>Anda bisa membuat filter yang menyertakan lebih dari satu instance
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a>,
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>, atau
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a>.
+Jika Anda melakukannya, Anda hanya perlu memastikan bahwa komponen bisa menangani semua kombinasi
+elemen filter tersebut.</p>
+
+<p>Bila ingin menangani beragam jenis intent, namun hanya dalam kombinasi
+tindakan, data, dan tipe kategori tertentu, maka Anda harus membuat banyak filter intent.</p>
+
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Membatasi akses ke komponen</h2>
+<p>Menggunakan filter intent bukanlah cara yang aman untuk mencegah aplikasi lain memulai
+komponen Anda. Walaupun filter intent membatasi komponen agar hanya merespons
+jenis intent implisit tertentu, aplikasi lain bisa saja memulai komponen aplikasi Anda
+dengan menggunakan intent eksplisit jika pengembangnya menentukan nama komponen Anda.
+Jika perlu <em>hanya aplikasi Anda sendiri</em> yang mampu memulai salah satu komponen,
+atur atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#exported">{@code
+exported}</a> ke {@code "false"} untuk komponen itu.
+</p>
+</div>
+</div>
+
+<p>Intent implisit diuji terhadap filter dengan membandingkan intent dengan masing-masing
+dari ketiga elemen. Agar dikirim ke komponen, intent harus lolos ketiga pengujian tersebut.
+Jika intent gagal dalam salah satu pengujian, sistem Android tidak akan mengirim intent ke
+komponen.  Akan tetapi, karena sebuah komponen dapat memiliki beberapa filter intent, intent yang tidak
+lolos melalui salah satu filter komponen mungkin akan lolos di filter lain.
+Informasi selengkapnya tentang cara sistem menetapkan intent disediakan dalam bagian di bawah ini
+tentang <a href="#Resolution">Resolusi Intent</a>.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Untuk menghindari menjalankan
+{@link android.app.Service} aplikasi yang berbeda secara tidak sengaja, selalu gunakan intent eksplisit untuk memulai layanan Anda sendiri dan jangan
+deklarasikan filter intent untuk layanan Anda.</p>
+
+<p class="note"><strong>Catatan:</strong>
+Untuk semua aktivitas, Anda harus mendeklarasikan filter intent dalam file manifes.
+Akan tetapi, filter untuk penerima siaran bisa didaftarkan secara dinamis dengan memanggil
+{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
+Handler) registerReceiver()}. Anda nanti bisa mencabut pendaftaran penerima dengan {@link
+android.content.Context#unregisterReceiver unregisterReceiver()}. Dengan begitu aplikasi Anda
+bisa mendengarkan siaran tertentu hanya selama periode waktu yang telah ditetapkan saat aplikasi Anda
+berjalan.</p>
+
+
+
+
+
+
+
+<h3 id="ExampleFilters">Contoh filter</h3>
+
+<p>Untuk lebih memahami beberapa perilaku filter intent, lihatlah cuplikan berikut
+dari file manifes aplikasi berbagi di jaringan sosial.</p>
+
+<pre>
+&lt;activity android:name="MainActivity">
+    &lt;!-- This activity is the main entry, should appear in app launcher -->
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.MAIN" />
+        &lt;category android:name="android.intent.category.LAUNCHER" />
+    &lt;/intent-filter>
+&lt;/activity>
+
+&lt;activity android:name="ShareActivity">
+    &lt;!-- This activity handles "SEND" actions with text data -->
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.SEND"/>
+        &lt;category android:name="android.intent.category.DEFAULT"/>
+        &lt;data android:mimeType="text/plain"/>
+    &lt;/intent-filter&gt;
+    &lt;!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.SEND"/>
+        &lt;action android:name="android.intent.action.SEND_MULTIPLE"/>
+        &lt;category android:name="android.intent.category.DEFAULT"/>
+        &lt;data android:mimeType="application/vnd.google.panorama360+jpg"/>
+        &lt;data android:mimeType="image/*"/>
+        &lt;data android:mimeType="video/*"/>
+    &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p>Aktivitas pertama, {@code MainActivity}, merupakan titik masuk utama aplikasi&mdash;aplikasi yang
+terbuka saat pengguna meluncurkan aplikasi dengan ikon launcher:</p>
+<ul>
+  <li>Tindakan {@link android.content.Intent#ACTION_MAIN}
+  menunjukkan ini adalah titik masuk utama dan tidak mengharapkan data intent apa pun.</li>
+  <li>Kategori {@link android.content.Intent#CATEGORY_LAUNCHER} menunjukjkan bahwa ikon
+  aktivitas ini harus ditempatkan dalam launcher aplikasi sistem. Jika elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+  tidak menetapkan ikon dengan{@code icon}, maka sistem akan menggunakan ikon dari elemen
+<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>.</li>
+</ul>
+<p>Keduanya harus dipasangkan bersama agar aktivitas muncul dalam launcher aplikasi.</p>
+
+<p>Aktivitas kedua, {@code ShareActivity}, dimaksudkan untuk memudahkan berbagi teks dan konten
+media. Walaupun pengguna mungkin memasuki aktivitas ini dengan mengarah ke aktivitas dari {@code MainActivity},
+pengguna juga bisa memasukkan {@code ShareActivity} secara langsung dari aplikasi lain yang mengeluarkan intent
+implisit yang cocok dengan salah satu dari kedua filter intent.</p>
+
+<p class="note"><strong>Catatan:</strong> Tipe MIME,
+<a href="https://developers.google.com/panorama/android/">{@code
+application/vnd.google.panorama360+jpg}</a>, merupakan tipe data khusus yang menetapkan
+foto panorama, yang bisa Anda tangani dengan API <a href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">panorama
+Google</a>.</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+<h2 id="PendingIntent">Menggunakan Intent Tertunda</h2>
+
+<p>Objek {@link android.app.PendingIntent} merupakan pembungkus objek {@link
+android.content.Intent}. Tujuan utama {@link android.app.PendingIntent}
+adalah memberikan izin pada aplikasi asing
+untuk menggunakan {@link android.content.Intent} yang termuat seolah-olah dieksekusi dari
+proses aplikasi Anda sendiri.</p>
+
+<p>Kasus penggunaan utama untuk intent tertunda antara lain:</p>
+<ul>
+  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan</a>
+  ({@link android.app.NotificationManager}
+  sistem Android akan mengeksekusi {@link android.content.Intent}) Anda.
+  <li>Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan
+<a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
+  (aplikasi layar Home mengeksekusi {@link android.content.Intent}).
+  <li>Mendeklarasikan intent untuk dieksekusi di waktu yang telah ditetapkan di masa mendatang
+({@link android.app.AlarmManager}  sistem Android akan mengeksekusi {@link android.content.Intent}).
+</ul>
+
+<p>Karena setiap objek {@link android.content.Intent} didesain untuk ditangani oleh tipe
+tertentu dari komponen aplikasi (baik {@link android.app.Activity}, {@link android.app.Service}, maupun
+ {@link android.content.BroadcastReceiver}), jadi {@link android.app.PendingIntent} harus
+dibuat dengan pertimbangan yang sama. Saat menggunakan intent tertunda, aplikasi Anda tidak akan
+mengeksekusi intent dengan panggilan seperti {@link android.content.Context#startActivity
+startActivity()}. Anda harus mendeklarasikan tipe komponen yang dimaksud saat membuat
+{@link android.app.PendingIntent} dengan memanggil metode kreator masing-masing:</p>
+
+<ul>
+  <li>{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()} untuk
+  {@link android.content.Intent} yang memulai {@link android.app.Activity}.</li>
+  <li>{@link android.app.PendingIntent#getService PendingIntent.getService()} untuk
+  {@link android.content.Intent} yang memulai {@link android.app.Service}.</li>
+  <li>{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} untuk
+  {@link android.content.Intent} yang memulai {@link android.content.BroadcastReceiver}.</li>
+</ul>
+
+<p>Kecuali jika aplikasi Anda <em>menerima</em> intent tertunda dari aplikasi lain,
+metode di atas untuk membuat {@link android.app.PendingIntent} menjadi satu-satunya metode
+{@link android.app.PendingIntent} yang mungkin Anda butuhkan.</p>
+
+<p>Tiap metode mengambil {@link android.content.Context} aplikasi saat itu,
+{@link android.content.Intent} yang ingin Anda bungkus, dan satu atau beberapa flag yang menetapkan
+cara penggunaan intent (misalnya apakah intent bisa digunakan lebih dari sekali).</p>
+
+<p>Informasi selengkapnya tentang intent tertunda disediakan pada dokumentasi untuk setiap
+kasus penggunaan yang bersangkutan, seperti dalam panduan API <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
+dan <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a>.</p>
+
+
+
+
+
+
+
+<h2 id="Resolution">Resolusi Intent</h2>
+
+
+<p>Saat sistem menerima intent implisit yang memulai suatu aktivitas, sistem tersebut akan mencari
+aktivitas terbaik untuk intent dengan membandingkan intent dengan filter intent berdasarkan tiga aspek:</p>
+
+<ul>
+  <li>Tindakan intent
+  <li>Data intent (baik URI maupun tipe data)
+  <li>Kategori intent
+</ul>
+
+<p>Bagian berikut menjelaskan cara pencocokan intent dengan komponen yang sesuai
+sehubungan dengan cara pendeklarasian filter intent dalam file manifes aplikasi.</p>
+
+
+<h3 id="ActionTest">Pengujian tindakan</h3>
+
+<p>Untuk menetapkan tindakan intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a>.  Misalnya:</p>
+
+<pre>
+&lt;intent-filter&gt;
+    &lt;action android:name="android.intent.action.EDIT" /&gt;
+    &lt;action android:name="android.intent.action.VIEW" /&gt;
+    ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>Untuk melewati filter ini, tindakan yang ditetapkan dalam {@link android.content.Intent}
+harus sesuai dengan salah satu tindakan yang tercantum dalam filter.</p>
+
+<p>Jika filter tidak mencantumkan tindakan apa pun, maka tidak ada intent
+yang dicocokkan, jadi semua intent gagal dalam pengujian. Akan tetapi, jika sebuah {@link android.content.Intent}
+tidak menetapkan suatu tindakan, maka akan lolos pengujian (asalkan filter
+berisi setidaknya satu tindakan).</p>
+
+
+
+<h3 id="CategoryTest">Pengujian kategori</h3>
+
+<p>Untuk menetapkan kategori intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a>.  Misalnya:</p>
+
+<pre>
+&lt;intent-filter&gt;
+    &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+    &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
+    ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>Agar intent bisa lolos pengujian kategori, setiap kategori dalam {@link android.content.Intent}
+harus sesuai dengan kategori dalam filter. Kebalikannya tidak diperlukan&mdash;filter intent bisa
+mendeklarasikan kategori lebih banyak daripada yang ditetapkan dalam {@link android.content.Intent} dan
+{@link android.content.Intent} tetap akan lolos. Oleh karena itu, intent tanpa kategori harus
+selalu lolos pengujian ini, kategori apa pun yang dideklarasikan dalam filter.</p>
+
+<p class="note"><strong>Catatan:</strong>
+Android secara otomatis menerapkan kategori {@link android.content.Intent#CATEGORY_DEFAULT}
+untuk semua intent implisit yang diteruskan ke {@link
+android.content.Context#startActivity startActivity()} dan {@link
+android.app.Activity#startActivityForResult startActivityForResult()}.
+Jadi jika ingin aktivitas Anda menerima intent implisit, aktivitas tersebut harus
+menyertakan kategori untuk{@code "android.intent.category.DEFAULT"} dalam filter intent (seperti
+yang ditampilkan dalam contoh{@code &lt;intent-filter&gt;} sebelumnya.</p>
+
+
+
+<h3 id="DataTest">Pengujian data</h3>
+
+<p>Untuk menetapkan data intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
+&lt;data&gt;}</a>.  Misalnya:</p>
+
+<pre>
+&lt;intent-filter&gt;
+    &lt;data android:mimeType="video/mpeg" android:scheme="http" ... /&gt;
+    &lt;data android:mimeType="audio/mpeg" android:scheme="http" ... /&gt;
+    ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>Tiap elemen <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+bisa menetapkan struktur URI dan tipe data (tipe media MIME).  Ada atribut
+terpisah &mdash; {@code scheme}, {@code host}, {@code port},
+dan {@code path} &mdash; untuk setiap bagian URI:
+</p>
+
+<p style="margin-left: 2em">{@code &lt;scheme&gt;://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;}</p>
+
+<p>
+Misalnya:
+</p>
+
+<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
+
+<p>Dalam URI ini, skemanya adalah {@code content}, host-nya adalah {@code com.example.project},
+port-nya adalah {@code 200}, dan path-nya adalah {@code folder/subfolder/etc}.
+</p>
+
+<p>Tiap atribut bersifat opsional dalam elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>,
+namun ada dependensi linear:</p>
+<ul>
+  <li>Jika skema tidak ditetapkan, host akan diabaikan.</li>
+  <li>Jika host tidak ditetapkan, port akan diabaikan.</li>
+  <li>Jika skema dan host tidak ditetapkan, path akan diabaikan.</li>
+</ul>
+
+<p>Bila URI dalam intent dibandingkan dengan spesifikasi URI dalam filter,
+pembandingannya hanya dengan bagian URI yang disertakan dalam filter. Misalnya:</p>
+<ul>
+  <li>Jika sebuah filter menetapkan hanya satu skema, semua URI dengan skema tersebut akan cocok
+dengan filter.</li>
+  <li>Jika sebuah filter menetapkan satu skema dan satu otoritas namun tanpa path, semua URI
+dengan skema dan otoritas yang sama akan lolos dari filter, apa pun path-nya.</li>
+  <li>Jika sebuah filter menetapkan satu skema, otoritas dan path, hanya URI dengan skema,
+otoritas, dan path sama yang bisa lolos dari filter.</li>
+</ul>
+
+<p class="note"><strong>Catatan:</strong> Spesifikasi path bisa berisi
+wildcard bintang (*) untuk hanya mencocokkan nama path secara parsial.</p>
+
+<p>Pengujian data membandingkan URI maupun tipe MIME dalam intent dengan URI
+dan tipe MIME yang ditetapkan dalam filter.  Aturannya adalah sebagai berikut:
+</p>
+
+<ol type="a">
+<li>Intent yang tidak berisi URI maupun tipe MIME hanya akan lolos
+pengujian jika filter tersebut tidak menetapkan URI atau tipe MIME apa pun.</li>
+
+<li>Intent yang berisi URI namun tidak berisi tipe MIME (baik secara eksplisit maupun tidak langsung dari
+URI) hanya akan lolos pengujian jika URI-nya cocok dengan format URI filter
+dan filternya juga tidak menetapkan tipe MIME.</li>
+
+<li>Intent yang berisi tipe MIME namun tidak berisi URI hanya akan lolos pengujian
+jika filter mencantumkan tipe MIME yang sama dan tidak menetapkan format URI.</li>
+
+<li>Intent yang berisi URI maupun tipe MIME (baik secara eksplisit maupun tidak langsung dari
+URI) hanya akan lolos pengujian bagian tipe MIME jika
+tipe tersebut cocok dengan tipe yang dicantumkan dalam filter.  Ini akan lolos pengujian bagian URI
+jika URI-nya cocok dengan URI dalam filter atau memiliki {@code content:}
+atau URI {@code file:} dan filter tidak menetapkan URI. Dengan kata lain,
+komponen dianggap mendukung data {@code content:} dan {@code file:} jika
+filternya <em>hanya</em> mencantumkan tipe MIME.</p></li>
+</ol>
+
+<p>
+Aturan terakhir ini, aturan (d), mencerminkan harapan
+bahwa komponen mampu mendapatkan data lokal dari file atau penyedia konten.
+Oleh karena itu, filter mereka mencatumkan tipe data saja dan tidak secara eksplisit
+harus menamai skema {@code content:} dan {@code file:}.
+Ini adalah kasus umum.  Elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
+seperti berikut ini, misalnya, memberi tahu Android bahwa komponen bisa mengambil data gambar dari penyedia
+konten dan menampilkannya:
+</p>
+
+<pre>
+&lt;intent-filter&gt;
+    &lt;data android:mimeType="image/*" /&gt;
+    ...
+&lt;/intent-filter&gt;</pre>
+
+<p>
+Karena sebagian besar data yang tersedia dikeluarkan oleh penyedia konten, filter yang
+menetapkan tipe data namun bukan URI mungkin adalah yang paling umum.
+</p>
+
+<p>
+Konfigurasi umum yang lain adalah filter dengan skema dan tipe data.  Misalnya
+, elemen <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>
+ seperti berikut ini akan memberi tahu Android bahwa
+komponen bisa mengambil data video dari jaringan untuk melakukan tindakan:
+</p>
+
+<pre>
+&lt;intent-filter&gt;
+    &lt;data android:scheme="http" android:type="video/*" /&gt;
+    ...
+&lt;/intent-filter&gt;</pre>
+
+
+
+<h3 id="imatch">Pencocokan intent</h3>
+
+<p>Intent dicocokkan dengan filter intent selain untuk menemukan komponen
+target yang akan diaktifkan, juga untuk menemukan sesuatu tentang rangkaian
+komponen pada perangkat.  Misalnya, aplikasi Home akan menempatkan launcher aplikasi
+dengan mencari semua aktivitas dengan filter intent yang menetapkan tindakan
+{@link android.content.Intent#ACTION_MAIN} dan
+kategori {@link android.content.Intent#CATEGORY_LAUNCHER}.</p>
+
+<p>Aplikasi Anda bisa menggunakan pencocokan intent dengan cara serupa.
+{@link android.content.pm.PackageManager} memiliki seperangkat metode {@code query...()}
+yang mengembalikan semua komponen yang bisa menerima intent tertentu, dan
+serangkaian metode{@code resolve...()} serupa yang menentukan komponen
+terbaik untuk merespons intent.  Misalnya,
+{@link android.content.pm.PackageManager#queryIntentActivities
+queryIntentActivities()} akan mengembalikan daftar semua aktivitas yang bisa melakukan
+intent yang diteruskan sebagai argumen, dan {@link
+android.content.pm.PackageManager#queryIntentServices
+queryIntentServices()} akan mengembalikan daftar layanan serupa.
+Tidak ada metode yang akan mengaktifkan komponen; mereka hanya mencantumkan komponen yang
+bisa merespons.  Ada metode serupa,
+{@link android.content.pm.PackageManager#queryBroadcastReceivers
+queryBroadcastReceivers()}, untuk penerima siaran.
+</p>
+
+
+
+
diff --git a/docs/html-intl/intl/id/guide/components/loaders.jd b/docs/html-intl/intl/id/guide/components/loaders.jd
new file mode 100644
index 0000000..88093cc
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/loaders.jd
@@ -0,0 +1,494 @@
+page.title=Aktivitas
+parent.title=Loader
+parent.link=activities.html
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+    <h2>Dalam dokumen ini</h2>
+    <ol>
+    <li><a href="#summary">Rangkuman Loader API</a></li>
+    <li><a href="#app">Menggunakan Loader dalam Aplikasi</a>
+      <ol>
+        <li><a href="#requirements"></a></li>
+        <li><a href="#starting">Memulai Loader</a></li>
+        <li><a href="#restarting">Me-restart Loader</a></li>
+        <li><a href="#callback">Menggunakan Callback LoaderManager</a></li>
+      </ol>
+    </li>
+    <li><a href="#example">Contoh</a>
+       <ol>
+         <li><a href="#more_examples">Contoh Selengkapnya</a></li>
+        </ol>
+    </li>
+  </ol>
+
+  <h2>Kelas-kelas utama</h2>
+    <ol>
+      <li>{@link android.app.LoaderManager}</li>
+      <li>{@link android.content.Loader}</li>
+
+    </ol>
+
+    <h2>Contoh-contoh terkait</h2>
+   <ol>
+     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
+LoaderCursor</a></li>
+     <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html">
+LoaderThrottle</a></li>
+   </ol>
+  </div>
+</div>
+
+<p>Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron
+dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:</p>
+  <ul>
+    <li>Loader tersedia untuk setiap {@link android.app.Activity} dan {@link
+android.app.Fragment}.</li>
+    <li>Loader menyediakan pemuatan data asinkron.</li>
+    <li>Loader memantau sumber data mereka dan memberikan hasil baru bila
+konten berubah.</li>
+    <li>Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat
+dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang
+datanya.</li>
+  </ul>
+
+<h2 id="summary">Rangkuman Loader API</h2>
+
+<p>Ada beberapa kelas dan antarmuka yang mungkin dilibatkan dalam menggunakan
+loader pada aplikasi. Semuanya dirangkum dalam tabel ini:</p>
+
+<table>
+  <tr>
+    <th>Kelas/Antarmuka</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.app.LoaderManager}</td>
+    <td>Kelas abstrak yang dikaitkan dengan {@link android.app.Activity} atau
+{@link android.app.Fragment} untuk mengelola satu atau beberapa instance {@link
+android.content.Loader}. Ini membantu aplikasi mengelola
+operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
+atau {@link android.app.Fragment}; penggunaan paling umumnya adalah dengan
+{@link android.content.CursorLoader}, akan tetapi aplikasi bebas menulis loader-nya
+ sendiri untuk memuat tipe data lainnya.
+    <br />
+    <br />
+    Hanya ada satu {@link android.app.LoaderManager} per aktivitas atau fragmen. Namun {@link android.app.LoaderManager} bisa memiliki
+beberapa loader.</td>
+  </tr>
+  <tr>
+    <td>{@link android.app.LoaderManager.LoaderCallbacks}</td>
+    <td>Antarmuka callback untuk klien berinteraksi dengan {@link
+android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link
+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
+untuk membuat loader baru.</td>
+  </tr>
+  <tr>
+    <td>{@link android.content.Loader}</td>
+    <td>Kelas abstrak yang melakukan pemuatan data asinkron. Ini
+adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link
+android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi
+loader aktif, loader harus memantau sumber datanya dan memberikan hasil
+baru bila konten berubah. </td>
+  </tr>
+  <tr>
+    <td>{@link android.content.AsyncTaskLoader}</td>
+    <td>Loader abstrak yang menyediakan {@link android.os.AsyncTask} untuk melakukan pekerjaan.</td>
+  </tr>
+  <tr>
+    <td>{@link android.content.CursorLoader}</td>
+    <td>Subkelas {@link android.content.AsyncTaskLoader} yang meng-query
+{@link android.content.ContentResolver} dan mengembalikan {@link
+android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link
+android.content.Loader} dengan cara standar untuk query kursor,
+yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor
+pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader
+ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link
+android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui
+fragmen atau API aktivitas.</td>
+  </tr>
+</table>
+
+<p>Kelas dan antarmuka dalam tabel di atas merupakan komponen
+esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya
+untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link
+android.app.LoaderManager} untuk memulai loader dan implementasi
+kelas {@link android.content.Loader} seperti {@link
+android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan
+kelas dan antarmuka ini dalam aplikasi.</p>
+
+<h2 id ="app">Menggunakan Loader dalam Aplikasi</h2>
+<p>Bagian ini menjelaskan cara menggunakan loader dalam aplikasi Android. Aplikasi
+yang menggunakan loader biasanya berisi yang berikut ini:</p>
+<ul>
+  <li>{@link android.app.Activity} atau {@link android.app.Fragment}.</li>
+  <li>Instance {@link android.app.LoaderManager}.</li>
+  <li>{@link android.content.CursorLoader} akan memuat data yang didukung oleh {@link
+android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri
+ dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk
+memuat data dari beberapa sumber lain.</li>
+  <li>Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}.
+Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader
+yang ada.</li>
+<li>Cara menampilkan data loader, seperti {@link
+android.widget.SimpleCursorAdapter}.</li>
+  <li>Sumber data, seperti {@link android.content.ContentProvider}, saat menggunakan
+{@link android.content.CursorLoader}.</li>
+</ul>
+<h3 id="starting">Memulai Loader</h3>
+
+<p>{@link android.app.LoaderManager} mengelola satu atau beberapa instance {@link
+android.content.Loader} dalam {@link android.app.Activity} atau
+{@link android.app.Fragment}. Hanya ada satu {@link
+android.app.LoaderManager} per aktivitas atau fragmen.</p>
+
+<p>Anda biasanya
+memulai {@link android.content.Loader} dalam metode {@link
+android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode
+{@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda
+melakukannya dengan cara berikut ini:</p>
+
+<pre>// Prepare the loader.  Either re-connect with an existing one,
+// or start a new one.
+getLoaderManager().initLoader(0, null, this);</pre>
+
+<p>Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil
+parameter berikut:</p>
+<ul>
+  <li>ID unik yang mengidentifikasi loader. Dalam contoh ini, ID-nya adalah 0.</li>
+<li>Argumen opsional untuk dipasok ke loader
+pada saat pembuatan (dalam contoh ini <code>null</code>).</li>
+
+<li>Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang
+akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh
+ini, kelas lokal mengimplementasikan antarmuka {@link
+android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan
+ke dirinya sendiri, {@code this}.</li>
+</ul>
+<p>Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader
+telah dimulai dan aktif. Ia memiliki dua kemungkinan hasil:</p>
+<ul>
+  <li>Jika loader yang disebutkan oleh ID sudah ada, loader yang dibuat terakhir akan digunakan
+kembali.</li>
+  <li>Jika loader yang disebutkan oleh ID <em>tidak</em> ada,
+{@link android.app.LoaderManager#initLoader initLoader()} akan memicu metode
+{@link android.app.LoaderManager.LoaderCallbacks} {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}.
+Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru.
+Untuk diskusi selengkapnya, lihat bagian <a href="#onCreateLoader">onCreateLoader</a>.</li>
+</ul>
+<p>Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks}
+yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila
+status loader berubah.  Jika saat panggilan ini status pemanggil sudah
+dimulai, dan loader yang diminta sudah ada dan telah menghasilkan
+datanya, maka sistem segera memanggil {@link
+android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+(selama {@link android.app.LoaderManager#initLoader initLoader()}),
+sehingga Anda harus siap bila hal ini terjadi. Lihat <a href="#onLoadFinished">
+onLoadFinished</a> untuk diskusi selengkapnya mengenai callback ini</p>
+
+<p>Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()}
+mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak
+perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola
+masa hidup loader secara otomatis. {@link android.app.LoaderManager}
+memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader
+dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader
+secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku
+loader, lihat contoh <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>).
+Anda paling sering akan menggunakan metode {@link
+android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses
+pemuatan saat terjadi kejadian tertentu. Untuk diskusi selengkapnya mengenai topik ini, lihat <a href="#callback">Menggunakan Callback LoaderManager</a>.</p>
+
+<h3 id="restarting">Me-restart Loader</h3>
+
+<p>Bila Anda menggunakan {@link android.app.LoaderManager#initLoader initLoader()}, seperti
+ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada.
+Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama
+dan mulai dari awal.</p>
+
+<p>Untuk membuang data lama, gunakan {@link
+android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi
+{@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart
+bila query pengguna berubah. Loader perlu di-restart
+agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:</p>
+
+<pre>
+public boolean onQueryTextChanged(String newText) {
+    // Called when the action bar search text has changed.  Update
+    // the search filter, and restart the loader to do a new query
+    // with this filter.
+    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
+    getLoaderManager().restartLoader(0, null, this);
+    return true;
+}</pre>
+
+<h3 id="callback">Menggunakan Callback LoaderManager</h3>
+
+<p>{@link android.app.LoaderManager.LoaderCallbacks} adalah antarmuka callback
+yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}. </p>
+<p>Loader, khususnya {@link android.content.CursorLoader}, diharapkan
+mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan
+datanya di aktivitas atau metode {@link android.app.Activity#onStop
+onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga
+bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data
+dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks}
+untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan
+berhenti menggunakan data loader.</p>
+
+<p>{@link android.app.LoaderManager.LoaderCallbacks} berisi metode
+ini:</p>
+<ul>
+  <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} —
+Membuat instance dan mengembalikan {@link android.content.Loader} baru untuk ID yang diberikan.
+</li></ul>
+<ul>
+  <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+— Dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
+</li></ul>
+<ul>
+  <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}
+    — Dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
+tidak tersedia.
+</li>
+</ul>
+<p>Metode ini dijelaskan lebih detail dalam bagian berikutnya.</p>
+
+<h4 id ="onCreateLoader">onCreateLoader</h4>
+
+<p>Saat Anda mencoba mengakses loader (misalnya, melalui {@link
+android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya
+loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link
+android.app.LoaderManager.LoaderCallbacks} {@link
+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di
+sinilah Anda membuat loader baru. Biasanya ini adalah {@link
+android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link
+android.content.Loader}. </p>
+
+<p>Dalam contoh ini, metode callback {@link
+android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
+ akan membuat {@link android.content.CursorLoader}. Anda harus membuat
+{@link android.content.CursorLoader} menggunakan metode konstruktornya, yang
+memerlukan set informasi lengkap untuk melakukan query ke {@link
+android.content.ContentProvider}. Secara khusus, ia memerlukan:</p>
+<ul>
+  <li><em>uri</em> — URI untuk konten yang akan diambil. </li>
+  <li><em>projection</em> — Daftar berisi kolom yang akan dikembalikan. Meneruskan
+<code>null</code> akan mengembalikan semua kolom, jadi tidak efisien. </li>
+  <li><em>selection</em> — Filter yang mendeklarasikan baris yang akan dikembalikan,
+diformat sebagai klausa SQL WHERE (tidak termasuk WHERE itu sendiri). Meneruskan
+<code>null</code> akan mengembalikan semua baris untuk URI yang diberikan. </li>
+  <li><em>selectionArgs</em> — Anda dapat menyertakan ?s dalam pilihan, yang akan
+digantikan dengan nilai dari <em>selectionArgs</em>, agar muncul dalam
+pilihan. Nilai-nilai akan diikat sebagai String. </li>
+  <li><em>sortOrder</em> — Cara menyusun baris, diformat sebagai klausa SQL
+ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan <code>null</code> akan
+menggunakan urutan sortir default, yang mungkin tidak berurutan.</li>
+</ul>
+<p>Misalnya:</p>
+<pre>
+ // If non-null, this is the current filter the user has provided.
+String mCurFilter;
+...
+public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
+    // This is called when a new Loader needs to be created.  This
+    // sample only has one Loader, so we don't care about the ID.
+    // First, pick the base URI to use depending on whether we are
+    // currently filtering.
+    Uri baseUri;
+    if (mCurFilter != null) {
+        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
+                  Uri.encode(mCurFilter));
+    } else {
+        baseUri = Contacts.CONTENT_URI;
+    }
+
+    // Now create and return a CursorLoader that will take care of
+    // creating a Cursor for the data being displayed.
+    String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
+            + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
+            + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
+    return new CursorLoader(getActivity(), baseUri,
+            CONTACTS_SUMMARY_PROJECTION, select, null,
+            Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
+}</pre>
+<h4 id="onLoadFinished">onLoadFinished</h4>
+
+<p>Metode ini dipanggil bila loader yang dibuat sebelumnya selesai dimuat.
+Metode ini dijamin dipanggil sebelum pelepasan data terakhir
+yang disediakan untuk loader ini.  Di titik ini Anda harus menyingkirkan semua penggunaan
+data lama (karena akan segera dilepas), namun jangan melepas sendiri
+data tersebut karena loader memilikinya dan akan menanganinya.</p>
+
+
+<p>Loader akan melepas data setelah mengetahui bahwa aplikasi tidak
+lagi menggunakannya.  Misalnya, jika data adalah kursor dari {@link
+android.content.CursorLoader}, Anda tidak boleh memanggil {@link
+android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan
+dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link
+android.widget.SimpleCursorAdapter#swapCursor swapCursor()} agar
+{@link android.database.Cursor} lama tidak ditutup. Misalnya:</p>
+
+<pre>
+// This is the Adapter being used to display the list's data.<br
+/>SimpleCursorAdapter mAdapter;
+...
+
+public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
+    // Swap the new cursor in.  (The framework will take care of closing the
+    // old cursor once we return.)
+    mAdapter.swapCursor(data);
+}</pre>
+
+<h4 id="onLoaderReset">onLoaderReset</h4>
+
+<p>Metode ini dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya
+tidak tersedia. Callback ini memungkinkan Anda mengetahui
+kapan data akan dilepas sehingga dapat menghapus acuannya ke callback.  </p>
+<p>Implementasi ini memanggil
+{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
+dengan nilai <code>null</code>:</p>
+
+<pre>
+// This is the Adapter being used to display the list's data.
+SimpleCursorAdapter mAdapter;
+...
+
+public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
+    // This is called when the last Cursor provided to onLoadFinished()
+    // above is about to be closed.  We need to make sure we are no
+    // longer using it.
+    mAdapter.swapCursor(null);
+}</pre>
+
+
+<h2 id="example">Contoh</h2>
+
+<p>Sebagai contoh, berikut ini adalah implementasi penuh {@link
+android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi
+hasil query terhadap penyedia konten kontak. Ia menggunakan {@link
+android.content.CursorLoader} untuk mengelola query pada penyedia.</p>
+
+<p>Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini,
+manifesnya harus menyertakan izin
+{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p>
+
+<pre>
+public static class CursorLoaderListFragment extends ListFragment
+        implements OnQueryTextListener, LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
+
+    // This is the Adapter being used to display the list's data.
+    SimpleCursorAdapter mAdapter;
+
+    // If non-null, this is the current filter the user has provided.
+    String mCurFilter;
+
+    @Override public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // Give some text to display if there is no data.  In a real
+        // application this would come from a resource.
+        setEmptyText(&quot;No phone numbers&quot;);
+
+        // We have a menu item to show in action bar.
+        setHasOptionsMenu(true);
+
+        // Create an empty adapter we will use to display the loaded data.
+        mAdapter = new SimpleCursorAdapter(getActivity(),
+                android.R.layout.simple_list_item_2, null,
+                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
+                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
+        setListAdapter(mAdapter);
+
+        // Prepare the loader.  Either re-connect with an existing one,
+        // or start a new one.
+        getLoaderManager().initLoader(0, null, this);
+    }
+
+    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        // Place an action bar item for searching.
+        MenuItem item = menu.add(&quot;Search&quot;);
+        item.setIcon(android.R.drawable.ic_menu_search);
+        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        SearchView sv = new SearchView(getActivity());
+        sv.setOnQueryTextListener(this);
+        item.setActionView(sv);
+    }
+
+    public boolean onQueryTextChange(String newText) {
+        // Called when the action bar search text has changed.  Update
+        // the search filter, and restart the loader to do a new query
+        // with this filter.
+        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
+        getLoaderManager().restartLoader(0, null, this);
+        return true;
+    }
+
+    @Override public boolean onQueryTextSubmit(String query) {
+        // Don't care about this.
+        return true;
+    }
+
+    @Override public void onListItemClick(ListView l, View v, int position, long id) {
+        // Insert desired behavior here.
+        Log.i(&quot;FragmentComplexList&quot;, &quot;Item clicked: &quot; + id);
+    }
+
+    // These are the Contacts rows that we will retrieve.
+    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
+        Contacts._ID,
+        Contacts.DISPLAY_NAME,
+        Contacts.CONTACT_STATUS,
+        Contacts.CONTACT_PRESENCE,
+        Contacts.PHOTO_ID,
+        Contacts.LOOKUP_KEY,
+    };
+    public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
+        // This is called when a new Loader needs to be created.  This
+        // sample only has one Loader, so we don't care about the ID.
+        // First, pick the base URI to use depending on whether we are
+        // currently filtering.
+        Uri baseUri;
+        if (mCurFilter != null) {
+            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
+                    Uri.encode(mCurFilter));
+        } else {
+            baseUri = Contacts.CONTENT_URI;
+        }
+
+        // Now create and return a CursorLoader that will take care of
+        // creating a Cursor for the data being displayed.
+        String select = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
+                + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
+                + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
+        return new CursorLoader(getActivity(), baseUri,
+                CONTACTS_SUMMARY_PROJECTION, select, null,
+                Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
+    }
+
+    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor data) {
+        // Swap the new cursor in.  (The framework will take care of closing the
+        // old cursor once we return.)
+        mAdapter.swapCursor(data);
+    }
+
+    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
+        // This is called when the last Cursor provided to onLoadFinished()
+        // above is about to be closed.  We need to make sure we are no
+        // longer using it.
+        mAdapter.swapCursor(null);
+    }
+}</pre>
+<h3 id="more_examples">Contoh Selengkapnya</h3>
+
+<p>Ada beberapa contoh berbeda dalam <strong>ApiDemos</strong> yang
+mengilustrasikan cara menggunakan loader:</p>
+<ul>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html">
+LoaderCursor</a> — Versi lengkap dari
+cuplikan yang ditampilkan di atas.</li>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — Contoh cara penggunaan throttling untuk
+mengurangi jumlah query dari penyedia konten saat datanya berubah.</li>
+</ul>
+
+<p>Untuk informasi tentang mengunduh dan menginstal contoh SDK, lihat <a href="http://developer.android.com/resources/samples/get.html"> Mendapatkan
+Contoh</a>. </p>
+
diff --git a/docs/html-intl/intl/id/guide/components/processes-and-threads.jd b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
new file mode 100644
index 0000000..cdab715
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/processes-and-threads.jd
@@ -0,0 +1,411 @@
+page.title=Proses dan Thread
+page.tags=daur hidup,latar belakang
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+<li><a href="#Processes">Proses</a>
+  <ol>
+    <li><a href="#Lifecycle">Daur hidup proses</a></li>
+  </ol>
+</li>
+<li><a href="#Threads">Thread</a>
+  <ol>
+    <li><a href="#WorkerThreads">Thread pekerja</a></li>
+    <li><a href="#ThreadSafe">Metode thread-safe</a></li>
+  </ol>
+</li>
+<li><a href="#IPC">Komunikasi antarproses</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>Bila komponen aplikasi dimulai dan tidak ada komponen aplikasi lain yang
+berjalan, sistem Android akan memulai proses Linux baru untuk aplikasi dengan satu thread
+eksekusi. Secara default, semua komponen aplikasi yang sama berjalan dalam proses dan
+thread yang sama (disebut thread "utama"). Jika komponen aplikasi dimulai dan sudah ada
+proses untuk aplikasi itu (karena komponen lain dari aplikasi itu sudah ada), maka komponen
+akan dimulai dalam proses itu dan menggunakan thread eksekusi yang sama. Akan tetapi, Anda bisa
+mengatur komponen berbeda di aplikasi agar berjalan di proses terpisah, dan Anda bisa membuat thread tambahan untuk
+setiap proses.</p>
+
+<p>Dokumen ini membahas cara kerja proses dan thread di aplikasi Android.</p>
+
+
+<h2 id="Processes">Proses</h2>
+
+<p>Secara default, semua komponen aplikasi yang sama berjalan dalam proses yang sama dan kebanyakan
+aplikasi tidak boleh mengubah ini. Akan tetapi, jika Anda merasa perlu mengontrol proses milik
+komponen tertentu, Anda dapat melakukannya dalam file manifes.</p>
+
+<p>Entri manifes untuk setiap tipe elemen komponen&mdash;<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code
+&lt;service&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
+&lt;receiver&gt;}</a>, dan <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code
+&lt;provider&gt;}</a>&mdash;mendukung atribut {@code android:process} yang bisa menetapkan
+dalam proses mana komponen harus dijalankan. Anda bisa mengatur atribut ini agar setiap komponen
+berjalan dalam prosesnya sendiri atau agar beberapa komponen menggunakan proses yang sama sementara yang lainnya tidak.  Anda juga bisa mengatur
+{@code android:process} agar komponen aplikasi yang berbeda berjalan dalam proses yang sama
+&mdash;sepanjang aplikasi menggunakan ID Linux yang sama dan ditandatangani
+dengan sertifikat yang sama.</p>
+
+<p>Elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+&lt;application&gt;}</a> juga mendukung atribut {@code android:process}, untuk mengatur
+nilai default yang berlaku bagi semua komponen.</p>
+
+<p>Android bisa memutuskan untuk mematikan proses pada waktu tertentu, bila memori tinggal sedikit dan diperlukan oleh
+proses lain yang lebih mendesak untuk melayani pengguna. Komponen
+aplikasi yang berjalan dalam proses yang dimatikan maka sebagai konsekuensinya juga akan dimusnahkan.  Proses dimulai
+kembali untuk komponen itu bila ada lagi pekerjaan untuk mereka lakukan.</p>
+
+<p>Saat memutuskan proses yang akan dimatikan, sistem Android akan mempertimbangkan kepentingan relatifnya bagi
+pengguna.  Misalnya, sistem lebih mudah menghentikan proses yang menjadi host aktivitas yang tidak
+ lagi terlihat di layar, dibandingkan dengan proses yang menjadi host aktivitas yang terlihat. Karena itu, keputusan
+untuk menghentikan proses bergantung pada keadaan komponen yang berjalan dalam proses tersebut. Aturan
+yang digunakan untuk menentukan proses yang akan dihentikan dibahas di bawah ini. </p>
+
+
+<h3 id="Lifecycle">Daur hidup proses</h3>
+
+<p>Sistem Android mencoba mempertahankan proses aplikasi selama mungkin, namun
+pada akhirnya perlu menghapus proses lama untuk mengambil kembali memori bagi proses baru atau yang lebih penting.  Untuk
+menentukan proses yang akan
+dipertahankan dan yang harus dimatikan, sistem menempatkan setiap proses ke dalam "hierarki prioritas" berdasarkan
+komponen yang berjalan dalam proses dan status komponen tersebut.  Proses yang memiliki
+prioritas terendah akan dimatikan terlebih dahulu, kemudian yang terendah berikutnya, dan seterusnya, jika perlu
+untuk memulihkan sumber daya sistem.</p>
+
+<p>Ada lima tingkatan dalam hierarki prioritas. Daftar berikut berisi beberapa
+tipe proses berdasarkan urutan prioritas (proses pertama adalah yang <em>terpenting</em> dan
+<em>dimatikan terakhir</em>):</p>
+
+<ol>
+  <li><b>Proses latar depan</b>
+    <p>Proses yang diperlukan untuk aktivitas yang sedang dilakukan pengguna.  Proses
+dianggap berada di latar depan jika salah satu kondisi berikut terpenuhi:</p>
+
+      <ul>
+        <li>Proses menjadi host {@link android.app.Activity} yang berinteraksi dengan pengguna dengan metode ({@link
+android.app.Activity}{@link android.app.Activity#onResume onResume()} telah
+dipanggil).</li>
+
+        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang sedang berinteraksi dengan
+pengguna.</li>
+
+        <li>Proses menjadi host {@link android.app.Service} yang berjalan "di latar depan"&mdash;
+layanan telah memanggil{@link android.app.Service#startForeground startForeground()}.
+
+        <li>Proses menjadi host {@link android.app.Service} yang menjalankan salah satu callback
+daur hidupnya ({@link android.app.Service#onCreate onCreate()}, {@link android.app.Service#onStart
+onStart()}, atau {@link android.app.Service#onDestroy onDestroy()}).</li>
+
+        <li>Proses menjadi host {@link android.content.BroadcastReceiver} yang menjalankan metode {@link
+        android.content.BroadcastReceiver#onReceive onReceive()}-nya.</li>
+    </ul>
+
+    <p>Secara umum, hanya ada beberapa proses latar depan pada waktu yang diberikan.  Proses dimatikan hanya sebagai
+upaya terakhir&mdash; jika memori hampir habis sehingga semuanya tidak bisa terus berjalan.  Pada umumnya, pada
+titik itu, perangkat dalam keadaan memory paging, sehingga menghentikan beberapa proses latar depan
+diperlukan agar antarmuka pengguna tetap responsif.</p></li>
+
+  <li><b>Proses yang terlihat</b>
+    <p>Proses yang tidak memiliki komponen latar depan, namun masih bisa
+memengaruhi apa yang dilihat pengguna di layar. Proses dianggap terlihat jika salah satu kondisi
+berikut terpenuhi:</p>
+
+      <ul>
+        <li>Proses ini menjadi host {@link android.app.Activity} yang tidak berada di latar depan, namun masih
+terlihat oleh penggunanya (metode {@link android.app.Activity#onPause onPause()} telah dipanggil).
+Ini bisa terjadi, misalnya, jika aktivitas latar depan memulai dialog, sehingga
+aktivitas sebelumnya terlihat berada di belakangnya.</li>
+
+        <li>Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang terlihat (atau latar
+depan)</li>
+      </ul>
+
+      <p>Proses yang terlihat dianggap sangat penting dan tidak akan dimatikan kecuali jika hal itu
+diperlukan agar semua proses latar depan tetap berjalan. </p>
+    </li>
+
+  <li><b>Proses layanan</b>
+    <p>Proses yang menjalankan layanan yang telah dimulai dengan metode {@link
+android.content.Context#startService startService()} dan tidak termasuk dalam salah satu dari dua kategori
+yang lebih tinggi. Walaupun proses pelayanan tidak langsung terkait dengan semua yang dilihat oleh pengguna, proses ini
+umumnya melakukan hal-hal yang dipedulikan pengguna (seperti memutar musik di latar belakang
+atau mengunduh data di jaringan), jadi sistem membuat proses tetap berjalan kecuali memori tidak cukup untuk
+mempertahankannya bersama semua proses latar depan dan proses yang terlihat. </p>
+  </li>
+
+  <li><b>Proses latar belakang</b>
+    <p>Proses yang menampung aktivitas yang saat ini tidak terlihat oleh pengguna (metode
+{@link android.app.Activity#onStop onStop()} aktivitas telah dipanggil). Proses ini tidak memiliki dampak
+langsung pada pengalaman pengguna, dan sistem bisa menghentikannya kapan saja untuk memperoleh kembali memori bagi
+proses latar depan, proses yang terlihat,
+atau proses layanan. Biasanya ada banyak proses latar belakang yang berjalan, sehingga disimpan
+dalam daftar LRU (least recently used atau paling sedikit digunakan) untuk memastikan bahwa proses dengan aktivitas yang paling baru
+terlihat oleh pengguna sebagai yang terakhir untuk dimatikan. Jika aktivitas mengimplementasikan metode
+ daur hidupnya dengan benar, dan menyimpan statusnya saat ini, menghentikan prosesnya tidak akan memiliki efek
+yang terlihat pada pengalaman pengguna, karena ketika pengguna kembali ke aktivitas, aktivitas itu memulihkan
+semua statusnya yang terlihat. Lihat dokumen <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>
+ untuk mendapatkan informasi tentang menyimpan dan memulihkan status.</p>
+  </li>
+
+  <li><b>Proses kosong</b>
+    <p>Sebuah proses yang tidak berisi komponen aplikasi aktif apa pun.  Alasan satu-satunya mempertahankan proses
+seperti ini tetap hidup adalah untuk keperluan caching, meningkatkan waktu mulai (startup) bila
+nanti komponen perlu dijalankan di dalamnya.  Sistem sering menghentikan proses ini untuk menyeimbangkan sumber
+daya sistem secara keseluruhan antara proses cache dan cache kernel yang mendasarinya.</p>
+  </li>
+</ol>
+
+
+  <p>Android sebisa mungkin memeringkat proses setinggi
+mungkin, berdasarkan prioritas komponen yang sedang aktif dalam proses.  Misalnya, jika suatu proses menjadi host sebuah layanan dan
+aktivitas yang terlihat, proses akan diperingkat sebagai proses yang terlihat, bukan sebagai proses layanan.</p>
+
+  <p>Selain itu, peringkat proses dapat meningkat karena adanya proses lain yang bergantung padanya
+&mdash;proses yang melayani proses lain tidak bisa diperingkat lebih rendah daripada proses yang
+sedang dilayaninya. Misalnya, jika penyedia konten dalam proses A melayani klien dalam proses B, atau
+jika layanan dalam proses A terikat dengan komponen dalam proses B, proses A selalu dipertimbangkan sebagai paling rendah
+prioritasnya dibandingkan dengan proses B.</p>
+
+  <p>Karena proses yang menjalankan layanan diperingkat lebih tinggi daripada aktivitas latar belakang,
+aktivitas yang memulai operasi yang berjalan lama mungkin lebih baik memulai <a href="{@docRoot}guide/components/services.html">layanan</a> untuk operasi itu, daripada hanya
+membuat thread pekerja&mdash;khususnya jika operasi mungkin akan berlangsung lebih lama daripada aktivitas.
+ Misalnya, aktivitas yang mengunggah gambar ke situs web harus memulai layanan
+untuk mengunggah sehingga unggahan bisa terus berjalan di latar belakang meskipun pengguna meninggalkan aktivitas tersebut.
+Menggunakan layanan akan memastikan operasi paling tidak memiliki prioritas "proses layanan",
+apa pun yang terjadi pada aktivitas. Ini menjadi alasan yang sama yang membuat penerima siaran harus
+menjalankan layanan daripada hanya menempatkan operasi yang menghabiskan waktu di thread.</p>
+
+
+
+
+<h2 id="Threads">Thread</h2>
+
+<p>Bila aplikasi diluncurkan, sistem akan membuat thread eksekusi untuk aplikasi tersebut, yang diberi nama,
+"main". Thread ini sangat penting karena bertugas mengirim kejadian ke widget
+antarmuka pengguna yang sesuai, termasuk kejadian menggambar. Ini juga merupakan thread yang
+membuat aplikasi berinteraksi dengan komponen dari Android UI toolkit (komponen dari paket {@link
+android.widget} dan {@link android.view}). Karena itu, thread 'main' juga terkadang
+disebut thread UI.</p>
+
+<p>Sistem ini <em>tidak</em> membuat thread terpisah untuk setiap instance komponen. Semua
+komponen yang berjalan di proses yang sama akan dibuat instance-nya dalam thread UI, dan sistem akan memanggil
+setiap komponen yang dikirim dari thread itu. Akibatnya, metode yang merespons callback sistem
+ (seperti {@link android.view.View#onKeyDown onKeyDown()} untuk melaporkan tindakan pengguna atau metode callback daur hidup)
+ selalu berjalan di thread UI proses.</p>
+
+<p>Misalnya saat pengguna menyentuh tombol pada layar, thread UI aplikasi akan mengirim kejadian
+sentuh ke widget, yang selanjutnya menetapkan status ditekan dan mengirim permintaan yang tidak divalidasi ke
+antrean kejadian. Thread UI akan menghapus antrean permintaan dan memberi tahu widget bahwa widget harus menggambar
+dirinya sendiri.</p>
+
+<p>Saat aplikasi melakukan pekerjaan intensif sebagai respons terhadap interaksi pengguna, model
+thread tunggal ini bisa menghasilkan kinerja yang buruk kecuali jika Anda mengimplementasikan aplikasi dengan benar. Khususnya jika
+ semua terjadi di thread UI, melakukan operasi yang panjang seperti akses ke jaringan atau query
+database akan memblokir seluruh UI. Bila thread diblokir, tidak ada kejadian yang bisa dikirim,
+termasuk kejadian menggambar. Dari sudut pandang pengguna, aplikasi
+tampak mogok (hang). Lebih buruk lagi, jika thread UI diblokir selama lebih dari beberapa detik
+(saat ini sekitar 5 detik) pengguna akan ditampilkan dialog "<a href="http://developer.android.com/guide/practices/responsiveness.html">aplikasi tidak
+merespons</a>" (ANR) yang populer karena reputasi buruknya. Pengguna nanti bisa memutuskan untuk keluar dari aplikasi dan menghapus aplikasi
+jika mereka tidak suka.</p>
+
+<p>Selain itu, toolkit Android UI <em>bukan</em> thread-safe. Jadi, Anda tidak harus memanipulasi
+UI dari thread pekerja&mdash;Anda harus melakukan semua manipulasi pada antarmuka pengguna dari thread
+UI. Sehingga hanya ada dua aturan untuk model thread tunggal Android:</p>
+
+<ol>
+<li>Jangan memblokir thread UI
+<li>Jangan mengakses toolkit Android UI dari luar thread UI
+</ol>
+
+<h3 id="WorkerThreads">Thread pekerja</h3>
+
+<p>Karena model thread tunggal yang dijelaskan di atas, Anda dilarang memblokir thread
+UI demi daya respons UI aplikasi. Jika memiliki operasi untuk dijalankan
+yang tidak seketika, Anda harus memastikan untuk melakukannya di thread terpisah (thread "latar belakang" atau
+thread "pekerja").</p>
+
+<p>Misalnya, berikut ini beberapa kode untuk listener klik yang mengunduh gambar dari
+thread terpisah dan menampilkannya dalam {@link android.widget.ImageView}:</p>
+
+<pre>
+public void onClick(View v) {
+    new Thread(new Runnable() {
+        public void run() {
+            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
+            mImageView.setImageBitmap(b);
+        }
+    }).start();
+}
+</pre>
+
+<p>Awalnya hal ini tampak bekerja dengan baik, karena menciptakan thread baru untuk menangani
+operasi jaringan. Akan tetapi, hal tersebut melanggar aturan kedua model thread tunggal: <em>jangan mengakses
+ toolkit Android UI dari luar thread UI</em>&mdash;sampel ini memodifikasi {@link
+android.widget.ImageView} dari thread pekerja sebagai ganti thread UI. Ini bisa
+mengakibatkan perilaku yang tidak terdefinisi dan tidak diharapkan, yang bisa menyulitkan dan menghabiskan waktu untuk melacaknya.</p>
+
+<p>Untuk memperbaiki masalah ini, Android menawarkan beberapa cara untuk mengakses thread UI dari
+thread lainnya. Berikut ini daftar metode yang bisa membantu:</p>
+
+<ul>
+<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable)
+Activity.runOnUiThread(Runnable)}</li>
+<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li>
+<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable,
+long)}</li>
+</ul>
+
+<p>Misalnya, Anda bisa memperbaiki kode di atas dengan menggunakan metode {@link
+android.view.View#post(java.lang.Runnable) View.post(Runnable)}:</p>
+
+<pre>
+public void onClick(View v) {
+    new Thread(new Runnable() {
+        public void run() {
+            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
+            mImageView.post(new Runnable() {
+                public void run() {
+                    mImageView.setImageBitmap(bitmap);
+                }
+            });
+        }
+    }).start();
+}
+</pre>
+
+<p>Kini implementasi ini thread-safe: operasi jaringan dilakukan terpisah dari thread
+ sementara {@link android.widget.ImageView} dimanipulasi dari thread UI.</p>
+
+<p>Akan tetapi, karena operasi semakin kompleks, jenis kode seperti ini bisa semakin rumit
+dan sulit dipertahankan. Untuk menangani interaksi yang lebih kompleks dengan thread pekerja, Anda bisa mempertimbangkan
+ penggunaan {@link android.os.Handler}di thread pekerja, untuk memproses pesan yang dikirim dari
+ thread UI. Mungkin solusi terbaiknya adalah memperpanjang kelas {@link android.os.AsyncTask},
+yang akan menyederhanakan eksekusi tugas-tugas thread pekerja yang perlu berinteraksi dengan UI.</p>
+
+
+<h4 id="AsyncTask">Menggunakan AsyncTask</h4>
+
+<p>Dengan {@link android.os.AsyncTask}, Anda bisa melakukan pekerjaan asinkron pada antarmuka
+pengguna. AsyncTask memblokir operasi di thread pekerja kemudian mempublikasikan hasilnya
+di thread UI, tanpa mengharuskan Anda untuk menangani sendiri thread dan/atau handler sendiri.</p>
+
+<p>Untuk menggunakannya, Anda harus menempatkan {@link android.os.AsyncTask} sebagai subkelas dan mengimplementasikan metode callback {@link
+android.os.AsyncTask#doInBackground doInBackground()} yang berjalan di kumpulan
+thread latar belakang. Untuk memperbarui UI, Anda harus mengimplementasikan {@link
+android.os.AsyncTask#onPostExecute onPostExecute()}, yang memberikan hasil dari {@link
+android.os.AsyncTask#doInBackground doInBackground()} dan berjalan di thread UI, jadi Anda bisa
+memperbarui UI dengan aman. Selanjutnya Anda bisa menjalankan tugas dengan memanggil {@link android.os.AsyncTask#execute execute()}
+dari thread UI.</p>
+
+<p>Misalnya, Anda bisa mengimplementasikan contoh sebelumnya menggunakan {@link android.os.AsyncTask} dengan cara
+ini:</p>
+
+<pre>
+public void onClick(View v) {
+    new DownloadImageTask().execute("http://example.com/image.png");
+}
+
+private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
+    /** The system calls this to perform work in a worker thread and
+      * delivers it the parameters given to AsyncTask.execute() */
+    protected Bitmap doInBackground(String... urls) {
+        return loadImageFromNetwork(urls[0]);
+    }
+
+    /** The system calls this to perform work in the UI thread and delivers
+      * the result from doInBackground() */
+    protected void onPostExecute(Bitmap result) {
+        mImageView.setImageBitmap(result);
+    }
+}
+</pre>
+
+<p>Kini UI aman dan kode jadi lebih sederhana, karena memisahkan pekerjaan ke
+dalam bagian-bagian yang harus dilakukan pada thread pekerja dan thread UI.</p>
+
+<p>Anda harus membaca acuan {@link android.os.AsyncTask} untuk memahami sepenuhnya
+cara menggunakan kelas ini, namun berikut ini ikhtisar singkat cara kerjanya:</p>
+
+<ul>
+<li>Anda bisa menetapkan tipe parameter, nilai kemajuan, dan nilai
+ akhir tugas, dengan menggunakan generik</li>
+<li>Metode {@link android.os.AsyncTask#doInBackground doInBackground()} berjalan secara otomatis pada
+thread pekerja</li>
+<li>{@link android.os.AsyncTask#onPreExecute onPreExecute()}, {@link
+android.os.AsyncTask#onPostExecute onPostExecute()}, dan {@link
+android.os.AsyncTask#onProgressUpdate onProgressUpdate()} semuanya dipanggil pada thread UI</li>
+<li>Nilai yang dikembalikan oleh {@link android.os.AsyncTask#doInBackground doInBackground()} akan dikirim ke
+{@link android.os.AsyncTask#onPostExecute onPostExecute()}</li>
+<li>Anda bisa memangil {@link android.os.AsyncTask#publishProgress publishProgress()} setiap saat di {@link
+android.os.AsyncTask#doInBackground doInBackground()} untuk mengeksekusi {@link
+android.os.AsyncTask#onProgressUpdate onProgressUpdate()} pada thread UI</li>
+<li>Anda bisa membatalkan tugas ini kapan saja, dari thread mana saja</li>
+</ul>
+
+<p class="caution"><strong>Perhatian:</strong> Masalah lain yang mungkin Anda temui saat menggunakan
+thread pekerja adalah restart tak terduga dalam aktivitas karena <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan konfigurasi runtime</a>
+ (seperti saat pengguna mengubah orientasi layar), yang bisa memusnahkan thread pekerja. Untuk
+melihat cara mempertahankan tugas selama restart ini dan cara membatalkan
+tugas dengan benar saat aktivitas dimusnahkan, lihat kode sumber untuk aplikasi sampel <a href="http://code.google.com/p/shelves/">Shelves</a>.</p>
+
+
+<h3 id="ThreadSafe">Metode thread-safe</h3>
+
+<p> Dalam beberapa situasi, metode yang Anda implementasikan bisa dipanggil dari lebih dari satu thread,
+dan karena itu harus ditulis agar menjadi thread-safe. </p>
+
+<p>Ini terutama terjadi untuk metode yang bisa dipanggil dari jauh &mdash;seperti metode dalam <a href="{@docRoot}guide/components/bound-services.html">layanan terikat</a>. Bila sebuah panggilan pada
+metode yang dijalankan dalam {@link android.os.IBinder} berasal dari proses yang sama di mana
+{@link android.os.IBinder IBinder} berjalan, metode ini akan dieksekusi di thread pemanggil.
+Akan tetapi, bila panggilan berasal proses lain, metode akan dieksekusi dalam thread yang dipilih dari
+ kumpulan (pool) thread yang dipertahankan sistem dalam proses yang sama seperti{@link android.os.IBinder
+IBinder} (tidak dieksekusi dalam thread UI proses).  Misalnya, karena metode
+{@link android.app.Service#onBind onBind()} layanan akan dipanggil dari thread UI
+proses layanan, metode yang diimplementasikan dalam objek yang dikembalikan {@link android.app.Service#onBind
+onBind()} (misalnya, subkelas yang mengimplementasikan metode RPC) akan dipanggil dari thread
+di pool. Karena layanan bisa memiliki lebih dari satu klien, maka lebih dari satu pool thread bisa melibatkan
+ metode {@link android.os.IBinder IBinder} yang sama sekaligus. Metode {@link android.os.IBinder
+IBinder} karenanya harus diimplementasikan sebagai thread-safe.</p>
+
+<p> Penyedia konten juga bisa menerima permintaan data yang berasal dalam proses lain.
+Meskipun kelas {@link android.content.ContentResolver} dan {@link android.content.ContentProvider}
+ menyembunyikan detail cara komunikasi antarproses dikelola, metode {@link
+android.content.ContentProvider} yang merespons permintaan itu&mdash;metode {@link
+android.content.ContentProvider#query query()}, {@link android.content.ContentProvider#insert
+insert()}, {@link android.content.ContentProvider#delete delete()}, {@link
+android.content.ContentProvider#update update()}, dan {@link android.content.ContentProvider#getType
+getType()}&mdash; dipanggil dari pool thread pada proses penyedia konten, bukan thread UI
+untuk proses tersebut.  Mengingat metode ini bisa dipanggil dari thread mana pun
+sekaligus, metode-metode ini juga harus diimplementasikan sebagai thread-safe. </p>
+
+
+<h2 id="IPC">Komunikasi Antarproses</h2>
+
+<p>Android menawarkan mekanisme komunikasi antarproses (IPC) menggunakan panggilan prosedur jauh
+ (RPC), yang mana metode ini dipanggil oleh aktivitas atau komponen aplikasi lain, namun dieksekusi dari
+jauh (di proses lain), bersama hasil yang dikembalikan ke
+pemanggil. Ini mengharuskan penguraian panggilan metode dan datanya ke tingkat yang bisa
+dipahami sistem operasi, mentransmisikannya dari proses lokal dan ruang alamat untuk proses jauh
+dan ruang proses, kemudian merakit kembali dan menetapkannya kembali di sana.  Nilai-nilai yang dikembalikan
+akan ditransmisikan dalam arah berlawanan.  Android menyediakan semua kode untuk melakukan transaksi IPC
+ ini, sehingga Anda bisa fokus pada pendefinisian dan implementasi antarmuka pemrograman RPC. </p>
+
+<p>Untuk melakukan IPC, aplikasi Anda harus diikat ke layanan, dengan menggunakan {@link
+android.content.Context#bindService bindService()}. Untuk informasi selengkapnya, lihat panduan pengembang <a href="{@docRoot}guide/components/services.html">Layanan</a>.</p>
+
+
+<!--
+<h2>Beginner's Path</h2>
+
+<p>For information about how to perform work in the background for an indefinite period of time
+(without a user interface), continue with the <b><a
+href="{@docRoot}guide/components/services.html">Services</a></b> document.</p>
+-->
diff --git a/docs/html-intl/intl/id/guide/components/recents.jd b/docs/html-intl/intl/id/guide/components/recents.jd
new file mode 100644
index 0000000..286fdc1
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/recents.jd
@@ -0,0 +1,256 @@
+page.title=Layar Ikhtisar
+page.tags="recents","overview"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#adding">Menambahkan Tugas ke Layar Ikhtisar</a>
+      <ol>
+        <li><a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a></li>
+        <li><a href="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</a></li>
+      </ol>
+    </li>
+    <li><a href="#removing">Menghapus Tugas</a>
+      <ol>
+        <li><a href="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</a></li>
+        <li><a href="#retain-finished">Mempertahankan tugas yang telah selesai</a></li>
+      </ol>
+    </li>
+  </ol>
+
+  <h2>Kelas-kelas utama</h2>
+  <ol>
+    <li>{@link android.app.ActivityManager.AppTask}</li>
+    <li>{@link android.content.Intent}</li>
+  </ol>
+
+  <h2>Kode contoh</h2>
+  <ol>
+    <li><a href="{@docRoot}samples/DocumentCentricApps/index.html">Aplikasi yang berorientasi dokumen</a></li>
+  </ol>
+
+</div>
+</div>
+
+<p>Layar ikhtisar (juga disebut sebagai layar terbaru, daftar tugas terbaru, atau aplikasi terbaru)
+UI tingkat sistem yang mencantumkan <a href="{@docRoot}guide/components/activities.html">
+aktivitas</a> dan <a href="{@docRoot}guide/components/tasks-and-back-stack.html">tugas</a> yang baru saja diakses. Pengguna
+bisa menyusuri daftar ini dan memilih satu tugas untuk dilanjutkan, atau pengguna bisa menghapus tugas dari
+daftar dengan gerakan mengusap. Dengan dirilisnya Android 5.0 (API level 21), beberapa instance aktivitas yang
+sama yang berisi dokumen berbeda dapat muncul sebagai tugas di layar ikhtisar. Misalnya,
+Google Drive mungkin memiliki satu tugas untuk setiap beberapa dokumen Google. Setiap dokumen muncul sebagai
+tugas dalam layar ikhtisar.</p>
+
+<img src="{@docRoot}images/components/recents.png" alt="" width="284" />
+<p class="img-caption"><strong>Gambar 1.</strong> Layar ikhtisar menampilkan tiga dokumen
+Google Drive, masing-masing dinyatakan sebagai tugas terpisah.</p>
+
+<p>Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
+aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.
+Akan tetapi, aplikasi Anda dapat menentukan cara dan waktu munculnya aktivitas di layar ikhtisar. Kelas
+{@link android.app.ActivityManager.AppTask} memungkinkan Anda mengelola tugas, dan flag
+ aktivitas kelas {@link android.content.Intent} memungkinkan Anda menentukan kapan aktivitas ditambahkan atau dihapus dari
+layar ikhtisar. Selain itu, atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
+&lt;activity&gt;</a></code> memungkinkan Anda menetapkan perilaku di manifes.</p>
+
+<h2 id="adding">Menambahkan Tugas ke Layar Ikhtisar</h2>
+
+<p>Penggunaan flag kelas {@link android.content.Intent} untuk menambahkan tugas memberi kontrol lebih besar
+atas waktu dan cara dokumen dibuka atau dibuka kembali di layar ikhtisar. Bila menggunakan atribut
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+, Anda dapat memilih antara selalu membuka dokumen dalam tugas baru atau menggunakan kembali tugas
+yang ada untuk dokumen tersebut.</p>
+
+<h3 id="flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</h3>
+
+<p>Bila membuat dokumen baru untuk aktivitas, Anda memanggil metode
+{@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()}
+ dari kelas {@link android.app.ActivityManager.AppTask}, dengan meneruskannya ke intent yang
+menjalankan aktivitas tersebut. Untuk menyisipkan jeda logis agar sistem memperlakukan aktivitas Anda sebagai tugas
+baru di layar ikhtisar, teruskan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
+dalam metode {@link android.content.Intent#addFlags(int) addFlags()} dari {@link android.content.Intent}
+yang memulai aktivitas itu.</p>
+
+<p class="note"><strong>Catatan:</strong> Flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
+menggantikan flag {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET},
+yang tidak digunakan lagi pada Android 5.0 (API level 21).</p>
+
+<p>Jika Anda menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} saat membuat
+dokumen baru, sistem akan selalu membuat tugas baru dengan aktivitas target sebagai akar.
+Dengan pengaturan ini, dokumen yang sama dapat dibuka di lebih dari satu tugas. Kode berikut memperagakan
+cara aktivitas utama melakukannya:</p>
+
+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
+DocumentCentricActivity.java</a></p>
+<pre>
+public void createNewDocument(View view) {
+      final Intent newDocumentIntent = newDocumentIntent();
+      if (useMultipleTasks) {
+          newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+      }
+      startActivity(newDocumentIntent);
+  }
+
+  private Intent newDocumentIntent() {
+      boolean useMultipleTasks = mCheckbox.isChecked();
+      final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
+      newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+      newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
+      return newDocumentIntent;
+  }
+
+  private static int incrementAndGet() {
+      Log.d(TAG, "incrementAndGet(): " + mDocumentCounter);
+      return mDocumentCounter++;
+  }
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Aktivitas yang dimulai dengan flag {@code FLAG_ACTIVITY_NEW_DOCUMENT}
+ harus telah menetapkan nilai atribut {@code android:launchMode="standard"} (default) dalam
+manifes.</p>
+
+<p>Bila aktivitas utama memulai aktivitas baru, sistem akan mencari tugas yang intent
+-nya cocok dengan nama komponen intent dalam tugas-tugas yang sudah ada dan mencari aktivitas dalam data Intent. Jika tugas
+tidak ditemukan, atau intent ada dalam flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
+, tugas baru akan dibuat dengan aktivitas tersebut sebagai akarnya. Jika ditemukan, sistem akan
+mengedepankan tugas itu dan meneruskan intent baru ke {@link android.app.Activity#onNewIntent onNewIntent()}.
+Aktivitas baru akan mendapatkan intent dan membuat dokumen baru di layar ikhtisar, seperti dalam
+contoh berikut:</p>
+
+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
+NewDocumentActivity.java</a></p>
+<pre>
+&#64;Override
+protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_new_document);
+    mDocumentCount = getIntent()
+            .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
+    mDocumentCounterTextView = (TextView) findViewById(
+            R.id.hello_new_document_text_view);
+    setDocumentCounterText(R.string.hello_new_document_counter);
+}
+
+&#64;Override
+protected void onNewIntent(Intent intent) {
+    super.onNewIntent(intent);
+    /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity
+    is reused to create a new document.
+     */
+    setDocumentCounterText(R.string.reusing_document_counter);
+}
+</pre>
+
+
+<h3 id="#attr-doclaunch">Menggunakan atribut Aktivitas untuk menambahkan tugas</h3>
+
+<p>Aktivitas juga dapat menetapkan dalam manifesnya agar selalu dimulai ke dalam tugas baru dengan menggunakan
+atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+, <a href="{@docRoot}guide/topics/manifest/activity-element.html#dlmode">
+{@code android:documentLaunchMode}</a>. Atribut ini memiliki empat nilai yang menghasilkan efek berikut
+bila pengguna membuka dokumen dengan aplikasi:</p>
+
+<dl>
+  <dt>"{@code intoExisting}"</dt>
+  <dd>Aktivitas menggunakan kembali tugas yang ada untuk dokumen tersebut. Ini sama dengan mengatur flag
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} <em>tanpa</em> mengatur flag
+ {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, seperti dijelaskan dalam
+ <a href="#flag-new-doc">Menggunakan flag Intent untuk menambahkan tugas</a>, di atas.</dd>
+
+  <dt>"{@code always}"</dt>
+  <dd>Aktivitas ini membuat tugas baru untuk dokumen, meski dokumen sudah dibuka. Menggunakan
+ nilai ini sama dengan menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
+ maupun {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}.</dd>
+
+  <dt>"{@code none”}"</dt>
+  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Layar ikhtisar memperlakukan
+ aktivitas seperti itu secara default: satu tugas ditampilkan untuk aplikasi, yang
+dilanjutkan dari aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
+
+  <dt>"{@code never}"</dt>
+  <dd>Aktivitas ini tidak membuat tugas baru untuk dokumen. Mengatur nilai ini akan mengesampingkan
+ perilaku flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}
+ dan {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, jika salah satunya ditetapkan di
+intent, dan layar ikhtisar menampilkan satu tugas untuk aplikasi, yang dilanjutkan dari
+ aktivitas apa pun yang terakhir dipanggil pengguna.</dd>
+</dl>
+
+<p class="note"><strong>Catatan:</strong> Untuk nilai selain {@code none} dan {@code never},
+aktivitas harus didefinisikan dengan {@code launchMode="standard"}. Jika atribut ini tidak ditetapkan, maka
+{@code documentLaunchMode="none"} akan digunakan.</p>
+
+<h2 id="removing">Menghapus Tugas</h2>
+
+<p>Secara default, tugas dokumen secara otomatis dihapus dari layar ikhtisar bila aktivitasnya
+selesai. Anda bisa mengesampingkan perilaku ini dengan kelas {@link android.app.ActivityManager.AppTask},
+dengan flag {@link android.content.Intent} atau atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
+&lt;activity&gt;</a></code>.</p>
+
+<p>Kapan saja Anda bisa mengecualikan tugas dari layar ikhtisar secara keseluruhan dengan menetapkan atribut
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+, <a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">
+{@code android:excludeFromRecents}</a> hingga {@code true}.</p>
+
+<p>Anda bisa menetapkan jumlah maksimum tugas yang dapat disertakan aplikasi Anda dalam layar ikhtisar dengan menetapkan
+atribut <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html#maxrecents">{@code android:maxRecents}
+</a> ke satu nilai integer. Nilai default-nya adalah 16. Bila telah mencapai jumlah maksimum, tugas yang terakhir
+digunakan akan dihapus dari layar ikhtisar. Nilai maksimum {@code android:maxRecents}
+ adalah 50 (25 pada perangkat dengan memori sedikit); nilai yang kurang dari 1 tidak berlaku.</p>
+
+<h3 id="#apptask-remove">Menggunakan kelas AppTask untuk menghapus tugas</h3>
+
+<p>Dalam aktivitas yang membuat tugas baru di layar ikhtisar, Anda bisa
+menetapkan kapan menghapus tugas dan menyelesaikan semua aktivitas yang terkait dengannya
+dengan memanggil metode {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}.</p>
+
+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
+NewDocumentActivity.java</a></p>
+<pre>
+public void onRemoveFromRecents(View view) {
+    // The document is no longer needed; remove its task.
+    finishAndRemoveTask();
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Penggunaan metode
+{@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}
+akan mengesampingkan penggunaan tag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, seperti
+dibahas di bawah ini.</p>
+
+<h3 id="#retain-finished">Mempertahankan tugas yang telah selesai</h3>
+
+<p>Jika Anda ingin mempertahankan tugas di layar ikhtisar, sekalipun aktivitas sudah selesai, teruskan
+flag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} dalam metode
+{@link android.content.Intent#addFlags(int) addFlags()} dari Intent yang memulai aktivitas itu.</p>
+
+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">
+DocumentCentricActivity.java</a></p>
+<pre>
+private Intent newDocumentIntent() {
+    final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
+    newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+      android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
+    newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
+    return newDocumentIntent;
+}
+</pre>
+
+<p>Untuk memperoleh efek yang sama, tetapkan atribut
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html#autoremrecents">
+{@code android:autoRemoveFromRecents}</a> hingga {@code false}. Nilai default-nya adalah {@code true}
+untuk aktivitas dokumen, dan {@code false} untuk aktivitas biasa. Penggunaan atribut ini akan mengesampingkan flag
+{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, yang telah dibahas sebelumnya.</p>
+
+
+
+
+
+
+
diff --git a/docs/html-intl/intl/id/guide/components/services.jd b/docs/html-intl/intl/id/guide/components/services.jd
new file mode 100644
index 0000000..b36e565
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/services.jd
@@ -0,0 +1,813 @@
+page.title=Layanan
+@jd:body
+
+<div id="qv-wrapper">
+<ol id="qv">
+<h2>Dalam dokumen ini</h2>
+<ol>
+<li><a href="#Basics">Dasar-Dasar</a></li>
+<ol>
+  <li><a href="#Declaring">Mendeklarasikan layanan dalam manifes</a></li>
+</ol>
+<li><a href="#CreatingAService">Membuat Layanan yang Sudah Dimulai</a>
+  <ol>
+    <li><a href="#ExtendingIntentService">Memperluas kelas IntentService</a></li>
+    <li><a href="#ExtendingService">Memperluas kelas Layanan</a></li>
+    <li><a href="#StartingAService">Memulai layanan</a></li>
+    <li><a href="#Stopping">Menghentikan layanan</a></li>
+  </ol>
+</li>
+<li><a href="#CreatingBoundService">Membuat Layanan Terikat</a></li>
+<li><a href="#Notifications">Mengirim Pemberitahuan ke Pengguna</a></li>
+<li><a href="#Foreground">Menjalankan Layanan di Latar Depan</a></li>
+<li><a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>
+<ol>
+  <li><a href="#LifecycleCallbacks">Mengimplementasikan callback daur hidup</a></li>
+</ol>
+</li>
+</ol>
+
+<h2>Kelas-kelas utama</h2>
+<ol>
+  <li>{@link android.app.Service}</li>
+  <li>{@link android.app.IntentService}</li>
+</ol>
+
+<h2>Contoh</h2>
+<ol>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code
+      ServiceStartArguments}</a></li>
+  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
+      LocalService}</a></li>
+</ol>
+
+<h2>Lihat juga</h2>
+<ol>
+<li><a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a></li>
+</ol>
+
+</div>
+
+
+<p>{@link android.app.Service} adalah sebuah komponen aplikasi yang bisa melakukan
+operasi yang berjalan lama di latar belakang dan tidak menyediakan antarmuka pengguna. Komponen
+aplikasi lain bisa memulai layanan dan komponen aplikasi tersebut akan terus berjalan
+di latar belakang walaupun pengguna beralih ke aplikasi lain. Selain itu, komponen bisa mengikat ke layanan
+untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan mungkin
+menangani transaksi jaringan, memutar musik, melakukan file I/O, atau berinteraksi dengan penyedia konten
+dari latar belakang.</p>
+
+<p>Ada dua bentuk dasar layanan:</p>
+
+<dl>
+  <dt>Sudah Dimulai</dt>
+  <dd>Layanan "sudah dimulai" bila komponen aplikasi (misalnya aktivitas) memulainya dengan
+memanggil {@link android.content.Context#startService startService()}. Sesudah dimulai, layanan
+bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya telah dimusnahkan. Biasanya,
+layanan yang sudah dimulai akan melakukan operasi tunggal dan tidak mengembalikan hasil ke pemanggilnya.
+Misalnya, layanan bisa mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai,
+layanan seharusnya berhenti sendiri.</dd>
+  <dt>Terikat</dt>
+  <dd>Layanan "terikat" bila komponen aplikasi mengikat kepadanya dengan memanggil {@link
+android.content.Context#bindService bindService()}. Layanan terikat menawarkan antarmuka
+klien-server yang memungkinkan komponen berinteraksi dengan layanan tersebut, mengirim permintaan, mendapatkan hasil dan bahkan
+melakukannya pada sejumlah proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama
+ada komponen aplikasi lain yang terikat padanya. Sejumlah komponen bisa terikat pada layanan secara bersamaan,
+namun bila semuanya melepas ikatan, layanan tersebut akan dimusnahkan.</dd>
+</dl>
+
+<p>Walaupun dokumentasi ini secara umum membahas kedua jenis layanan secara terpisah, layanan
+Anda bisa menggunakan keduanya&mdash;layanan bisa dimulai (untuk berjalan terus-menerus) sekaligus memungkinkan pengikatan.
+Cukup mengimplementasikan dua metode callback: {@link
+android.app.Service#onStartCommand onStartCommand()} untuk memungkinkan komponen memulainya dan {@link
+android.app.Service#onBind onBind()} untuk memungkinkan pengikatan.</p>
+
+<p>Apakah aplikasi Anda sudah dimulai, terikat, atau keduanya, semua komponen aplikasi
+bisa menggunakan layanan (bahkan dari aplikasi terpisah), demikian pula semua komponen bisa menggunakan
+suatu aktivitas&mdash;dengan memulainya dengan {@link android.content.Intent}. Akan tetapi, Anda bisa mendeklarasikan
+layanan sebagai privat, pada file manifes, dan memblokir akses dari aplikasi lain. Hal ini
+dibahas selengkapnya di bagian tentang <a href="#Declaring">Mendeklarasikan layanan dalam
+manifes</a>.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Layanan berjalan di
+thread utama proses yang menjadi host-nya&mdash;layanan <strong>tidak</strong> membuat thread-nya sendiri
+dan <strong>tidak</strong> berjalan pada proses terpisah (kecuali bila Anda tentukan demikian). Artinya,
+jika layanan Anda akan melakukan pekerjaan yang membutuhkan tenaga CPU besar atau operasi yang memblokir (seperti
+pemutaran MP3 atau jaringan), Anda perlu membuat thread baru dalam layanan untuk melakukan pekerjaan tersebut. Dengan menggunakan
+thread terpisah, Anda mengurangi risiko terjadinya kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan
+thread utama aplikasi bisa tetap dikhususkan pada interaksi pengguna dengan aktivitas Anda.</p>
+
+
+<h2 id="Basics">Dasar-Dasar</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <h3>Haruskah menggunakan layanan atau thread?</h3>
+  <p>Layanan sekadar komponen yang bisa berjalan di latar belakang walaupun pengguna sedang tidak
+berinteraksi dengan aplikasi Anda. Sehingga, Anda harus membuat layanan bila memang itu
+yang dibutuhkan.</p>
+  <p>Bila Anda perlu melakukan pekerjaan di luar thread utama, namun hanya bila pengguna sedang berinteraksi
+dengan aplikasi, maka Anda harus membuat thread baru sebagai ganti layanan baru. Misalnya,
+bila Anda ingin memutar musik, namun hanya saat aktivitas Anda berjalan, Anda bisa membuat
+thread dalam {@link android.app.Activity#onCreate onCreate()}, mulai menjalankannya di {@link
+android.app.Activity#onStart onStart()}, kemudian menghentikannya di {@link android.app.Activity#onStop
+onStop()}. Pertimbangkan juga untuk menggunakan {@link android.os.AsyncTask} atau {@link android.os.HandlerThread},
+sebagai ganti kelas {@link java.lang.Thread} yang lazim digunakan. Lihat dokumen <a href="{@docRoot}guide/components/processes-and-threads.html#Threads">Proses dan
+Threading</a> untuk informasi selengkapnya tentang thread.</p>
+  <p>Ingatlah jika menggunakan layanan, layanan tersebut tetap berjalan di thread utama aplikasi Anda secara
+default, jadi Anda harus tetap membuat thread baru dalam layanan bila layanan tersebut melakukan operasi yang intensif
+atau operasi yang memblokir.</p>
+</div>
+</div>
+
+<p>Untuk membuat layanan, Anda harus membuat subkelas {@link android.app.Service} (atau
+salah satu dari subkelasnya yang ada). Dalam implementasi, Anda perlu mengesampingkan sebagian metode callback yang
+menangani aspek utama daur hidup layanan dan memberikan mekanisme bagi komponen untuk mengikat
+pada layanan, bila dibutuhkan. Metode callback terpenting yang perlu Anda kesampingkan adalah:</p>
+
+<dl>
+  <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
+    <dd>Sistem akan memanggil metode ini bila komponen lain, misalnya aktivitas,
+meminta dimulainya layanan, dengan memanggil {@link android.content.Context#startService
+startService()}. Setelah metode ini dieksekusi, layanan akan dimulai dan bisa berjalan di
+latar belakang terus-menerus. Jika mengimplementasikan ini, Anda bertanggung jawab menghentikan layanan bila
+bila pekerjaannya selesai, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link
+android.content.Context#stopService stopService()}. (Jika hanya ingin menyediakan pengikatan, Anda tidak
+perlu mengimplementasikan metode ini.)</dd>
+  <dt>{@link android.app.Service#onBind onBind()}</dt>
+    <dd>Sistem akan memanggil metode ini bila komponen lain ingin mengikat pada
+layanan (misalnya untuk melakukan RPC), dengan memanggil {@link android.content.Context#bindService
+bindService()}. Dalam mengimplementasikan metode ini, Anda harus menyediakan antarmuka yang digunakan
+klien untuk berkomunikasi dengan layanan, dengan mengembalikan {@link android.os.IBinder}. Anda harus selalu
+mengimplementasikan metode ini, namun jika tidak ingin mengizinkan pengikatan, Anda perlu mengembalikan null.</dd>
+  <dt>{@link android.app.Service#onCreate()}</dt>
+    <dd>Sistem memanggil metode ini bila layanan dibuat untuk pertama kalinya, untuk melakukan prosedur
+penyiapan satu kali (sebelum memanggil {@link android.app.Service#onStartCommand onStartCommand()} atau
+{@link android.app.Service#onBind onBind()}). Bila layanan sudah berjalan, metode ini tidak
+dipanggil.</dd>
+  <dt>{@link android.app.Service#onDestroy()}</dt>
+    <dd>Sistem memanggil metode ini bila layanan tidak lagi digunakan dan sedang dimusnahkan.
+Layanan Anda perlu mengimplementasikannya untuk membersihkan sumber daya seperti thread, listener
+terdaftar, penerima, dll. Ini adalah panggilan terakhir yang diterima layanan.</dd>
+</dl>
+
+<p>Bila komponen memulai layanan dengan memanggil {@link
+android.content.Context#startService startService()} (yang menyebabkan panggilan ke {@link
+android.app.Service#onStartCommand onStartCommand()}), maka layanan
+terus berjalan hingga terhenti sendiri dengan {@link android.app.Service#stopSelf()} atau bila komponen
+lain menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
+
+<p>Bila komponen memanggil
+{@link android.content.Context#bindService bindService()} untuk membuat layanan (dan {@link
+android.app.Service#onStartCommand onStartCommand()} <em>tidak</em> dipanggil), maka layanan hanya berjalan
+selama komponen terikat kepadanya. Setelah layanan dilepas ikatannya dari semua klien,
+sistem akan menghancurkannya.</p>
+
+<p>Sistem Android akan menghentikan paksa layanan hanya bila memori tinggal sedikit dan sistem harus memulihkan
+sumber daya sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat pada suatu aktivitas yang mendapatkan
+fokus pengguna, layanan tersebut lebih kecil kemungkinannya untuk dimatikan, dan jika layanan dideklarasikan untuk <a href="#Foreground">berjalan di latar depan</a> (akan dibahas kemudian), maka sudah hampir pasti ia tidak akan dimatikan.
+Sebaliknya, bila layanan sudah dimulai dan berjalan lama, maka sistem akan menurunkan posisinya
+dalam daftar tugas latar belakang seiring waktu dan layanan akan sangat rentan untuk
+dimatikan&mdash;bila layanan Anda dimulai, maka Anda harus mendesainnya agar bisa menangani restart
+oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai kembali begitu sumber daya
+kembali tersedia (tetapi ini juga bergantung pada nilai yang Anda kembalikan dari {@link
+android.app.Service#onStartCommand onStartCommand()}, sebagaimana akan dibahas nanti). Untuk informasi selengkapnya
+tentang kapan sistem mungkin akan memusnahkan layanan, lihat dokumen
+<a href="{@docRoot}guide/components/processes-and-threads.html">Proses dan Threading</a>.</p>
+
+<p>Dalam bagian selanjutnya, Anda akan melihat bagaimana membuat masing-masing tipe layanan dan cara menggunakannya
+dari komponen aplikasi lain.</p>
+
+
+
+<h3 id="Declaring">Mendeklarasikan layanan dalam manifes</h3>
+
+<p>Sebagaimana aktivitas (dan komponen lainnya), Anda harus mendeklarasikan semua layanan dalam file manifes
+aplikasi Anda.</p>
+
+<p>Untuk mendeklarasikan layanan Anda, tambahkan sebuah elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
+sebagai anak
+elemen <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>. Misalnya:</p>
+
+<pre>
+&lt;manifest ... &gt;
+  ...
+  &lt;application ... &gt;
+      &lt;service android:name=".ExampleService" /&gt;
+      ...
+  &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>Lihat acuan elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>
+untuk informasi selengkapnya tentang cara mendeklarasikan layanan Anda dalam manifes.</p>
+
+<p>Ada atribut lain yang bisa Anda sertakan dalam elemen <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> untuk
+mendefinisikan properti seperti izin yang dibutuhkan untuk memulai layanan dan proses
+tempat berjalannya layanan. <a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> adalah satu-satunya atribut yang diperlukan
+&mdash;atribut tersebut menetapkan nama kelas layanan. Setelah
+mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak
+kode karena dependensi terhadap intent eksplisit untuk memulai atau mengikat layanan (bacalah posting blog berjudul <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
+That Cannot Change</a>).
+
+<p>Untuk memastikan aplikasi Anda aman, <strong>selalu gunakan intent eksplisit saat memulai atau mengikat
+{@link android.app.Service} Anda</strong> dan jangan mendeklarasikan filter intent untuk layanan. Jika
+Anda perlu membiarkan adanya ambiguitas tentang layanan mana yang dimulai, Anda bisa
+menyediakan filter intent bagi layanan dan tidak memasukkan nama komponen pada {@link
+android.content.Intent}, namun Anda juga harus menyesuaikan paket bagi intent tersebut dengan {@link
+android.content.Intent#setPackage setPackage()}, yang memberikan klarifikasi memadai bagi
+target layanan.</p>
+
+<p>Anda juga bisa memastikan layanan tersedia hanya bagi aplikasi Anda dengan
+menyertakan atribut <a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
+dan mengaturnya ke {@code "false"}. Hal ini efektif menghentikan aplikasi lain agar tidak memulai
+layanan Anda, bahkan saat menggunakan intent eksplisit.</p>
+
+
+
+
+<h2 id="CreatingStartedService">Membuat Layanan yang Sudah Dimulai</h2>
+
+<p>Layanan yang sudah dimulai adalah layanan yang dimulai komponen lain dengan memanggil {@link
+android.content.Context#startService startService()}, yang menyebabkan panggilan ke metode
+{@link android.app.Service#onStartCommand onStartCommand()} layanan.</p>
+
+<p>Bila layanan sudah dimulai, layanan tersebut memiliki daur hidup yang tidak bergantung pada
+komponen yang memulainya dan bisa berjalan terus-menerus di latar belakang walaupun
+komponen yang memulainya dimusnahkan. Dengan sendirinya, layanan akan berhenti sendiri bila pekerjaannya
+selesai dengan memanggil {@link android.app.Service#stopSelf stopSelf()}, atau komponen lain bisa menghentikannya
+dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
+
+<p>Komponen aplikasi seperti aktivitas bisa memulai layanan dengan memanggil {@link
+android.content.Context#startService startService()} dan meneruskan {@link android.content.Intent}
+yang menetapkan layanan dan menyertakan data untuk digunakan layanan. Layanan menerima
+{@link android.content.Intent} ini dalam metode {@link android.app.Service#onStartCommand
+onStartCommand()}.</p>
+
+<p>Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas tersebut bisa
+memulai layanan pendamping dan mengiriminya data untuk disimpan dengan meneruskan intent ke {@link
+android.content.Context#startService startService()}. Layanan akan menerima intent dalam {@link
+android.app.Service#onStartCommand onStartCommand()}, menghubungkan ke Internet dan melakukan
+transaksi database. Bila transaksi selesai, layanan akan berhenti sendiri dan
+dimusnahkan.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Layanan berjalan dalam proses yang sama dengan aplikasi
+tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut, secara default. Jadi, bila layanan Anda
+melakukan operasi yang intensif atau operasi pemblokiran saat pengguna berinteraksi dengan aktivitas dari
+aplikasi yang sama, layanan akan memperlambat kinerja aktivitas. Agar tidak memengaruhi
+kinerja aplikasi, Anda harus memulai thread baru di dalam layanan.</p>
+
+<p>Biasanya, ada dua kelas yang bisa Anda perluas untuk membuat layanan yang sudah dimulai:</p>
+<dl>
+  <dt>{@link android.app.Service}</dt>
+  <dd>Ini adalah kelas dasar untuk semua layanan. Bila memperluas kelas ini, Anda perlu
+membuat thread baru sebagai tempat melaksanakan semua pekerjaan layanan tersebut, karena layanan
+menggunakan thread utama aplikasi Anda secara default, dan hal ini bisa memperlambat
+kinerja aktivitas yang dijalankan aplikasi Anda.</dd>
+  <dt>{@link android.app.IntentService}</dt>
+  <dd>Ini adalah subkelas {@link android.app.Service} yang menggunakan thread pekerja untuk menangani
+semua permintaan memulai, satu per satu. Ini adalah pilihan terbaik jika Anda tidak mengharuskan layanan
+menangani beberapa permintaan sekaligus. Anda cukup mengimplementasikan {@link
+android.app.IntentService#onHandleIntent onHandleIntent()}, yang menerima intent untuk setiap
+permintaan memulai agar bisa melakukan pekerjaan latar belakang.</dd>
+</dl>
+
+<p>Bagian selanjutnya membahas cara mengimplementasikan layanan Anda menggunakan
+salah satu dari kelas-kelas ini.</p>
+
+
+<h3 id="ExtendingIntentService">Memperluas kelas IntentService</h3>
+
+<p>Mengingat kebanyakan layanan yang sudah dimulai tidak perlu menangani beberapa permintaan
+sekaligus (yang bisa berupa skenario multi-threading berbahaya), mungkin Anda sebaiknya mengimplementasikan
+layanan menggunakan kelas {@link android.app.IntentService}.</p>
+
+<p>Berikut ini yang dilakukan {@link android.app.IntentService}:</p>
+
+<ul>
+  <li>Membuat thread pekerja default yang menjalankan semua intent yang disampaikan ke {@link
+android.app.Service#onStartCommand onStartCommand()} terpisah dari thread utama aplikasi
+Anda.</li>
+  <li>Membuat antrean pekerjaan yang meneruskan intent satu per satu ke implementasi {@link
+android.app.IntentService#onHandleIntent onHandleIntent()}, sehingga Anda tidak perlu
+mengkhawatirkan multi-threading.</li>
+  <li>Menghentikan layanan setelah semua permintaan memulai telah ditangani, jadi Anda tidak perlu memanggil
+{@link android.app.Service#stopSelf}.</li>
+  <li>Menyediakan implementasi default {@link android.app.IntentService#onBind onBind()} yang
+mengembalikan null.</li>
+  <li>Menyediakan implementasi default {@link android.app.IntentService#onStartCommand
+onStartCommand()} yang mengirimkan intent ke antrean pekerjaan kemudian ke implementasi {@link
+android.app.IntentService#onHandleIntent onHandleIntent()} Anda.</li>
+</ul>
+
+<p>Oleh karena itu, Anda hanya perlu mengimplementasikan {@link
+android.app.IntentService#onHandleIntent onHandleIntent()} untuk melakukan pekerjaan yang diberikan oleh
+klien. (Akan tetapi, Anda juga perlu menyediakan konstruktor kecil bagi layanan.)</p>
+
+<p>Berikut ini contoh implementasi {@link android.app.IntentService}:</p>
+
+<pre>
+public class HelloIntentService extends IntentService {
+
+  /**
+   * A constructor is required, and must call the super {@link android.app.IntentService#IntentService}
+   * constructor with a name for the worker thread.
+   */
+  public HelloIntentService() {
+      super("HelloIntentService");
+  }
+
+  /**
+   * The IntentService calls this method from the default worker thread with
+   * the intent that started the service. When this method returns, IntentService
+   * stops the service, as appropriate.
+   */
+  &#64;Override
+  protected void onHandleIntent(Intent intent) {
+      // Normally we would do some work here, like download a file.
+      // For our sample, we just sleep for 5 seconds.
+      long endTime = System.currentTimeMillis() + 5*1000;
+      while (System.currentTimeMillis() &lt; endTime) {
+          synchronized (this) {
+              try {
+                  wait(endTime - System.currentTimeMillis());
+              } catch (Exception e) {
+              }
+          }
+      }
+  }
+}
+</pre>
+
+<p>Anda hanya memerlukan: konstruktor dan implementasi {@link
+android.app.IntentService#onHandleIntent onHandleIntent()}.</p>
+
+<p>Jika Anda memutuskan untuk juga mengesampingkan metode callback lain, seperti {@link
+android.app.IntentService#onCreate onCreate()}, {@link
+android.app.IntentService#onStartCommand onStartCommand()}, atau {@link
+android.app.IntentService#onDestroy onDestroy()}, pastikan memanggil implementasi super, sehingga
+{@link android.app.IntentService} bisa menangani hidup thread pekerja dengan baik.</p>
+
+<p>Misalnya, {@link android.app.IntentService#onStartCommand onStartCommand()} harus mengembalikan
+implementasi default (yang merupakan cara penyampaian intent ke {@link
+android.app.IntentService#onHandleIntent onHandleIntent()}):</p>
+
+<pre>
+&#64;Override
+public int onStartCommand(Intent intent, int flags, int startId) {
+    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
+    return super.onStartCommand(intent,flags,startId);
+}
+</pre>
+
+<p>Selain {@link android.app.IntentService#onHandleIntent onHandleIntent()}, satu-satunya metode lain
+yang tidak mengharuskan Anda memanggil super kelas adalah {@link android.app.IntentService#onBind
+onBind()} (namun Anda hanya perlu mengimplementasikannya bila layanan mengizinkan pengikatan).</p>
+
+<p>Dalam bagian berikutnya, Anda akan melihat bagaimana layanan serupa diimplementasikan saat
+memperluas kelas {@link android.app.Service} basis, yang membutuhkan kode lebih banyak lagi, namun mungkin
+cocok jika Anda perlu menangani beberapa permintaan memulai sekaligus.</p>
+
+
+<h3 id="ExtendingService">Memperluas kelas Layanan</h3>
+
+<p>Seperti telah Anda lihat di bagian sebelumnya, menggunakan {@link android.app.IntentService} membuat
+implementasi layanan yang sudah dimulai jadi sangat sederhana. Namun, bila Anda mengharuskan layanan untuk
+melakukan multi-threading (sebagai ganti memproses permintaan memulai melalui antrean pekerjaan), maka Anda
+bisa memperluas kelas {@link android.app.Service} untuk menangani masing-masing intent.</p>
+
+<p>Sebagai perbandingan, contoh kode berikut ini adalah implementasi kelas {@link
+android.app.Service} yang melakukan pekerjaan yang persis sama dengan contoh di atas menggunakan {@link
+android.app.IntentService}. Artinya, untuk setiap permintaan memulai, kode tersebut akan menggunakan thread pekerja
+untuk melakukan pekerjaan dan memproses permintaan satu per satu.</p>
+
+<pre>
+public class HelloService extends Service {
+  private Looper mServiceLooper;
+  private ServiceHandler mServiceHandler;
+
+  // Handler that receives messages from the thread
+  private final class ServiceHandler extends Handler {
+      public ServiceHandler(Looper looper) {
+          super(looper);
+      }
+      &#64;Override
+      public void handleMessage(Message msg) {
+          // Normally we would do some work here, like download a file.
+          // For our sample, we just sleep for 5 seconds.
+          long endTime = System.currentTimeMillis() + 5*1000;
+          while (System.currentTimeMillis() &lt; endTime) {
+              synchronized (this) {
+                  try {
+                      wait(endTime - System.currentTimeMillis());
+                  } catch (Exception e) {
+                  }
+              }
+          }
+          // Stop the service using the startId, so that we don't stop
+          // the service in the middle of handling another job
+          stopSelf(msg.arg1);
+      }
+  }
+
+  &#64;Override
+  public void onCreate() {
+    // Start up the thread running the service.  Note that we create a
+    // separate thread because the service normally runs in the process's
+    // main thread, which we don't want to block.  We also make it
+    // background priority so CPU-intensive work will not disrupt our UI.
+    HandlerThread thread = new HandlerThread("ServiceStartArguments",
+            Process.THREAD_PRIORITY_BACKGROUND);
+    thread.start();
+
+    // Get the HandlerThread's Looper and use it for our Handler
+    mServiceLooper = thread.getLooper();
+    mServiceHandler = new ServiceHandler(mServiceLooper);
+  }
+
+  &#64;Override
+  public int onStartCommand(Intent intent, int flags, int startId) {
+      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
+
+      // For each start request, send a message to start a job and deliver the
+      // start ID so we know which request we're stopping when we finish the job
+      Message msg = mServiceHandler.obtainMessage();
+      msg.arg1 = startId;
+      mServiceHandler.sendMessage(msg);
+
+      // If we get killed, after returning from here, restart
+      return START_STICKY;
+  }
+
+  &#64;Override
+  public IBinder onBind(Intent intent) {
+      // We don't provide binding, so return null
+      return null;
+  }
+
+  &#64;Override
+  public void onDestroy() {
+    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
+  }
+}
+</pre>
+
+<p>Seperti yang bisa Anda lihat, ini membutuhkan lebih banyak pekerjaan daripada menggunakan {@link android.app.IntentService}.</p>
+
+<p>Akan tetapi, karena Anda menangani sendiri setiap panggilan ke {@link android.app.Service#onStartCommand
+onStartCommand()}, Anda bisa melakukan beberapa permintaan sekaligus. Itu bukan yang
+dilakukan contoh ini, namun jika itu yang diinginkan, Anda bisa membuat thread baru untuk setiap
+permintaan dan langsung menjalankannya (sebagai ganti menunggu permintaan sebelumnya selesai).</p>
+
+<p>Perhatikan bahwa metode {@link android.app.Service#onStartCommand onStartCommand()} harus mengembalikan
+integer. Integer tersebut merupakan nilai yang menjelaskan cara sistem melanjutkan layanan dalam
+kejadian yang dimatikan oleh sistem (sebagaimana dibahas di atas, implementasi default {@link
+android.app.IntentService} menangani hal ini untuk Anda, walaupun Anda bisa memodifikasinya). Nilai yang dikembalikan
+dari {@link android.app.Service#onStartCommand onStartCommand()} harus berupa salah satu
+konstanta berikut ini:</p>
+
+<dl>
+  <dt>{@link android.app.Service#START_NOT_STICKY}</dt>
+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
+onStartCommand()} dikembalikan, <em>jangan</em> membuat lagi layanan tersebut, kecuali jika ada intent
+tertunda yang akan disampaikan. Inilah pilihan teraman untuk menghindari menjalankan layanan Anda
+bila tidak diperlukan dan bila aplikasi Anda bisa me-restart pekerjaan yang belum selesai.</dd>
+  <dt>{@link android.app.Service#START_STICKY}</dt>
+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
+onStartCommand()} dikembalikan, buat kembali layanan dan panggil {@link
+android.app.Service#onStartCommand onStartCommand()}, namun <em>jangan</em> menyampaikan ulang intent terakhir.
+Sebagai gantinya, sistem akan memanggil {@link android.app.Service#onStartCommand onStartCommand()} dengan
+intent null, kecuali jika ada intent tertunda untuk memulai layanan, dan dalam hal ini,
+intent tersebut disampaikan. Ini cocok bagi pemutar media (atau layanan serupa) yang tidak
+mengeksekusi perintah, namun berjalan terus-menerus dan menunggu pekerjaan.</dd>
+  <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt>
+    <dd>Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand
+onStartCommand()} kembali, buat kembali layanan dan panggil {@link
+android.app.Service#onStartCommand onStartCommand()} dengan intent terakhir yang disampaikan ke
+layanan. Intent yang tertunda akan disampaikan pada gilirannya. Ini cocok bagi layanan yang
+aktif melakukan pekerjaan yang harus segera dilanjutkan, misalnya mengunduh file.</dd>
+</dl>
+<p>Untuk detail selengkapnya tentang nilai pengembalian ini, lihat dokumentasi acuan untuk setiap
+konstanta.</p>
+
+
+
+<h3 id="StartingAService">Memulai Layanan</h3>
+
+<p>Anda bisa memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan
+{@link android.content.Intent} (yang menetapkan layanan yang akan dimulai) ke {@link
+android.content.Context#startService startService()}. Sistem Android akan memanggil metode {@link
+android.app.Service#onStartCommand onStartCommand()} layanan dan meneruskan {@link
+android.content.Intent} padanya. (Jangan sekali-kali memanggil {@link android.app.Service#onStartCommand
+onStartCommand()} secara langsung.)</p>
+
+<p>Misalnya, aktivitas bisa memulai contoh layanan di bagian sebelumnya ({@code
+HelloSevice}) menggunakan intent eksplisit dengan {@link android.content.Context#startService
+startService()}:</p>
+
+<pre>
+Intent intent = new Intent(this, HelloService.class);
+startService(intent);
+</pre>
+
+<p>Metode {@link android.content.Context#startService startService()} segera kembali dan
+sistem Android akan memanggil metode {@link android.app.Service#onStartCommand
+onStartCommand()} layanan. Jika layanan belum berjalan, sistem mula-mula memanggil {@link
+android.app.Service#onCreate onCreate()}, kemudian memanggil {@link android.app.Service#onStartCommand
+onStartCommand()}.</p>
+
+<p>Jika layanan juga tidak menyediakan pengikatan, intent yang disampaikan dengan {@link
+android.content.Context#startService startService()} adalah satu-satunya mode komunikasi antara
+komponen aplikasi dan layanan. Akan tetapi, jika Anda ingin agar layanan mengirimkan hasilnya kembali, maka
+klien yang memulai layanan bisa membuat {@link android.app.PendingIntent} untuk siaran
+(dengan {@link android.app.PendingIntent#getBroadcast getBroadcast()}) dan menyampaikannya ke layanan
+dalam {@link android.content.Intent} yang memulai layanan. Layanan kemudian bisa menggunakan
+siaran untuk menyampaikan hasil.</p>
+
+<p>Beberapa permintaan untuk memulai layanan menghasilkan beberapa panggilan pula ke
+{@link android.app.Service#onStartCommand onStartCommand()} layanan. Akan tetapi, hanya satu permintaan untuk menghentikan
+layanan (dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
+android.content.Context#stopService stopService()}) dibutuhkan untuk menghentikannya.</p>
+
+
+<h3 id="Stopping">Menghentikan layanan</h3>
+
+<p>Layanan yang sudah dimulai harus mengelola daur hidupnya sendiri. Artinya, sistem tidak menghentikan atau
+memusnahkan layanan kecuali jika harus memulihkan memori sistem dan layanan
+terus berjalan setelah {@link android.app.Service#onStartCommand onStartCommand()} kembali. Jadi,
+layanan tersebut harus berhenti sendiri dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau
+komponen lain bisa menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.</p>
+
+<p>Setelah diminta untuk berhenti dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link
+android.content.Context#stopService stopService()}, sistem akan menghapus layanan
+secepatnya.</p>
+
+<p>Akan tetapi, bila layanan Anda menangani beberapa permintaan ke {@link
+android.app.Service#onStartCommand onStartCommand()} sekaligus, Anda tidak boleh menghentikan
+layanan bila Anda baru selesai memproses permintaan memulai, karena setelah itu mungkin Anda sudah menerima permintaan memulai
+yang baru (berhenti pada permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari
+masalah ini, Anda bisa menggunakan {@link android.app.Service#stopSelf(int)} untuk memastikan bahwa permintaan
+Anda untuk menghentikan layanan selalu berdasarkan pada permintaan memulai terbaru. Artinya, bila Anda memanggil {@link
+android.app.Service#stopSelf(int)}, Anda akan meneruskan ID permintaan memulai (<code>startId</code>
+yang disampaikan ke {@link android.app.Service#onStartCommand onStartCommand()}) yang terkait dengan permintaan berhenti
+Anda. Kemudian jika layanan menerima permintaan memulai baru sebelum Anda bisa memanggil {@link
+android.app.Service#stopSelf(int)}, maka ID tidak akan sesuai dan layanan tidak akan berhenti.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Aplikasi Anda perlu menghentikan layanannya
+bila selesai bekerja untuk menghindari pemborosan sumber daya sistem dan tenaga baterai. Jika perlu,
+komponen lain bisa menghentikan layanan secara eksplisit dengan memanggil {@link
+android.content.Context#stopService stopService()}. Bahkan jika Anda mengaktifkan pengikatan bagi layanan,
+Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke {@link
+android.app.Service#onStartCommand onStartCommand()}.</p>
+
+<p>Untuk informasi selengkapnya tentang daur hidup layanan, lihat bagian di bawah ini tentang <a href="#Lifecycle">Mengelola Daur Hidup Layanan</a>.</p>
+
+
+
+<h2 id="CreatingBoundService">Membuat Layanan Terikat</h2>
+
+<p>Layanan terikat adalah layanan yang memungkinkan komponen aplikasi untuk mengikatnya dengan memanggil {@link
+android.content.Context#bindService bindService()} guna membuat koneksi yang berlangsung lama
+(dan umumnya tidak mengizinkan komponen untuk <em>memulainya</em> dengan memanggil {@link
+android.content.Context#startService startService()}).</p>
+
+<p>Anda sebaiknya membuat layanan terikat bila ingin berinteraksi dengan layanan dari aktivitas
+dan komponen lain dalam aplikasi Anda atau mengeskpos sebagian fungsionalitas aplikasi Anda ke
+ke aplikasi lain, melalui komunikasi antarproses (IPC).</p>
+
+<p>Untuk membuat layanan terikat, Anda harus mengimplementasikan metode callback {@link
+android.app.Service#onBind onBind()} untuk mengembalikan {@link android.os.IBinder} yang
+mendefinisikan antarmuka bagi komunikasi dengan layanan. Komponen aplikasi lain kemudian bisa memanggil
+{@link android.content.Context#bindService bindService()} untuk mengambil antarmuka dan
+mulai memanggil metode pada layanan. Layanan hanya hidup untuk melayani komponen aplikasi yang
+terikat padanya, jadi bila tidak ada komponen yang terikat pada layanan, sistem akan memusnahkannya
+(Anda <em>tidak</em> perlu menghentikan layanan terikat seperti halnya bila layanan dimulai
+melalui {@link android.app.Service#onStartCommand onStartCommand()}).</p>
+
+<p>Untuk membuat layanan terikat, hal yang perlu dilakukan pertama kali adalah mendefinisikan antarmuka yang menetapkan
+cara klien berkomunikasi dengan layanan. Antarmuka antara layanan
+dan klien ini harus berupa implementasi {@link android.os.IBinder} dan yang harus dikembalikan
+layanan Anda dari metode callback {@link android.app.Service#onBind
+onBind()}. Setelah menerima {@link android.os.IBinder}, klien bisa mulai
+berinteraksi dengan layanan melalui antarmuka tersebut.</p>
+
+<p>Beberapa klien bisa mengikat ke layanan sekaligus. Bila klien selesai berinteraksi dengan
+layanan, klien akan memanggil {@link android.content.Context#unbindService unbindService()} untuk melepas ikatan. Bila
+tidak ada klien yang terikat pada layanan, sistem akan menghapus layanan tersebut.</p>
+
+<p>Ada beberapa cara untuk mengimplementasikan layanan terikat dan implementasinya lebih
+rumit daripada layanan yang sudah dimulai, jadi layanan terikat dibahas dalam dokumen
+terpisah tentang <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>.</p>
+
+
+
+<h2 id="Notifications">Mengirim Pemberitahuan ke Pengguna</h2>
+
+<p>Setelah berjalan, layanan bisa memberi tahu pengguna tentang suatu kejadian menggunakan <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>.</p>
+
+<p>Pemberitahuan Toast adalah pesan yang muncul sebentar pada permukaan jendela saat ini
+kemudian menghilang, sementara pemberitahuan baris status memberikan ikon di baris status dengan
+pesan yang bisa dipilih oleh pengguna untuk melakukan suatu tindakan (misalnya memulai suatu aktivitas).</p>
+
+<p>Biasanya, pemberitahuan baris status adalah teknik terbaik bila ada pekerjaan latar belakang yang sudah selesai
+(misalnya file selesai
+diunduh) dan pengguna kini bisa menggunakannya. Bila pengguna memilih pemberitahuan dari
+tampilan diperluas, pemberitahuan akan bisa memulai aktivitas (misalnya menampilkan file yang baru diunduh).</p>
+
+<p>Lihat panduan pengembang <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Pemberitahuan Toast</a> atau <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Baris Status</a>
+untuk informasi selengkapnya.</p>
+
+
+
+<h2 id="Foreground">Menjalankan Layanan di Latar Depan</h2>
+
+<p>Layanan latar depan adalah layanan yang dianggap sebagai sesuatu yang
+diketahui secara aktif oleh pengguna, jadi bukan sesuatu yang akan dihapus oleh sistem bila memori menipis. Sebuah
+layanan latar depan harus memberikan pemberitahuan bagi baris status, yang ditempatkan pada
+heading "Ongoing" yang artinya pemberitahuan tersebut tidak bisa diabaikan kecuali jika layanan
+dihentikan atau dihapus dari latar depan.</p>
+
+<p>Misalnya, pemutar musik yang memutar musik dari suatu layanan harus diatur untuk berjalan di
+latar depan, karena pengguna mengetahui operasi tersebut
+secara eksplisit. Pemberitahuan di baris status bisa menunjukkan lagu saat ini dan memungkinkan
+pengguna untuk menjalankan suatu aktivitas untuk berinteraksi dengan pemutar musik.</p>
+
+<p>Untuk meminta agar layanan Anda berjalan di latar depan, panggil {@link
+android.app.Service#startForeground startForeground()}. Metode ini memerlukan dua parameter: sebuah integer
+yang mengidentifikasi pemberitahuan secara unik dan {@link
+android.app.Notification} untuk baris status. Misalnya:</p>
+
+<pre>
+Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
+        System.currentTimeMillis());
+Intent notificationIntent = new Intent(this, ExampleActivity.class);
+PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
+notification.setLatestEventInfo(this, getText(R.string.notification_title),
+        getText(R.string.notification_message), pendingIntent);
+startForeground(ONGOING_NOTIFICATION_ID, notification);
+</pre>
+
+<p class="caution"><strong>Perhatian:</strong> ID integer yang Anda berikan ke {@link
+android.app.Service#startForeground startForeground()} tidak boleh 0.</p>
+
+
+<p>Untuk menghapus layanan dari latar depan, panggil {@link
+android.app.Service#stopForeground stopForeground()}. Metode ini memerlukan boolean, yang menunjukkan
+apakah pemberitahuan baris status juga akan dihapus. Metode ini <em>tidak</em> menghentikan
+layanan. Akan tetapi, jika Anda menghentikan layanan saat masih berjalan di latar depan
+maka pemberitahuan juga akan dihapus.</p>
+
+<p>Untuk informasi selengkapnya tentang pemberitahuan, lihat <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Membuat Pemberitahuan
+Baris Status</a>.</p>
+
+
+
+<h2 id="Lifecycle">Mengelola Daur Hidup Layanan</h2>
+
+<p>Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, lebih penting lagi adalah
+memerhatikan dengan cermat bagaimana layanan Anda dibuat dan dimusnahkan, karena suatu layanan
+bisa berjalan di latar belakang tanpa disadari oleh pengguna.</p>
+
+<p>Daur hidup layanan&mdash;dari saat dibuat hingga dimusnahkan&mdash;bisa mengikuti
+dua path berbeda:</p>
+
+<ul>
+<li>Layanan yang sudah dimulai
+  <p>Layanan dibuat bila komponen lain memanggil {@link
+android.content.Context#startService startService()}. Layanan kemudian berjalan terus-menerus dan harus
+berhenti sendiri dengan memanggil {@link
+android.app.Service#stopSelf() stopSelf()}. Komponen lain juga bisa menghentikan
+layanan dengan memanggil {@link android.content.Context#stopService
+stopService()}. Bila layanan dihentikan, sistem akan menghancurkannya.</p></li>
+
+<li>Layanan terikat
+  <p>Layanan dibuat bila komponen lain (klien) memanggil {@link
+android.content.Context#bindService bindService()}. Klien kemudian berkomunikasi dengan layanan
+melalui antarmuka {@link android.os.IBinder}. Klien bisa menutup koneksi dengan memanggil
+{@link android.content.Context#unbindService unbindService()}. Sejumlah klien bisa mengikat pada
+layanan yang sama dan bila semuanya melepas ikatan, sistem akan memusnahkan layanan tersebut. (Layanan
+<em>tidak</em> perlu berhenti sendiri.)</p></li>
+</ul>
+
+<p>Kedua path tersebut tidak benar-benar terpisah. Artinya, Anda bisa mengikat ke layanan yang sudah
+dimulai dengan {@link android.content.Context#startService startService()}. Misalnya, layanan
+musik latar belakang bisa dimulai dengan memanggil {@link android.content.Context#startService
+startService()} dengan {@link android.content.Intent} yang mengidentifikasi musik yang akan diputar. Kemudian,
+mungkin saat pengguna ingin mengontrol pemutar musik atau mendapatkan informasi
+tentang lagu yang diputar, aktivitas bisa mengikat ke layanan dengan memanggil {@link
+android.content.Context#bindService bindService()}. Dalam kasus seperti ini, {@link
+android.content.Context#stopService stopService()} atau {@link android.app.Service#stopSelf
+stopSelf()} tidak menghentikan layanan sampai semua klien melepas ikatan. </p>
+
+
+<h3 id="LifecycleCallbacks">Mengimplementasikan callback daur hidup</h3>
+
+<p>Seperti halnya aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan
+untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan skeleton
+berikut memperagakan setiap metode daur hidup:</p>
+
+<pre>
+public class ExampleService extends Service {
+    int mStartMode;       // indicates how to behave if the service is killed
+    IBinder mBinder;      // interface for clients that bind
+    boolean mAllowRebind; // indicates whether onRebind should be used
+
+    &#64;Override
+    public void {@link android.app.Service#onCreate onCreate}() {
+        // The service is being created
+    }
+    &#64;Override
+    public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) {
+        // The service is starting, due to a call to {@link android.content.Context#startService startService()}
+        return <em>mStartMode</em>;
+    }
+    &#64;Override
+    public IBinder {@link android.app.Service#onBind onBind}(Intent intent) {
+        // A client is binding to the service with {@link android.content.Context#bindService bindService()}
+        return <em>mBinder</em>;
+    }
+    &#64;Override
+    public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) {
+        // All clients have unbound with {@link android.content.Context#unbindService unbindService()}
+        return <em>mAllowRebind</em>;
+    }
+    &#64;Override
+    public void {@link android.app.Service#onRebind onRebind}(Intent intent) {
+        // A client is binding to the service with {@link android.content.Context#bindService bindService()},
+        // after onUnbind() has already been called
+    }
+    &#64;Override
+    public void {@link android.app.Service#onDestroy onDestroy}() {
+        // The service is no longer used and is being destroyed
+    }
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Tidak seperti metode callback daur hidup aktivitas, Anda
+<em>tidak</em> perlu memanggil implementasi superkelas metode callback tersebut.</p>
+
+<img src="{@docRoot}images/service_lifecycle.png" alt="" />
+<p class="img-caption"><strong>Gambar 2.</strong> Daur hidup layanan. Diagram di sebelah kiri
+menampilkan daur hidup bila layanan dibuat dengan {@link android.content.Context#startService
+startService()} dan diagram di sebelah kanan menampilkan daur hidup bila layanan dibuat
+dengan {@link android.content.Context#bindService bindService()}.</p>
+
+<p>Dengan mengimplementasikan metode-metode ini, Anda bisa memantau dua loop tersarang (nested loop) daur hidup layanan: </p>
+
+<ul>
+<li><strong>Seluruh masa pakai</strong> layanan terjadi antara saat {@link
+android.app.Service#onCreate onCreate()} dipanggil dan saat {@link
+android.app.Service#onDestroy} kembali. Seperti halnya aktivitas, layanan melakukan penyiapan awal di
+{@link android.app.Service#onCreate onCreate()} dan melepaskan semua sisa sumber daya yang ada di {@link
+android.app.Service#onDestroy onDestroy()}.  Misalnya,
+layanan pemutar musik bisa membuat thread tempat musik akan diputar dalam {@link
+android.app.Service#onCreate onCreate()}, kemudian menghentikan thread tersebut dalam {@link
+android.app.Service#onDestroy onDestroy()}.
+
+<p>Metode {@link android.app.Service#onCreate onCreate()} dan {@link android.app.Service#onDestroy
+onDestroy()} diperlukan semua layanan, baik yang
+dibuat oleh {@link android.content.Context#startService startService()} maupun {@link
+android.content.Context#bindService bindService()}.</p></li>
+
+<li><strong>Masa pakai aktif</strong> layanan dimulai dengan panggilan ke {@link
+android.app.Service#onStartCommand onStartCommand()} atau {@link android.app.Service#onBind onBind()}.
+Masing-masing metode diberikan {@link
+android.content.Intent} yang diteruskan ke {@link android.content.Context#startService
+startService()} atau {@link android.content.Context#bindService bindService()}.
+<p>Jika layanan telah dimulai, masa pakai aktif akan berakhir pada saat yang sama dengan
+berakhirnya seluruh masa pakai (layanan masih aktif bahkan setelah {@link android.app.Service#onStartCommand
+onStartCommand()} kembali). Jika layanan tersebut terikat, masa pakai aktifnya akan berakhir bila {@link
+android.app.Service#onUnbind onUnbind()} kembali.</p>
+</li>
+</ul>
+
+<p class="note"><strong>Catatan:</strong> Meskipun layanan yang sudah dimulai dihentikan dengan panggilan ke
+{@link android.app.Service#stopSelf stopSelf()} atau {@link
+android.content.Context#stopService stopService()}, tidak ada callback tersendiri bagi
+layanan tersebut (tidak ada callback {@code onStop()}). Jadi, kecuali jika layanan terikat ke klien,
+sistem akan memusnahkannya bila layanan dihentikan&mdash;{@link
+android.app.Service#onDestroy onDestroy()} adalah satu-satunya callback yang diterima.</p>
+
+<p>Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Walaupun gambar tersebut memisahkan
+layanan yang dibuat oleh {@link android.content.Context#startService startService()} dari layanan
+yang dibuat oleh {@link android.content.Context#bindService bindService()}, ingatlah
+bahwa suatu layanan, bagaimana pun dimulainya, bisa memungkinkan klien mengikat padanya.
+Jadi, suatu layanan yang awalnya dimulai dengan {@link android.app.Service#onStartCommand
+onStartCommand()} (oleh klien yang memanggil {@link android.content.Context#startService startService()})
+masih bisa menerima panggilan ke {@link android.app.Service#onBind onBind()} (bila klien memanggil
+{@link android.content.Context#bindService bindService()}).</p>
+
+<p>Untuk informasi selengkapnya tentang membuat layanan yang menyediakan pengikatan, lihat dokumen <a href="{@docRoot}guide/components/bound-services.html">Layanan Terikat</a>,
+yang menyertakan informasi selengkapnya tentang metode callback {@link android.app.Service#onRebind onRebind()}
+di bagian tentang <a href="{@docRoot}guide/components/bound-services.html#Lifecycle">Mengelola Daur Hidup
+Layanan Terikat</a>.</p>
+
+
+<!--
+<h2>Beginner's Path</h2>
+
+<p>To learn how to query data from the system or other applications (such as contacts or media
+stored on the device), continue with the <b><a
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b>
+document.</p>
+-->
diff --git a/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
new file mode 100644
index 0000000..4c344ae
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/components/tasks-and-back-stack.jd
@@ -0,0 +1,578 @@
+page.title=Tugas dan Back-Stack
+parent.title=Aktivitas
+parent.link=activities.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+<li><a href="#ActivityState">Menyimpan Status Aktivitas</a></li></li>
+<li><a href="#ManagingTasks">Mengelola Tugas</a>
+  <ol>
+    <li><a href="#TaskLaunchModes">Mendefinisikan mode peluncuran</a></li>
+    <li><a href="#Affinities">Menangani afinitas</a></li>
+    <li><a href="#Clearing">Menghapus back-stack</a></li>
+    <li><a href="#Starting">Memulai tugas</a></li>
+  </ol>
+</li>
+</ol>
+
+<h2>Artikel</h2>
+<ol>
+  <li><a href="http://android-developers.blogspot.com/2010/04/multitasking-android-way.html">
+  Multitasking Ala Android</a></li>
+</ol>
+
+<h2>Lihat juga</h2>
+<ol>
+  <li><a href="{@docRoot}design/patterns/navigation.html">Desain Android:
+Navigasi</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html">Elemen manifes
+{@code &lt;activity&gt;}</a></li>
+  <li><a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a></li>
+</ol>
+</div>
+</div>
+
+
+<p>Sebuah aplikasi biasanya berisi beberapa <a href="{@docRoot}guide/components/activities.html">aktivitas</a>. Setiap aktivitas
+harus didesain dengan jenis tindakan tertentu yang bisa dilakukan pengguna dan bisa memulai aktivitas
+lain. Misalnya, aplikasi email mungkin memiliki satu aktivitas untuk menampilkan daftar pesan baru.
+Bila pengguna memilih sebuah pesan, aktivitas baru akan terbuka untuk melihat pesan tersebut.</p>
+
+<p>Aktivitas bahkan bisa memulai aktivitas yang ada dalam aplikasi lain di perangkat. Misalnya
+, jika aplikasi Anda ingin mengirim pesan email, Anda bisa mendefinisikan intent untuk melakukan tindakan
+"kirim" dan menyertakan sejumlah data, seperti alamat email dan pesan. Aktivitas dari aplikasi
+lain yang mendeklarasikan dirinya untuk menangani jenis intent ini akan terbuka. Dalam hal ini, intent
+tersebut untuk mengirim email, sehingga aktivitas "menulis" pada aplikasi email akan dimulai (jika beberapa aktivitas
+mendukung intent yang sama, maka sistem akan memungkinkan pengguna memilih mana yang akan digunakan). Bila email telah
+dikirim, aktivitas Anda akan dilanjutkan dan seolah-olah aktivitas email adalah bagian dari aplikasi Anda. Meskipun
+aktivitas mungkin dari aplikasi yang berbeda, Android akan tetap mempertahankan pengalaman pengguna yang mulus
+dengan menjalankan kedua aktivitas dalam <em>tugas</em> yang sama.</p>
+
+<p>Tugas adalah kumpulan aktivitas yang berinteraksi dengan pengguna
+saat melakukan pekerjaan tertentu. Aktivitas tersebut diatur dalam tumpukan (<em>back-stack</em>), dalam
+urutan membuka setiap aktivitas.</p>
+
+<!-- SAVE FOR WHEN THE FRAGMENT DOC IS ADDED
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h3>Adding fragments to a task's back stack</h3>
+
+<p>Your activity can also include {@link android.app.Fragment}s to the back stack. For example,
+suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the
+other being a layout to display an item from the list (fragment B). When the user selects an item
+from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be
+desireable for the user to navigate back to reveal fragment B, using the <em>Back</em> button.</p>
+<p>In order to add fragment B to the back stack so that this is possible, you must call {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link
+android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment
+C.</p>
+<p>For more information about using fragments and adding them to the back stack, see the {@link
+android.app.Fragment} class documentation.</p>
+
+</div>
+</div>
+-->
+
+<p>Layar Home perangkat adalah tempat memulai hampir semua tugas. Bila pengguna menyentuh ikon di launcher
+aplikasi
+(atau pintasan pada layar Home), tugas aplikasi tersebut akan muncul pada latar depan. Jika tidak ada
+tugas untuk aplikasi (aplikasi tidak digunakan baru-baru ini), maka tugas baru
+akan dibuat dan aktivitas "utama" untuk aplikasi tersebut akan terbuka sebagai aktivitas akar dalam back-stack.</p>
+
+<p>Bila aktivitas saat ini dimulai lagi, aktivitas baru akan didorong ke atas back-stack dan
+mengambil fokus. Aktivitas sebelumnya tetap dalam back-stack, namun dihentikan. Bila aktivitas
+dihentikan, sistem akan mempertahankan status antarmuka penggunanya saat ini. Bila pengguna menekan tombol
+<em>Back</em>
+, aktivitas saat ini akan dikeluarkan dari atas back-stack (aktivitas dimusnahkan) dan
+ aktivitas sebelumnya dilanjutkan (status UI sebelumnya dipulihkan). Aktivitas dalam back-stack
+tidak pernah disusun ulang, hanya didorong dan dikeluarkan dari back-stack&mdash;yang didorong ke back-stack saat dimulai oleh
+aktivitas saat ini dan dikeluarkan bila pengguna meninggalkannya menggunakan tombol <em>Back</em>. Dengan demikian,
+back-stack
+beroperasi sebagai struktur objek "masuk terakhir, keluar pertama". Gambar 1 melukiskan perilaku
+ini dengan jangka waktu yang menunjukkan kemajuan antar aktivitas beserta
+back-stack pada setiap waktu.</p>
+
+<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Representasi tentang cara setiap aktivitas baru dalam
+tugas menambahkan item ke back-stack. Bila pengguna menekan tombol <em>Back</em>, aktivitas
+saat ini
+akan dimusnahkan dan aktivitas sebelumnya dilanjutkan.</p>
+
+
+<p>Jika pengguna terus menekan <em>Back</em>, maka setiap aktivitas dalam back-stack akan dikeluarkan untuk
+menampilkan
+yang sebelumnya, sampai pengguna kembali ke layar Home (atau aktivitas mana pun yang sedang dijalankan saat tugas
+dimulai. Bila semua aktivitas telah dihapus dari back-stack, maka tugas tidak akan ada lagi.</p>
+
+<div class="figure" style="width:287px">
+<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p
+class="img-caption"><strong>Gambar 2.</strong> Dua tugas: Tugas B menerima interaksi pengguna
+di latar depan, sedangkan Tugas A di latar belakang, menunggu untuk dilanjutkan.</p>
+</div>
+<div class="figure" style="width:215px">
+  <img src="{@docRoot}images/fundamentals/diagram_multiple_instances.png" alt="" /> <p
+class="img-caption"><strong>Gambar 3.</strong> Satu aktivitas dibuat instance-nya beberapa kali.</p>
+</div>
+
+<p>Tugas adalah unit kohesif yang bisa dipindahkan ke "latar belakang" bila pengguna memulai tugas baru atau masuk ke
+layar Home, melalui tombol<em>Home</em>. Sementara di latar belakang, semua aktivitas dalam
+tugas
+dihentikan, namun back-stack untuk tugas tidak berubah&mdash;tugas kehilangan fokus saat
+tugas lain berlangsung, seperti yang ditampilkan dalam gambar 2. Kemudian, tugas bisa kembali ke "latar depan" agar pengguna
+bisa melanjutkan tugas di tempat menghentikannya. Anggaplah, misalnya, tugas saat ini (Tugas A) memiliki tiga
+aktivitas dalam back-stack&mdash;dua pada aktivitas saat ini. Pengguna menekan tombol <em>Home</em>
+, kemudian
+memulai aplikasi baru dari launcher aplikasi. Bila muncul layar Home, Tugas A akan beralih
+ke latar belakang. Bila aplikasi baru dimulai, sistem akan memulai tugas untuk aplikasi tersebut
+(Tugas B) dengan back-stack aktivitas sendiri. Setelah berinteraksi dengan aplikasi
+tersebut, pengguna akan kembali ke Home lagi dan memilih aplikasi yang semula
+memulai Tugas A. Sekarang, Tugas A muncul di
+latar depan&mdash;ketiga aktivitas dalam back-stack tidak berubah dan aktivitas di atas
+back-stack akan dilanjutkan. Pada
+titik ini pengguna juga bisa beralih kembali ke Tugas B dengan masuk ke Home dan memilih ikon aplikasi
+yang memulai tugas tersebut (atau dengan memilih tugas aplikasi dari
+<a href="{@docRoot}guide/components/recents.html">layar ikhtisar</a>).
+Ini adalah contoh dari melakukan multitasking di Android.</p>
+
+<p class="note"><strong>Catatan:</strong> Beberapa tugas bisa berlangsung di latar belakang secara bersamaan.
+Akan tetapi, jika pengguna menjalankan banyak tugas di latar belakang sekaligus, sistem mungkin mulai
+menghapus aktivitas latar belakang untuk memulihkan memori, yang akan menyebabkan status aktivitas hilang.
+Lihat bagian berikut tentang <a href="#ActivityState">Status aktivitas</a>.</p>
+
+<p>Karena aktivitas di back-stack tidak pernah diatur ulang, jika aplikasi Anda memungkinkan
+pengguna untuk memulai aktivitas tertentu dari lebih dari satu aktivitas, instance baru
+aktivitas tersebut akan dibuat dan didorong ke back-stack (bukannya memunculkan instance sebelumnya dari
+aktivitas ke atas). Dengan demikian, satu aktivitas pada aplikasi Anda mungkin dibuat beberapa
+kali (bahkan dari beberapa tugas), seperti yang ditampilkan dalam gambar 3. Dengan demikian, jika pengguna mengarahkan mundur
+menggunakan tombol <em>Back</em>, setiap instance aktivitas ini akan ditampilkan dalam urutan saat
+dibuka (masing-masing
+dengan status UI sendiri). Akan tetapi, Anda bisa memodifikasi perilaku ini jika tidak ingin aktivitas
+dibuat instance-nya lebih dari sekali. Caranya dibahas di bagian selanjutnya tentang <a href="#ManagingTasks">Mengelola Tugas</a>.</p>
+
+
+<p>Untuk meringkas perilaku default aktivitas dan tugas:</p>
+
+<ul>
+  <li>Bila Aktivitas A memulai Aktivitas B, Aktivitas A dihentikan, namun sistem mempertahankan statusnya
+(seperti posisi gulir dan teks yang dimasukkan ke dalam formulir).
+Jika pengguna menekan tombol <em>Back</em> saat dalam Aktivitas B, Aktivitas A akan dilanjutkan dengan status
+yang dipulihkan.</li>
+  <li>Bila pengguna meninggalkan tugas dengan menekan tombol <em>Home</em> aktivitas saat ini akan
+dihentikan dan
+tugas beralih ke latar belakang. Sistem akan mempertahankan status setiap aktivitas dalam tugas. Jika
+nanti pengguna melanjutkan tugas dengan memilih ikon launcher yang memulai tugas, tugas tersebut akan
+beralih ke latar depan dan melanjutkan aktivitas di atas back-stack.</li>
+  <li>Jika pengguna menekan tombol <em>Back</em>, aktivitas saat ini akan dikeluarkan dari back-stack
+dan
+dimusnahkan. Aktivitas sebelumnya dalam back-stack akan dilanjutkan. Bila suatu aktivitas dimusnahkan, sistem
+<em>tidak akan</em>mempertahankan status aktivitas.</li>
+  <li>Aktivitas bisa dibuat instance-nya beberapa kali, bahkan dari tugas-tugas lainnya.</li>
+</ul>
+
+
+<div class="note design">
+<p><strong>Desain Navigasi</strong></p>
+  <p>Untuk mengetahui selengkapnya tentang cara kerja navigasi aplikasi di Android, baca panduan <a href="{@docRoot}design/patterns/navigation.html">Navigasi</a> Desain Android.</p>
+</div>
+
+
+<h2 id="ActivityState">Menyimpan Status Aktivitas</h2>
+
+<p>Seperti dibahas di atas, perilaku default sistem akan mempertahankan status aktivitas bila
+dihentikan. Dengan cara ini, bila pengguna mengarah kembali ke aktivitas sebelumnya, antarmuka pengguna akan muncul
+seperti saat ditinggalkan. Akan tetapi, Anda bisa&mdash;dan <strong>harus</strong>&mdash;secara proaktif mempertahankan
+status aktivitas menggunakan metode callback, jika aktivitas ini dimusnahkan dan harus
+dibuat kembali.</p>
+
+<p>Bila sistem menghentikan salah satu aktivitas (seperti saat aktivitas baru dimulai atau tugas
+dipindah ke latar belakang), sistem mungkin memusnahkan aktivitas sepenuhnya jika perlu memulihkan
+memori sistem. Bila hal ini terjadi, informasi tentang status aktivitas akan hilang. Jika hal ini terjadi, sistem
+masih
+mengetahui bahwa aktivitas memiliki tempat di back-stack, namun saat aktivitas tersebut dibawa ke bagian teratas
+back-stack, sistem harus membuatnya kembali (bukan melanjutkannya). Untuk
+menghindari hilangnya pekerjaan pengguna, Anda harus secara proaktif mempertahankannya dengan menerapkan metode callback
+{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}
+dalam aktivitas.</p>
+
+<p>Untuk informasi selengkapnya tentang cara menyimpan status aktivitas Anda, lihat dokumen
+<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Aktivitas</a>.</p>
+
+
+
+<h2 id="ManagingTasks">Mengelola Tugas</h2>
+
+<p>Cara Android mengelola tugas dan back-stack, seperti yang dijelaskan di atas&mdash;dengan menempatkan semua
+aktivitas yang dimulai secara berurutan dalam tugas yang sama dan dalam back-stack "masuk terakhir, keluar pertama"&mdash;berfungsi
+dengan baik untuk kebanyakan aplikasi dan Anda tidak perlu khawatir tentang cara mengaitkan aktivitas
+dengan tugas atau cara penempatannya di back-stack. Akan tetapi, Anda bisa memutuskan apakah ingin menyela
+perilaku normal. Mungkin Anda ingin agar suatu aktivitas dalam aplikasi untuk memulai tugas baru bila telah
+dimulai (sebagai ganti menempatkannya dalam tugas saat ini); atau, bila memulai aktivitas, Anda ingin
+memajukan instance yang ada (sebagai ganti membuat instance
+baru pada bagian teratas back-stack); atau, Anda ingin back-stack dihapus dari semua
+aktivitas selain untuk aktivitas akar bila pengguna meninggalkan tugas.</p>
+
+<p>Anda bisa melakukan semua ini dan lainnya, dengan atribut dalam elemen manifes
+<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+dan dengan flag pada intent yang Anda teruskan ke
+{@link android.app.Activity#startActivity startActivity()}.</p>
+
+<p>Dalam hal ini, atribut<a href="{@docRoot}guide/topics/manifest/activity-element.html">
+{@code &lt;activity&gt;}</a> utama yang bisa Anda gunakan adalah:</p>
+
+<ul class="nolist">
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">
+  {@code taskAffinity}</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">
+  {@code launchMode}</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
+  {@code allowTaskReparenting}</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">
+  {@code clearTaskOnLaunch}</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
+  {@code alwaysRetainTaskState}</a></li>
+  <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">
+  {@code finishOnTaskLaunch}</a></li>
+</ul>
+
+<p>Dan flag intent utama yang bisa Anda gunakan adalah:</p>
+
+<ul class="nolist">
+  <li>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</li>
+  <li>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</li>
+  <li>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</li>
+</ul>
+
+<p>Dalam bagian berikut, Anda akan melihat cara menggunakan beberapa atribut manifes ini dan flag
+intent untuk mendefinisikan cara mengaitkan aktivitas dengan tugas dan cara perilakunya di back-stack.</p>
+
+<p>Juga, pertimbangan cara menyatakan dan mengelola tugas dan aktivitas
+dibahas secara terpisah di layar ikhtisar. Lihat <a href="{@docRoot}guide/components/recents.html">Layar Ikhtisar</a>
+untuk informasi selengkapnya. Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
+aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Kebanyakan aplikasi tidak harus menyela perilaku
+default untuk aktivitas dan tugas. Jika merasa bahwa aktivitas Anda perlu memodifikasi
+perilaku default, lakukan dengan hati-hati dan pastikan menguji kegunaan aktivitas selama
+dijalankan dan saat mengarahkan kembali ke sana dari aktivitas dan tugas lain dengan tombol <em>Back</em>.
+Pastikan menguji perilaku navigasi yang mungkin bertentangan dengan perilaku yang diharapkan pengguna.</p>
+
+
+<h3 id="TaskLaunchModes">Mendefinisikan mode peluncuran</h3>
+
+<p>Mode peluncuran memungkinkan Anda mendefinisikan cara mengaitkan instance baru dari suatu aktivitas dengan
+tugas saat ini. Anda bisa mendefinisikan beragam mode peluncuran dalam dua cara:</p>
+<ul class="nolist">
+  <li><a href="#ManifestForTasks">Menggunakan file manifes</a>
+    <p>Bila Anda mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
+dengan tugas-tugas saat mulai.</li>
+  <li><a href="#IntentFlagsForTasks">Menggunakan flag intent</a>
+    <p>Saat memanggil{@link android.app.Activity#startActivity startActivity()},
+Anda bisa menyertakan flag dalam {@link android.content.Intent} yang menyatakan cara (atau
+apakah) aktivitas baru tersebut harus dikaitkan dengan tugas saat ini.</p></li>
+</ul>
+
+<p>Dengan demikian, jika Aktivitas A memulai Aktivitas B, Aktivitas B bisa mendefinisikan dalam manifesnya cara
+mengaitkan dengan tugas saat ini (jika sama sekali) dan Aktivitas A juga bisa meminta cara mengaitkan Aktivitas B
+dengan tugas saat ini. Jika kedua aktivitas mendefinisikan cara mengaitkan Aktivitas B
+dengan tugas, maka permintaan Aktivitas A (sebagaimana didefinisikan dalam intent) lebih dihargai daripada
+permintaan Aktivitas B (sebagaimana didefinisikan dalam manifesnya).</p>
+
+<p class="note"><strong>Catatan:</strong> Beberapa mode peluncuran yang tersedia untuk file manifes
+tidak tersedia sebagai flag untuk intent dan, juga, beberapa mode peluncuran yang tersedia sebagai flag
+untuk intent tidak bisa didefinisikan dalam manifest.</p>
+
+
+<h4 id="ManifestForTasks">Menggunakan file manifes</h4>
+
+<p>Saat mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas
+dengan tugas menggunakan <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
+melalui atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
+launchMode}</a> elemen.</p>
+
+<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
+launchMode}</a> menetapkan instruksi tentang cara meluncurkan aktivitas
+ke dalam tugas. Ada empat macam mode peluncuran yang bisa Anda tetapkan ke atribut
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code>
+:</p>
+
+<dl>
+<dt>{@code "standard"} (mode default)</dt>
+  <dd>Default. Sistem membuat instance baru aktivitas dalam tugas yang
+akan menjadi tempat memulainya dan mengarahkan intent ke sana. Aktivitas ini bisa dibuat instance-nya beberapa kali,
+masing-masing instance bisa dimiliki oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance.</dd>
+<dt>{@code "singleTop"}</dt>
+  <dd>Jika instance aktivitas sudah ada di bagian teratas tugas saat ini, sistem
+akan mengarahkan intent ke instance tersebut melalui panggilan ke metode {@link
+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru dari
+aktivitas tersebut. Aktivitas bisa dibuat instance-nya beberapa kali, masing-masing instance bisa dimiliki
+oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance (namun hanya jika
+aktivitas di bagian teratas back-stack <em>bukan</em> instance yang ada dari aktivitas tersebut).
+  <p>Misalnya, anggaplah back-stack tugas terdiri dari aktivitas A akar dengan aktivitas B, C,
+dan D di bagian teratas (back-stack adalah A-B-C-D; D yang teratas). Intent masuk untuk aktivitas tipe D.
+Jika D memiliki mode peluncuran {@code "standard"} default, instance baru dari kelas ini akan diluncurkan dan
+back-stack menjadi A-B-C-D-D. Namun, jika mode peluncuran D adalah {@code "singleTop"}, instance
+yang ada dari D akan menerima intent melalui {@link
+android.app.Activity#onNewIntent onNewIntent()}, karena ada di bagian teratas back-stack&mdash;
+back-stack tetap A-B-C-D. Akan tetapi, jika intent masuk untuk aktivitas tipe B, maka
+instance B baru akan ditambahkan ke back-stack, sekalipun mode peluncuran adalah{@code "singleTop"}.</p>
+  <p class="note"><strong>Catatan:</strong> Bila instance dari aktivitas baru telah dibuat,
+pengguna bisa menekan tombol <em>Back</em> untuk kembali ke aktivitas sebelumnya. Namun bila instance
+yang ada dari
+aktivitas menangani intent baru, pengguna tidak bisa menekan tombol <em>Back</em> untuk kembali ke
+status
+aktivitas sebelum intent baru masuk di {@link android.app.Activity#onNewIntent
+onNewIntent()}.</p>
+</dd>
+
+<dt>{@code "singleTask"}</dt>
+  <dd>Sistem membuat tugas baru dan membuat instance aktivitas di akar tugas baru.
+Akan tetapi, jika instance aktivitas sudah ada dalam tugas terpisah, sistem akan mengarahkan
+intent ke instance yang ada melalui panggilan ke metode {@link
+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru. Hanya
+boleh ada satu instance aktivitas untuk setiap kalinya.
+  <p class="note"><strong>Catatan:</strong> Meskipun aktivitas dimulai di tugas baru, tombol
+<em>Back</em> tetap akan mengembalikan pengguna ke aktivitas sebelumnya.</p></dd>
+<dt>{@code "singleInstance"}.</dt>
+  <dd>Sama seperti {@code "singleTask"}, namun sistem tidak meluncurkan aktivitas lain ke
+tugas yang menyimpan instance. Aktivitas selalu satu dan satu-satunya anggota dari tugasnya;
+aktivitas apa pun yang dimulai dengan ini akan dibuka di tugas yang terpisah.</dd>
+</dl>
+
+
+<p>Sebagai contoh lainnya, aplikasi Browser Android mendeklarasikan bahwa aktivitas browser web harus
+selalu dibuka dalam tugasnya sendiri&mdash;dengan menetapkan mode pembuka {@code singleTask} dalam elemen<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.
+Ini berarti bahwa jika aplikasi Anda mengeluarkan
+intent untuk membuka Browser Android, aktivitasnya <em>tidak</em> akan ditempatkan dalam tugas
+yang sama seperti aplikasi Anda. Sebagai gantinya, tugas baru akan dimulai untuk Browser atau, jika Browser
+sudah memiliki tugas yang berjalan di latar belakang, tugas tersebut akan dimajukan untuk menangani intent
+baru.</p>
+
+<p>Baik aktivitas dimulai dalam tugas baru atau maupun dalam tugas yang sama seperti aktivitas yang memulainya, tombol
+<em>Back</em> selalu membawa pengguna ke aktivitas sebelumnya. Akan tetapi, jika
+Anda memulai aktivitas yang menetapkan mode pembuka {@code singleTask}, maka jika instance
+aktivitas tersebut ada dalam tugas latar belakang, seluruh tugas tersebut akan dibawa ke latar depan. Pada titik
+ini, back-stack sekarang menyertakan semua aktivitas dari tugas yang dimajukan, di atas
+back-stack. Gambar 4 mengilustrasikan tipe skenario ini.</p>
+
+<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" />
+<p class="img-caption"><strong>Gambar 4.</strong> Representasi tentang cara aktivitas dengan
+mode pembuka "singleTask" ditambahkan ke back-stack. Jika aktivitas tersebut sudah menjadi bagian dari
+tugas latar belakang dengan back-stack sendiri, maka seluruh back-stack juga
+dimajukan, di atas tugas saat ini.</p>
+
+<p>Untuk informasi selengkapnya tentang menggunakan mode pembuka dalam file manifes, lihat dokumentasi elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+, di mana atribut {@code launchMode} dan nilai-nilai yang diterima
+akan dibahas selengkapnya.</p>
+
+<p class="note"><strong>Catatan:</strong> Perilaku yang Anda tentukan untuk aktivitas dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
+bisa dikesampingkan dengan flag yang disertakan bersama intent yang memulai aktivitas Anda, seperti dibahas dalam
+bagian berikutnya.</p>
+
+
+
+<h4 id="#IntentFlagsForTasks">Menggunakan flag Intent</h4>
+
+<p>Saat memulai aktivitas, Anda bisa memodifikasi asosiasi default aktivitas pada tugasnya
+ dengan menyertakan flag dalam intent yang Anda kirimkan ke {@link
+android.app.Activity#startActivity startActivity()}. Flag yang bisa Anda gunakan untuk memodifikasi perilaku default
+adalah:</p>
+
+<p>
+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt>
+    <dd>Memulai aktivitas dalam tugas baru. Jika tugas sudah dijalankan untuk aktivitas yang sekarang
+Anda mulai, tugas tersebut akan dibawa ke latar depan dengan status terakhir yang dipulihkan dan aktivitas
+akan menerima intent baru dalam {@link android.app.Activity#onNewIntent onNewIntent()}.
+    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTask"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
+yang dibahas di bagian sebelumnya.</p></dd>
+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</dt>
+    <dd>Jika aktivitas yang dimulai adalah aktivitas saat ini (di bagian teratas back-stack), maka
+instance yang ada akan menerima panggilan ke {@link android.app.Activity#onNewIntent onNewIntent()}
+sebagai ganti membuat instance baru aktivitas.
+    <p>Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTop"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
+yang dibahas di bagian sebelumnya.</p></dd>
+  <dt>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</dt>
+    <dd>Jika aktivitas yang dimulai sudah berjalan dalam tugas saat ini, maka sebagai
+ganti meluncurkan instance baru aktivitas tersebut, semua kegiatan lain di atasnya akan
+dimusnahkan dan intent ini akan disampaikan ke instance aktivitas yang dilanjutkan (sekarang di atas),
+melalui {@link android.app.Activity#onNewIntent onNewIntent()}).
+    <p>Tidak ada nilai untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a>
+ yang menghasilkan perilaku ini.</p>
+    <p>{@code FLAG_ACTIVITY_CLEAR_TOP} paling sering digunakan bersama dengan
+    {@code FLAG_ACTIVITY_NEW_TASK}.
+Bila digunakan bersama-sama, flag ini adalah cara penempatan aktivitas yang ada
+dalam tugas lain dan meletakkannya dalam posisi yang memungkinkannya merespons intent. </p>
+    <p class="note"><strong>Catatan:</strong> Jika mode pembuka aktivitas yang didesain adalah
+{@code "standard"},
+ini juga akan dihapus dari back-stack dan instance baru akan diluncurkan di tempatnya untuk menangani
+intent yang masuk.  Itu karena instance baru selalu dibuat untuk intent baru bila
+mode peluncuran adalah {@code "standard"}. </p>
+</dd>
+</dl>
+
+
+
+
+
+<h3 id="Affinities">Menangani afinitas</h3>
+
+<p><em>Afinitas</em> menunjukkan tugas mana yang disukai aktivitas untuk dimiliki. Secara default, semua
+aktivitas aplikasi yang sama memiliki afinitas untuk satu sama lain. Jadi, secara default, semua
+aktivitas dalam aplikasi yang sama lebih menyukai berada dalam tugas yang sama. Akan tetapi, Anda bisa memodifikasi
+afinitas default untuk suatu aktivitas. Aktivitas yang didefinisikan dalam
+aplikasi yang berbeda bisa berbagi afinitas, atau aktivitas yang didefinisikan dalam aplikasi yang sama bisa
+diberi afinitas tugas yang berbeda.</p>
+
+<p>Anda bisa memodifikasi afinitas untuk setiap yang diberikan
+dengan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
+elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>.</p>
+
+<p>Atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
+mengambil nilai string, yang harus unik dari nama paket default
+yang dideklarasikan dalam elemen <a href="{@docRoot}guide/topics/manifest/manifest-element.html">
+{@code &lt;manifest&gt;}
+</a>, karena sistem menggunakan nama untuk mengidentifikasi afinitas
+tugas default untuk aplikasi.</p>
+
+<p>Afinitas berperan dalam dua keadaan:</p>
+<ul>
+  <li>Bila intent yang meluncurkan aktivitas berisi flag
+  {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
+.
+
+<p>Aktivitas baru, secara default, diluncurkan ke dalam tugas aktivitas
+yang disebut {@link android.app.Activity#startActivity startActivity()}. Ini didorong ke back-stack
+yang sama seperti caller.  Akan tetapi, jika intent yang diteruskan ke
+{@link android.app.Activity#startActivity startActivity()}
+berisi flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
+, maka sistem akan mencari tugas yang berbeda untuk menampung aktivitas baru. Sering kali, itu adalah tugas baru.
+Akan tetapi, tidak harus demikian.  Jika sudah ada tugas lama dengan afinitas yang sama seperti
+aktivitas baru, aktivitas ini akan diluncurkan ke dalam tugas tersebut.  Jika tidak, tugas baru akan dimulai.</p>
+
+<p>Jika flag ini menyebabkan aktivitas memulai tugas baru dan pengguna menekan tombol <em>Home</em>
+untuk meninggalkannya,
+harus ada cara bagi pengguna untuk mengarahkan kembali ke tugas. Beberapa entitas (seperti
+notification manager) selalu memulai aktivitas dalam tugas eksternal, tidak pernah sebagai bagian dari miliknya sendiri, jadi
+selalu menempatkan {@code FLAG_ACTIVITY_NEW_TASK} dalam intent yang diteruskan ke
+{@link android.app.Activity#startActivity startActivity()}.
+Jika Anda memiliki aktivitas yang bisa dipanggil melalui
+entitas eksternal yang mungkin menggunakan flag ini, hati-hatilah karena pengguna memiliki cara independen untuk kembali
+ke tugas yang telah dimulai, seperti dengan ikon launcher (aktivitas akar dari tugas
+memiliki filter intent {@link android.content.Intent#CATEGORY_LAUNCHER}; lihat bagian <a href="#Starting">Memulai tugas</a> di bawah ini).</p>
+</li>
+
+  <li>Bila aktivitas memiliki atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
+{@code allowTaskReparenting}</a> sendiri yang diatur ke {@code "true"}.
+  <p>Dalam hal ini, aktivitas bisa berpindah dari tugas yang dimulainya ke tugas yang afinitasnya
+dimilikinya, bila tugas tersebut di bawa ke latar depan.</p>
+  <p>Misalnya, anggaplah sebuah aktivitas melaporkan kondisi cuaca di sejumlah kota terpilih
+yang didefinisikan sebagai bagian dari aplikasi perjalanan.  Aktivitas memiliki afinitas yang sama dengan aktivitas lain dalam aplikasi
+yang sama (afinitas aplikasi default) dan aktivitas ini memungkinkan re-parenting dengan atribut ini.
+Bila salah satu aktivitas Anda memulai aktivitas laporan cuaca, awalnya aktivitas ini dimiliki oleh tugas
+yang sama dengan aktivitas Anda. Akan tetapi, bila tugas aplikasi perjalanan di bawa ke latar depan,
+aktivitas laporan cuaca akan ditetapkan kembali ke tugas itu dan ditampilkan di dalamnya.</p>
+</li>
+</ul>
+
+<p class="note"><strong>Tip:</strong> Jika file {@code .apk} berisi lebih dari satu "aplikasi"
+dari sudut pandang pengguna, Anda mungkin perlu menggunakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a>
+ untuk menetapkan afinitas berbeda pada aktivitas yang terkait dengan setiap "aplikasi".</p>
+
+
+
+<h3 id="Clearing">Menghapus back-stack</h3>
+
+<p>Jika pengguna meninggalkan tugas dalam waktu yang lama, sistem akan menghapus tugas semua aktivitas kecuali
+aktivitas akar.  Bila pengguna kembali ke tugas itu lagi, hanya aktivitas akar yang akan dipulihkan.
+Sistem berperilaku seperti ini, karena, setelah sekian waktu, pengguna mungkin telah mengabaikan
+apa yang mereka kerjakan sebelum dan kembali ke tugas itu untuk memulai sesuatu yang baru. </p>
+
+<p>Ada beberapa atribut aktivitas yang bisa Anda gunakan untuk memodifikasi perilaku ini: </p>
+
+<dl>
+<dt><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code>
+</dt>
+<dd>Jika atribut ini ditetapkan ke {@code "true"} dalam aktivitas akar tugas,
+perilaku default yang baru dijelaskan tidak akan terjadi.
+ Tugas akan mempertahankan semua aktivitas dalam back-stack bahkan setelah sekian lama.</dd>
+
+<dt><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt>
+<dd>Jika atribut ini diatur ke {@code "true"} dalam aktivitas akar tugas, back-
+stack akan dihapus hingga aktivitas akar bila pengguna meninggalkan tugas
+dan kembali lagi.  Dengan kata lain, ini adalah lawan dari
+<a href="{@docRoot}guide/topics/manifest/activity-element.html#always">
+{@code alwaysRetainTaskState}</a>. Pengguna selalu kembali ke tugas dengan
+status awalnya, walaupun hanya sebentar meninggalkan tugas.</dd>
+
+<dt><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code>
+</dt>
+<dd>Atribut ini seperti <a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code clearTaskOnLaunch}</a>,
+namun beroperasi pada
+satu aktivitas, bukan pada seluruh tugas.  Hal ini juga bisa menyebabkan aktivitas
+hilang, termasuk aktivitas akar.  Bila ini diatur ke {@code "true"},
+aktivitas akan tetap menjadi bagian dari tugas hanya untuk sesi saat ini.  Jika pengguna
+keluar dan kemudian kembali ke tugas tersebut, tugas tidak akan ada lagi.</dd>
+</dl>
+
+
+
+
+<h3 id="Starting">Memulai tugas</h3>
+
+<p>Anda bisa mengatur aktivitas sebagai titik masuk untuk tugas dengan memberikan filter intent dengan
+{@code "android.intent.action.MAIN"} sebagai tindakan yang ditetapkan dan
+{@code "android.intent.category.LAUNCHER"}
+sebagai kategori yang ditetapkan. Misalnya:</p>
+
+<pre>
+&lt;activity ... &gt;
+    &lt;intent-filter ... &gt;
+        &lt;action android:name="android.intent.action.MAIN" /&gt;
+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+    &lt;/intent-filter&gt;
+    ...
+&lt;/activity&gt;
+</pre>
+
+<p>Filter intent semacam ini akan menyebabkan ikon dan label untuk
+aktivitas ditampilkan dalam launcher aplikasi, yang akan memberi cara kepada pengguna untuk meluncurkan aktivitas dan
+kembali ke tugas yang dibuatnya kapan saja setelah ia telah diluncurkan.
+</p>
+
+<p>Kemampuan kedua ini penting: Pengguna harus bisa meninggalkan tugas dan kemudian kembali ke tugas tersebut
+nanti dengan menggunakan launcher aktivitas ini. Karena itu, kedua <a href="#LaunchModes">mode
+pembuka</a> yang menandai aktivitas selalu memulai tugas, {@code "singleTask"} dan
+{@code "singleInstance"}, hanya boleh digunakan bila aktivitas memiliki filter
+{@link android.content.Intent#ACTION_MAIN}
+dan {@link android.content.Intent#CATEGORY_LAUNCHER}. Bayangkan, misalnya, apa yang akan
+terjadi jika filter tidak ada: Intent meluncurkan aktivitas{@code "singleTask"}, memulai
+tugas yang baru, dan pengguna menghabiskan lebih banyak waktu mengerjakan tugas tersebut. Pengguna kemudian menekan tombol
+<em>Home</em>. Tugas kini dikirim ke latar belakang dan tidak terlihat. Sekarang pengguna tidak memiliki cara untuk kembali
+ke tugas tersebut, karena tidak dinyatakan dalam launcher aplikasi.</p>
+
+<p>Untuk kasus-kasus di mana Anda tidak ingin pengguna bisa kembali ke aktivitas, atur dalam
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+ pada
+<a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code finishOnTaskLaunch}</a>
+elemen ke {@code "true"} (lihat <a href="#Clearing">Menghapus back-stack</a>).</p>
+
+<p>Informasi lebih jauh tentang cara menyatakan dan mengelola tugas dan aktivitas dalam
+layar ikhtisar tersedia dalam<a href="{@docRoot}guide/components/recents.html">
+Layar Ikhtisar</a>.</p>
+
+<!--
+<h2>Beginner's Path</h2>
+
+<p>For more information about how to use intents to
+activate other application components and publish the intents to which your components
+respond, continue with the <b><a
+href="{@docRoot}guide/components/intents-filters.html">Intents and Intent
+Filters</a></b> document.</p>
+-->
diff --git a/docs/html-intl/intl/id/guide/index.jd b/docs/html-intl/intl/id/guide/index.jd
new file mode 100644
index 0000000..f24fab6
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/index.jd
@@ -0,0 +1,74 @@
+page.title=Pengantar Android
+
+@jd:body
+
+
+<div class="sidebox" style="width:220px"><!-- width to match col-4 below -->
+<p>Untuk mempelajari cara kerja aplikasi, mulailah dengan
+<a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>.</p>
+<p>Untuk langsung memulai pemrograman, bacalah <a href="{@docRoot}training/basics/firstapp/index.html">Membangun Aplikasi Pertama Anda.</a></p>
+</div>
+
+<p>Android menyediakan kerangka kerja aplikasi yang kaya dan memungkinkan Anda membangun aplikasi dan permainan
+inovatif untuk perangkat seluler di lingkungan bahasa pemrograman Java. Dokumen yang tercantum di navigasi
+sebelah kiri menyediakan detail tentang cara membangun aplikasi menggunakan berbagai API Android.</p>
+
+<p>Jika Anda masih baru dengan pengembangan Android, Anda perlu memahami
+konsep dasar berikut mengenai kerangka kerja aplikasi Android:</p>
+
+
+<div class="landing-banner">
+
+<div class="col-6">
+
+<h4>Aplikasi menyediakan beberapa titik masuk</h4>
+
+<p>Aplikasi Android dibangun sebagai kombinasi beragam komponen yang bisa dipanggil
+satu per satu. Misalnya, satu <em>aktivitas</em> individual menyediakan satu
+layar untuk antarmuka pengguna, dan <em>layanan</em> yang secara terpisah melakukan
+tugas di latar belakang.</p>
+
+<p>Dari satu komponen Anda dapat memulai komponen lainnya menggunakan <em>intent</em>. Anda bahkan dapat memulai
+satu komponen dalam aplikasi berbeda, seperti aktivitas dalam aplikasi peta untuk menampilkan alamat. Model ini
+menyediakan beberapa titik masuk untuk aplikasi tunggal dan memungkinkan setiap aplikasi untuk berfungsi sebagai "default"
+pengguna bagi tindakan yang dapat dipanggil aplikasi lain.</p>
+
+
+<p><b>Ketahui selengkapnya:</b></p>
+<ul class="nolist">
+<li><a href="{@docRoot}guide/components/fundamentals.html">Dasar-Dasar Aplikasi</a>
+<li><a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>
+<li><a href="{@docRoot}guide/components/activities.html">Aktivitas</a>
+</ul>
+
+</div>
+
+
+<div class="col-6">
+
+<h4>Aplikasi beradaptasi dengan perangkat berbeda</h4>
+
+<p>Android menyediakan kerangka kerja aplikasi adaptif yang memungkinkan Anda menyediakan sumber daya unik
+bagi konfigurasi perangkat yang berbeda-beda. Misalnya, Anda bisa membuat berbagai file layout
+XML untuk ukuran layar yang berbeda-beda dan sistem akan menentukan
+layout yang akan diterapkan berdasarkan ukuran layar perangkat yang ada saat ini.</p>
+
+<p>Anda dapat melakukan query ketersediaan fitur perangkat saat dijalankan (runtime) jika ada fitur aplikasi yang memerlukan
+perangkat keras spesifik seperti kamera. Jika diperlukan, Anda juga bisa mendeklarasikan fitur yang dibutuhkan aplikasi
+agar pasar aplikasi seperti Google Play Store tidak mengizinkan instalasi pada perangkat yang tidak
+mendukung fitur itu.</p>
+
+
+<p><b>Ketahui selengkapnya:</b></p>
+<ul class="nolist">
+<li><a href="{@docRoot}guide/practices/compatibility.html">Kompatibilitas Perangkat</a>
+<li><a href="{@docRoot}guide/topics/resources/overview.html">Ikhtisar Sumber Daya</a>
+<li><a href="{@docRoot}guide/topics/ui/overview.html">Ikhtisar Antarmuka Pengguna</a>
+</ul>
+
+</div>
+
+</div><!-- end landing-banner -->
+
+
+
diff --git a/docs/html-intl/intl/id/guide/platform/j8-jack.jd b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
new file mode 100644
index 0000000..4389184
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/platform/j8-jack.jd
@@ -0,0 +1,197 @@
+page.title=Fitur Bahasa Java 8
+page.keywords="android N", "Java 8", "Jack"
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <ol>
+      <li>
+        <a href="#supported-features">API dan Fitur Bahasa Java 8 yang didukung</a>
+      </li>
+      <li>
+        <a href="#configuration">Mengaktifkan Fitur Java 8 dan Jack Toolchain</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>Android N memperkenalkan dukungan untuk fitur bahasa Java 8
+  yang bisa Anda gunakan saat mengembangkan aplikasi yang menargetkan Android N.
+  Halaman ini menjelaskan fitur bahasa baru yang didukung dalam Android N
+  Preview, cara menyiapkan proyek Anda dengan benar untuk menggunakannya, dan setiap masalah
+  yang diketahui yang mungkin Anda temui.
+</p>
+
+<p>Untuk mulai menggunakan fitur-fitur ini, Anda perlu mengunduh dan menyiapkan Android
+Studio 2.1 dan Android N Preview SDK, yang menyertakan
+Jack toolchain yang diperlukan dan Plugin Android untuk Gradle yang telah diperbarui. Jika Anda belum
+memasang Android N Preview SDK, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan Pengembangan untuk Android N</a>.</p>
+
+
+
+<p class="note">
+  <strong>Catatan:</strong> Menggunakan fitur bahasa Java 8 yang baru bukanlah
+  persyaratan untuk mengembangkan aplikasi yang menargetkan platform Android N. Jika Anda
+  tidak ingin menulis kode dengan fitur bahasa Java 8, Anda bisa membiarkan nilai kompatibilitas
+  sumber dan target proyek disetel ke Java 7, namun Anda tetap harus
+  mengompilasi dengan JDK 8 untuk membangun pada platform Android N.
+</p>
+
+<h2 id="supported-features">
+  API dan Fitur Bahasa Java 8 yang Didukung
+</h2>
+
+<p>
+  Saat ini tidak semua fitur bahasa Java 8 didukung Android. Akan tetapi,
+  fitur berikut sekarang tersedia saat mengembangkan aplikasi yang menargetkan
+  Android N Preview:
+</p>
+
+<ul>
+  <li>
+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html">Metode
+    antarmuka default dan statis</a>
+  </li>
+
+  <li>
+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">
+    Ekspresi Lambda</a> (juga tersedia pada API level 23 dan yang lebih rendah)
+  </li>
+
+  <li>
+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html">Anotasi
+    yang bisa diulang</a>
+  </li>
+
+  <li>
+    <a class="external-link" href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">
+    Referensi Metode</a> (juga tersedia pada API level 23 dan yang lebih rendah)
+  </li>
+</ul>
+
+<p class="note">
+  <strong>Catatan:</strong> Untuk menguji ekspresi lambda dan referensi metode pada
+  Android versi sebelumnya, bukalah file {@code build.gradle}
+  Anda, serta setel {@code compileSdkVersion} dan {@code targetSdkVersion} ke 23 atau
+  yang lebih rendah. Anda tetap perlu <a href="#configuration">mengaktifkan Jack
+  toolchain</a> untuk menggunakan fitur Java 8 ini.
+</p>
+
+<p>
+  Selain itu, API fitur bahasa Java 8 berikut ini sekarang tersedia:
+</p>
+
+<ul>
+  <li>Reflection API dan API terkait bahasa:
+    <ul>
+      <li>
+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html">
+        {@code java.lang.FunctionalInterface}</a>
+      </li>
+
+      <li>
+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Repeatable.html">
+        {@code java.lang.annotation.Repeatable}</a>
+      </li>
+
+      <li>
+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#isDefault--">
+        {@code java.lang.reflect.Method.isDefault()}</a>
+      </li>
+
+      <li>dan Reflection API yang terkait dengan anotasi yang bisa diulang, seperti
+     <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html#getAnnotationsByType-java.lang.Class-">
+{@code AnnotatedElement.getAnnotationsByType(Class)}</a>
+      </li>
+    </ul>
+  </li>
+
+  <li>Utility API:
+    <ul>
+      <li>
+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">
+        {@code java.util.function}</a>
+      </li>
+
+      <li>
+        <a class="external-link" href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html">
+        {@code java.util.stream}</a>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<h2 id="configuration">
+  Mengaktifkan Fitur Java 8 dan Jack Toolchain
+</h2>
+
+<p>
+  Agar dapat menggunakan fitur bahasa Java 8 yang baru, Anda juga perlu menggunakan
+  <a class="external-link" href="https://source.android.com/source/jack.html">Jack toolchain</a> yang baru.  Toolchain Android
+ yang baru ini mengompilasi sumber bahasa Java menjadi dex
+  bytecode yang bisa dibaca Android, memiliki format  pustaka {@code .jack} sendiri, dan menyediakan sebagian besar fitur toolchain
+  sebagai bagian dari alat bantu tunggal: pengemasan ulang, penciutan, pengaburan, dan
+  multidex.
+</p>
+
+<p>Inilah perbandingan dua toolchain yang digunakan untuk membangun file Android DEX:</p>
+<ul>
+  <li>Toolchain javac lawas:<br>
+  <b>javac</b> ({@code .java} --&gt; {@code .class}) --&gt; <b>dx</b> ({@code
+ .class} --&gt; {@code .dex})
+  </li>
+
+  <li>Jack Toolchain baru:<br>
+  <b>Jack</b> ({@code .java} --&gt; {@code .jack} --&gt; {@code .dex})
+  </li>
+</ul>
+
+<h3>
+  Mengonfigurasi Gradle
+</h3>
+
+<p>
+  Untuk mengaktifkan fitur bahasa Java 8 dan Jack bagi proyek Anda, masukkan
+  yang berikut dalam file {@code build.gradle} level modul Anda:
+</p>
+
+<pre>
+android {
+  ...
+  defaultConfig {
+    ...
+    jackOptions {
+      enabled true
+    }
+  }
+  compileOptions {
+    sourceCompatibility JavaVersion.VERSION_1_8
+    targetCompatibility JavaVersion.VERSION_1_8
+  }
+}
+</pre>
+
+<h3 id="known-issues">
+  Masalah yang Diketahui
+</h3>
+
+<p>
+  <a href="{@docRoot}tools/building/building-studio.html#instant-run">Instant
+  Run</a> saat ini tidak berfungsi pada Jack dan akan dinonaktifkan saat menggunakan
+  toolchain baru.
+</p>
+
+<p>Karena Jack tidak menghasilkan file kelas antara saat mengompilasi sebuah
+aplikasi, alat yang bergantung pada file-file ini sekarang tidak berfungsi pada Jack. Beberapa
+contoh alat ini adalah:</p>
+
+<ul>
+  <li>Pendeteksi lint yang beroperasi pada file kelas
+  </li>
+
+  <li>Alat dan pustaka yang mewajibkan file kelas aplikasi (misalnya
+pengujian instrumentasi dengan JaCoCo)
+  </li>
+</ul>
+
+<p>Jika Anda menemukan masalah lain saat menggunakan Jack, <a href="http://tools.android.com/filing-bugs">laporkan bug</a>.</p>
\ No newline at end of file
diff --git a/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
new file mode 100644
index 0000000..050abf4
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/manifest/manifest-intro.jd
@@ -0,0 +1,517 @@
+page.title=Manifes Aplikasi
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+<li><a href="#filestruct">Struktur File Manifes</a></li>
+<li><a href="#filec">Konvensi File</a>
+<li><a href="#filef">Fitur File</a>
+	<ol>
+	<li><a href="#ifs">Filter Intent</a></li>
+	<li><a href="#iconlabel">Ikon dan Label</a></li>
+	<li><a href="#perms">Izin</a></li>
+	<li><a href="#libs">Pustaka</a></li>
+	</ol></li>
+</ol>
+</div>
+</div>
+
+<p>
+  Setiap aplikasi harus memiliki file AndroidManifest.xml (bernama persis seperti ini) di direktori akar.
+ <span itemprop="description">File manifes
+ menyediakan informasi penting tentang aplikasi ke sistem Android,
+ informasi yang harus dimiliki sistem agar bisa menjalankan setiap kode
+aplikasi.</span> Di antaranya, manifes melakukan hal berikut ini:
+</p>
+
+<ul>
+<li>Menamai paket Java untuk aplikasi.
+Nama paket berfungsi sebagai identifier unik untuk aplikasi.</li>
+
+<li>Menjelaskan berbagai komponen aplikasi&mdash;aktivitas,
+ layanan, penerima siaran, dan penyedia konten
+yang membentuk aplikasi.  Menamai kelas yang mengimplementasikan setiap komponen dan
+mempublikasikan kemampuannya (misalnya, pesan {@link android.content.Intent
+Intent} mana yang bisa ditanganinya).  Deklarasi ini memberi tahu sistem Android mengenai
+komponennya dan dalam kondisi apa bisa diluncurkan.</li>
+
+<li>Menentukan proses yang akan menjadi host komponen aplikasi.</li>
+
+<li>Mendeklarasikan izin aplikasi mana yang harus dimiliki untuk
+mengakses bagian yang dilindungi pada API dan berinteraksi dengan aplikasi lain.</li>
+
+<li>Juga mendeklarasikan izin lain yang harus dimiliki untuk
+untuk berinteraksi dengan komponen aplikasi.</li>
+
+<li>Mencantumkan daftar kelas {@link android.app.Instrumentation} yang memberikan
+profil dan informasi lain saat aplikasi berjalan.  Deklarasi ini
+hanya ada di manifes saat aplikasi dibuat dan diuji;
+ deklarasi dihapus sebelum aplikasi dipublikasikan.</li>
+
+<li>Mendeklarasikan tingkat minimum API Android yang diperlukan
+aplikasi.</li>
+
+<li>Mencantumkan daftar pustaka yang harus ditautkan aplikasi.</li>
+</ul>
+
+
+<h2 id="filestruct">Struktur File Manifes</h2>
+
+<p>
+Diagram di bawah ini menampilkan struktur umum file manifes dan setiap
+elemen yang bisa ditampungnya.  Setiap elemen, bersama
+atributnya, didokumentasikan secara lengkap dalam file terpisah.  Untuk melihat
+informasi terperinci tentang setiap elemen, klik nama elemen dalam diagram,
+dalam daftar abjad elemen yang mengikuti diagram, atau penyebutan nama
+elemen lainnya.
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a>
+
+    <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk /&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration /&gt;</a>  <!-- ##api level 3## -->
+    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature /&gt;</a>  <!-- ##api level 4## -->
+    <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens /&gt;</a>  <!-- ##api level 4## -->
+    <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">&lt;compatible-screens /&gt;</a>  <!-- ##api level 9## -->
+    <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture /&gt;</a>  <!-- ##api level 11## -->
+
+    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a>
+                <a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action /&gt;</a>
+                <a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category /&gt;</a>
+                <a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data /&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+        <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;/activity&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+        <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;/activity-alias&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data/&gt;</a>
+        <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;/service&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+        <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;/receiver&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission /&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+            <a href="{@docRoot}guide/topics/manifest/path-permission-element.html">&lt;path-permission /&gt;</a>
+        <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;/provider&gt;</a>
+
+        <a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library /&gt;</a>
+
+    <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;/application&gt;</a>
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;/manifest&gt;</a>
+</pre>
+
+<p>
+Semua elemen yang bisa muncul dalam file manifes tercantum di bawah ini
+dalam urutan abjad.  Ini adalah satu-satunya elemen legal; Anda tidak bisa
+menambahkan elemen atau atribut sendiri.
+</p>
+
+<p style="margin-left: 2em">
+<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>  <!-- ##api level 4## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>  <!-- ##api level 3## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>  <!-- ##api level 4## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></code>
+</p>
+
+
+
+
+<h2 id="filec">Konvensi File</h2>
+
+<p>
+Sebagian konvensi dan aturan berlaku secara umum untuk semua elemen
+dan atribut di manifes:
+</p>
+
+<dl>
+<dt><b>Elemen</b></dt>
+<dd>Hanya elemen
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> dan
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+yang diwajibkan, masing-masing harus ada dan hanya boleh terjadi sekali.
+Umumnya elemen lain bisa terjadi berkali-kali atau sama sekali tidak terjadi &mdash; meskipun
+setidaknya sebagian dari elemen itu harus ada untuk agar manifes mencapai sesuatu yang
+berarti.
+
+<p>
+Jika elemen tidak berisi apa pun, berarti elemen itu berisi elemen lain.
+Semua nilai diatur melalui atribut, bukan sebagai data karakter dalam elemen.
+</p>
+
+<p>
+Elemen yang sama tingkatan umumnya tidak diurutkan.  Misalnya, elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>, dan
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+bisa dicampur dalam urutan apa pun.  (Elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+ merupakan eksepsi untuk aturan ini:  Elemen ini harus mengikuti
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+ini aliasnya.)
+</p></dd>
+
+<dt><b>Atribut</b></dt>
+<dd>Secara formal, semua atribut opsional.  Akan tetapi, ada sebagian
+yang harus ditetapkan agar elemen bisa mencapai tujuannya.  Gunakan
+dokumentasi sebagai panduan.  Bagi atribut yang benar-benar opsional, ini menyebutkan
+nilai default atau menyatakan apa yang terjadi jika tidak ada spesifikasi.
+
+<p>Selain untuk beberapa atribut elemen akar
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>,
+ semua nama atribut dimulai dengan awalan {@code android:} &mdash;
+misalnya, {@code android:alwaysRetainTaskState}.  Karena awalan ini universal, dokumentasi umumnya meniadakannya saat mengacu atribut
+dengan nama.
+</p></dd>
+
+<dt><b>Mendeklarasikan nama kelas</b></dt>
+<dd>Banyak elemen berhubungan dengan objek Java, termasuk elemen
+aplikasi itu sendiri (elemen
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+) dan aktivitas komponen &mdash; utamanya
+(<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>),
+layanan
+(<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>),
+penerima siaran
+(<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>),
+dan penyedia konten
+(<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>).
+
+<p>
+Jika mendefinisikan subkelas, seperti yang selalu Anda definisikan untuk kelas komponen
+({@link android.app.Activity}, {@link android.app.Service},
+{@link android.content.BroadcastReceiver}, dan {@link android.content.ContentProvider}),
+subkelas dideklarasikan melalui atribut {@code name}.  Nama harus menyertakan tujuan
+paket lengkap.
+Misalnya, subkelas {@link android.app.Service} mungkin dideklarasikan sebagai berikut:
+</p>
+
+<pre>&lt;manifest . . . &gt;
+    &lt;application . . . &gt;
+        &lt;service android:name="com.example.project.SecretService" . . . &gt;
+            . . .
+        &lt;/service&gt;
+        . . .
+    &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+Akan tetapi, sebagai shorthand, jika karakter pertama string adalah titik,
+string akan ditambahkan ke nama paket aplikasi (seperti yang ditetapkan dalam elemen
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+ melalui atribut
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code>
+).  Penetapan berikut sama dengan di atas:
+</p>
+
+<pre>&lt;manifest package="com.example.project" . . . &gt;
+    &lt;application . . . &gt;
+        &lt;service android:name=".SecretService" . . . &gt;
+            . . .
+        &lt;/service&gt;
+        . . .
+    &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+Saat memulai komponen, Android akan membuat instance subkelas yang diberi nama.
+Jika subkelas tidak ditetapkan, maka akak dibuat instance kelas dasar.
+</p></dd>
+
+<dt><b>Banyak nilai</b></dt>
+<dd>Jika lebih dari satu nilai yang dapat ditetapkan, elemen ini hampir selalu
+diulangi, bukan menampilkan daftar banyak nilai dalam satu elemen.
+Misalnya, filter intent dapat mencantumkan beberapa tindakan:
+
+<pre>&lt;intent-filter . . . &gt;
+    &lt;action android:name="android.intent.action.EDIT" /&gt;
+    &lt;action android:name="android.intent.action.INSERT" /&gt;
+    &lt;action android:name="android.intent.action.DELETE" /&gt;
+    . . .
+&lt;/intent-filter&gt;</pre></dd>
+
+<dt><b>Nilai sumber daya</b></dt>
+<dd>Beberapa atribut memiliki nilai yang bisa ditampilkan kepada pengguna &mdash; misalnya
+, label dan ikon aktivitas.  Nilai atribut ini
+harus dilokalkan dan karenanya ditetapkan dari sumber daya atau tema.  Nilai sumber
+daya dinyatakan dalam format berikut,</p>
+
+<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
+
+<p>
+dalam hal ini nama <i>package</i> boleh dihilangkan jika sumber daya ada dalam paket yang sama dengan
+dengan aplikasi, <i>type</i> adalah tipe sumber daya &mdash; seperti "string" atau
+"drawable" &mdash; dan <i>name</i> adalah nama yang mengidentifikasi sumber daya tertentu.
+Misalnya:
+</p>
+
+<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</pre>
+
+<p>
+Nilai tema diekspresikan dengan cara yang sama, namun dengan awal '{@code ?}'
+dan bukan '{@code @}':
+</p>
+
+<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>}
+</p></dd>
+
+<dt><b>Nilai-nilai string</b></dt>
+<dd>Bila nilai atribut adalah string, dua garis miring kiri ('{@code \\}')
+harus digunakan untuk meninggalkan karakter &mdash; misalnya, '{@code \\n}' untuk
+baris baru atau '{@code \\uxxxx}' untuk karakter Unicode.</dd>
+</dl>
+
+
+<h2 id="filef">Fitur File</h2>
+
+<p>
+Bagian berikut menjelaskan cara menerapkan sebagian fitur Android
+dalam file manifest.
+</p>
+
+
+<h3 id="ifs">Filter Intent</h3>
+
+<p>
+Komponen inti dari aplikasi (aktivitasnya, layanannya, dan penerima
+siaran) diaktifkan oleh <i>intent</i>.  Intent adalah
+sekumpulan informasi (objek {@link android.content.Intent}) yang menjelaskan
+tindakan yang diinginkan &mdash; termasuk data yang akan ditindaklanjuti, kategori
+komponen yang harus melakukan tindakan, dan petunjuk terkait lainnya.
+Android mencari komponen yang sesuai untuk merespons intent, meluncurkan
+instance komponen baru jika diperlukan, dan meneruskannya ke
+objek Intent.
+</p>
+
+<p>
+Komponen mengiklankan kemampuannya &mdash; jenis intent yang bisa diresponsnya
+ &mdash; melalui <i>filter intent</i>.  Karena sistem Android
+harus mempelajari intent yang dapat ditangani komponen sebelum meluncurkan komponen,
+filter intent ditetapkan dalam manifes sebagai elemen
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+.  Sebuah komponen dapat memiliki filter dalam jumlah berapa saja, masing-masing menjelaskan
+kemampuan yang berbeda.
+</p>
+
+<p>
+Intent yang secara eksplisit menamai komponen target akan mengaktifkan komponen itu;
+filter tidak berperan.  Namun intent yang tidak menetapkan target
+dengan nama dapat mengaktifkan komponen hanya jika dapat melewati salah satu filter
+komponen.
+</p>
+
+<p>
+Untuk informasi tentang cara objek Intent diuji terhadap filter intent,
+lihat dokumen terpisah,
+<a href="{@docRoot}guide/components/intents-filters.html">Intent
+dan Filter Intent</a>.
+</p>
+
+
+<h3 id="iconlabel">Ikon dan Label</h3>
+
+<p>
+Sejumlah elemen memiliki atribut {@code icon} dan {@code label} untuk
+ikon kecil dan label teks yang bisa ditampilkan kepada pengguna.  Sebagian ada juga yang memiliki atribut
+{@code description}untuk teks penjelasan yang lebih panjang yang juga bisa
+ditampilkan pada layar.  Misalnya, elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+ memiliki ketiga atribut ini, jadi saat pengguna ditanya apakah akan
+memberi izin bagi aplikasi yang memintanya, ikon yang mewakili
+izin, nama izin, dan keterangan yang
+mengikutinya bisa ditampilkan kepada pengguna.
+</p>
+
+<p>
+Dalam setiap kasus, ikon dan label yang ditetapkan dalam elemen yang memuatnya menjadi
+{@code icon} default dan pengaturan {@code label} untuk semua subelemen kontainer ini.
+Karena itu, ikon dan label yang ditetapkan dalam elemen
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+adalah ikon dan label default untuk setiap komponen aplikasi.
+Demikian pula, ikon dan label yang ditetapkan untuk komponen &mdash; misalnya, elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+&mdash; adalah pengaturan default untuk setiap elemen komponen
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+.  Jika elemen
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+menetapkan label, namun suatu aktivitas dan filter intent-nya tidak menetapkan label,
+maka label aplikasi akan dianggap sama-sama sebagai label aktvitas dan
+filter intent.
+</p>
+
+<p>
+Ikon dan label yang ditetapkan untuk filter intent digunakan untuk mewakili komponen
+kapan saja komponen ditampilkan kepada pengguna saat memenuhi fungsi yang
+diiklankan oleh filter.  Misalnya, filter dengan pengaturan
+"{@code android.intent.action.MAIN}" dan
+"{@code android.intent.category.LAUNCHER}" mengiklankan aktivitas
+sebagai aktivitas yang memulai aplikasi&mdash;, yaitu
+sebagai salah satu aktivitas yang harus ditampilkan dalam launcher aplikasi.  Ikon dan label yang
+diatur dalam filter karenanya adalah ikon dan label yang ditampilkan dalam launcher.
+</p>
+
+
+<h3 id="perms">Izin</h3>
+
+<p>
+Sebuah <i>izin</i> adalah pembatasan yang membatasi akses ke bagian
+kode atau ke data pada perangkat.   Pembatasan diberlakukan untuk melindungi data dan kode
+penting yang bisa disalahgunakan untuk mengganggu atau merusak pengalaman pengguna.
+</p>
+
+<p>
+Setiap izin diidentifikasi melalui label yang unik.  Sering kali, label menunjukkan
+tindakan yang dibatasi.  Misalnya, berikut ini adalah beberapa izin yang didefinisikan
+oleh Android:
+</p>
+
+<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS}
+<br/>{@code android.permission.READ_OWNER_DATA}
+<br/>{@code android.permission.SET_WALLPAPER}
+<br/>{@code android.permission.DEVICE_POWER}</p>
+
+<p>
+Sebuah fitur bisa dilindungi paling banyak oleh satu izin.
+</p>
+
+<p>
+Jika aplikasi memerlukan akses ke fitur yang dilindungi oleh izin,
+aplikasi harus mendeklarasikan bahwa aplikasi memerlukan izin itu dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+ dalam manifes.  Kemudian, bila aplikasi telah diinstal pada
+perangkat, installer akan menentukan apakah izin yang diminta akan diberikan atau tidak
+dengan memeriksa otoritas yang menandatangani
+sertifikat aplikasi dan, dalam beberapa kasus, bertanya pada pengguna.
+Jika izin diberikan, aplikasi tersebut bisa menggunakan
+fitur yang dilindungi.  Jika tidak, upaya aplikasi untuk mengakses fitur tersebut akan gagal
+tanpa ada pemberitahuan apa pun kepada pengguna.
+</p>
+
+<p>
+Aplikasi juga bisa melindungi komponennya sendiri (aktivitas, layanan,
+penerima siaran, dan penyedia konten) dengan izin.  Aplikasi bisa menerapkan
+izin mana pun yang didefinisikan oleh Android (tercantum dalam
+{@link android.Manifest.permission android.Manifest.permission}) atau dideklarasikan
+oleh aplikasi lain.  Atau aplikasi bisa mendefinisikannya sendiri.  Izin baru dideklarasikan
+dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+.  Misalnya, aktivitas dapat dilindungi sebagai berikut:
+</p>
+
+<pre>
+&lt;manifest . . . &gt;
+    &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
+    &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
+    . . .
+    &lt;application . . .&gt;
+        &lt;activity android:name="com.example.project.FreneticActivity"
+                  android:permission="com.example.project.DEBIT_ACCT"
+                  . . . &gt;
+            . . .
+        &lt;/activity&gt;
+    &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>
+Perhatikan, dalam contoh ini izin {@code DEBIT_ACCT} tidak hanya
+dideklarasikan dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+, penggunaannya juga diminta dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+.  Penggunaannya harus diminta agar komponen
+aplikasi lainnya bisa menjalankan aktivitas yang dilindungi, meskipun perlindungan itu
+diberlakukan oleh aplikasi itu sendiri.
+</p>
+
+<p>
+Dalam contoh yang sama, jika atribut {@code permission} ditetapkan
+untuk izin yang dideklarasikan di tempat lain
+lain (seperti {@code android.permission.CALL_EMERGENCY_NUMBERS}, maka atribut
+tidak perlu mendeklarasikannya lagi dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+.  Akan tetapi, penggunaannya masih perlu dengan
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>.
+</p>
+
+<p>
+Elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+mendeklarasikan namespace untuk grup izin yang akan didefinisikan dalam
+kode.  Dan
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+mendefinisikan label untuk seperangkat izin (yang sama-sama dideklarasikan dalam manifes dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+dan yang dideklarasikan di tempat lain).  Ini hanya memengaruhi cara izin
+dikelompokkan saat ditampilkan kepada pengguna.  Elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+ tidak menetapkan izin mana dimiliki grup;
+elemen hanya memberi nama grup.  Izin ditempatkan dalam grup
+dengan memberikan nama grup ke elemen
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+ melalui atribut
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">permissionGroup</a></code>
+.
+</p>
+
+
+<h3 id="libs">Pustaka</h3>
+
+<p>
+Setiap aplikasi ditautkan dengan pustaka default Android, yang
+menyertakan paket dasar untuk membangun aplikasi (dengan kelas umum
+seperti Activity, Service, Intent, View, Button, Application, ContentProvider,
+dan sebagainya).
+</p>
+
+<p>
+Akan tetapi, sebagian paket berada dalam pustakanya sendiri.  Jika aplikasi Anda
+menggunakan kode salah satu paket ini, aplikasi secara eksplisit meminta untuk ditautkan dengan
+paket tersebut.  Manifes harus berisi elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code> yang
+terpisah untuk menamai setiap pustaka.  (Nama pustaka bisa ditemukan
+dalam dokumentasi paket.)
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
new file mode 100644
index 0000000..3058815
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/calendar-provider.jd
@@ -0,0 +1,1184 @@
+page.title=Penyedia Kalender
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+    <h2>Dalam dokumen ini</h2>
+    <ol>
+  <li><a href="#overview">Dasar-Dasar</a></li>
+  <li><a href="#manifest">Izin Pengguna</a></li>
+  <li><a href="#calendar">Tabel kalender</a>
+<ol>
+      <li><a href="#query">Membuat query kalender</a></li>
+      <li><a href="#modify-calendar">Memodifikasi kalender</a></li>
+      <li><a href="#insert-calendar">Menyisipkan kalender</a></li>
+    </ol>
+  </li>
+  <li><a href="#events">Tabel Events</a>
+<ol>
+      <li><a href="#add-event">Menambahkan Kejadian</a></li>
+      <li><a href="#update-event">Memperbarui Kejadian</a></li>
+      <li><a href="#delete-event">Menghapus Kejadian</a></li>
+    </ol>
+  </li>
+  <li><a href="#attendees">Tabel peserta</a>
+<ol>
+      <li><a href="#add-attendees">Menambahkan Peserta</a></li>
+    </ol>
+  </li>
+  <li><a href="#reminders">Tabel pengingat</a>
+<ol>
+      <li><a href="#add-reminders">Menambahkan Pengingat</a></li>
+    </ol>
+  </li>
+  <li><a href="#instances">Tabel Instances</a>
+  <ol>
+      <li><a href="#query-instances">Membuat query tabel Instance</a></li>
+  </ol></li>
+  <li><a href="#intents">Intent Kalender</a>
+  <ol>
+      <li><a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a></li>
+      <li><a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a></li>
+      <li><a href="#intent-view">Menggunakan intent untuk menampilkan data kalender</a></li>
+    </ol>
+  </li>
+
+  <li><a href="#sync-adapter">Adaptor Sinkronisasi</a></li>
+</ol>
+
+    <h2>Kelas-kelas utama</h2>
+    <ol>
+      <li>{@link android.provider.CalendarContract.Calendars}</li>
+      <li>{@link android.provider.CalendarContract.Events}</li>
+      <li>{@link android.provider.CalendarContract.Attendees}</li>
+      <li>{@link android.provider.CalendarContract.Reminders}</li>
+    </ol>
+</div>
+</div>
+
+<p>Penyedia Kalender adalah repository untuk kejadian kalender seorang pengguna. API
+Penyedia Kalender memungkinkan Anda melakukan query, menyisipkan, memperbarui, dan menghapus
+pada kalender, kejadian, peserta, pengingat, dan seterusnya.</p>
+
+
+<p>API Penyedia Kalender bisa digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya
+bervariasi menurut tipe program yang membuat panggilan. Dokumen ini
+terutama berfokus pada penggunaan API Penyedia Kalender sebagai sebuah aplikasi. Untuk
+pembahasan ragam adaptor sinkronisasi, lihat
+<a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
+
+
+<p>Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus
+berisi izin yang sesuai, yang dijelaskan dalam <a href="#manifest">Izin
+Pengguna</a>. Untuk mempermudah dilakukannya operasi umum,
+Penyedia Kalender menyediakan satu set intent, seperti dijelaskan dalam <a href="#intents">Intent
+Kalender</a>. Semua intent ini membawa pengguna ke aplikasi Kalender untuk menyisipkan, menampilkan,
+dan mengedit kejadian. Pengguna berinteraksi dengan aplikasi Kalender kemudian
+kembali ke aplikasi semula. Jadi, aplikasi Anda tidak perlu meminta izin,
+juga tidak perlu menyediakan antarmuka pengguna untuk menampilkan atau membuat kejadian.</p>
+
+<h2 id="overview">Dasar-Dasar</h2>
+
+<p><a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia konten</a> menyimpan data dan menjadikannya bisa diakses oleh
+aplikasi. Penyedia konten yang ditawarkan oleh platform Android (termasuk Penyedia Kalender) biasanya mengekspos data sebagai satu set tabel berdasarkan
+model database relasional, dengan tiap baris berupa record dan tiap kolom berupa data
+yang memiliki tipe dan arti tertentu. Melalui API Penyedia Kalender, aplikasi
+dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel-tabel database yang menyimpan
+data kalender seorang pengguna.</p>
+
+<p>Setiap penyedia konten membuka sebuah URI publik (yang dibungkus sebagai objek
+{@link android.net.Uri}
+) yang mengidentifikasikan set datanya secara unik.  Penyedia konten yang mengontrol
+ beberapa set data (beberapa tabel) mengekspos URI terpisah untuk tiap set.  Semua
+URI untuk penyedia diawali dengan string "content://".  String ini
+mengidentifikasi data sebagai dikontrol oleh penyedia konten. Penyedia Kalender
+mendefinisikan konstanta untuk URI masing-masing kelas (tabel). URI ini
+memiliki format <code><em>&lt;class&gt;</em>.CONTENT_URI</code>. Misalnya,
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.</p>
+
+<p>Gambar 1 menampilkan representasi grafis model data Penyedia Kalender. Gambar ini menampilkan
+tabel dan bidang utama yang saling berkaitan.</p>
+
+<img src="{@docRoot}images/providers/datamodel.png" alt="Calendar Provider Data Model" />
+<p class="img-caption"><strong>Gambar 1.</strong> Model data Penyedia Kalender.</p>
+
+<p>Seorang pengguna bisa memiliki beberapa kalender, dan kalender yang berbeda bisa dikaitkan dengan tipe akun yang berbeda (Google Calendar, Exchange, dan seterusnya).</p>
+
+<p>{@link android.provider.CalendarContract} mendefinisikan model data dari informasi yang terkait dengan kalender dan kejadian. Data ini disimpan di sejumlah tabel, yang dicantumkan di bawah ini.</p>
+
+<table>
+  <tr>
+    <th>Tabel (Kelas)</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td><p>{@link android.provider.CalendarContract.Calendars}</p></td>
+
+    <td>Tabel ini menyimpan
+informasi khusus kalender. Tiap baris dalam tabel ini berisi data untuk
+satu kalender, seperti nama, warna, informasi sinkronisasi, dan seterusnya.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Events}</td>
+
+    <td>Tabel ini menyimpan
+informasi khusus kejadian. Tiap baris dalam tabel ini berisi informasi untuk satu
+kejadian&mdash;misalnya, judul kejadian, lokasi, waktu mulai, waktu
+selesai, dan seterusnya. Kejadian bisa terjadi satu kali atau bisa berulang beberapa kali. Peserta,
+pengingat, dan properti perluasan disimpan dalam tabel terpisah.
+Masing-masing memiliki sebuah {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
+yang mengacu {@link android.provider.BaseColumns#_ID} dalam tabel Events.</td>
+
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances}</td>
+
+    <td>Tabel ini menyimpan
+waktu mulai dan waktu selesai setiap bentuk kejadian. Tiap baris dalam tabel ini
+mewakili satu bentuk kejadian. Untuk kejadian satu kali ada pemetaan 1:1
+antara instance dan kejadian. Untuk kejadian berulang, beberapa baris akan dibuat
+secara otomatis yang sesuai dengan beberapa kejadian itu.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Attendees}</td>
+
+    <td>Tabel ini menyimpan
+informasi peserta (tamu) kejadian. Tiap baris mewakili satu tamu
+kejadian. Ini menetapkan tipe tamu dan respons kehadiran tamu
+untuk kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Reminders}</td>
+
+    <td>Tabel ini menyimpan
+data peringatan/pemberitahuan. Tiap baris mewakili satu peringatan untuk sebuah kejadian. Sebuah
+kejadian bisa memiliki beberapa pengingat. Jumlah maksimum pengingat per kejadian
+ditetapkan dalam
+{@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS},
+yang diatur oleh adaptor sinkronisasi yang
+memiliki kalender yang diberikan. Pengingat ditetapkan dalam menit sebelum kejadian
+dan memiliki metode yang menentukan cara pengguna akan diperingatkan.</td>
+  </tr>
+
+</table>
+
+<p>API Penyedia Kalender didesain agar luwes dan tangguh. Sementara itu
+, Anda perlu memberikan pengalaman pengguna akhir yang baik dan
+melindungi integritas kalender dan datanya. Untuk mencapainya, berikut ini adalah
+beberapa hal yang harus diingat saat menggunakan API ini:</p>
+
+<ul>
+
+<li><strong>Menyisipkan, memperbarui, dan menampilkan kejadian kalender.</strong> Untuk menyisipkan, mengubah, dan membaca kejadian secara langsung dari Penyedia Kalender, Anda memerlukan <a href="#manifest">izin</a> yang sesuai. Akan tetapi, jika Anda tidak sedang membuat aplikasi atau adaptor sinkronisasi kalender berfitur lengkap, maka tidak perlu meminta izin. Sebagai gantinya, Anda bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Bila menggunakan intent, aplikasi Anda akan mengirim pengguna ke aplikasi Kalender untuk melakukan operasi yang diinginkan
+dalam sebuah formulir yang sudah diisi. Setelah operasi selesai, formulir dikembalikan ke aplikasi Anda.
+Dengan mendesain aplikasi untuk melakukan operasi umum melalui Kalender,
+Anda akan memberi pengguna sebuah antarmuka pengguna yang konsisten dan tangguh. Inilah
+pendekatan yang disarankan. Untuk informasi selengkapnya, lihat <a href="#intents">Intent
+Kalender</a>.</p>
+
+
+<li><strong>Adaptor sinkronisasi.</strong> Adaptor sinkronisasi menyinkronkan data kalender
+pada perangkat pengguna dengan server atau sumber data lain. Dalam tabel
+{@link android.provider.CalendarContract.Calendars} dan
+{@link android.provider.CalendarContract.Events},
+ada kolom yang dicadangkan untuk digunakan adaptor sinkronisasi.
+Penyedia dan aplikasi tidak boleh memodifikasinya. Sebenarnya, tabel-tabel itu tidak
+terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk informasi selengkapnya tentang
+adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</li>
+
+</ul>
+
+
+<h2 id="manifest">Izin Pengguna</h2>
+
+<p>Untuk membaca data kalender, aplikasi harus menyertakan izin {@link
+android.Manifest.permission#READ_CALENDAR} dalam file manifesnya. File
+harus menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR}
+untuk menghapus, menyisipkan, atau memperbarui data kalender:</p>
+
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;...&gt;
+    &lt;uses-sdk android:minSdkVersion=&quot;14&quot; /&gt;
+    &lt;uses-permission android:name=&quot;android.permission.READ_CALENDAR&quot; /&gt;
+    &lt;uses-permission android:name=&quot;android.permission.WRITE_CALENDAR&quot; /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+
+<h2 id="calendar">Tabel Kalender</h2>
+
+<p>Tabel {@link android.provider.CalendarContract.Calendars} berisi data
+untuk tiap kalender. Kolom-kolom
+berikut ini bisa ditulisi oleh aplikasi maupun <a href="#sync-adapter">adaptor sinkronisasi</a>.
+Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat
+acuan {@link android.provider.CalendarContract.Calendars}.</p>
+<table>
+  <tr>
+    <th>Konstanta</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Calendars#NAME}</td>
+    <td>Nama kalender.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME}</td>
+    <td>Nama kalender ini yang ditampilkan kepada pengguna.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Calendars#VISIBLE}</td>
+
+    <td>Sebuah boolean yang menunjukkan apakah kalender dipilih untuk ditampilkan. Nilai
+0 menunjukkan bahwa kejadian yang terkait dengan kalender ini tidak boleh
+ditampilkan.  Nilai 1 menunjukkan bahwa kejadian yang terkait dengan kalender ini harus
+ditampilkan. Nilai ini memengaruhi pembuatan baris dalam tabel {@link
+android.provider.CalendarContract.Instances}.</td>
+
+
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS}</td>
+
+    <td>Sebuah boolean yang menunjukkan apakah kalender harus disinkronkan dan apakah
+kejadiannya harus disimpan pada perangkat. Nilai 0 berarti jangan menyinkronkan kalender ini atau
+simpan kejadiannya pada perangkat.  Nilai 1 berarti menyinkronkan kejadian untuk kalender ini
+dan simpan kejadiannya pada perangkat.</td>
+  </tr>
+</table>
+
+<h3 id="query">Membuat query kalender</h3>
+
+<p>Berikut ini adalah contoh yang menampilkan cara mendapatkan kalender yang dimiliki oleh
+pengguna tertentu. Untuk memudahkan, dalam contoh ini, operasi query ditampilkan dalam
+thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan dalam
+thread asinkron, sebagai ganti pada thread utama. Untuk diskusi selengkapnya, lihat
+<a href="{@docRoot}guide/components/loaders.html">Loader</a>. Jika Anda tidak sekadar
+membaca data melainkan memodifikasinya, lihat {@link android.content.AsyncQueryHandler}.
+</p>
+
+
+<pre>
+// Projection array. Creating indices for this array instead of doing
+// dynamic lookups improves performance.
+public static final String[] EVENT_PROJECTION = new String[] {
+    Calendars._ID,                           // 0
+    Calendars.ACCOUNT_NAME,                  // 1
+    Calendars.CALENDAR_DISPLAY_NAME,         // 2
+    Calendars.OWNER_ACCOUNT                  // 3
+};
+
+// The indices for the projection array above.
+private static final int PROJECTION_ID_INDEX = 0;
+private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
+private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
+private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre>
+
+
+<div class="sidebox-wrapper"> <div class="sidebox"> <h3>Mengapa Anda harus menyertakan
+ACCOUNT_TYPE?</h3> <p>Jika Anda membuat query pada {@link
+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
+Calendars.ACCOUNT_NAME}, Anda juga harus menyertakan
+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
+dalam pemilihan. Itu karena akun yang bersangkutan
+hanya dianggap unik mengingat <code>ACCOUNT_NAME</code> dan
+<code>ACCOUNT_TYPE</code>-nya. <code>ACCOUNT_TYPE</code> adalah string yang sesuai dengan
+autentikator akun yang digunakan bila akun didaftarkan dengan
+{@link android.accounts.AccountManager}. Ada juga sebuah tipe akun khusus yang disebut {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} untuk kalender
+yang tidak terkait dengan akun perangkat. Akun {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} tidak
+disinkronkan.</p> </div> </div>
+
+
+<p> Di bagian berikutnya pada contoh ini, Anda akan membuat query. Pemilihan
+akan menetapkan kriteria untuk query. Dalam contoh ini, query mencari
+kalender yang memiliki <code>ACCOUNT_NAME</code>
+"sampleuser@google.com", <code>ACCOUNT_TYPE</code>
+"com.google", dan <code>OWNER_ACCOUNT</code>
+"sampleuser@google.com". Jika Anda ingin melihat semua kalender yang
+telah ditampilkan pengguna, bukan hanya kalender yang dimiliki pengguna, hilangkan <code>OWNER_ACCOUNT</code>.
+Query tersebut akan menghasilkan objek {@link android.database.Cursor}
+yang bisa Anda gunakan untuk menyusuri set hasil yang dikembalikan oleh
+query database. Untuk diskusi selengkapnya tentang penggunaan query dalam penyedia konten,
+lihat <a href="{@docRoot}guide/topics/providers/content-providers.html">Penyedia Kalender</a>.</p>
+
+
+<pre>// Run query
+Cursor cur = null;
+ContentResolver cr = getContentResolver();
+Uri uri = Calendars.CONTENT_URI;
+String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
+                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
+                        + Calendars.OWNER_ACCOUNT + " = ?))";
+String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google",
+        "sampleuser@gmail.com"};
+// Submit the query and get a Cursor object back.
+cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);</pre>
+
+<p>Bagian berikutnya ini menggunakan kursor untuk merunut set hasil. Bagian ini menggunakan
+konstanta yang disiapkan pada awal contoh ini untuk menghasilkan nilai-nilai
+bagi tiap bidang.</p>
+
+<pre>// Use the cursor to step through the returned records
+while (cur.moveToNext()) {
+    long calID = 0;
+    String displayName = null;
+    String accountName = null;
+    String ownerName = null;
+
+    // Get the field values
+    calID = cur.getLong(PROJECTION_ID_INDEX);
+    displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
+    accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
+    ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX);
+
+    // Do something with the values...
+
+   ...
+}
+</pre>
+
+<h3 id="modify-calendar">Memodifikasi kalender</h3>
+
+<p>Untuk melakukan pembaruan kalender, Anda bisa menyediakan {@link
+android.provider.BaseColumns#_ID} kalender itu baik sebagai ID yang ditambahkan ke
+URI
+
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+atau sebagai item pemilihan pertama. Pemilihan
+harus diawali dengan <code>&quot;_id=?&quot;</code>, dan
+<code>selectionArg</code> pertama harus berupa {@link
+android.provider.BaseColumns#_ID} kalender.
+Anda juga bisa melakukan pembaruan dengan menuliskan kode ID dalam URI. Contoh ini mengubah
+nama tampilan kalender dengan pendekatan
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+:</p>
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long calID = 2;
+ContentValues values = new ContentValues();
+// The new display name for the calendar
+values.put(Calendars.CALENDAR_DISPLAY_NAME, &quot;Trevor's Calendar&quot;);
+Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);</pre>
+
+<h3 id="insert-calendar">Menyisipkan kalender</h2>
+
+<p>Kalender didesain untuk dikelola terutama oleh sebuah adaptor sinkronisasi, sehingga Anda
+hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Biasanya,
+aplikasi hanya bisa membuat perubahan semu pada kalender, misalnya mengubah nama tampilan. Jika
+perlu membuat sebuah kalender lokal, aplikasi bisa melakukannya dengan melakukan
+penyisipan kalender sebagai adaptor sinkronisasi, menggunakan {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} dari {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}.
+{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}
+adalah sebuah tipe akun khusus untuk kalender yang tidak
+terkait dengan akun perangkat. Kalender tipe ini tidak disinkronkan dengan server. Untuk
+diskusi tentang adaptor sinkronisasi, lihat <a href="#sync-adapter">Adaptor Sinkronisasi</a>.</p>
+
+<h2 id="events">Tabel Events</h2>
+
+<p>Tabel {@link android.provider.CalendarContract.Events} berisi detail
+untuk tiap kejadian. Untuk menambah, memperbarui, atau menghapus kejadian, aplikasi harus
+menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR} dalam
+<a href="#manifest">file manifesnya</a>.</p>
+
+<p>Kolom-kolom Events berikut ini bisa ditulis oleh aplikasi maupun
+adaptor sinkronisasi. Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat acuan {@link
+android.provider.CalendarContract.Events}.</p>
+
+<table>
+  <tr>
+    <th>Konstanta</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID}</td>
+    <td>{@link android.provider.BaseColumns#_ID} kalender yang dimiliki kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#ORGANIZER}</td>
+    <td>Email pengatur (pemilik) kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE}</td>
+    <td>Judul kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</td>
+    <td>Tempat kejadian. </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</td>
+    <td>Keterangan kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#DTSTART}</td>
+    <td>Waktu mulai kejadian dalam milidetik UTC sejak waktu patokan. </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td>
+    <td>Waktu selesai kejadian dalam milidetik UTC sejak waktu patokan. </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}</td>
+    <td>Zona waktu kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE}</td>
+    <td>Zona waktu untuk waktu selesai kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#DURATION}</td>
+
+    <td>Durasi kejadian dalam format <a href="http://tools.ietf.org/html/rfc5545#section-3.8.2.5">RFC5545</a>.
+Misalnya, nilai <code>&quot;PT1H&quot;</code> menyatakan bahwa kejadian
+akan berlangsung satu jam, dan nilai <code>&quot;P2W&quot;</code> menunjukkan
+durasi 2 minggu. </td>
+
+
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td>
+
+    <td>Nilai 1 menunjukkan kejadian ini memakan waktu sehari penuh, seperti yang didefinisikan oleh
+zona waktu lokal. Nilai 0 menunjukkan kejadian adalah kejadian biasa yang mungkin dimulai
+dan selesai pada sembarang waktu selama suatu hari.</td>
+
+
+  </tr>
+
+
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td>
+
+    <td>Aturan perulangan untuk format kejadian. Misalnya,
+<code>&quot;FREQ=WEEKLY;COUNT=10;WKST=SU&quot;</code>. Anda bisa menemukan
+contoh selengkapnya <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.3">di sini</a>.</td>
+
+  </tr>
+
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#RDATE}</td>
+    <td>Tanggal perulangan kejadian.
+    Anda biasanya menggunakan {@link android.provider.CalendarContract.EventsColumns#RDATE}
+    bersama dengan {@link android.provider.CalendarContract.EventsColumns#RRULE}
+    untuk mendefinisikan satu set agregat
+kejadian berulang. Untuk diskusi selengkapnya, lihat <a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.2">Spesifikasi RFC5545</a>.</td>
+</tr>
+
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY}</td>
+
+    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa
+dijadwalkan. </td>
+
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY}</td>
+    <td>Apakah tamu bisa memodifikasi kejadian atau tidak. </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS}</td>
+    <td>Apakah tamu bisa mengundang tamu lain atau tidak. </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS}</td>
+    <td>Apakah tamu bisa membaca daftar peserta atau tidak.</td>
+  </tr>
+</table>
+
+<h3 id="add-event">Menambahkan Kejadian</h3>
+
+<p>Bila aplikasi Anda menyisipkan kejadian baru, sebaiknya Anda menggunakan
+Intent {@link android.content.Intent#ACTION_INSERT INSERT}, seperti dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>. Akan tetapi, jika
+perlu, Anda bisa menyisipkan kejadian secara langsung. Bagian ini menjelaskan
+caranya.</p>
+
+
+<p>Berikut ini adalah aturan untuk menyisipkan kejadian baru: </p>
+<ul>
+
+  <li>Anda harus menyertakan {@link
+android.provider.CalendarContract.EventsColumns#CALENDAR_ID} dan {@link
+android.provider.CalendarContract.EventsColumns#DTSTART}.</li>
+
+<li>Anda harus menyertakan {@link
+android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}. Untuk mendapatkan daftar
+ID zona waktu yang diinstal pada sistem, gunakan {@link
+java.util.TimeZone#getAvailableIDs()}. Perhatikan bahwa aturan ini tidak berlaku jika
+Anda menyisipkan kejadian melalui Intent {@link
+android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
+skenario itu, sebuah zona waktu default akan diberikan.</li>
+
+  <li>Untuk kejadian tidak-berulang, Anda harus menyertakan {@link
+android.provider.CalendarContract.EventsColumns#DTEND}. </li>
+
+
+  <li>Untuk kejadian berulang, Anda harus menyertakan sebuah {@link
+android.provider.CalendarContract.EventsColumns#DURATION} selain {@link
+android.provider.CalendarContract.EventsColumns#RRULE} atau {@link
+android.provider.CalendarContract.EventsColumns#RDATE}. Perhatikan bahwa aturan ini tidak berlaku jika
+Anda menyisipkan kejadian melalui Intent {@link
+android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam <a href="#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>&mdash;dalam
+skenario itu, Anda bisa menggunakan {@link
+android.provider.CalendarContract.EventsColumns#RRULE} bersama {@link android.provider.CalendarContract.EventsColumns#DTSTART} dan {@link android.provider.CalendarContract.EventsColumns#DTEND}, dan aplikasi Calendar
+akan mengubahnya menjadi durasi secara otomatis.</li>
+
+</ul>
+
+<p>Berikut ini adalah contoh penyisipan kejadian. Penyisipan ini dilakukan dalam thread UI
+demi kemudahan. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan di
+thread asinkron untuk memindahkan tindakan ke dalam thread latar belakang. Untuk
+informasi selengkapnya, lihat {@link android.content.AsyncQueryHandler}.</p>
+
+
+<pre>
+long calID = 3;
+long startMillis = 0;
+long endMillis = 0;
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2012, 9, 14, 7, 30);
+startMillis = beginTime.getTimeInMillis();
+Calendar endTime = Calendar.getInstance();
+endTime.set(2012, 9, 14, 8, 45);
+endMillis = endTime.getTimeInMillis();
+...
+
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Events.DTSTART, startMillis);
+values.put(Events.DTEND, endMillis);
+values.put(Events.TITLE, &quot;Jazzercise&quot;);
+values.put(Events.DESCRIPTION, &quot;Group workout&quot;);
+values.put(Events.CALENDAR_ID, calID);
+values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
+Uri uri = cr.insert(Events.CONTENT_URI, values);
+
+// get the event ID that is the last element in the Uri
+long eventID = Long.parseLong(uri.getLastPathSegment());
+//
+// ... do something with event ID
+//
+//</pre>
+
+<p class="note"><strong>Catatan:</strong> Perhatikan cara contoh ini menangkap ID kejadian
+setelah kejadian dibuat. Inilah cara termudah untuk mendapatkan ID kejadian. Anda akan sering
+memerlukan ID kejadian untuk melakukan operasi kalender lainnya&mdash;misalnya, untuk menambahkan
+peserta atau pengingat ke kejadian.</p>
+
+
+<h3 id="update-event">Memperbarui Kejadian</h3>
+
+<p>Bila aplikasi Anda ingin memperbolehkan pengguna mengedit kejadian, sebaiknya
+gunakan Intent {@link android.content.Intent#ACTION_EDIT EDIT}, seperti
+dijelaskan dalam <a href="#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
+Akan tetapi, jika perlu, Anda bisa mengedit kejadian secara langsung. Untuk melakukan pembaruan
+suatu kejadian, Anda bisa memberikan <code>_ID</code>
+kejadian itu sebagai ID yang ditambahkan ke URI ({@link
+android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+atau sebagai item pemilihan pertama.
+Pemilihan harus dimulai dengan <code>&quot;_id=?&quot;</code>, dan
+<code>selectionArg</code> yang pertama harus berupa <code>_ID</code> kejadian. Anda juga bisa
+melakukan pembaruan dengan menggunakan pemilihan tanpa ID. Berikut ini adalah contoh pembaruan
+kejadian. Contoh ini mengubah judul kejadian dengan pendekatan
+{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}
+:</p>
+
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long eventID = 188;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+Uri updateUri = null;
+// The new title for the event
+values.put(Events.TITLE, &quot;Kickboxing&quot;);
+updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);  </pre>
+
+<h3 id="delete-event">Menghapus Kejadian</h3>
+
+<p>Anda bisa menghapus kejadian dengan {@link
+android.provider.BaseColumns#_ID} sebagai ID yang ditambahkan pada URI, atau dengan
+pemilihan standar. Jika Anda menggunakan ID yang ditambahkan, Anda tidak bisa melakukan pemilihan.
+Ada dua versi penghapusan: sebagai aplikasi dan sebagai adaptor sinkronisasi. Penghapusan
+aplikasi mengatur kolom yang <em>dihapus</em> ke 1. Flag ini yang memberi tahu
+adaptor sinkronisasi bahwa baris telah dihapus dan bahwa penghapusan ini harus
+diberitahukan ke server. Penghapusan adaptor sinkronisasi menghapus kejadian dari
+database bersama semua data terkaitnya. Berikut ini adalah contoh aplikasi
+yang menghapus kejadian melalui {@link android.provider.BaseColumns#_ID}-nya:</p>
+
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long eventID = 201;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+Uri deleteUri = null;
+deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+int rows = getContentResolver().delete(deleteUri, null, null);
+Log.i(DEBUG_TAG, &quot;Rows deleted: &quot; + rows);
+</pre>
+
+<h2 id="attendees">Tabel Peserta</h2>
+
+<p>Tiap baris tabel {@link android.provider.CalendarContract.Attendees}
+mewakili satu peserta atau tamu dari sebuah kejadian. Memanggil
+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()}
+akan menghasilkan daftar peserta untuk
+kejadian dengan {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} ini
+harus cocok dengan {@link
+android.provider.BaseColumns#_ID} kejadian tertentu.</p>
+
+<p>Tabel berikut mencantumkan
+bidang-bidang yang bisa ditulis. Saat menyisipkan peserta baru, Anda harus menyertakan semuanya
+kecuali <code>ATTENDEE_NAME</code>.
+</p>
+
+
+<table>
+  <tr>
+    <th>Konstanta</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}</td>
+    <td>ID kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME}</td>
+    <td>Nama peserta.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL}</td>
+    <td>Alamat email peserta.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP}</td>
+    <td><p>Hubungan peserta dengan kejadian. Salah satu dari:</p>
+      <ul>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ATTENDEE}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_NONE}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ORGANIZER}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_PERFORMER}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_SPEAKER}</li>
+    </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE}</td>
+    <td><p>Tipe peserta. Salah satu dari: </p>
+      <ul>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_REQUIRED}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_OPTIONAL}</li>
+    </ul></td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS}</td>
+    <td><p>Status kehadiran peserta. Salah satu dari:</p>
+      <ul>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_ACCEPTED}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_DECLINED}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_INVITED}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_NONE}</li>
+        <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_TENTATIVE}</li>
+    </ul></td>
+  </tr>
+</table>
+
+<h3 id="add-attendees">Menambahkan Peserta</h3>
+
+<p>Berikut ini adalah contoh yang menambahkan satu peserta ke kejadian. Perhatikan bahwa
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
+diperlukan:</p>
+
+<pre>
+long eventID = 202;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Attendees.ATTENDEE_NAME, &quot;Trevor&quot;);
+values.put(Attendees.ATTENDEE_EMAIL, &quot;trevor@example.com&quot;);
+values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
+values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
+values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
+values.put(Attendees.EVENT_ID, eventID);
+Uri uri = cr.insert(Attendees.CONTENT_URI, values);
+</pre>
+
+<h2 id="reminders">Tabel Pengingat</h2>
+
+<p>Tiap baris tabel {@link android.provider.CalendarContract.Reminders}
+mewakili satu pengingat untuk sebuah kejadian. Memanggil
+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} akan menghasilkan daftar pengingat untuk
+kejadian dengan
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.</p>
+
+
+<p>Tabel berikut mencantumkan bidang-bidang yang bisa ditulis untuk pengingat. Semua bidang harus
+disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menetapkan
+tipe pengingat yang didukungnya dalam tabel {@link
+android.provider.CalendarContract.Calendars}. Lihat
+{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS}
+untuk detailnya.</p>
+
+
+<table>
+  <tr>
+    <th>Konstanta</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID}</td>
+    <td>ID kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.RemindersColumns#MINUTES}</td>
+    <td>Menit yang ditunggu untuk memicu kejadian pengingat.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.RemindersColumns#METHOD}</td>
+    <td><p>Metode alarm, seperti yang diatur pada server. Salah satu dari:</p>
+      <ul>
+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_ALERT}</li>
+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_DEFAULT}</li>
+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_EMAIL}</li>
+        <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_SMS}</li>
+    </ul></td>
+  </tr>
+</table>
+
+<h3 id="add-reminders">Menambahkan Pengingat</h3>
+
+<p>Contoh ini menambahkan pengingat ke kejadian. Pengingat dipicu 15
+menit sebelum kejadian.</p>
+<pre>
+long eventID = 221;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Reminders.MINUTES, 15);
+values.put(Reminders.EVENT_ID, eventID);
+values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
+Uri uri = cr.insert(Reminders.CONTENT_URI, values);</pre>
+
+<h2 id="instances">Tabel Instances</h2>
+
+<p>Tabel
+{@link android.provider.CalendarContract.Instances} menyimpan
+waktu mulai dan waktu selesai kejadian. Tiap baris dalam tabel ini
+mewakili satu bentuk kejadian. Tabel instance tidak bisa ditulis dan hanya
+menyediakan sebuah cara untuk membuat query kejadian. </p>
+
+<p>Tabel berikut mencantumkan beberapa bidang yang bisa Anda query untuk suatu instance. Perhatikan
+bahwa zona waktu didefinisikan oleh
+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE}
+dan
+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.</p>
+
+
+<table>
+  <tr>
+    <th>Konstanta</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#BEGIN}</td>
+    <td>Waktu mulai instance, dalam milidetik UTC.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#END}</td>
+    <td>Waktu selesai instance, dalam milidetik UTC.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#END_DAY}</td>
+
+    <td>Hari selesai Julian dari instance, relatif terhadap
+zona waktu Kalender.
+
+</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td>
+
+    <td>Menit selesai dari instance yang diukur dari tengah malam di zona waktu
+Kalender.</td>
+
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#EVENT_ID}</td>
+    <td>Kejadian <code>_ID</code> untuk instance ini.</td>
+  </tr>
+    <tr>
+    <td>{@link android.provider.CalendarContract.Instances#START_DAY}</td>
+    <td>Hari mulai Julian dari instance, relatif terhadap zona waktu Kalender.
+ </td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.Instances#START_MINUTE}</td>
+
+    <td>Menit mulai dari instance yang diukur dari tengah malam, relatif terhadap
+zona waktu Kalender.
+</td>
+
+  </tr>
+
+</table>
+
+<h3 id="query-instances">Membuat query tabel Instance</h3>
+
+<p>Untuk membuat query tabel Instances, Anda perlu menetapkan rentang waktu query
+dalam URI. Dalam contoh ini, {@link android.provider.CalendarContract.Instances}
+mendapatkan akses ke bidang {@link
+android.provider.CalendarContract.EventsColumns#TITLE} melalui
+implementasi antarmuka {@link android.provider.CalendarContract.EventsColumns}-nya.
+Dengan kata lain, {@link
+android.provider.CalendarContract.EventsColumns#TITLE} dihasilkan melalui
+tampilan database, bukan melalui query terhadap tabel {@link
+android.provider.CalendarContract.Instances} mentah.</p>
+
+<pre>
+private static final String DEBUG_TAG = "MyActivity";
+public static final String[] INSTANCE_PROJECTION = new String[] {
+    Instances.EVENT_ID,      // 0
+    Instances.BEGIN,         // 1
+    Instances.TITLE          // 2
+  };
+
+// The indices for the projection array above.
+private static final int PROJECTION_ID_INDEX = 0;
+private static final int PROJECTION_BEGIN_INDEX = 1;
+private static final int PROJECTION_TITLE_INDEX = 2;
+...
+
+// Specify the date range you want to search for recurring
+// event instances
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2011, 9, 23, 8, 0);
+long startMillis = beginTime.getTimeInMillis();
+Calendar endTime = Calendar.getInstance();
+endTime.set(2011, 10, 24, 8, 0);
+long endMillis = endTime.getTimeInMillis();
+
+Cursor cur = null;
+ContentResolver cr = getContentResolver();
+
+// The ID of the recurring event whose instances you are searching
+// for in the Instances table
+String selection = Instances.EVENT_ID + " = ?";
+String[] selectionArgs = new String[] {"207"};
+
+// Construct the query with the desired date range.
+Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
+ContentUris.appendId(builder, startMillis);
+ContentUris.appendId(builder, endMillis);
+
+// Submit the query
+cur =  cr.query(builder.build(),
+    INSTANCE_PROJECTION,
+    selection,
+    selectionArgs,
+    null);
+
+while (cur.moveToNext()) {
+    String title = null;
+    long eventID = 0;
+    long beginVal = 0;
+
+    // Get the field values
+    eventID = cur.getLong(PROJECTION_ID_INDEX);
+    beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
+    title = cur.getString(PROJECTION_TITLE_INDEX);
+
+    // Do something with the values.
+    Log.i(DEBUG_TAG, "Event:  " + title);
+    Calendar calendar = Calendar.getInstance();
+    calendar.setTimeInMillis(beginVal);
+    DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
+    Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));
+    }
+ }</pre>
+
+<h2 id="intents">Intent Kalender</h2>
+<p>Aplikasi Anda tidak memerlukan <a href="#manifest">izin</a> untuk membaca dan menulis data kalender. Sebagai gantinya, aplikasi bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Tabel berikut mencantumkan intent yang didukung oleh Penyedia Kalender:</p>
+<table>
+  <tr>
+    <th>Tindakan</th>
+    <th>URI</th>
+
+    <th>Keterangan</th>
+    <th>Ekstra</th>
+  </tr>
+  <tr>
+    <td><br>
+    {@link android.content.Intent#ACTION_VIEW VIEW} <br></td>
+    <td><p><code>content://com.android.calendar/time/&lt;ms_since_epoch&gt;</code></p>
+    Anda juga bisa mengacu ke URI dengan
+{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI}.
+Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
+
+    </td>
+    <td>Membuka kalender pada waktu yang ditetapkan oleh <code>&lt;ms_since_epoch&gt;</code>.</td>
+    <td>Tidak ada.</td>
+  </tr>
+  <tr>
+    <td><p>{@link android.content.Intent#ACTION_VIEW VIEW} </p>
+
+     </td>
+    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
+
+    Anda juga bisa mengacu ke URI dengan
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+Untuk contoh yang menggunakan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Menggunakan intent untuk menampilkan data kalender</a>.
+
+    </td>
+    <td>Menampilkan kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
+
+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
+      <br>
+      <br>
+    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
+  </tr>
+
+  <tr>
+    <td>{@link android.content.Intent#ACTION_EDIT EDIT} </td>
+    <td><p><code>content://com.android.calendar/events/&lt;event_id&gt;</code></p>
+
+  Anda juga bisa mengacu ke URI dengan
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">Menggunakan intent untuk mengedit kejadian</a>.
+
+
+    </td>
+    <td>Mengedit kejadian yang ditetapkan oleh <code>&lt;event_id&gt;</code>.</td>
+
+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
+      <br>
+      <br>
+    {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
+  </tr>
+
+  <tr>
+    <td>{@link android.content.Intent#ACTION_EDIT EDIT} <br>
+    <br>
+    {@link android.content.Intent#ACTION_INSERT INSERT} </td>
+    <td><p><code>content://com.android.calendar/events</code></p>
+
+   Anda juga bisa mengacu ke URI dengan
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+Untuk contoh penggunaan intent ini, lihat <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">Menggunakan intent untuk menyisipkan kejadian</a>.
+
+    </td>
+
+    <td>Membuat sebuah kejadian.</td>
+    <td>Ekstra apa saja yang tercantum dalam tabel di bawah.</td>
+  </tr>
+</table>
+
+<p>Tabel berikut mencantumkan ekstra intent yang didukung oleh Penyedia Kalender:
+</p>
+<table>
+  <tr>
+    <th>Ekstra Intent</th>
+    <th>Keterangan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE}</td>
+    <td>Nama kejadian.</td>
+  </tr>
+  <tr>
+
+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
+CalendarContract.EXTRA_EVENT_BEGIN_TIME}</td>
+    <td>Waktu mulai kejadian dalam milidetik sejak waktu patokan.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME
+CalendarContract.EXTRA_EVENT_END_TIME}</td>
+
+    <td>Waktu selesai kejadian dalam milidetik sejak waktu patokan.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY
+CalendarContract.EXTRA_EVENT_ALL_DAY}</td>
+
+    <td>Sebuah boolean yang menunjukkan bahwa kejadian sehari penuh. Nilai bisa
+<code>true</code> atau <code>false</code>.</td> </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION
+Events.EVENT_LOCATION}</td>
+
+    <td>Lokasi kejadian.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION
+Events.DESCRIPTION}</td>
+
+    <td>Keterangan kejadian.</td>
+  </tr>
+  <tr>
+    <td>
+    {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</td>
+    <td>Alamat email mereka yang harus diundang berupa daftar yang dipisahkan koma.</td>
+  </tr>
+  <tr>
+    <td>
+    {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE}</td>
+    <td>Aturan perulangan kejadian.</td>
+  </tr>
+  <tr>
+    <td>
+    {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL
+Events.ACCESS_LEVEL}</td>
+
+    <td>Apakah kejadian bersifat privat atau publik.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY
+Events.AVAILABILITY}</td>
+
+    <td>Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa dijadwalkan.</td>
+
+</table>
+<p>Bagian berikut menjelaskan cara menggunakan semua intent ini.</p>
+
+
+<h3 id="intent-insert">Menggunakan intent untuk menyisipkan kejadian</h3>
+
+<p>Penggunaan Intent {@link android.content.Intent#ACTION_INSERT INSERT}
+akan memungkinkan aplikasi Anda menyerahkan tugas penyisipan kejadian ke Kalender itu sendiri.
+Dengan pendekatan ini, aplikasi Anda bahkan tidak perlu menyertakan izin {@link
+android.Manifest.permission#WRITE_CALENDAR} dalam <a href="#manifest">file manifesnya</a>.</p>
+
+
+<p>Bila pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengirim
+izin ke Kalender untuk menyelesaikan penambahan kejadian. Intent {@link
+android.content.Intent#ACTION_INSERT INSERT} menggunakan bidang-bidang ekstra
+untuk mengisi formulir lebih dahulu dengan detail kejadian dalam Kalender. Pengguna nanti bisa
+membatalkan kejadian, mengedit formulir sebagaimana diperlukan, atau menyimpan kejadian ke
+kalender mereka.</p>
+
+
+
+<p>Berikut ini adalah cuplikan kode yang menjadwalkan kejadian pada tanggal 19 Januari 2012, yang berjalan
+dari 7:30 pagi hingga 8:30 pagi Perhatikan hal-hal berikut tentang cuplikan kode ini:</p>
+
+<ul>
+  <li>Cuplikan kode ini menetapkan {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}
+  sebagai URI-nya.</li>
+
+  <li>Cuplikan kode ini menggunakan bidang-bidang ekstra {@link
+android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
+CalendarContract.EXTRA_EVENT_BEGIN_TIME} dan {@link
+android.provider.CalendarContract#EXTRA_EVENT_END_TIME
+CalendarContract.EXTRA_EVENT_END_TIME} untuk mengisi dahulu formulir
+dengan waktu kejadian. Nilai-nilai untuk waktu ini harus dalam milidetik UTC
+sejak waktu patokan.</li>
+
+  <li>Cuplikan kode ini menggunakan bidang ekstra {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}
+untuk memberikan daftar undangan yang dipisah koma, yang ditetapkan melalui alamat email.</li>
+
+</ul>
+<pre>
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2012, 0, 19, 7, 30);
+Calendar endTime = Calendar.getInstance();
+endTime.set(2012, 0, 19, 8, 30);
+Intent intent = new Intent(Intent.ACTION_INSERT)
+        .setData(Events.CONTENT_URI)
+        .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
+        .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
+        .putExtra(Events.TITLE, &quot;Yoga&quot;)
+        .putExtra(Events.DESCRIPTION, &quot;Group class&quot;)
+        .putExtra(Events.EVENT_LOCATION, &quot;The gym&quot;)
+        .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
+        .putExtra(Intent.EXTRA_EMAIL, &quot;rowan@example.com,trevor@example.com&quot;);
+startActivity(intent);
+</pre>
+
+<h3 id="intent-edit">Menggunakan intent untuk mengedit kejadian</h3>
+
+<p>Anda bisa memperbarui kejadian secara langsung, seperti dijelaskan dalam <a href="#update-event">Memperbarui kejadian</a>. Namun penggunaan Intent {@link
+android.content.Intent#ACTION_EDIT EDIT} memungkinkan aplikasi yang
+tidak memiliki izin untuk menyerahkan pengeditan kejadian ke aplikasi Kalender.
+Bila pengguna selesai mengedit kejadian dalam Kalender, pengguna akan dikembalikan ke
+aplikasi semula.</p> <p>Berikut ini adalah contoh intent yang mengatur
+judul baru bagi kejadian yang ditetapkan dan memungkinkan pengguna mengedit kejadian dalam Kalender.</p>
+
+
+<pre>long eventID = 208;
+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+Intent intent = new Intent(Intent.ACTION_EDIT)
+    .setData(uri)
+    .putExtra(Events.TITLE, &quot;My New Title&quot;);
+startActivity(intent);</pre>
+
+<h3 id="intent-view">Menggunakan intent untuk menampilkan data kalender</h3>
+<p>Penyedia Kalender menyediakan dua cara menggunakan Intent {@link android.content.Intent#ACTION_VIEW VIEW}:</p>
+<ul>
+  <li>Untuk membuka Kalender pada tanggal tertentu.</li>
+  <li>Untuk menampilkan sebuah kejadian.</li>
+
+</ul>
+<p>Berikut ini adalah contoh yang menampilkan cara membuka Kalender pada tanggal tertentu:</p>
+<pre>// A date-time specified in milliseconds since the epoch.
+long startMillis;
+...
+Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
+builder.appendPath(&quot;time&quot;);
+ContentUris.appendId(builder, startMillis);
+Intent intent = new Intent(Intent.ACTION_VIEW)
+    .setData(builder.build());
+startActivity(intent);</pre>
+
+<p>Berikut ini adalah contoh yang menampilkan cara membuka kejadian untuk menampilkan:</p>
+<pre>long eventID = 208;
+...
+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+Intent intent = new Intent(Intent.ACTION_VIEW)
+   .setData(uri);
+startActivity(intent);
+</pre>
+
+
+<h2 id="sync-adapter">Adaptor Sinkronisasi</h2>
+
+
+<p>Hanya ada perbedaan kecil dalam cara aplikasi dan adaptor sinkronisasi
+mengakses Penyedia Kalender:</p>
+
+<ul>
+  <li>Adaptor sinkronisasi perlu menetapkan bahwa dirinya sebuah adaptor sinkronisasi dengan mengatur {@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} ke <code>true</code>.</li>
+
+
+  <li>Adaptor sinkronisasi perlu memberikan {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} dan {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} sebagai parameter query dalam URI. </li>
+
+  <li>Adaptor sinkronisasi memiliki akses tulis ke lebih banyak kolom daripada aplikasi atau widget.
+  Misalnya, aplikasi hanya bisa mengubah sedikit karakteristik kalender,
+  misalnya nama, nama tampilan, pengaturan visibilitas, dan apakah kalender
+  disinkronkan atau tidak. Sebagai perbandingan, adaptor sinkronisasi bisa mengakses bukan hanya kolom-kolom itu, namun banyak kolom lainnya,
+  misalnya warna kalender, zona waktu, tingkat akses, lokasi, dan seterusnya.
+Akan tetapi, adaptor sinkronisasi dibatasi pada <code>ACCOUNT_NAME</code> dan
+<code>ACCOUNT_TYPE</code> yang ditetapkannya.</li> </ul>
+
+<p>Berikut ini adalah metode pembantu yang bisa Anda gunakan untuk menghasilkan URI bagi penggunaan dengan adaptor sinkronisasi:</p>
+<pre> static Uri asSyncAdapter(Uri uri, String account, String accountType) {
+    return uri.buildUpon()
+        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,&quot;true&quot;)
+        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
+        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
+ }
+</pre>
+<p>Untuk contoh implementasi adaptor sinkronisasi (yang tidak terkait secara khusus dengan Kalender), lihat
+<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>.
diff --git a/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
new file mode 100644
index 0000000..994c56b
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/contacts-provider.jd
@@ -0,0 +1,2356 @@
+page.title=Penyedia Kontak
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Tampilan Cepat</h2>
+<ul>
+    <li>Repository informasi Android tentang orang.</li>
+    <li>
+        Sinkronisasi dengan web.
+    </li>
+    <li>
+        Mengintegrasikan data aliran sosial.
+    </li>
+</ul>
+<h2>Dalam dokumen ini</h2>
+<ol>
+    <li>
+        <a href="#InformationTypes">Organisasi Penyedia Kontak</a>
+    </li>
+    <li>
+        <a href="#RawContactBasics">Kontak mentah</a>
+    </li>
+    <li>
+        <a href="#DataBasics">Data</a>
+    </li>
+    <li>
+        <a href="#ContactBasics">Kontak</a>
+    </li>
+    <li>
+        <a href="#Sources">Data Dari Adaptor Sinkronisasi</a>
+    </li>
+    <li>
+        <a href="#Permissions">Izin yang Diperlukan</a>
+    </li>
+    <li>
+        <a href="#UserProfile">Profil Pengguna</a>
+    </li>
+    <li>
+        <a href="#ContactsProviderMetadata">Metadata Penyedia Kontak</a>
+    </li>
+    <li>
+        <a href="#Access">Akses Penyedia Kontak</a>
+    <li>
+    </li>
+    <li>
+        <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>
+    </li>
+    <li>
+        <a href="#SocialStream">Data Aliran Sosial</a>
+    </li>
+    <li>
+        <a href="#AdditionalFeatures">Fitur Tambahan Penyedia Kontak</a>
+    </li>
+</ol>
+<h2>Kelas-kelas utama</h2>
+<ol>
+    <li>{@link android.provider.ContactsContract.Contacts}</li>
+    <li>{@link android.provider.ContactsContract.RawContacts}</li>
+    <li>{@link android.provider.ContactsContract.Data}</li>
+    <li>{@code android.provider.ContactsContract.StreamItems}</li>
+</ol>
+<h2>Contoh-Contoh Terkait</h2>
+<ol>
+    <li>
+        <a href="{@docRoot}resources/samples/ContactManager/index.html">
+        Contact Manager
+        </a>
+    </li>
+    <li>
+        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+        Contoh Adaptor Sinkronisasi</a>
+    </li>
+</ol>
+<h2>Lihat Juga</h2>
+<ol>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Dasar-Dasar Penyedia Konten
+        </a>
+    </li>
+</ol>
+</div>
+</div>
+<p>
+    Penyedia Kontak adalah komponen Android yang tangguh dan fleksibel dalam mengelola
+ repository data pusat tentang orang di perangkat. Penyedia Kontak adalah sumber data
+ yang Anda lihat dalam aplikasi kontak perangkat, dan Anda juga bisa mengakses datanya dalam aplikasi
+    Anda sendiri serta mentransfer data antara perangkat dan layanan online. Penyedia mengakomodasi
+    berbagai sumber data dan mencoba mengelola data sebanyak mungkin untuk setiap orang, sehingga
+   organisasinya menjadi kompleks. Karena itu, API penyedia menyertakan
+    satu set kelas kontrak dan antarmuka ekstensif yang membantu pengambilan dan
+    modifikasi data.
+</p>
+<p>
+    Panduan ini menjelaskan hal-hal berikut:
+</p>
+    <ul>
+        <li>
+            Struktur penyedia dasar.
+        </li>
+        <li>
+            Cara mengambil data dari penyedia.
+        </li>
+        <li>
+            Cara memodifikasi data di penyedia.
+        </li>
+        <li>
+            Cara menulis adaptor sinkronisasi untuk menyinkronkan data dari server Anda ke
+            Penyedia Kontak.
+        </li>
+    </ul>
+<p>
+    Panduan ini beranggapan bahwa Anda mengetahui dasar-dasar penyedia konten Android. Untuk mengetahui selengkapnya
+    tentang penyedia konten Android, bacalah
+    panduan<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+    Dasar-Dasar Penyedia Konten</a>. Contoh aplikasi
+    <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>
+    adalah contoh penggunaan adaptor sinkronisasi untuk mentransfer data antara Penyedia Kontak
+    dan contoh aplikasi yang memiliki host di Google Web Services.
+</p>
+<h2 id="InformationTypes">Organisasi Penyedia Kontak</h2>
+<p>
+    Penyedia Kontak adalah komponen penyedia konten Android. Komponen ini memelihara tiga tipe
+    data tentang seseorang, masing-masing disesuaikan dengan tabel yang ditawarkan oleh penyedia, seperti
+    yang terlihat dalam gambar 1:
+</p>
+<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" />
+<p class="img-caption">
+  <strong>Gambar 1.</strong> Struktur tabel Penyedia Kontak.
+</p>
+<p>
+    Ketiga tabel disebut secara umum menurut nama kelas kontrak. Kelas
+    mendefinisikan konstanta untuk URI konten, nama kolom, dan nilai kolom yang digunakan oleh tabel-tabel:
+</p>
+<dl>
+    <dt>
+        Tabel {@link android.provider.ContactsContract.Contacts}
+    </dt>
+    <dd>
+        Baris mewakili orang yang berbeda, berdasarkan agregrasi baris kontak mentah.
+    </dd>
+    <dt>
+        Tabel {@link android.provider.ContactsContract.RawContacts}
+    </dt>
+    <dd>
+        Baris berisi rangkuman data seseorang, untuk tipe dan akun pengguna tertentu.
+    </dd>
+    <dt>
+        Tabel {@link android.provider.ContactsContract.Data}
+    </dt>
+    <dd>
+        Baris berisi data untuk kontak mentah, seperti alamat email atau nomor telepon.
+    </dd>
+</dl>
+<p>
+    Tabel lain yang diwakili oleh kelas kontrak dalam {@link android.provider.ContactsContract}
+    adalah tabel tambahan yang digunakan Penyedia Kontak untuk mengelola operasinya atau mendukung
+    fungsi tertentu dalam kontak atau aplikasi telepon perangkat.
+</p>
+<h2 id="RawContactBasics">Kontak mentah</h2>
+<p>
+    Kontak mentah mewakili data seseorang yang berasal dari satu tipe akun dan nama
+  akun. Karena Penyedia Kontak memungkinkan lebih dari satu layanan online sebagai sumber
+    data untuk satu orang, Penyedia Kontak memungkinkan multikontak mentah untuk orang yang sama.
+    Multikontak mentah juga memungkinkan seorang pengguna mengombinasikan data seseorang dari lebih dari satu akun
+    bertipe akun yang sama.
+</p>
+<p>
+    Sebagian besar data untuk kontak mentah tidak disimpan dalam
+    tabel {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, data tersebut disimpan dalam satu atau beberapa baris
+    dalam tabel {@link android.provider.ContactsContract.Data}. Setiap baris data memiliki kolom
+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} yang
+    berisi nilai {@code android.provider.BaseColumns#_ID RawContacts._ID} dari
+    baris {@link android.provider.ContactsContract.RawContacts} induknya.
+</p>
+<h3 id="RawContactsColumns">Kolom-kolom kontak mentah yang penting</h3>
+<p>
+    Kolom-kolom penting dalam tabel {@link android.provider.ContactsContract.RawContacts}
+    tercantum pada tabel 1. Bacalah catatan yang diberikan setelah tabel:
+</p>
+<p class="table-caption" id="table1">
+    <strong>Tabel 1.</strong> Kolom-kolom kontak mentah yang penting.
+</p>
+<table>
+    <tr>
+        <th scope="col">Nama kolom</th>
+        <th scope="col">Kegunaan</th>
+        <th scope="col">Catatan</th>
+    </tr>
+    <tr>
+        <td>
+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME}
+        </td>
+        <td>
+            Nama akun untuk tipe akun yang merupakan sumber kontak mentah ini.
+            Misalnya, nama akun dari akun Google adalah salah satu alamat Gmail
+   pemilik perangkat. Lihat entri berikutnya untuk
+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} untuk informasi
+            selengkapnya.
+        </td>
+        <td>
+            Format nama ini khusus untuk tipe akun ini. Format ini tidak
+            harus alamat email.
+        </td>
+    </tr>
+    <tr>
+        <td>
+            {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE}
+        </td>
+        <td>
+            Tipe akun yang merupakan sumber kontak mentah ini. Misalnya, tipe
+           akun dari akun Google adalah <code>com.google</code>. Selalu batasi tipe akun Anda
+            dengan identifier domain untuk domain yang Anda miliki atau kontrol. Hal ini akan memastikan bahwa tipe
+            akun Anda bersifat unik.
+        </td>
+        <td>
+            Tipe akun yang menawarkan data kontak biasanya memiliki adaptor sinkronisasi terkait yang
+            menyinkronkan dengan Penyedia Kontak.
+    </tr>
+    <tr>
+        <td>
+            {@link android.provider.ContactsContract.RawContactsColumns#DELETED}
+        </td>
+        <td>
+            Flag "deleted" untuk kontak mentah.
+        </td>
+        <td>
+            Flag ini memungkinkan Penyedia Kontak memelihara baris secara internal hingga adaptor
+            sinkronisasi bisa menghapus baris dari server mereka dan akhirnya menghapus baris
+            dari repository.
+        </td>
+    </tr>
+</table>
+<h4>Catatan</h4>
+<p>
+    Berikut ini adalah catatan penting tentang
+    tabel {@link android.provider.ContactsContract.RawContacts}:
+</p>
+<ul>
+    <li>
+        Nama kontak mentah tidak disimpan di barisnya dalam
+        {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, nama tersebut disimpan dalam
+         tabel {@link android.provider.ContactsContract.Data}, pada
+        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. Kontak mentah
+        hanya memiliki satu baris dari tipe ini dalam tabel {@link android.provider.ContactsContract.Data}.
+    </li>
+    <li>
+        <strong>Perhatian:</strong> Untuk menggunakan data akun sendiri dalam baris kontak mentah, akun harus
+        didaftarkan lebih dahulu dengan {@link android.accounts.AccountManager}. Caranya, mintalah
+        pengguna untuk menambahkan tipe akun dan nama akun ke dalam daftar akun. Jika Anda tidak
+        melakukannya, Penyedia Kontak secara otomatis akan menghapus baris kontak mentah Anda.
+        <p>
+            Misalnya, Anda menginginkan aplikasi memelihara data kontak untuk layanan berbasis web
+            dengan domain {@code com.example.dataservice}, dan akun pengguna untuk layanan Anda
+            adalah {@code becky.sharp@dataservice.example.com}, pengguna harus menambahkan lebih dahulu "type"
+            akun ({@code com.example.dataservice}) dan "name" akun
+            ({@code becky.smart@dataservice.example.com}) sebelum aplikasi Anda bisa menambahkan baris kontak mentah.
+            Anda bisa menjelaskan ketentuan ini kepada pengguna dalam dokumentasi, atau meminta
+            pengguna untuk menambahkan tipe dan nama, atau keduanya. Tipe akun dan nama akun
+            dijelaskan lebih detail di bagian berikutnya.
+    </li>
+</ul>
+<h3 id="RawContactsExample">Sumber data kontak mentah</h3>
+<p>
+    Untuk memahami cara kerja kontak mentah, perhatikan pengguna "Emily Dickinson" yang mendefinisikan
+    tiga akun pengguna berikut pada perangkatnya:
+</p>
+<ul>
+    <li><code>emily.dickinson@gmail.com</code></li>
+    <li><code>emilyd@gmail.com</code></li>
+    <li>Akun Twitter "belle_of_amherst"</li>
+</ul>
+<p>
+    Pengguna ini telah mengaktifkan <em>Sync Contacts</em> untuk ketiga akun dalam pengaturan
+    <em>Accounts</em>.
+</p>
+<p>
+    Anggaplah Emily Dickinson membuka jendela browser, masuk ke Gmail sebagai
+    <code>emily.dickinson@gmail.com</code>, membuka
+    Contacts, dan menambahkan "Thomas Higginson". Kemudian, ia masuk ke Gmail sebagai
+    <code>emilyd@gmail.com</code> dan mengirimkan email kepada "Thomas Higginson", yang
+    menambahkan Thomas secara otomatis sebagai kontak. Ia juga mengikuti "colonel_tom" (ID Twitter Thomas Higginson) di
+    Twitter.
+</p>
+<p>
+    Penyedia Kontak membuat tiga kontak mentah akibat pekerjaan ini:
+</p>
+<ol>
+    <li>
+        Kontak mentah untuk "Thomas Higginson" yang dikaitkan dengan <code>emily.dickinson@gmail.com</code>.
+        Tipe akun penggunanya adalah Google.
+    </li>
+    <li>
+        Kontak mentah kedua untuk "Thomas Higginson" yang dikaitkan dengan <code>emilyd@gmail.com</code>.
+        Tipe akun pengguna juga Google. Ada kontak mentah kedua
+       meskipun nama tersebut identik dengan nama sebelumnya karena orang bersangkutan ditambahkan untuk
+        akun pengguna yang berbeda.
+    </li>
+    <li>
+        Kontak mentah ketiga untuk "Thomas Higginson" yang dikaitkan dengan "belle_of_amherst". Tipe
+        akun penggunanya adalah Twitter.
+    </li>
+</ol>
+<h2 id="DataBasics">Data</h2>
+<p>
+    Seperti yang telah disebutkan, data untuk kontak mentah disimpan dalam
+    baris {@link android.provider.ContactsContract.Data} yang ditautkan dengan nilai
+    <code>_ID</code> kontak mentah. Cara ini memungkinkan satu kontak mentah memiliki beberapa instance tipe data
+    yang sama dengan alamat email atau nomor telepon. Misalnya, jika
+    "Thomas Higginson" untuk {@code emilyd@gmail.com} (baris kontak mentah untuk Thomas Higginson
+   yang dikaitkan dengan akun Google <code>emilyd@gmail.com</code>) memiliki alamat email rumah
+    <code>thigg@gmail.com</code> dan alamat email kerja
+    <code>thomas.higginson@gmail.com</code>, Penyedia Kontak akan menyimpan dua baris alamat
+    email dan menautkan keduanya ke kontak mentah.
+</p>
+<p>
+    Perhatikan bahwa tipe data yang berbeda disimpan dalam satu tabel ini. Baris-baris nama tampilan,
+    nomor telepon, email, alamat surat, foto, dan data situs web semuanya bisa ditemukan dalam
+    tabel {@link android.provider.ContactsContract.Data}. Untuk membantu mengelola ini,
+    tabel {@link android.provider.ContactsContract.Data} memiliki beberapa kolom dengan nama deskriptif,
+    dalam kolom lain dengan nama generik. Konten kolom bernama deskriptif memiliki arti yang sama
+    terlepas dari tipe data dalam barisnya, sedangkan konten kolom bernama generik memiliki
+    arti yang berbeda-beda sesuai dengan tipe data.
+</p>
+<h3 id="DescriptiveColumns">Nama kolom deskriptif</h3>
+<p>
+    Beberapa contoh nama kolom deskriptif adalah:
+</p>
+<dl>
+    <dt>
+        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
+    </dt>
+    <dd>
+        Nilai kolom <code>_ID</code> kontak mentah untuk data ini.
+    </dd>
+    <dt>
+        {@link android.provider.ContactsContract.Data#MIMETYPE}
+    </dt>
+    <dd>
+        Tipe data yang disimpan dalam baris ini, dinyatakan berupa tipe MIME custom. Penyedia Kontak
+        menggunakan tipe MIME yang didefinisikan dalam subkelas
+        {@link android.provider.ContactsContract.CommonDataKinds}. Tipe MIME ini adalah sumber terbuka,
+        dan bisa digunakan oleh setiap aplikasi atau adaptor sinkronisasi yang bisa digunakan bersama Penyedia Kontak.
+    </dd>
+    <dt>
+        {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
+    </dt>
+    <dd>
+        Jika tipe baris data ini bisa terjadi lebih dari satu kali untuk suatu kontak mentah,
+        kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
+        menandai baris data yang berisi data utama untuk tipe itu. Misalnya, jika
+        pengguna menekan lama sebuah nomor telepon untuk kontak dan memilih <strong>Set default</strong>,
+       maka baris {@link android.provider.ContactsContract.Data} yang berisi angka itu
+        mengatur kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}-nya ke suatu
+        nilai bukan nol.
+    </dd>
+</dl>
+<h3 id="GenericColumns">Nama kolom generik</h3>
+<p>
+    Ada 15 kolom generik bernama <code>DATA1</code> hingga
+    <code>DATA15</code> yang tersedia secara umum dan empat kolom generik
+    tambahan <code>SYNC1</code> hingga <code>SYNC4</code> yang harus digunakan hanya oleh adaptor
+    sinkronisasi. Konstanta nama kolom generik selalu berfungsi, terlepas dari tipe
+    data dalam baris .
+</p>
+<p>
+    Kolom <code>DATA1</code> diindeks.  Penyedia Kontak selalu menggunakan kolom ini untuk
+    data yang diharapkan penyedia akan menjadi target yang paling sering dari suatu query. Misalnya,
+    dalam baris email, kolom ini berisi alamat email sebenarnya.
+</p>
+<p>
+    Sesuai konvensi, kolom <code>DATA15</code> dicadangkan untuk menyimpan data Binary Large Object
+    (BLOB) seperti thumbnail foto.
+</p>
+<h3 id="TypeSpecificNames">Nama kolom bertipe spesifik</h3>
+<p>
+    Guna memudahkan pekerjaan dengan kolom untuk tipe baris tertentu, Penyedia Kontak
+    juga menyediakan konstanta nama kolom bertipe spesifik, yang didefinisikan dalam subkelas
+    {@link android.provider.ContactsContract.CommonDataKinds}. Konstanta cuma memberikan nama
+    konstanta yang berbeda ke nama kolom yang sama, yang membantu Anda mengakses data dalam baris
+    bertipe spesifik.
+</p>
+<p>
+    Misalnya, kelas {@link android.provider.ContactsContract.CommonDataKinds.Email} mendefinisikan
+    konstanta nama kolom bertipe spesifik untuk baris {@link android.provider.ContactsContract.Data}
+    yang memiliki tipe MIME
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+    Email.CONTENT_ITEM_TYPE}. Kelas ini berisi konstanta
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} untuk kolom
+    alamat email. Nilai sesungguhnya dari
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} adalah "data1", yang
+    sama dengan nama generik kolom.
+</p>
+<p class="caution">
+    <strong>Perhatian:</strong> Jangan tambahkan data custom Anda sendiri ke
+    tabel {@link android.provider.ContactsContract.Data} dengan menggunakan baris yang memiliki salah satu
+    tipe MIME yang telah didefinisikan penyedia. Jika melakukannya, Anda bisa kehilangan data atau menyebabkan penyedia
+    gagal berfungsi. Misalnya, Anda seharusnya tidak menambahkan baris bertipe MIME
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+    Email.CONTENT_ITEM_TYPE} yang berisi nama pengguna sebagai ganti alamat email dalam
+    kolom <code>DATA1</code>. Jika Anda menggunakan tipe MIME custom sendiri untuk baris bersangkutan, maka Anda bebas
+    untuk mendefinisikan nama kolom bertipe spesifik dan menggunakan kolom sekehendak Anda.
+</p>
+<p>
+    Gambar 2 menampilkan cara kolom deskriptif dan kolom data muncul dalam
+    baris {@link android.provider.ContactsContract.Data}, dan cara nama kolom bertipe spesifik "melapisi"
+    nama kolom generik
+</p>
+<img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" />
+<p class="img-caption">
+  <strong>Gambar 2.</strong> Nama kolom bertipe spesifik dan nama kolom generik.
+</p>
+<h3 id="ColumnMaps">Kelas nama kolom bertipe spesifik</h3>
+<p>
+    Tabel 2 berisi daftar kelas nama kolom bertipe spesifik yang paling umum digunakan:
+</p>
+<p class="table-caption" id="table2">
+  <strong>Tabel 2.</strong> Kelas nama kolom bertipe spesifik</p>
+<table>
+  <tr>
+    <th scope="col">Kelas pemetaan</th>
+    <th scope="col">Tipe data</th>
+    <th scope="col">Catatan</th>
+  </tr>
+  <tr>
+    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td>
+    <td>Data nama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
+    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td>
+    <td>Foto utama untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
+    <td>Kontak mentah hanya memiliki salah satu baris ini.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td>
+    <td>Alamat email untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
+    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td>
+    <td>Alamat pos untuk kontak mentah yang dikaitkan dengan baris data ini.</td>
+    <td>Kontak mentah bisa memiliki beberapa alamat email.</td>
+  </tr>
+  <tr>
+    <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td>
+    <td>Identifier yang menautkan kontak mentah ke salah satu grup dalam Penyedia Kontak.</td>
+    <td>
+        Grup adalah fitur opsional pada tipe akun dan nama akun. Grup dijelaskan
+       lebih detail di bagian <a href="#Groups">Grup kontak</a>.
+    </td>
+  </tr>
+</table>
+<h3 id="ContactBasics">Kontak</h3>
+<p>
+    Penyedia Kontak mengombinasikan baris kontak mentah di semua tipe akun dan nama akun
+    untuk membentuk <strong>kontak</strong>. Hal ini memudahkan menampilkan dan memodifikasi semua data
+    yang telah dikumpulkan pengguna untuk seseorang. Penyedia Kontak mengelola pembuatan baris
+    kontak baru, dan agregasi kontak mentah dengan baris kontak yang ada. Baik aplikasi maupun adaptor sinkronisasi
+    tidak boleh menambahkan kontak dan sebagian kolom dalam baris kontak yang bersifat hanya baca.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Jika Anda mencoba menambahkan kontak ke Penyedia Kontak dengan
+    {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, Anda akan mendapatkan
+    eksepsi {@link java.lang.UnsupportedOperationException}. Jika Anda mencoba memperbarui sebuah kolom
+   yang tercantum sebagai "hanya-baca", pembaruan akan diabaikan.
+</p>
+<p>
+    Penyedia Kontak membuat kontak baru untuk merespons penambahan kontak mentah baru
+    yang tidak cocok dengan kontak yang ada. Penyedia juga melakukan ini jika data
+    kontak mentah yang ada berubah sehingga tidak lagi cocok dengan kontak yang
+    sebelumnya dihubungkan. Jika aplikasi atau adaptor sinkronisasi membuat kontak mentah baru yang
+    <em>memang</em> cocok dengan kontak yang ada, kontak mentah baru akan diagregasikan ke kontak
+    yang ada.
+</p>
+<p>
+    Penyedia Kontak menautkan baris kontak ke baris kontak mentahnya dengan kolom
+    <code>_ID</code> dari baris kontak dalam tabel {@link android.provider.ContactsContract.Contacts Contacts}.
+ Kolom <code>CONTACT_ID</code> tabel kontak mentah
+    {@link android.provider.ContactsContract.RawContacts} berisi nilai <code>_ID</code> untuk
+    baris kontak yang dikaitkan dengan tiap baris kontak mentah.
+</p>
+<p>
+    Tabel {@link android.provider.ContactsContract.Contacts} juga memiliki kolom
+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} yang merupakan
+    tautan "permanen" ke baris kontak. Karena memelihara kontak
+    secara otomatis, Penyedia Kontak bisa mengubah nilai {@code android.provider.BaseColumns#_ID} baris kontak
+    untuk merespons agregasi atau sinkronisasi. Sekalipun ini terjadi, URI konten
+    {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} yang dikombinasikan dengan
+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} kontak akan tetap
+    menunjuk ke baris kontak itu, sehingga Anda bisa menggunakan
+    {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
+   untuk memelihara tautan ke kontak "favorit", dan seterusnya. Kolom ini memiliki formatnya sendiri, yang
+    tidak terkait dengan format kolom {@code android.provider.BaseColumns#_ID}.
+</p>
+<p>
+    Gambar 3 menampilkan cara ketiga tabel utama terkait satu sama lain.
+</p>
+<img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" />
+<p class="img-caption">
+  <strong>Gambar 3.</strong> Hubungan tabel Contacts, Raw Contacts, dan Details.
+</p>
+<h2 id="Sources">Data Dari Adaptor Sinkronisasi</h2>
+<p>
+    Pengguna memasukkan data kontak secara langsung ke dalam perangkat, namun data juga mengalir masuk ke Penyedia Kontak
+    dari layanan web melalui <strong>adaptor sinkronisasi</strong>, yang mengotomatiskan
+    transfer data antara perangkat dan layanan. Adaptor sinkronisasi berjalan di latar belakang
+    di bawah kontrol sistem, dan memanggil metode {@link android.content.ContentResolver}
+   untuk mengelola data.
+</p>
+<p>
+    Di Android, layanan web yang digunakan adaptor sinkronisasi diidentifikasi melalui tipe akun.
+    Setiap adaptor sinkronisasi bekerja dengan satu tipe akun, tetapi bisa mendukung beberapa nama akun untuk
+    tipe itu. Tipe akun dan nama akun dijelaskan secara singkat di bagian
+    <a href="#RawContactsExample">Sumber data kontak mentah</a>. Definisi berikut menyediakan
+    detail selengkapnya, dan menjelaskan cara tipe dan nama akun berkaitan dengan adaptor sinkronisasi dan layanan.
+</p>
+<dl>
+    <dt>
+        Tipe akun
+    </dt>
+    <dd>
+        Mengidentifikasi layanan tempat pengguna menyimpan data. Sering kali, pengguna harus
+        mengautentikasi diri dengan layanan. Misalnya, Google Contacts adalah tipe akun, yang diidentifikasi
+        dengan kode <code>google.com</code>. Nilai ini sesuai dengan tipe akun yang digunakan oleh
+        {@link android.accounts.AccountManager}.
+    </dd>
+    <dt>
+        Nama akun
+    </dt>
+    <dd>
+        Mengidentifikasi akun atau login tertentu untuk suatu tipe akun. Akun Google Contacts
+        sama dengan akun Google, yang memiliki alamat email sebagai nama akun.
+        Layanan lain mungkin menggunakan nama pengguna satu-kata atau identitas berupa angka.
+    </dd>
+</dl>
+<p>
+    Tipe akun tidak harus unik. Pengguna boleh mengonfigurasi beberapa akun Google Contacts
+    dan mengunduh data ke Penyedia Kontak; ini mungkin terjadi jika pengguna memiliki satu set
+    kontak pribadi untuk satu nama akun pribadi, dan satu set lagi untuk pekerjaan. Nama akun
+    biasanya unik. Bersama-sama, keduanya mengidentifikasi aliran data tertentu antara Penyedia Kontak dan
+    layanan eksternal.
+</p>
+<p>
+    Jika Anda ingin mentransfer data layanan ke Penyedia Kontak, Anda perlu menulis
+    adaptor sinkronisasi sendiri. Hal ini dijelaskan lebih detail di bagian
+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
+</p>
+<p>
+    Gambar 4 menampilkan cara Penyedia Kontak dimasukkan ke dalam aliran data
+    tentang orang. Dalam kotak bertanda "sync adapters", setiap adaptor diberi label menurut tipe akunnya.
+</p>
+<img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" />
+<p class="img-caption">
+  <strong>Gambar 4.</strong> Aliran data Penyedia Kontak.
+</p>
+<h2 id="Permissions">Izin yang Diperlukan</h2>
+<p>
+    Aplikasi yang ingin mengakses Penyedia Kontak harus meminta izin
+   berikut:
+</p>
+<dl>
+    <dt>Akses baca ke satu atau beberapa tabel</dt>
+    <dd>
+        {@link android.Manifest.permission#READ_CONTACTS}, yang ditetapkan dalam
+        <code>AndroidManifest.xml</code> dengan elemen
+        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+        &lt;uses-permission&gt;</a></code> sebagai
+        <code>&lt;uses-permission android:name="android.permission.READ_CONTACTS"&gt;</code>.
+    </dd>
+    <dt>Akses tulis ke satu atau beberapa tabel</dt>
+    <dd>
+        {@link android.Manifest.permission#WRITE_CONTACTS}, yang ditetapkan dalam
+        <code>AndroidManifest.xml</code> dengan elemen
+        <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+        &lt;uses-permission&gt;</a></code> sebagai
+        <code>&lt;uses-permission android:name="android.permission.WRITE_CONTACTS"&gt;</code>.
+    </dd>
+</dl>
+<p>
+    Izin ini tidak diperluas ke data profil pengguna. Profil pengguna dan izin
+   yang diperlukan dibahas di bagian berikut,
+    <a href="#UserProfile">Profil Pengguna</a>.
+</p>
+<p>
+    Ingatlah bahwa data kontak pengguna bersifat pribadi dan sensitif. Pengguna mempersoalkan
+    privasinya, sehingga tidak ingin aplikasi mengumpulkan data tentang diri atau kontak mereka.
+    Jika alasan Anda memerlukan izin untuk mengakses data kontak tidak jelas, pengguna mungkin memberi
+    aplikasi Anda peringkat rendah atau langsung menolak menginstalnya.
+</p>
+<h2 id="UserProfile">Profil Pengguna</h2>
+<p>
+    Tabel {@link android.provider.ContactsContract.Contacts} berisi satu baris yang berisi
+    data profil untuk pengguna perangkat. Data ini menjelaskan data perangkat  <code>user</code> bukannya
+    salah satu kontak pengguna. Baris kontak profil ditautkan ke baris
+     kontak mentah untuk setiap sistem yang menggunakan profil.
+    Setiap baris kontak mentah profil bisa memiliki beberapa baris data. Konstanta untuk mengakses profil
+    pengguna tersedia dalam kelas {@link android.provider.ContactsContract.Profile}.
+</p>
+<p>
+    Akses ke profil pengguna memerlukan izin khusus. Selain itu, izin
+    {@link android.Manifest.permission#READ_CONTACTS} dan
+    {@link android.Manifest.permission#WRITE_CONTACTS} diperlukan untuk membaca dan menulis, akses
+    ke profil pengguna memerlukan masing-masing izin {@code android.Manifest.permission#READ_PROFILE} dan
+    {@code android.Manifest.permission#WRITE_PROFILE} untuk akses baca dan tulis.
+
+</p>
+<p>
+    Ingatlah bahwa Anda harus mempertimbangkan profil pengguna bersifat sensitif. Izin
+    {@code android.Manifest.permission#READ_PROFILE} memungkinkan Anda mengakses data yang mengidentifikasi secara pribadi
+    pengguna perangkat. Pastikan memberi tahu pengguna alasan
+    Anda memerlukan izin akses profil pengguna dalam keterangan aplikasi Anda.
+</p>
+<p>
+    Untuk mengambil baris kontak berisi profil pengguna,
+    panggil {@link android.content.ContentResolver#query(Uri,String[], String, String[], String)
+    ContentResolver.query()}. Atur URI konten ke
+    {@link android.provider.ContactsContract.Profile#CONTENT_URI} dan jangan sediakan
+    kriteria pemilihan apa pun. Anda juga bisa menggunakan URI konten ini sebagai URI dasar untuk mengambil kontak
+    mentah atau data untuk profil. Misalnya, cuplikan kode ini mengambil data untuk profil:
+</p>
+<pre>
+// Sets the columns to retrieve for the user profile
+mProjection = new String[]
+    {
+        Profile._ID,
+        Profile.DISPLAY_NAME_PRIMARY,
+        Profile.LOOKUP_KEY,
+        Profile.PHOTO_THUMBNAIL_URI
+    };
+
+// Retrieves the profile from the Contacts Provider
+mProfileCursor =
+        getContentResolver().query(
+                Profile.CONTENT_URI,
+                mProjection ,
+                null,
+                null,
+                null);
+</pre>
+<p class="note">
+    <strong>Catatan:</strong> Jika Anda mengambil beberapa baris kontak, dan ingin menentukan apakah salah satu baris
+    adalah profil pengguna, uji
+    kolom {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} pada baris tersebut. Kolom ini
+    diatur ke "1" jika kontak adalah profil pengguna.
+</p>
+<h2 id="ContactsProviderMetadata">Metadata Penyedia Kontak</h2>
+<p>
+    Penyedia Kontak mengelola data yang mencatat status data kontak dalam
+    repository. Metadata repository ini disimpan di berbagai tempat, termasuk baris-baris tabel
+    Raw Contacts, Data, dan Contacts,
+    tabel {@link android.provider.ContactsContract.Settings}, dan
+    tabel {@link android.provider.ContactsContract.SyncState}. Tabel berikut menampilkan
+    efek setiap potongan metadata ini:
+</p>
+<p class="table-caption" id="table3">
+  <strong>Tabel 3.</strong> Metadata di Penyedia Kontak</p>
+<table>
+    <tr>
+        <th scope="col">Tabel</th>
+        <th scope="col">Kolom</th>
+        <th scope="col">Nilai</th>
+        <th scope="col">Arti</th>
+    </tr>
+    <tr>
+        <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td>
+        <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td>
+        <td>"0" - tidak berubah sejak sinkronisasi terakhir.</td>
+        <td rowspan="2">
+            Menandai kontak mentah yang berubah pada perangkat dan telah disinkronkan kembali ke
+           server. Nilai diatur secara otomatis oleh Penyedia Kontak bila aplikasi
+            Android memperbarui baris.
+            <p>
+                Adaptor sinkronisasi yang memodifikasi kontak mentah atau tabel data harus selalu menambahkan
+                string {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} ke
+                URI konten yang digunakannya. Ini mencegah penyedia menandai baris sebagai kotor.
+                Sebaliknya, modifikasi oleh adaptor sinkronisasi tampak seperti modifikasi lokal dan
+                dikirim ke server, meskipun server adalah sumber modifikasi.
+            </p>
+        </td>
+    </tr>
+    <tr>
+            <td>"1" - berubah sejak sinkronisasi terakhir, harus disinkronkan kembali ke server.</td>
+    </tr>
+    <tr>
+        <td>{@link android.provider.ContactsContract.RawContacts}</td>
+        <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td>
+        <td>Nomor versi baris ini.</td>
+        <td>
+            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris atau
+            data terkaitnya berubah.
+        </td>
+    </tr>
+    <tr>
+        <td>{@link android.provider.ContactsContract.Data}</td>
+        <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td>
+        <td>Nomor versi baris ini.</td>
+        <td>
+            Penyedia Kontak menambahkan nilai ini secara otomatis bila baris data
+            berubah.
+        </td>
+    </tr>
+    <tr>
+        <td>{@link android.provider.ContactsContract.RawContacts}</td>
+        <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td>
+        <td>
+            Nilai string yang mengidentifikasi secara unik kontak mentah ini ke akun tempat
+            kontak dibuat.
+        </td>
+        <td>
+            Bila adaptor sinkronisasi membuat kontak mentah baru, kolom ini harus diatur ke
+            ID unik server untuk kontak mentah itu. Bila aplikasi Android membuat kontak mentah
+            baru, aplikasi harus membiarkan kolom ini kosong. Ini mengisyaratkan pada adaptor
+            sinkronisasi bahwa adaptor harus membuat kontak mentah baru pada server, dan mendapatkan
+            nilai untuk {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}.
+            <p>
+                Khususnya, id sumber harus <strong>unik</strong> untuk setiap tipe
+                akun dan stabil di semua sinkronisasi:
+            </p>
+                <ul>
+                    <li>
+                        Unik: Setiap kontak mentah untuk satu akun harus memiliki id sumbernya sendiri. Jika Anda
+                        tidak memberlakukan aturan ini, masalah akan timbul dalam aplikasi kontak.
+                        Perhatikan bahwa dua kontak mentah untuk tipe akun yang <em>sama</em> boleh memiliki
+                       id sumber yang sama. Misalnya, kontak mentah "Thomas Higginson" untuk
+                        akun {@code emily.dickinson@gmail.com} boleh memiliki id sumber
+                        yang sama dengan kontak mentah "Thomas Higginson" untuk akun
+                        {@code emilyd@gmail.com}.
+                    </li>
+                    <li>
+                        Stabil: Id sumber adalah bagian tetap dari data layanan online untuk
+                        kontak mentah. Misalnya, jika pengguna membersihkan Contacts Storage dari
+                        pengaturan aplikasi dan menyinkronkan ulang, kontak mentah yang dipulihkan akan memiliki id sumber
+                        yang sama dengan sebelumnya. Jika Anda tidak memberlakukan hal ini, pintasan akan berhenti
+                        berfungsi.
+                    </li>
+                </ul>
+        </td>
+    </tr>
+    <tr>
+        <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td>
+        <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td>
+        <td>"0" - Kontak dalam grup ini tidak boleh terlihat dalam UI aplikasi Android.</td>
+        <td>
+            Kolom ini digunakan untuk kompatibilitas dengan server yang memungkinkan pengguna menyembunyikan kontak dalam
+            grup tertentu.
+        </td>
+    </tr>
+    <tr>
+        <td>"1" - Kontak dalam grup ini boleh terlihat dalam UI aplikasi.</td>
+    </tr>
+    <tr>
+        <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td>
+        <td rowspan="2">
+            {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td>
+        <td>
+            "0" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
+            tidak akan terlihat pada UI aplikasi Android.
+        </td>
+        <td rowspan="2">
+            Secara default, kontak tidak terlihat jika tidak satu pun kontak mentahnya milik grup
+            (Keanggotaan grup untuk kontak mentah ditandai oleh satu atau beberapa baris
+            {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}
+            dalam tabel {@link android.provider.ContactsContract.Data}).
+            Dengan mengatur flag ini dalam baris tabel {@link android.provider.ContactsContract.Settings}
+            untuk tipe akun dan akun, Anda bisa memaksakan kontak tanpa grup agar terlihat.
+            Satu kegunaan flag ini adalah menampilkan kontak dari server yang tidak menggunakan grup.
+        </td>
+    </tr>
+    <tr>
+        <td>
+            "1" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup
+            akan terlihat pada UI aplikasi.
+        </td>
+
+    </tr>
+    <tr>
+        <td>{@link android.provider.ContactsContract.SyncState}</td>
+        <td>(semua)</td>
+        <td>
+            Gunakan tabel ini untuk menyimpan metadata bagi adaptor sinkronisasi Anda.
+        </td>
+        <td>
+            Dengan tabel ini, Anda bisa menyimpan status sinkronisasi dan data lain yang terkait dengan sinkronisasi secara persisten pada
+            perangkat.
+        </td>
+    </tr>
+</table>
+<h2 id="Access">Akses Penyedia Kontak</h2>
+<p>
+    Bagian ini menjelaskan panduan untuk mengakses data dari Penyedia Kontak, yang berfokus pada
+    hal-hal berikut:
+</p>
+<ul>
+    <li>
+        Query entitas.
+    </li>
+    <li>
+        Modifikasi batch.
+    </li>
+    <li>
+        Pengambilan dan modifikasi dengan intent.
+    </li>
+    <li>
+        Integritas data.
+    </li>
+</ul>
+<p>
+    Membuat modifikasi dari adaptor sinkronisasi juga secara lebih detail di bagian
+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>.
+</p>
+<h3 id="Entities">Membuat query entitas</h3>
+<p>
+    Karena disusun secara hierarki, tabel-tabel Penyedia Kontak sering kali berguna untuk
+    mengambil baris dan semua baris "anak" yang ditautkan dengannya. Misalnya, untuk menampilkan
+    semua informasi untuk satu orang, Anda mungkin ingin mengambil semua
+    baris {@link android.provider.ContactsContract.RawContacts} untuk satu baris
+    {@link android.provider.ContactsContract.Contacts}, atau semua
+    baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk satu baris
+    {@link android.provider.ContactsContract.RawContacts}. Untuk memudahkan hal ini, Penyedia Kontak
+    menawarkan konstruksi <strong>entitas</strong>, yang berfungsi seperti gabungan database di antara
+    tabel-tabel.
+</p>
+<p>
+    Entitas adalah seperti tabel yang terdiri atas kolom-kolom terpilih dari tabel induk dan tabel anaknya.
+    Bila membuat query sebuah entitas, Anda memberikan proyeksi dan kriteria pencarian berdasarkan kolom-kolom
+    yang tersedia dari entitas itu. Hasilnya adalah sebuah {@link android.database.Cursor} yang
+    berisi satu baris untuk setiap baris tabel anak yang diambil. Misalnya, jika Anda membuat query
+    {@link android.provider.ContactsContract.Contacts.Entity} untuk satu nama kontak
+    dan semua baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk semua
+    kontak mentah bagi nama itu, Anda akan mendapatkan kembali {@link android.database.Cursor} berisi satu baris
+    untuk setiap baris {@link android.provider.ContactsContract.CommonDataKinds.Email}.
+</p>
+<p>
+    Entitas menyederhanakan query. Dengan entitas, Anda bisa mengambil semua data kontak untuk satu
+    kontak atau kontak mentah sekaligus, sebagai ganti harus membuat query tabel induk terlebih dahulu untuk mendapatkan
+    ID, lalu harus membuat query tabel anak dengan ID itu. Selain itu, Penyedia Kontak akan memproses
+    query terhadap entitas dalam satu transaksi, yang memastikan bahwa data yang diambil
+    konsisten secara internal.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Entitas biasanya tidak berisi semua kolom tabel induk dan
+    anak. Jika Anda mencoba menggunakan nama kolom yang tidak ada dalam daftar konstanta
+    nama kolom untuk entitas, Anda akan mendapatkan {@link java.lang.Exception}.
+</p>
+<p>
+    Cuplikan berikut menampilkan cara mengambil semua baris kontak mentah untuk sebuah kontak. Cuplikan ini
+    adalah bagian dari aplikasi lebih besar yang memiliki dua aktivitas, "main" dan "detail". Aktivitas utama
+    menampilkan daftar baris kontak; bila pengguna memilih satu baris, aktivitas akan mengirimkan ID-nya ke aktivitas
+    detail. Aktivitas detail menggunakan{@link android.provider.ContactsContract.Contacts.Entity}
+    untuk menampilkan semua baris data dari semua kontak mentah yang dikaitkan dengan kontak
+    terpilih.
+</p>
+<p>
+    Cuplikan ini diambil dari aktivitas "detail":
+</p>
+<pre>
+...
+    /*
+     * Appends the entity path to the URI. In the case of the Contacts Provider, the
+     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
+     */
+    mContactUri = Uri.withAppendedPath(
+            mContactUri,
+            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
+
+    // Initializes the loader identified by LOADER_ID.
+    getLoaderManager().initLoader(
+            LOADER_ID,  // The identifier of the loader to initialize
+            null,       // Arguments for the loader (in this case, none)
+            this);      // The context of the activity
+
+    // Creates a new cursor adapter to attach to the list view
+    mCursorAdapter = new SimpleCursorAdapter(
+            this,                        // the context of the activity
+            R.layout.detail_list_item,   // the view item containing the detail widgets
+            mCursor,                     // the backing cursor
+            mFromColumns,                // the columns in the cursor that provide the data
+            mToViews,                    // the views in the view item that display the data
+            0);                          // flags
+
+    // Sets the ListView's backing adapter.
+    mRawContactList.setAdapter(mCursorAdapter);
+...
+&#64;Override
+public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) {
+
+    /*
+     * Sets the columns to retrieve.
+     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
+     * DATA1 contains the first column in the data row (usually the most important one).
+     * MIMETYPE indicates the type of data in the data row.
+     */
+    String[] projection =
+        {
+            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
+            ContactsContract.Contacts.Entity.DATA1,
+            ContactsContract.Contacts.Entity.MIMETYPE
+        };
+
+    /*
+     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
+     * contact collated together.
+     */
+    String sortOrder =
+            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
+            " ASC";
+
+    /*
+     * Returns a new CursorLoader. The arguments are similar to
+     * ContentResolver.query(), except for the Context argument, which supplies the location of
+     * the ContentResolver to use.
+     */
+    return new CursorLoader(
+            getApplicationContext(),  // The activity's context
+            mContactUri,              // The entity content URI for a single contact
+            projection,               // The columns to retrieve
+            null,                     // Retrieve all the raw contacts and their data rows.
+            null,                     //
+            sortOrder);               // Sort by the raw contact ID.
+}
+</pre>
+<p>
+    Bila selesai dimuat, {@link android.app.LoaderManager} akan memicu callback ke
+    {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D)
+    onLoadFinished()}. Salah satu argumen masuk pada metode ini adalah
+    {@link android.database.Cursor} bersama hasil query. Dalam aplikasi Anda sendiri, Anda bisa memperoleh
+    data dari {@link android.database.Cursor} ini untuk menampilkannya atau menggunakannya lebih jauh.
+</p>
+<h3 id="Transactions">Modifikasi batch</h3>
+<p>
+    Bila memungkinkan, Anda harus menyisipkan, memperbarui, dan menghapus data dalam Penyedia Kontak dengan
+    "batch mode", dengan membuat {@link java.util.ArrayList} dari
+    objek-objek {@link android.content.ContentProviderOperation} dan memanggil
+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
+    Penyedia Kontak menjalankan semua operasi dalam satu
+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} transaksi,
+    modifikasi Anda tidak akan pernah meninggalkan repository kontak dalam keadaan
+    tidak konsisten. Modifikasi batch juga memudahkan penyisipan kontak mentah dan data detailnya
+    sekaligus.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Untuk memodifikasi <em>satu</em> kontak mentah, pertimbangkan untuk mengirim intent ke
+    aplikasi kontak perangkat daripada menangani modifikasi dalam aplikasi Anda.
+    Cara ini dijelaskan lebih detail di bagian
+    <a href="#Intents">Pengambilan dan modifikasi dengan intent</a>.
+</p>
+<h4>Yield point</h4>
+<p>
+    Modifikasi batch yang berisi operasi dalam jumlah besar bisa memblokir proses lain,
+    yang mengakibatkan pengalaman pengguna yang buruk secara keseluruhan. Untuk menata semua modifikasi yang ingin Anda
+    jalankan dalam sesedikit mungkin daftar terpisah, sambil mencegah modifikasi dari
+    memblokir sistem, Anda harus menetapkan <strong>yield point</strong> untuk satu atau beberapa operasi.
+    Yield point (titik hasil) adalah objek {@link android.content.ContentProviderOperation} yang mengatur
+    nilai {@link android.content.ContentProviderOperation#isYieldAllowed()}-nya ke
+    <code>true</code>. Bila menemui yield point, Penyedia Kontak akan menghentikan pekerjaannya untuk
+    membiarkan proses lain berjalan dan menutup transaksi saat ini. Bila dimulai lagi, penyedia akan
+    melanjutkan dengan operasi berikutnya di {@link java.util.ArrayList} dan memulai transaksi
+    baru.
+</p>
+<p>
+    Yield point memang menyebabkan lebih dari satu transaksi per panggilan ke
+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena
+    itu, Anda harus menetapkan yield point pada operasi terakhir untuk satu set baris terkait.
+    Misalnya, Anda harus menetapkan yield point pada operasi terakhir di satu set yang menambahkan
+    baris kontak mentah dan baris data terkait, atau operasi terakhir untuk satu set baris yang terkait
+    dengan satu kontak.
+</p>
+<p>
+    Yield point juga merupakan unit operasi atomis. Semua akses antara dua yield point bisa
+    saja berhasil atau gagal sebagai satu unit. Jika Anda mengatur yield point, operasi
+    atomis terkecil adalah seluruh batch operasi. Jika menggunakan yield point, Anda akan mencegah
+    operasi menurunkan kinerja sistem, sekaligus memastikan subset
+    operasi bersifat atomis.
+</p>
+<h4>Acuan balik modifikasi</h4>
+<p>
+    Saat Anda menyisipkan baris kontak mentah baru dan baris data terkaitnya sebagai satu set
+    objek {@link android.content.ContentProviderOperation}, Anda harus menautkan baris data ke
+    baris kontak mentah dengan memasukkan nilai
+    {@code android.provider.BaseColumns#_ID} kontak mentah sebagai
+    nilai {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Akan tetapi, nilai
+    ini tidak tersedia saat Anda membuat {@link android.content.ContentProviderOperation}
+    untuk baris data, karena Anda belum menerapkan
+    {@link android.content.ContentProviderOperation} untuk baris kontak mentah. Solusinya,
+     kelas {@link android.content.ContentProviderOperation.Builder} memiliki metode
+    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}.
+    Metode ini memungkinkan Anda menyisipkan atau mengubah kolom dengan
+    hasil dari operasi sebelumnya.
+</p>
+<p>
+    Metode {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
+    memiliki dua argumen:
+</p>
+    <dl>
+        <dt>
+            <code>key</code>
+        </dt>
+        <dd>
+            Kunci dari pasangan kunci-nilai. Nilai argumen ini harus berupa nama kolom
+            dalam tabel yang Anda modifikasi.
+        </dd>
+        <dt>
+            <code>previousResult</code>
+        </dt>
+        <dd>
+            Indeks berbasis 0 dari nilai pada larik
+            objek {@link android.content.ContentProviderResult} dari
+            {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Saat
+            operasi batch diterapkan, hasil tiap operasi akan disimpan dalam
+            larik hasil antara. Nilai <code>previousResult</code> adalah indeks
+            dari salah satu hasil ini, yang diambil dan disimpan bersama nilai <code>key</code>.
+ Cara ini memungkinkan Anda menyisipkan record kontak mentah baru dan mendapatkan kembali nilai
+            {@code android.provider.BaseColumns#_ID}-nya, lalu membuat "acuan balik" ke
+            nilai itu saat Anda menambahkan baris {@link android.provider.ContactsContract.Data}.
+            <p>
+                Seluruh larik hasil dibuat saat Anda memanggil
+                {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} untuk pertama kali,
+                dengan ukuran setara dengan ukuran {@link java.util.ArrayList} dari
+                objek {@link android.content.ContentProviderOperation} yang Anda sediakan. Akan tetapi, semua
+                elemen dalam larik hasil diatur ke <code>null</code>, dan jika Anda mencoba
+                melakukan acuan balik ke hasil untuk operasi yang belum diterapkan,
+{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
+                akan mengeluarkan {@link java.lang.Exception}.
+
+            </p>
+        </dd>
+    </dl>
+<p>
+    Cuplikan kode berikut menampilkan cara menyisipkan kontak mentah baru dan data secara batch. Cuplikan kode ini
+    menyertakan kode yang menetapkan yield point dan menggunakan acuan balik. Cuplikan kode ini adalah
+    versi perluasan dari metode<code>createContacEntry()</code>, yang merupakan bagian dari kelas
+    <code>ContactAdder</code> dalam
+    aplikasi contoh <code><a href="{@docRoot}resources/samples/ContactManager/index.html">
+    Contact Manager</a></code>.
+</p>
+<p>
+    Cuplikan pertama mengambil data kontak dari UI. Pada saat ini, pengguna sudah
+    memilih akun tempat kontak mentah baru harus ditambahkan.
+</p>
+<pre>
+// Creates a contact entry from the current UI values, using the currently-selected account.
+protected void createContactEntry() {
+    /*
+     * Gets values from the UI
+     */
+    String name = mContactNameEditText.getText().toString();
+    String phone = mContactPhoneEditText.getText().toString();
+    String email = mContactEmailEditText.getText().toString();
+
+    int phoneType = mContactPhoneTypes.get(
+            mContactPhoneTypeSpinner.getSelectedItemPosition());
+
+    int emailType = mContactEmailTypes.get(
+            mContactEmailTypeSpinner.getSelectedItemPosition());
+</pre>
+<p>
+    Cuplikan berikutnya membuat operasi untuk menyisipkan baris kontak mentah ke dalam
+    tabel {@link android.provider.ContactsContract.RawContacts}:
+</p>
+<pre>
+    /*
+     * Prepares the batch operation for inserting a new raw contact and its data. Even if
+     * the Contacts Provider does not have any data for this person, you can't add a Contact,
+     * only a raw contact. The Contacts Provider will then add a Contact automatically.
+     */
+
+     // Creates a new array of ContentProviderOperation objects.
+    ArrayList&lt;ContentProviderOperation&gt; ops =
+            new ArrayList&lt;ContentProviderOperation&gt;();
+
+    /*
+     * Creates a new raw contact with its account type (server type) and account name
+     * (user's account). Remember that the display name is not stored in this row, but in a
+     * StructuredName data row. No other data is required.
+     */
+    ContentProviderOperation.Builder op =
+            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
+            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
+
+    // Builds the operation and adds it to the array of operations
+    ops.add(op.build());
+</pre>
+<p>
+    Berikutnya, kode akan membuat baris data untuk baris-baris nama tampilan, telepon, dan email.
+</p>
+<p>
+    Setiap objek pembangun operasi menggunakan
+    {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}
+    untuk mendapatkan
+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Acuan menunjuk
+    balik ke objek {@link android.content.ContentProviderResult} dari operasi pertama,
+    yang menambahkan baris kontak mentah dan mengembalikan nilai {@code android.provider.BaseColumns#_ID}
+    barunya. Hasilnya, setiap data ditautkan secara otomatis oleh
+    {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}-nya
+    ke baris {@link android.provider.ContactsContract.RawContacts} baru yang memilikinya.
+</p>
+<p>
+    Objek {@link android.content.ContentProviderOperation.Builder} yang menambahkan baris email
+    diberi flag {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean)
+    withYieldAllowed()}, yang mengatur yield point:
+</p>
+<pre>
+    // Creates the display name for the new raw contact, as a StructuredName data row.
+    op =
+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+            /*
+             * withValueBackReference sets the value of the first argument to the value of
+             * the ContentProviderResult indexed by the second argument. In this particular
+             * call, the raw contact ID column of the StructuredName data row is set to the
+             * value of the result returned by the first operation, which is the one that
+             * actually adds the raw contact row.
+             */
+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+
+            // Sets the data row's MIME type to StructuredName
+            .withValue(ContactsContract.Data.MIMETYPE,
+                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+
+            // Sets the data row's display name to the name in the UI.
+            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
+
+    // Builds the operation and adds it to the array of operations
+    ops.add(op.build());
+
+    // Inserts the specified phone number and type as a Phone data row
+    op =
+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+            /*
+             * Sets the value of the raw contact id column to the new raw contact ID returned
+             * by the first operation in the batch.
+             */
+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+
+            // Sets the data row's MIME type to Phone
+            .withValue(ContactsContract.Data.MIMETYPE,
+                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
+
+            // Sets the phone number and type
+            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
+            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);
+
+    // Builds the operation and adds it to the array of operations
+    ops.add(op.build());
+
+    // Inserts the specified email and type as a Phone data row
+    op =
+            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+            /*
+             * Sets the value of the raw contact id column to the new raw contact ID returned
+             * by the first operation in the batch.
+             */
+            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+
+            // Sets the data row's MIME type to Email
+            .withValue(ContactsContract.Data.MIMETYPE,
+                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
+
+            // Sets the email address and type
+            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
+            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);
+
+    /*
+     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
+     * will yield priority to other threads. Use after every set of operations that affect a
+     * single contact, to avoid degrading performance.
+     */
+    op.withYieldAllowed(true);
+
+    // Builds the operation and adds it to the array of operations
+    ops.add(op.build());
+</pre>
+<p>
+    Cuplikan terakhir menampilkan panggilan ke
+    {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} yang
+    menyisipkan baris-baris kontak mentah dan data baru.
+</p>
+<pre>
+    // Ask the Contacts Provider to create a new contact
+    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
+            mSelectedAccount.getType() + ")");
+    Log.d(TAG,"Creating contact: " + name);
+
+    /*
+     * Applies the array of ContentProviderOperation objects in batch. The results are
+     * discarded.
+     */
+    try {
+
+            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
+    } catch (Exception e) {
+
+            // Display a warning
+            Context ctx = getApplicationContext();
+
+            CharSequence txt = getString(R.string.contactCreationFailure);
+            int duration = Toast.LENGTH_SHORT;
+            Toast toast = Toast.makeText(ctx, txt, duration);
+            toast.show();
+
+            // Log exception
+            Log.e(TAG, "Exception encountered while inserting contact: " + e);
+    }
+}
+</pre>
+<p>
+    Operasi batch juga memungkinkan Anda menerapkan <strong>kontrol konkurensi optimistis</strong>,
+    sebuah metode yang menerapkan transaksi modifikasi tanpa harus mengunci repository yang mendasari.
+    Untuk menggunakan metode ini, terapkan transaksi dan periksa modifikasi lain yang
+    mungkin telah dibuat bersamaan. Jika ternyata modifikasi tidak konsisten, Anda
+    mengembalikan transaksi ke kondisi semula dan mencobanya kembali.
+</p>
+<p>
+    Kontrol konkurensi optimistis berguna untuk perangkat seluler, apabila hanya ada satu pengguna setiap
+   kalinya, dan akses simultan ke repository data jarang terjadi. Karena penguncian tidak digunakan,
+    tidak ada waktu yang terbuang untuk memasang kunci atau menunggu transaksi lain untuk melepas kunci.
+</p>
+<p>
+    Untuk menggunakan kontrol konkurensi optimistis saat memperbarui satu baris
+    {@link android.provider.ContactsContract.RawContacts}, ikuti langkah-langkah ini:
+</p>
+<ol>
+    <li>
+        Ambil kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
+        kontak mentah bersama data lain yang Anda ambil.
+    </li>
+    <li>
+        Buat sebuah objek {@link android.content.ContentProviderOperation.Builder} yang cocok untuk
+        memberlakukan batasan, dengan menggunakan metode
+        {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Untuk URI konten,
+        gunakan {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
+        RawContacts.CONTENT_URI}
+        dengan {@code android.provider.BaseColumns#_ID} kontak mentah yang ditambahkan padanya.
+    </li>
+    <li>
+        Untuk objek {@link android.content.ContentProviderOperation.Builder}, panggil
+        {@link android.content.ContentProviderOperation.Builder#withValue(String, Object)
+        withValue()} untuk membandingkan kolom {@link android.provider.ContactsContract.SyncColumns#VERSION}
+        dengan nomor versi yang baru saja Anda ambil.
+    </li>
+    <li>
+        Untuk {@link android.content.ContentProviderOperation.Builder} yang sama, panggil
+        {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int)
+        withExpectedCount()} untuk memastikan bahwa hanya satu baris yang diuji oleh pernyataan ini.
+    </li>
+    <li>
+        Panggil {@link android.content.ContentProviderOperation.Builder#build()} untuk membuat
+        objek {@link android.content.ContentProviderOperation}, kemudian tambahkan objek ini sebagai
+        objek pertama di {@link java.util.ArrayList} yang Anda teruskan ke
+        {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}.
+    </li>
+    <li>
+        Terapkan transaksi batch.
+    </li>
+</ol>
+<p>
+    Jika baris kontak mentah diperbarui oleh operasi lain antara waktu Anda membaca baris dan
+    waktu Anda mencoba memodifikasinya, "asert" {@link android.content.ContentProviderOperation}
+    akan gagal, dan seluruh batch operasi akan dibatalkan. Anda nanti bisa memilih untuk mencoba ulang
+    batch atau melakukan tindakan lain.
+</p>
+<p>
+    Cuplikan berikut memperagakan cara membuat "asert"
+    {@link android.content.ContentProviderOperation} setelah membuat query satu kontak mentah yang menggunakan
+     {@link android.content.CursorLoader}:
+</p>
+<pre>
+/*
+ * The application uses CursorLoader to query the raw contacts table. The system calls this method
+ * when the load is finished.
+ */
+public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
+
+    // Gets the raw contact's _ID and VERSION values
+    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
+    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
+}
+
+...
+
+// Sets up a Uri for the assert operation
+Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);
+
+// Creates a builder for the assert operation
+ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);
+
+// Adds the assertions to the assert operation: checks the version and count of rows tested
+assertOp.withValue(SyncColumns.VERSION, mVersion);
+assertOp.withExpectedCount(1);
+
+// Creates an ArrayList to hold the ContentProviderOperation objects
+ArrayList ops = new ArrayList&lt;ContentProviderOperationg&gt;;
+
+ops.add(assertOp.build());
+
+// You would add the rest of your batch operations to "ops" here
+
+...
+
+// Applies the batch. If the assert fails, an Exception is thrown
+try
+    {
+        ContentProviderResult[] results =
+                getContentResolver().applyBatch(AUTHORITY, ops);
+
+    } catch (OperationApplicationException e) {
+
+        // Actions you want to take if the assert operation fails go here
+    }
+</pre>
+<h3 id="Intents">Pengambilan dan modifikasi dengan intent</h3>
+<p>
+    Mengirimkan intent ke aplikasi kontak perangkat memungkinkan Anda mengakses Penyedia Kontak
+    secara tidak langsung. Intent akan memulai UI aplikasi kontak perangkat, tempat pengguna bisa
+    melakukan pekerjaan yang terkait dengan kontak. Dengan tipe akses ini, pengguna bisa:
+    <ul>
+        <li>Memilih kontak dari daftar dan meneruskannya ke aplikasi untuk pekerjaan lebih jauh.</li>
+        <li>Mengedit data kontak yang ada.</li>
+        <li>Memasukkan kontak mentah baru untuk akun mereka.</li>
+        <li>Menghapus kontak atau data kontak.</li>
+    </ul>
+<p>
+    Jika pengguna menyisipkan atau memperbarui data, Anda bisa mengumpulkan data lebih dahulu dan mengirimkannya sebagai
+    bagian dari intent.
+</p>
+<p>
+    Bila Anda menggunakan intent untuk mengakses Penyedia Kontak melalui aplikasi kontak perangkat, Anda
+    tidak perlu menulis UI atau kode sendiri untuk mengakses penyedia. Anda juga tidak harus
+   meminta izin untuk membaca dari atau menulis ke penyedia. Aplikasi kontak perangkat bisa
+    mendelegasikan izin membaca untuk kontak kepada Anda, dan karena Anda membuat modifikasi pada
+    penyedia melalui aplikasi lain, Anda tidak perlu memiliki izin menulis.
+</p>
+<p>
+    Proses umum pengiriman intent untuk mengakses penyedia dijelaskan secara detail dalam panduan
+    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+    Dasar-Dasar Penyedia Konten</a> di bagian "Akses data melalui intent". Tindakan,
+    tipe MIME, dan nilai data yang Anda gunakan untuk tugas yang tersedia dirangkum dalam Tabel 4, sedangkan
+    nilai ekstra yang bisa Anda gunakan bersama
+    {@link android.content.Intent#putExtra(String, String) putExtra()} tercantum dalam
+    dokumentasi acuan untuk {@link android.provider.ContactsContract.Intents.Insert}:
+</p>
+<p class="table-caption" id="table4">
+  <strong>Tabel 4.</strong> Intent Penyedia Kontak.
+</p>
+<table style="width:75%">
+    <tr>
+        <th scope="col" style="width:10%">Tugas</th>
+        <th scope="col" style="width:5%">Tindakan</th>
+        <th scope="col" style="width:10%">Data</th>
+        <th scope="col" style="width:10%">Tipe MIME</th>
+        <th scope="col" style="width:25%">Catatan</th>
+    </tr>
+    <tr>
+        <td><strong>Memilih kontak dari daftar</strong></td>
+        <td>{@link android.content.Intent#ACTION_PICK}</td>
+        <td>
+            Salah satu dari:
+            <ul>
+                <li>
+{@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI},
+                    yang menampilkan daftar kontak.
+                </li>
+                <li>
+{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI},
+                    yang menampilkan daftar nomor telepon untuk kontak mentah.
+                </li>
+                <li>
+{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI
+StructuredPostal.CONTENT_URI},
+                    yang menampilkan daftar alamat pos untuk kontak mentah.
+                </li>
+                <li>
+{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI},
+                    yang menampilkan daftar alamat email untuk kontak baru.
+                </li>
+            </ul>
+        </td>
+        <td>
+            Tidak digunakan
+        </td>
+        <td>
+            Menampilkan daftar kontak mentah atau daftar data dari kontak mentah, sesuai dengan tipe
+            URI konten yang Anda sediakan.
+            <p>
+                Panggil
+         {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
+                yang menghasilkan URI konten dari baris terpilih. Bentuk URI adalah
+                URI konten tabel dengan <code>LOOKUP_ID</code> baris yang ditambahkan padanya.
+                Aplikasi kontak perangkat mendelegasikan izin membaca dan menulis untuk URI konten ini
+                selama masa pakai aktivitas Anda. Lihat panduan
+                <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+                Dasar-Dasar Penyedia Konten</a> untuk detail selengkapnya.
+            </p>
+        </td>
+    </tr>
+    <tr>
+        <td><strong>Menyisipkan kontak mentah baru</strong></td>
+        <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td>
+        <td>N/A</td>
+        <td>
+            {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
+            RawContacts.CONTENT_TYPE}, tipe MIME untuk satu set kontak mentah.
+        </td>
+        <td>
+            Menampilkan layar <strong>Add Contact</strong> aplikasi kontak perangkat. Nilai
+            ekstra yang Anda tambahkan ke intent akan ditampilkan. Jika dikirimkan bersama
+        {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
+            URI konten dari kontak mentah yang baru saja ditambahkan akan dikembalikan ke
+            {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
+           metode callback aktivitas Anda pada argumen {@link android.content.Intent}, di
+            bidang "data". Untuk mendapatkan nilainya, panggil {@link android.content.Intent#getData()}.
+        </td>
+    </tr>
+    <tr>
+        <td><strong>Mengedit kontak</strong></td>
+        <td>{@link android.content.Intent#ACTION_EDIT}</td>
+        <td>
+            {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} untuk
+            kontak. Aktivitas editor memungkinkan pengguna mengedit setiap data yang dikaitkan
+            dengan kontak ini.
+        </td>
+        <td>
+            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+            Contacts.CONTENT_ITEM_TYPE}, kontak tunggal.</td>
+        <td>
+            Menampilkan layar Edit Contact dalam aplikasi kontak. Nilai ekstra yang Anda tambahkan
+            ke intent akan ditampilkan. Bila pengguna mengklik <strong>Done</strong> untuk menyimpan
+            hasil edit, aktivitas Anda kembali ke latar depan.
+        </td>
+    </tr>
+    <tr>
+        <td><strong>Menampilkan picker yang juga bisa menambahkan data.</strong></td>
+        <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td>
+        <td>
+            N/A
+        </td>
+        <td>
+            {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE}
+        </td>
+         <td>
+            Intent ini selalu menampilkan layar picker aplikasi kontak. Pengguna bisa memilih
+            kontak untuk diedit, atau menambahkan kontak baru. Layar edit atau layar tambah
+            akan muncul, sesuai dengan pilihan pengguna, dan data ekstra yang Anda kirimkan dalam intent
+            akan ditampilkan. Jika aplikasi Anda menampilkan data kontak seperti email atau nomor telepon, gunakan
+            intent ini untuk memungkinkan pengguna menambahkan data ke kontak yang ada.
+
+            <p class="note">
+                <strong>Catatan:</strong> Tidak perlu mengirimkan nilai nama dalam ekstra intent ini,
+                karena pengguna selalu mengambil nama yang ada atau menambahkan nama baru. Lebih-lebih,
+                jika Anda mengirimkan nama, dan pengguna memilih untuk melakukan edit, aplikasi kontak akan
+                menampilkan nama yang Anda kirimkan, yang menimpa nilai sebelumnya. Jika pengguna tidak
+                menyadari hal ini dan menyimpan hasil edit, nilai lama akan hilang.
+            </p>
+         </td>
+    </tr>
+</table>
+<p>
+    Aplikasi kontak perangkat tidak memperbolehkan Anda menghapus kontak mentah atau datanya dengan
+    intent. Sebagai gantinya, untuk menghapus kontak mentah, gunakan
+    {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()}
+    atau {@link android.content.ContentProviderOperation#newDelete(Uri)
+    ContentProviderOperation.newDelete()}.
+</p>
+<p>
+    Cuplikan berikut menampilkan cara menyusun dan mengirimkan intent yang menyisipkan kontak dan data
+    mentah baru:
+</p>
+<pre>
+// Gets values from the UI
+String name = mContactNameEditText.getText().toString();
+String phone = mContactPhoneEditText.getText().toString();
+String email = mContactEmailEditText.getText().toString();
+
+String company = mCompanyName.getText().toString();
+String jobtitle = mJobTitle.getText().toString();
+
+// Creates a new intent for sending to the device's contacts application
+Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);
+
+// Sets the MIME type to the one expected by the insertion activity
+insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
+
+// Sets the new contact name
+insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);
+
+// Sets the new company and job title
+insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
+insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);
+
+/*
+ * Demonstrates adding data rows as an array list associated with the DATA key
+ */
+
+// Defines an array list to contain the ContentValues objects for each row
+ArrayList&lt;ContentValues&gt; contactData = new ArrayList&lt;ContentValues&gt;();
+
+
+/*
+ * Defines the raw contact row
+ */
+
+// Sets up the row as a ContentValues object
+ContentValues rawContactRow = new ContentValues();
+
+// Adds the account type and name to the row
+rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());
+rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());
+
+// Adds the row to the array
+contactData.add(rawContactRow);
+
+/*
+ * Sets up the phone number data row
+ */
+
+// Sets up the row as a ContentValues object
+ContentValues phoneRow = new ContentValues();
+
+// Specifies the MIME type for this data row (all data rows must be marked by their type)
+phoneRow.put(
+        ContactsContract.Data.MIMETYPE,
+        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+);
+
+// Adds the phone number and its type to the row
+phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
+
+// Adds the row to the array
+contactData.add(phoneRow);
+
+/*
+ * Sets up the email data row
+ */
+
+// Sets up the row as a ContentValues object
+ContentValues emailRow = new ContentValues();
+
+// Specifies the MIME type for this data row (all data rows must be marked by their type)
+emailRow.put(
+        ContactsContract.Data.MIMETYPE,
+        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
+);
+
+// Adds the email address and its type to the row
+emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
+
+// Adds the row to the array
+contactData.add(emailRow);
+
+/*
+ * Adds the array to the intent's extras. It must be a parcelable object in order to
+ * travel between processes. The device's contacts app expects its key to be
+ * Intents.Insert.DATA
+ */
+insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
+
+// Send out the intent to start the device's contacts app in its add contact activity.
+startActivity(insertIntent);
+</pre>
+<h3 id="DataIntegrity">Integritas data</h3>
+<p>
+    Karena repository kontak berisi data penting dan sensitif yang diharapkan pengguna agar
+    benar dan terbaru. Penyedia Kontak memiliki aturan yang didefinisikan dengan baik demi integritas data. Anda
+    bertanggung jawab untuk mematuhi aturan ini saat memodifikasi data kontak. Aturan-aturan penting itu
+    dicantumkan di sini:
+</p>
+<dl>
+    <dt>
+        Selalu tambahkan baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}
+        untuk setiap baris {@link android.provider.ContactsContract.RawContacts} yang Anda tambahkan.
+    </dt>
+    <dd>
+        Baris {@link android.provider.ContactsContract.RawContacts} tanpa
+        baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} dalam
+        tabel {@link android.provider.ContactsContract.Data} bisa menyebabkan masalah selama
+       agregasi.
+    </dd>
+    <dt>
+        Selalu tautkan baris {@link android.provider.ContactsContract.Data} baru ke baris
+        {@link android.provider.ContactsContract.RawContacts} induknya.
+    </dt>
+    <dd>
+        Baris {@link android.provider.ContactsContract.Data} yang tidak ditautkan ke
+        {@link android.provider.ContactsContract.RawContacts} tidak akan terlihat dalam aplikasi kontak
+        perangkat, dan itu bisa menimbulkan masalah dengan adaptor sinkronisasi.
+    </dd>
+    <dt>
+        Ubah data hanya untuk kontak mentah yang Anda miliki.
+    </dt>
+    <dd>
+        Ingatlah bahwa Penyedia Kontak biasanya mengelola data dari berbagai
+        tipe akun/layanan online. Anda harus memastikan bahwa aplikasi Anda hanya memodifikasi
+        atau menghapus data untuk baris milik Anda, dan bahwa aplikasi hanya menyisipkan data dengan
+        tipe akun dan nama yang Anda kontrol.
+    </dd>
+    <dt>
+        Selalu gunakan konstanta yang didefinisikan dalam {@link android.provider.ContactsContract} dan
+        subkelasnya untuk otoritas, URI konten, URI path, nama kolom, tipe MIME, dan
+        nilai {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE}.
+    </dt>
+    <dd>
+        Menggunakan konstanta ini membantu Anda menghindari kesalahan. Anda juga akan diberi tahu dengan peringatan
+        compiler jika salah satu konstanta sudah usang.
+    </dd>
+</dl>
+<h3 id="CustomData">Baris data custom</h3>
+<p>
+    Dengan membuat dan menggunakan tipe MIME custom sendiri, Anda bisa menyisipkan, mengedit, menghapus, dan mengambil
+    baris data sendiri dalam tabel {@link android.provider.ContactsContract.Data}. Baris Anda
+    dibatasi untuk menggunakan kolom yang didefinisikan dalam
+    {@link android.provider.ContactsContract.DataColumns}, meskipun Anda bisa memetakan nama kolom
+    bertipe spesifik sendiri ke nama kolom default. Dalam aplikasi kontak perangkat,
+    data untuk baris Anda ditampilkan, tetapi tidak bisa diedit atau dihapus, dan pengguna tidak bisa menambahkan
+    data lain. Untuk memudahkan pengguna mengubah baris data custom Anda, Anda harus menyediakan aktivitas
+    editor dalam aplikasi Anda sendiri.
+</p>
+<p>
+    Untuk menampilkan data custom, sediakan file <code>contacts.xml</code> berisi elemen
+    <code>&lt;ContactsAccountType&gt;</code> dan satu atau beberapa elemen anak
+    <code>&lt;ContactsDataKind&gt;</code>. Hal ini dijelaskan lebih detail di
+    bagian <a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; element</code></a>.
+</p>
+<p>
+    Untuk mengetahui selengkapnya tentang tipe MIME custom, bacalah panduan
+    <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+    Membuat Penyedia Konten</a>.
+</p>
+<h2 id="SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</h2>
+<p>
+    Penyedia Kontak didesain khusus untuk menangani <strong>sinkronisasi</strong>
+    data kontak antara perangkat dan layanan online. Hal ini memungkinkan pengguna mengunduh
+    data yang ada dari perangkat baru dan mengunggah data yang ada ke akun baru.
+    Sinkronisasi juga memastikan bahwa pengguna memiliki data terbaru, apa pun
+    sumber penambahan dan perubahan itu. Keuntungan lain dari sinkronisasi adalah membuat
+    data kontak tersedia sekalipun perangkat tidak terhubung ke jaringan.
+</p>
+<p>
+    Walaupun Anda bisa menerapkan sinkronisasi dengan berbagai cara, sistem Android menyediakan
+    kerangka kerja sinkronisasi plug-in yang mengotomatiskan tugas-tugas berikut:
+    <ul>
+
+    <li>
+        Memeriksa ketersediaan jaringan.
+    </li>
+    <li>
+        Menjadwalkan dan menjalankan sinkronisasi, berdasarkan preferensi pengguna.
+    </li>
+    <li>
+        Memulai kembali sinkronisasi yang telah berhenti.
+    </li>
+    </ul>
+<p>
+    Untuk menggunakan kerangka kerja ini, Anda harus menyediakan plug-in adaptor sinkronisasi. Setiap adaptor sinkronisasi bersifat unik bagi
+    layanan dan penyedia konten, tetapi mampu menangani beberapa nama akun untuk layanan yang sama. Kerangka
+    kerja ini juga memungkinkan beberapa adaptor sinkronisasi untuk layanan dan penyedia yang sama.
+</p>
+<h3 id="SyncClassesFiles">Kelas dan file adaptor sinkronisasi</h3>
+<p>
+    Anda mengimplementasikan adaptor sinkronisasi sebagai subkelas
+    {@link android.content.AbstractThreadedSyncAdapter} dan menginstalnya sebagai bagian dari aplikasi
+    Android. Sistem akan mempelajari adaptor sinkronisasi dari elemen-elemen di manifes
+     aplikasi Anda dan dari file XML khusus yang ditunjuk oleh manifes. File XML mendefinisikan
+    tipe akun untuk layanan online dan otoritas untuk penyedia konten, yang bersama-sama
+    mengidentifikasi adaptor secara unik. Adaptor sinkronisasi tidak menjadi aktif hingga pengguna menambahkan
+    akun untuk tipe akun adaptor sinkronisasi dan memungkinkan sinkronisasi untuk penyedia
+    konten yang disinkronkan dengan adaptor sinkronisasi.  Pada saat itu, sistem mulai mengelola adaptor,
+    memanggilnya seperlunya untuk menyinkronkan antara penyedia konten dan server.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Menggunakan tipe akun sebagai bagian dari identifikasi adaptor sinkronisasi memungkinkan
+    sistem mendeteksi dan menghimpun adaptor-adaptor sinkronisasi yang mengakses berbagai layanan dari
+    organisasi yang sama. Misalnya, adaptor sinkronisasi untuk semua layanan online Google semuanya memiliki tipe akun
+    yang sama <code>com.google</code>. Bila pengguna menambahkan akun Google ke perangkatnya, semua
+    adaptor sinkronisasi yang terinstal untuk layanan Google akan dicantumkan bersama; setiap adaptor sinkronisasi
+    yang tercantum akan menyinkronkan diri dengan berbagai penyedia konten pada perangkat.
+</p>
+<p>
+    Karena sebagian besar layanan mengharuskan pengguna untuk memeriksa identitas sebelum mengakses
+    data, sistem Android menawarkan kerangka kerja autentikasi yang serupa dengan, dan sering kali
+    digunakan bersama, kerangka kerja adaptor sinkronisasi. Kerangka kerja autentikasi menggunakan
+    autentikator plug-in yang merupakan subkelas
+    {@link android.accounts.AbstractAccountAuthenticator}. Autentikator memeriksa
+    identitas pengguna dalam langkah-langkah berikut:
+    <ol>
+        <li>
+            Mengumpulkan nama pengguna, kata sandi, atau informasi serupa (
+            <strong>kredensial</strong> pengguna).
+        </li>
+        <li>
+            Mengirimkan kredensial ke layanan
+        </li>
+        <li>
+            Memeriksa balasan layanan.
+        </li>
+    </ol>
+<p>
+    Jika layanan menerima kredensial, autentikator bisa
+    menyimpan kredensial itu untuk digunakan nanti. Karena kerangka kerja autentikator plug-in,
+    {@link android.accounts.AccountManager} bisa menyediakan akses ke setiap token autentikasi yang didukung suatu autentikator
+    dan dipilihnya untuk diekspos, seperti token autentikasi OAuth2.
+</p>
+<p>
+    Meskipun autentikasi tidak diharuskan, sebagian besar layanan kontak menggunakannya.
+    Akan tetapi, Anda tidak wajib menggunakan kerangka kerja autentikasi Android untuk melakukan autentikasi.
+</p>
+<h3 id="SyncAdapterImplementing">Implementasi adaptor sinkronisasi</h3>
+<p>
+    Untuk mengimplementasikan adaptor sinkronisasi bagi Penyedia Kontak, perlu Anda memulai dengan membuat
+    aplikasi Android yang berisi elemen-elemen berikut:
+</p>
+    <dl>
+        <dt>
+            Komponen {@link android.app.Service} yang merespons permintaan sistem untuk
+            mengikat ke adaptor sinkronisasi.
+        </dt>
+        <dd>
+            Bila sistem ingin menjalankan sinkronisasi, sistem akan memanggil metode
+            {@link android.app.Service#onBind(Intent) onBind()} layanan untuk mendapatkan
+            {@link android.os.IBinder} bagi adaptor sinkronisasi. Hal ini memungkinkan sistem melakukan
+            panggilan lintas proses ke metode adaptor.
+            <p>
+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+               Sample Sync Adapter</a>, nama kelas layanan ini adalah
+                <code>com.example.android.samplesync.syncadapter.SyncService</code>.
+            </p>
+        </dd>
+        <dt>
+            Adaptor sinkronisasi yang sesungguhnya, diimplementasikan sebagai subkelas konkret dari
+            {@link android.content.AbstractThreadedSyncAdapter}.
+        </dt>
+        <dd>
+            Kelas ini melakukan pekerjaan mengunduh data dari server, mengunggah data ke
+            perangkat, dan menyelesaikan konflik. Pekerjaan utama adaptor
+            diselesaikan dengan metode {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
+            Account, Bundle, String, ContentProviderClient, SyncResult)
+            onPerformSync()}. Instance kelas ini harus dibuat sebagai singleton.
+            <p>
+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+               Sample Sync Adapter</a>, adaptor sinkronisasi didefinisikan dalam kelas
+                <code>com.example.android.samplesync.syncadapter.SyncAdapter</code>.
+            </p>
+        </dd>
+        <dt>
+            Subkelas {@link android.app.Application}.
+        </dt>
+        <dd>
+            Kelas ini berfungsi sebagai pabrik untuk singleton adaptor sinkronisasi. Gunakan
+            metode {@link android.app.Application#onCreate()} untuk membuat instance adaptor sinkronisasi , dan
+            menyediakan metode "getter" statis untuk mengembalikan singleton ke
+            metode {@link android.app.Service#onBind(Intent) onBind()} dari layanan
+            adaptor sinkronisasi.
+        </dd>
+        <dt>
+            <strong>Opsional:</strong> Komponen {@link android.app.Service} yang merespons
+            permintaan dari sistem untuk autentikasi pengguna.
+        </dt>
+        <dd>
+            {@link android.accounts.AccountManager} memulai layanan ini untuk memulai proses
+            autentikasi. Metode {@link android.app.Service#onCreate()} layanan membuat instance
+            objek autentikator. Bila sistem ingin mengautentikasi akun pengguna untuk
+            adaptor sinkronisasi aplikasi, sistem akan memanggil metode
+{@link android.app.Service#onBind(Intent) onBind()}            layanan guna mendapatkan
+            {@link android.os.IBinder} bagi autentikator. Hal ini memungkinkan sistem melakukan
+            panggilan lintas proses ke metode autentikator.
+            <p>
+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+               Sample Sync Adapter</a>, nama kelas layanan ini adalah
+                <code>com.example.android.samplesync.authenticator.AuthenticationService</code>.
+            </p>
+        </dd>
+        <dt>
+            <strong>Opsional:</strong> Subkelas konkret
+            {@link android.accounts.AbstractAccountAuthenticator} yang menangani permintaan
+            autentikasi.
+        </dt>
+        <dd>
+            Kelas ini menyediakan metode yang dipicu {@link android.accounts.AccountManager}
+            untuk mengautentikasi kredensial pengguna dengan layanan. Detail
+            proses autentikasi sangat bervariasi, berdasarkan teknologi server yang digunakan. Anda harus
+            mengacu ke dokumentasi bagi perangkat lunak server untuk mengetahui selengkapnya tentang autentikasi.
+            <p>
+                Dalam contoh aplikasi <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+               Sample Sync Adapter</a>, autentikator didefinisikan dalam kelas
+                <code>com.example.android.samplesync.authenticator.Authenticator</code>.
+            </p>
+        </dd>
+        <dt>
+            File XML yang mendefinisikan adaptor sinkronisasi dan autentikator bagi sistem.
+        </dt>
+        <dd>
+            Komponen-komponen layanan adaptor sinkronisasi dan autentikator
+            didefinisikan dalam elemen-elemen
+<code>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code>
+            di manifes aplikasi. Elemen-elemen ini
+            berisi
+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
+elemen anak yang menyediakan data tertentu ke
+            sistem:
+            <ul>
+                <li>
+                    Elemen
+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
+                    untuk layanan adaptor sinkronisasi menunjuk ke
+                    file XML <code>res/xml/syncadapter.xml</code>. Pada gilirannya, file ini mendefinisikan
+                    URI untuk layanan web yang akan disinkronkan dengan Penyedia Kontak,
+                    dan tipe akun untuk layanan web.
+                </li>
+                <li>
+                    <strong>Opsional:</strong> Elemen
+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code>
+                   untuk autentikator menunjuk ke file XML
+                    <code>res/xml/authenticator.xml</code>. Pada gilirannya, file ini menetapkan
+                    tipe akun yang didukung autentikator, serta sumber daya UI yang
+                    muncul selama proses autentikasi. Tipe akun yang ditetapkan dalam elemen ini
+                    harus sama dengan tipe akun yang ditetapkan untuk adaptor
+                    sinkronisasi.
+                </li>
+            </ul>
+        </dd>
+    </dl>
+<h2 id="SocialStream">Data Aliran Sosial</h2>
+<p>
+    Tabel-tabel {@code android.provider.ContactsContract.StreamItems} dan
+    {@code android.provider.ContactsContract.StreamItemPhotos}
+    mengelola data yang masuk dari jaringan sosial. Anda bisa menulis adaptor sinkronisasi yang menambahkan data aliran
+    dari jaringan Anda sendiri ke tabel-tabel ini, atau Anda bisa membaca data aliran dari tabel-tabel ini dan
+    menampilkannya dalam aplikasi sendiri, atau keduanya. Dengan fitur-fitur ini, layanan dan aplikasi
+    jaringan sosial Anda bisa diintegrasikan ke dalam pengalaman jaringan sosial Android.
+</p>
+<h3 id="StreamText">Teks aliran sosial</h3>
+<p>
+    Item aliran selalu dikaitkan dengan kontak mentah.
+    {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} menautkan ke
+    nilai <code>_ID</code> untuk kontak mentah. Tipe akun dan nama akun kontak
+    mentah juga disimpan dalam baris item aliran.
+</p>
+<p>
+    Simpanlah data dari aliran Anda dalam kolom-kolom berikut:
+</p>
+<dl>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE}
+    </dt>
+    <dd>
+        <strong>Diperlukan.</strong> Tipe akun pengguna untuk kontak mentah yang dikaitkan dengan
+        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME}
+    </dt>
+    <dd>
+        <strong>Diperlukan.</strong> Nama akun pengguna untuk kontak mentah yang dikaitkan dengan
+        item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran.
+    </dd>
+    <dt>
+        Kolom identifier
+    </dt>
+    <dd>
+        <strong>Diperlukan.</strong> Anda harus memasukkan kolom identifier berikut saat
+        menyisipkan item aliran:
+        <ul>
+            <li>
+                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:
+                Nilai {@code android.provider.BaseColumns#_ID} kontak yang dikaitkan dengan item aliran
+                ini.
+            </li>
+            <li>
+                {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}:
+                Nilai {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
+                kontak yang dikaitkan dengan item aliran ini.
+            </li>
+            <li>
+                {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:
+                Nilai {@code android.provider.BaseColumns#_ID} kontak mentah yang dikaitkan dengan item aliran
+                ini.
+            </li>
+        </ul>
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
+    </dt>
+    <dd>
+        Opsional. Menyimpan informasi rangkuman yang bisa Anda tampilkan di awal item aliran.
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemsColumns#TEXT}
+    </dt>
+    <dd>
+        Teks item aliran, baik konten yang diposting oleh sumber item,
+        maupun keterangan beberapa tindakan yang menghasilkan item aliran. Kolom ini bisa berisi
+        sembarang gambar sumber daya pemformatan dan tertanam yang bisa dirender oleh
+        {@link android.text.Html#fromHtml(String) fromHtml()}. Penyedia bisa memotong atau
+        menghapus konten yang panjang, tetapi penyedia akan mencoba menghindari memutus tag.
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}
+    </dt>
+    <dd>
+        String teks berisi waktu item aliran yang disisipkan atau diperbarui, berupa
+        <em>milidetik</em> sejak waktu patokan. Aplikasi yang menyisipkan atau memperbarui item aliran
+        bertanggung jawab memelihara kolom ini; aplikasi tidak dipelihara secara otomatis oleh
+        Penyedia Kontak.
+    </dd>
+</dl>
+<p>
+    Untuk menampilkan informasi pengidentifikasi item aliran Anda, gunakan
+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON},
+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}, dan
+    {@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} untuk menautkan ke sumber daya
+    dalam aplikasi Anda.
+</p>
+<p>
+    Tabel {@code android.provider.ContactsContract.StreamItems} juga berisi kolom-kolom
+    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} hingga
+    {@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} untuk penggunaan eksklusif oleh
+    adaptor sinkronisasi.
+</p>
+<h3 id="StreamPhotos">Foto aliran sosial</h3>
+<p>
+   Tabel {@code android.provider.ContactsContract.StreamItemPhotos} menyimpan foto-foto yang dikaitkan
+   dengan item aliran. Kolom
+{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID}   tabel ini
+   menautkan ke nilai dalam kolom {@code android.provider.BaseColumns#_ID}
+   tabel {@code android.provider.ContactsContract.StreamItems}. Acuan foto disimpan dalam
+   tabel pada kolom-kolom ini:
+</p>
+<dl>
+    <dt>
+        Kolom {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (BLOB).
+    </dt>
+    <dd>
+        Representasi biner foto, yang diubah ukurannya oleh penyedia untuk penyimpanan dan tampilan.
+        Kolom ini tersedia untuk kompatibilitas ke belakang dengan versi Penyedia Kontak
+        sebelumnya yang menggunakannya untuk menyimpan foto. Akan tetapi, pada versi saat ini
+        Anda tidak boleh menggunakan kolom ini untuk menyimpan foto. Sebagai gantinya, gunakan
+         {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} atau
+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (keduanya
+        dijelaskan dalam poin-poin berikut) untuk menyimpan foto di file. Kolom ini sekarang
+        berisi thumbnail foto, yang tersedia untuk dibaca.
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID}
+    </dt>
+    <dd>
+        Identifier numerik foto untuk kontak mentah. Tambahkan nilai ini ke konstanta
+        {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI}
+        untuk mendapatkan URI konten yang menunjuk ke satu file foto, kemudian panggil
+        {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
+        openAssetFileDescriptor()} untuk mendapatkan handle ke file foto.
+    </dd>
+    <dt>
+        {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}
+    </dt>
+    <dd>
+        URI konten menunjuk langsung ke file foto untuk foto yang diwakili oleh baris ini.
+        Panggillah {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
+        openAssetFileDescriptor()} dengan URI ini untuk mendapatkan handle ke file foto.
+    </dd>
+</dl>
+<h3 id="SocialStreamTables">Menggunakan tabel aliran sosial</h3>
+<p>
+    Tabel-tabel ini sama fungsinya dengan tabel-tabel utama lainnya dalam Penyedia Kontak, kecuali:
+</p>
+    <ul>
+        <li>
+            Tabel-tabel ini memerlukan izin akses tambahan. Untuk membaca dari tabel, aplikasi Anda
+            harus memiliki izin {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Untuk memodifikasi
+            tabel, aplikasi Anda harus memiliki izin
+            {@code android.Manifest.permission#WRITE_SOCIAL_STREAM}.
+        </li>
+        <li>
+            Untuk tabel {@code android.provider.ContactsContract.StreamItems}, jumlah baris
+            yang disimpan bagi setiap kontak mentah adalah terbatas. Setelah batasnya tercapai,
+            Penyedia Kontak akan membuat ruang untuk baris item aliran baru dengan menghapus secara otomatis
+            baris yang memiliki
+            {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} terlama. Untuk mendapatkan
+            batas, keluarkan query ke URI konten
+            {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Anda bisa membiarkan
+            semua argumen selain URI konten diatur ke <code>null</code>. Query
+            menghasilkan sebuah Kursor yang berisi baris tunggal, dengan kolom tunggal
+            {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}.
+        </li>
+    </ul>
+
+<p>
+    Kelas {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} mendefinisikan
+    subtabel {@code android.provider.ContactsContract.StreamItemPhotos} yang berisi
+    baris foto untuk satu item aliran.
+</p>
+<h3 id="SocialStreamInteraction">Interaksi aliran sosial</h3>
+<p>
+    Data aliran sosial yang dikelola oleh Penyedia Kontak, bersama aplikasi kontak
+    perangkat, menawarkan cara andal untuk menghubungkan sistem jaringan sosial Anda
+    dengan kontak yang ada. Tersedia fitur-fitur berikut:
+</p>
+    <ul>
+        <li>
+            Dengan menyinkronkan layanan jaringan sosial ke Penyedia Kontak dengan adaptor
+            sinkronisasi, Anda bisa mengambil aktivitas terbaru untuk kontak pengguna dan menyimpannya dalam tabel-tabel
+             {@code android.provider.ContactsContract.StreamItems} dan
+            {@code android.provider.ContactsContract.StreamItemPhotos} untuk digunakan nanti.
+        </li>
+        <li>
+            Selain sinkronisasi rutin, Anda bisa memicu adaptor sinkronisasi agar mengambil
+            data tambahan bila pengguna memilih sebuah kontak untuk ditampilkan. Hal ini memungkinkan adaptor sinkronisasi Anda
+            mengambil foto resolusi tinggi dan item aliran terbaru untuk kontak.
+        </li>
+        <li>
+            Dengan mendaftarkan pemberitahuan pada aplikasi kontak perangkat dan Penyedia Kontak,
+            Anda bisa <em>menerima</em> intent saat kontak ditampilkan, dan pada saat itu
+            memperbarui status kontak dari layanan Anda. Pendekatan ini mungkin lebih cepat dan menggunakan
+            bandwidth lebih sedikit daripada melakukan sinkronisasi penuh dengan adaptor sinkronisasi.
+        </li>
+        <li>
+            Pengguna bisa menambahkan kontak ke layanan jaringan sosial Anda sambil melihat kontak
+            dalam aplikasi kontak perangkat. Anda mengaktifkannya dengan fitur "invite contact",
+            yang Anda aktifkan dengan kombinasi aktivitas yang menambahkan kontak yang ada ke jaringan
+           Anda, dan file XML yang menyediakan aplikasi kontak perangkat dan
+            Penyedia Kontak dengan detail aplikasi Anda.
+        </li>
+    </ul>
+<p>
+    Sinkronisasi rutin item aliran dengan Penyedia Kontak sama dengan
+    sinkronisasi lainnya. Untuk mengetahui selengkapnya tentang sinkronisasi, lihat bagian
+    <a href="#SyncAdapters">Adaptor Sinkronisasi Penyedia Kontak</a>. Mendaftarkan pemberitahuan dan
+    mengundang kontak dibahas dalam dua bagian berikutnya.
+</p>
+<h4>Pendaftaran untuk menangani tampilan jaringan sosial</h4>
+<p>
+    Untuk mendaftarkan adaptor sinkronisasi agar menerima pemberitahuan saat pengguna menampilkan kontak
+    yang dikelola oleh adaptor sinkronisasi Anda:
+</p>
+<ol>
+    <li>
+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Dalam file ini, tambahkan elemen
+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Untuk mendaftarkan layanan yang diberitahukan saat pengguna membuka halaman detail kontak dalam
+        aplikasi kontak perangkat, tambahkan atribut
+        <code>viewContactNotifyService="<em>serviceclass</em>"</code> ke elemen, dengan
+        <code><em>serviceclass</em></code> sebagai nama kelas mutlak (fully qualified) dari layanan
+        yang seharusnya menerima intent dari aplikasi kontak perangkat. Untuk layanan
+        notifier, gunakan kelas yang memperluas {@link android.app.IntentService}, guna memudahkan layanan
+        untuk menerima intent. Data dalam intent yang masuk berisi URI konten dari kontak
+        mentah yang diklik pengguna. Untuk layanan notifier, Anda bisa mengikatnya ke kemudian memanggil
+        adaptor sinkronisasi Anda untuk memperbarui data bagi kontak mentah.
+    </li>
+</ol>
+<p>
+    Untuk mendaftarkan aktivitas agar dipanggil saat pengguna mengklik item aliran atau foto atau keduanya:
+</p>
+<ol>
+    <li>
+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Dalam file ini, tambahkan elemen
+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada item aliran dalam
+        aplikasi kontak perangkat, tambahkan atribut
+        <code>viewStreamItemActivity="<em>activityclass</em>"</code> ke elemen, dengan
+        <code><em>activityclass</em></code> sebagai nama kelas mutlak (fully-qualified) dari aktivitas
+        yang harus menerima intent dari aplikasi kontak perangkat.
+    </li>
+    <li>
+        Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada foto aliran dalam
+        aplikasi kontak perangkat, tambahkan atribut
+        <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> ke elemen, dengan
+        <code><em>activityclass</em></code> adalah kelas nama mutlak aktivitas
+        yang harus menerima intent dari aplikasi kontak perangkat.
+    </li>
+</ol>
+<p>
+    Elemen <code>&lt;ContactsAccountType&gt;</code> dijelaskan lebih detail di
+    bagian <a href="#SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</a>.
+</p>
+<p>
+    Intent yang masuk berisi URI konten dari materi atau foto yang diklik pengguna.
+    Untuk mendapatkan aktivitas terpisah bagi item teks dan foto, gunakan kedua atribut dalam file yang sama.
+</p>
+<h4>Berinteraksi dengan layanan jaringan sosial Anda</h4>
+<p>
+    Pengguna tidak harus meninggalkan aplikasi perangkat kontak untuk mengundang kontak ke situs
+    jaringan sosial Anda. Sebagai gantinya, Anda bisa meminta aplikasi kontak perangkat mengirimkan intent untuk mengundang
+    kontak ke salah satu aktivitas Anda. Untuk mempersiapkannya:
+</p>
+<ol>
+    <li>
+        Buat file yang bernama <code>contacts.xml</code> dalam direktori <code>res/xml/</code>
+        proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Dalam file ini, tambahkan elemen
+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code>.
+        Jika elemen ini sudah ada, langkah ini boleh dilewati.
+    </li>
+    <li>
+        Tambahkan atribut-atribut berikut:
+        <ul>
+            <li><code>inviteContactActivity="<em>activityclass</em>"</code></li>
+            <li>
+                <code>inviteContactActionLabel="&#64;string/<em>invite_action_label</em>"</code>
+            </li>
+        </ul>
+        Nilai <code><em>activityclass</em></code> adalah nama kelas mutlak
+        aktivitas yang harus menerima intent ini. Nilai <code><em>invite_action_label</em></code>
+        adalah string teks yang ditampilkan dalam menu <strong>Add Connection</strong> dalam
+        aplikasi kontak perangkat.
+    </li>
+</ol>
+<p class="note">
+    <strong>Catatan:</strong> <code>ContactsSource</code> adalah nama tag yang sudah usang untuk
+    <code>ContactsAccountType</code>.
+</p>
+<h3 id="ContactsFile">Acuan contacts.xml</h3>
+<p>
+    File <code>contacts.xml</code> berisi elemen XML yang mengontrol interaksi adaptor sinkronisasi
+    Anda dan aplikasi dengan aplikasi kontak dan Penyedia Kontak. Elemen-elemen ini
+    dijelaskan di bagian-bagian selanjutnya.
+</p>
+<h4 id="SocialStreamAcctType">Elemen &lt;ContactsAccountType&gt;</h4>
+<p>
+    Elemen <code>&lt;ContactsAccountType&gt;</code> mengontrol interaksi aplikasi
+    Anda dengan aplikasi kontak. Sintaksnya adalah sebagai berikut:
+</p>
+<pre>
+&lt;ContactsAccountType
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        inviteContactActivity="<em>activity_name</em>"
+        inviteContactActionLabel="<em>invite_command_text</em>"
+        viewContactNotifyService="<em>view_notify_service</em>"
+        viewGroupActivity="<em>group_view_activity</em>"
+        viewGroupActionLabel="<em>group_action_text</em>"
+        viewStreamItemActivity="<em>viewstream_activity_name</em>"
+        viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"&gt;
+</pre>
+<p>
+    <strong>dimuat dalam:</strong>
+</p>
+<p>
+    <code>res/xml/contacts.xml</code>
+</p>
+<p>
+    <strong>bisa berisi:</strong>
+</p>
+<p>
+    <strong><code>&lt;ContactsDataKind&gt;</code></strong>
+</p>
+<p>
+    <strong>Keterangan:</strong>
+</p>
+<p>
+    Mendeklarasikan komponen Android dan label UI yang memungkinkan pengguna mengundang salah satu kontak ke
+    jaringan sosial, memberi tahu pengguna bila salah satu aliran jaringan sosial diperbarui, dan
+    seterusnya.
+</p>
+<p>
+    Perhatikan bahwa awalan atribut <code>android:</code> tidak perlu untuk atribut-atribut
+    <code>&lt;ContactsAccountType&gt;</code>.
+</p>
+<p>
+    <strong>Atribut:</strong>
+</p>
+<dl>
+    <dt>{@code inviteContactActivity}</dt>
+    <dd>
+        Nama kelas mutlak aktivitas dalam aplikasi yang Anda ingin
+        aktifkan bila pengguna memilih <strong>Add connection</strong> dari aplikasi kontak
+        perangkat.
+    </dd>
+    <dt>{@code inviteContactActionLabel}</dt>
+    <dd>
+        String teks yang ditampilkan untuk aktivitas yang ditetapkan dalam
+        {@code inviteContactActivity}, dalam menu <strong>Add connection</strong>.
+        Misalnya, Anda bisa menggunakan string "Ikuti di jaringan saya". Anda bisa menggunakan identifier sumber daya
+        string untuk tabel ini.
+    </dd>
+    <dt>{@code viewContactNotifyService}</dt>
+    <dd>
+        Nama kelas mutlak layanan dalam aplikasi Anda yang harus menerima
+        pemberitahuan saat pengguna menampilkan kontak. Pemberitahuan ini dikirimkan oleh aplikasi kontak
+        perangkat; hal ini memungkinkan aplikasi Anda menunda operasi yang banyak memproses data
+        hingga dibutuhkan. Misalnya, aplikasi Anda bisa merespons pemberitahuan ini
+        dengan membaca dalam dan menampilkan foto resolusi tinggi kontak dan item aliran sosial
+        terbaru. Fitur ini dijelaskan lebih detail di bagian
+        <a href="#SocialStreamInteraction">Interaksi aliran sosial</a>. Anda bisa melihat
+        contoh layanan pemberitahuan dalam file <code>NotifierService.java</code> dalam contoh aplikasi
+        <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a>.
+
+    </dd>
+    <dt>{@code viewGroupActivity}</dt>
+    <dd>
+        Nama kelas mutlak aktivitas dalam aplikasi yang bisa menampilkan
+        informasi grup. Bila pengguna mengklik label grup dalam aplikasi
+        kontak perangkat, UI aktivitas ini akan ditampilkan.
+    </dd>
+    <dt>{@code viewGroupActionLabel}</dt>
+    <dd>
+        Label yang ditampilkan aplikasi kontak untuk kontrol UI yang memungkinkan
+        pengguna melihat grup dalam aplikasi Anda.
+        <p>
+            Misalnya, jika Anda menginstal aplikasi Google+ di perangkat dan menyinkronkan
+            Google+ dengan aplikasi kontak, Anda akan melihat lingkaran Google+ tercantum sebagai grup
+            dalam tab <strong>Groups</strong> aplikasi kontak Anda. Jika Anda mengklik
+            lingkaran Google+, Anda akan melihat orang-orang di lingkaran itu tercantum sebagai satu "grup". Di atas
+            tampilan, Anda akan melihat ikon Google+; jika mengklik ikon itu, kontrol akan beralih ke
+            aplikasi Google+. Aplikasi kontak melakukan ini dengan
+            {@code viewGroupActivity}, yang menggunakan ikon Google+ sebagai nilai
+            {@code viewGroupActionLabel}.
+        </p>
+        <p>
+            Identifier sumber daya string diperbolehkan untuk atribut ini.
+        </p>
+    </dd>
+    <dt>{@code viewStreamItemActivity}</dt>
+    <dd>
+        Nama kelas mutlak aktivitas dalam aplikasi Anda
+        yang diluncurkan aplikasi kontak perangkat bila pengguna mengklik item aliran untuk kontak mentah.
+    </dd>
+    <dt>{@code viewStreamItemPhotoActivity}</dt>
+    <dd>
+        Nama kelas mutlak aktivitas yang diluncurkan
+        aplikasi kontak perangkat bila pengguna mengklik foto dalam item aliran
+        untuk kontak mentah.
+    </dd>
+</dl>
+<h4 id="SocialStreamDataKind">Elemen &lt;ContactsDataKind&gt;</h4>
+<p>
+    Elemen <code>&lt;ContactsDataKind&gt;</code> mengontrol tampilan baris data custom
+    aplikasi Anda dalam UI aplikasi kontak. Sintaksnya adalah sebagai berikut:
+</p>
+<pre>
+&lt;ContactsDataKind
+        android:mimeType="<em>MIMEtype</em>"
+        android:icon="<em>icon_resources</em>"
+        android:summaryColumn="<em>column_name</em>"
+        android:detailColumn="<em>column_name</em>"&gt;
+</pre>
+<p>
+    <strong>dimuat dalam:</strong>
+</p>
+<code>&lt;ContactsAccountType&gt;</code>
+<p>
+    <strong>Keterangan:</strong>
+</p>
+<p>
+    Gunakan elemen ini untuk memerintahkan aplikasi kontak agar menampilkan konten baris data custom sebagai
+    bagian dari detail kontak mentah. Setiap elemen anak <code>&lt;ContactsDataKind&gt;</code>
+    <code>&lt;ContactsAccountType&gt;</code> mewakili tipe baris data custom yang
+    ditambahkan adaptor sinkronisasi Anda ke tabel {@link android.provider.ContactsContract.Data}. Tambahkan satu
+    elemen <code>&lt;ContactsDataKind&gt;</code> untuk setiap tipe MIME custom yang Anda gunakan. Anda tidak harus
+    menambahkan elemen jika Anda memiliki baris data custom yang datanya tidak ingin ditampilkan.
+</p>
+<p>
+    <strong>Atribut:</strong>
+</p>
+<dl>
+    <dt>{@code android:mimeType}</dt>
+    <dd>
+        Tipe MIME custom yang telah Anda definisikan untuk salah satu tipe baris data custom dalam
+        tabel {@link android.provider.ContactsContract.Data}. Misalnya, nilai
+        <code>vnd.android.cursor.item/vnd.example.locationstatus</code> bisa berupa tipe MIME
+       custom untuk baris data yang mencatat lokasi kontak yang terakhir diketahui.
+    </dd>
+    <dt>{@code android:icon}</dt>
+    <dd>
+
+        <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Sumber daya drawable</a>
+        Android yang ditampilkan aplikasi kontak di samping data Anda. Gunakan ini untuk menunjukkan kepada
+        pengguna bahwa data berasal dari layanan Anda.
+    </dd>
+    <dt>{@code android:summaryColumn}</dt>
+    <dd>
+        Nama kolom untuk yang pertama dari dua nilai yang diambil dari baris data. Nilai
+        ditampilkan sebagai baris pertama entri untuk baris data ini. Baris pertama
+        dimaksudkan untuk digunakan sebagai rangkuman data, tetapi itu bersifat opsional. Lihat juga
+        <a href="#detailColumn">android:detailColumn</a>.
+    </dd>
+    <dt>{@code android:detailColumn}</dt>
+    <dd>
+        Nama kolom untuk yang kedua dari dua nilai yang diambil dari baris data. Nilai
+        ditampilkan sebagai baris kedua entri untuk baris data ini. Lihat juga
+        {@code android:summaryColumn}.
+    </dd>
+</dl>
+<h2 id="AdditionalFeatures">Fitur Tambahan Penyedia Kontak</h2>
+<p>
+    Di samping fitur-fitur utama yang dijelaskan di bagian sebelumnya, Penyedia Kontak menawarkan
+   fitur-fitur berguna ini untuk digunakan bersama data kontak:
+</p>
+    <ul>
+       <li>Grup kontak</li>
+       <li>Fitur foto</li>
+    </ul>
+<h3 id="Groups">Grup kontak</h3>
+<p>
+    Penyedia Kontak secara opsional bisa melabeli kumpulan kontak terkait dengan data
+    <strong>grup</strong>. Jika server yang dikaitkan dengan akun pengguna
+    ingin mempertahankan grup, adaptor sinkronisasi untuk tipe akun dari akun itu harus mentransfer
+    data grup antara Penyedia Kontak dan server. Bila pengguna menambahkan kontak baru ke
+    server, kemudian memasukkan kontak ini dalam grup baru, adaptor sinkronisasi harus menambahkan grup baru
+    ke tabel {@link android.provider.ContactsContract.Groups}. Grup atau grup-grup yang memiliki kontak
+    disimpan dalam tabel {@link android.provider.ContactsContract.Data}, dengan menggunakan
+    tipe MIME {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}.
+</p>
+<p>
+    Jika Anda mendesain adaptor sinkronisasi yang akan menambahkan data kontak mentah dari
+    server ke Penyedia Kontak, dan Anda tidak menggunakan grup, maka Anda harus memberi tahu
+    penyedia itu agar membuat data Anda terlihat. Dalam kode yang dijalankan bila pengguna menambahkan akun
+    ke perangkat, perbarui baris {@link android.provider.ContactsContract.Settings}
+    yang ditambahkan Penyedia Kontak untuk akunnya. Dalam baris ini, atur nilai kolom
+    {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE
+    Settings.UNGROUPED_VISIBLE} ke 1. Bila melakukannya, Penyedia Kontak akan selalu
+    membuat data kontak Anda terlihat, meskipun Anda tidak menggunakan grup.
+</p>
+<h3 id="Photos">Foto kontak</h3>
+<p>
+    Tabel {@link android.provider.ContactsContract.Data} menyimpan foto sebagai baris dengan tipe MIME
+    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
+    Photo.CONTENT_ITEM_TYPE}. Kolom
+    {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} baris yang ditautkan ke
+    kolom {@code android.provider.BaseColumns#_ID} kontak mentah yang memiliki kolom itu.
+    Kelas {@link android.provider.ContactsContract.Contacts.Photo} mendefinisikan subtabel
+    {@link android.provider.ContactsContract.Contacts} yang berisi informasi foto untuk foto
+    utama kontak, yang merupakan foto utama dari kontak mentah utama kontak itu. Demikian pula,
+    kelas {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} mendefinisikan subtabel
+    {@link android.provider.ContactsContract.RawContacts} yang berisi informasi foto untuk
+    foto utama kontak mentah.
+</p>
+<p>
+    Dokumentasi acuan untuk {@link android.provider.ContactsContract.Contacts.Photo} dan
+    {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} berisi contoh-contoh
+    pengambilan informasi foto. Tidak ada kelas praktis untuk mengambil
+    thumbnail utama kontak mentah, tetapi Anda bisa mengirim query ke
+    tabel {@link android.provider.ContactsContract.Data}, dengan memilih
+    {@code android.provider.BaseColumns#_ID} kontak mentah,
+    {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
+    Photo.CONTENT_ITEM_TYPE}, dan kolom {@link android.provider.ContactsContract.Data#IS_PRIMARY}
+    untuk menemukan baris foto utama kontak mentah.
+</p>
+<p>
+    Data aliran sosial untuk seseorang bisa juga disertai foto. Data ini disimpan dalam
+    tabel {@code android.provider.ContactsContract.StreamItemPhotos}, yang dijelaskan lebih detail
+    di bagian <a href="#StreamPhotos">Foto aliran sosial</a>.
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
new file mode 100644
index 0000000..4af9277
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-basics.jd
@@ -0,0 +1,1196 @@
+page.title=Dasar-Dasar Penyedia Konten
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+<!-- In this document -->
+<h2>Dalam dokumen ini</h2>
+<ol>
+    <li>
+        <a href="#Basics">Ikhtisar</a>
+        <ol>
+            <li>
+                <a href="#ClientProvider">Mengakses penyedia</a>
+            </li>
+            <li>
+                <a href="#ContentURIs">URI Konten</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#SimpleQuery">Mengambil Data dari Penyedia</a>
+        <ol>
+            <li>
+                <a href="#RequestPermissions">Meminta izin akses baca</a>
+            </li>
+            <li>
+                <a href="#Query">Membuat query</a>
+            </li>
+            <li>
+                <a href="#DisplayResults">Menampilkan hasil query</a>
+            </li>
+            <li>
+                <a href="#GettingResults">Mendapatkan data dari hasil query</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#Permissions">Izin Penyedia Konten</a>
+    </li>
+    <li>
+        <a href="#Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</a>
+        <ol>
+            <li>
+                <a href="#Inserting">Menyisipkan data</a>
+            </li>
+            <li>
+                <a href="#Updating">Memperbarui data</a>
+            </li>
+            <li>
+                <a href="#Deleting">Menghapus data</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#DataTypes">Tipe Data Penyedia</a>
+    </li>
+    <li>
+        <a href="#AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</a>
+        <ol>
+            <li>
+                <a href="#Batch">Akses batch</a>
+            </li>
+            <li>
+                <a href="#Intents">Akses data melalui intent</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#ContractClasses">Kelas-kelas Kontrak</a>
+    </li>
+    <li>
+        <a href="#MIMETypeReference">Acuan Tipe MIME</a>
+    </li>
+</ol>
+
+    <!-- Key Classes -->
+<h2>Kelas-kelas utama</h2>
+    <ol>
+        <li>
+            {@link android.content.ContentProvider}
+        </li>
+        <li>
+            {@link android.content.ContentResolver}
+        </li>
+        <li>
+            {@link android.database.Cursor}
+        </li>
+        <li>
+            {@link android.net.Uri}
+        </li>
+    </ol>
+
+    <!-- Related Samples -->
+<h2>Contoh-Contoh Terkait</h2>
+    <ol>
+        <li>
+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+        Kursor (Orang)</a>
+        </li>
+        <li>
+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+        Kursor (Telepon)</a>
+        </li>
+    </ol>
+
+    <!-- See also -->
+<h2>Lihat juga</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+            Membuat Penyedia Konten</a>
+        </li>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+            Penyedia Kalender</a>
+        </li>
+    </ol>
+</div>
+</div>
+
+    <!-- Intro paragraphs -->
+<p>
+    Penyedia konten mengelola akses ke repository data pusat. Penyedia
+    adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan
+    data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh
+    aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia
+    dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani
+    komunikasi antar-proses dan akses data aman.
+</p>
+<p>
+    Topik ini menerangkan dasar-dasar dari hal-hal berikut:
+</p>
+    <ul>
+        <li>Cara kerja penyedia konten.</li>
+        <li>API yang Anda gunakan untuk mengambil data dari penyedia konten.</li>
+        <li>API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten.</li>
+        <li>Fitur API lainnya yang memudahkan kita menggunakan penyedia.</li>
+    </ul>
+
+    <!-- Basics -->
+<h2 id="Basics">Ikhtisar</h2>
+<p>
+    Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang
+    serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe
+    data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong
+    data yang dikumpulkan untuk sebuah instance.
+</p>
+<p>
+    Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang
+    menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan
+    wujud data yang mungkin ada dalam tabel penyedia ini:
+</p>
+<p class="table-caption">
+    <strong>Tabel 1:</strong> Contoh tabel kamus pengguna.
+</p>
+<table id="table1" style="width: 50%;">
+    <tr>
+        <th style="width:20%" align="center" scope="col">word</th>
+        <th style="width:20%" align="center" scope="col">app id</th>
+        <th style="width:20%" align="center" scope="col">frequency</th>
+        <th style="width:20%" align="center" scope="col">locale</th>
+        <th style="width:20%" align="center" scope="col">_ID</th>
+    </tr>
+    <tr>
+        <td align="center" scope="row">mapreduce</td>
+        <td align="center">user1</td>
+        <td align="center">100</td>
+        <td align="center">en_US</td>
+        <td align="center">1</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">precompiler</td>
+        <td align="center">user14</td>
+        <td align="center">200</td>
+        <td align="center">fr_FR</td>
+        <td align="center">2</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">applet</td>
+        <td align="center">user2</td>
+        <td align="center">225</td>
+        <td align="center">fr_CA</td>
+        <td align="center">3</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">const</td>
+        <td align="center">user1</td>
+        <td align="center">255</td>
+        <td align="center">pt_BR</td>
+        <td align="center">4</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">int</td>
+        <td align="center">user5</td>
+        <td align="center">100</td>
+        <td align="center">en_UK</td>
+        <td align="center">5</td>
+    </tr>
+</table>
+<p>
+    Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak
+    ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya
+    bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam
+    penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom <code>locale</code>-nya. Untuk
+    penyedia ini, kolom <code>_ID</code> berfungsi sebagai "kunci utama" kolom yang
+    dipelihara oleh penyedia secara otomatis.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan
+    menggunakan <code>_ID</code> sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi,
+    jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu
+    nama kolom harus <code>_ID</code>. Ketentuan ini dijelaskan secara lebih detail di bagian
+    <a href="#DisplayResults">Menampilkan hasil query</a>.
+</p>
+<h3 id="ClientProvider">Mengakses penyedia</h3>
+<p>
+    Aplikasi mengakses data dari penyedia konten dengan
+    sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil
+    metode dengan nama identik dalam objek penyedia, instance salah satu
+    subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode
+    {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar
+    "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten.
+</p>
+<p>
+    Objek {@link android.content.ContentResolver} dalam
+    proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki
+    penyedia itu secara otomatis akan menangani komunikasi antar-proses.
+    {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara
+    repository datanya dan penampilan eksternal data sebagai tabel.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta
+    izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian
+    <a href="#Permissions">Izin Penyedia Konten</a>
+</p>
+<p>
+    Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna,
+    Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}.
+    Metode {@link android.content.ContentResolver#query query()} memanggil
+    metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh
+    Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah
+    panggilan {@link android.content.ContentResolver#query ContentResolver.query()}:
+<p>
+<pre>
+// Queries the user dictionary and returns results
+mCursor = getContentResolver().query(
+    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
+    mProjection,                        // The columns to return for each row
+    mSelectionClause                    // Selection criteria
+    mSelectionArgs,                     // Selection criteria
+    mSortOrder);                        // The sort order for the returned rows
+</pre>
+<p>
+    Tabel 2 menampilkan cara argumen untuk
+    {@link android.content.ContentResolver#query
+    query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL:
+</p>
+<p class="table-caption">
+    <strong>Tabel 2:</strong> Query() dibandingkan dengan query SQL.
+</p>
+<table id="table2" style="width: 75%;">
+    <tr>
+        <th style="width:25%" align="center" scope="col">Argumen query()</th>
+        <th style="width:25%" align="center" scope="col">Kata kunci/parameter SELECT</th>
+        <th style="width:50%" align="center" scope="col">Catatan</th>
+    </tr>
+    <tr>
+        <td align="center"><code>Uri</code></td>
+        <td align="center"><code>FROM <em>table_name</em></code></td>
+        <td><code>Uri</code> memetakan ke tabel dalam penyedia yang bernama <em>table_name</em>.</td>
+    </tr>
+    <tr>
+        <td align="center"><code>projection</code></td>
+        <td align="center"><code><em>col,col,col,...</em></code></td>
+        <td>
+            <code>projection</code> adalah satu larik kolom yang harus disertakan untuk tiap baris
+            yang diambil.
+        </td>
+    </tr>
+    <tr>
+        <td align="center"><code>selection</code></td>
+        <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
+        <td><code>selection</code> menetapkan kriteria untuk memilih baris.</td>
+    </tr>
+    <tr>
+        <td align="center"><code>selectionArgs</code></td>
+        <td align="center">
+            (Tidak ada padanan persis. Argumen pemilihan mengganti <code>?</code> placeholder dalam
+            klausa pemilihan.)
+        </td>
+    </tr>
+    <tr>
+        <td align="center"><code>sortOrder</code></td>
+        <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
+        <td>
+            <code>sortOrder</code> menetapkan urutan munculnya baris dalam
+            {@link android.database.Cursor} yang dihasilkan.
+        </td>
+    </tr>
+</table>
+<h3 id="ContentURIs">URI Konten</h3>
+<p>
+    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
+    menyertakan nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
+    nama yang menunjuk ke tabel (<strong>path</strong>). Bila Anda memanggil
+    metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu
+    argumennya.
+</p>
+<p>
+    Dalam baris kode sebelumnya, konstanta
+    {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari
+    tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver}
+    akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan
+    membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal.
+{@link android.content.ContentResolver}    kemudian bisa mengirim argumen query ke penyedia
+    yang benar.
+</p>
+<p>
+    {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih
+    tabel yang akan diakses. Penyedia biasanya memiliki <strong>path</strong> untuk tiap tabel yang dieksposnya.
+</p>
+<p>
+    Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah:
+</p>
+<pre>
+content://user_dictionary/words
+</pre>
+<p>
+    dalam hal ini string <code>user_dictionary</code> adalah otoritas penyedia, dan string
+    <code>words</code> adalah path tabel. String
+    <code>content://</code> (<strong>skema</strong>) selalu ada,
+    dan mengidentifikasinya sebagai URI konten.
+</p>
+<p>
+    Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai
+    ke akhir URI. Misalnya, untuk mengambil sebuah baris yang <code>_ID</code>-nya adalah
+    <code>4</code> dari kamus pengguna, Anda bisa menggunakan URI konten ini:
+</p>
+<pre>
+Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
+</pre>
+<p>
+    Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus
+    salah satunya.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder}
+    berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik.
+{@link android.content.ContentUris}    berisi metode praktis untuk menambahkan nilai ID ke
+    URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId
+    withAppendedId()} untuk menambahkan id ke URI konten User Dictionary.
+</p>
+
+
+    <!-- Retrieving Data from the Provider -->
+<h2 id="SimpleQuery">Mengambil Data dari Penyedia</h2>
+<p>
+    Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna
+    sebagai contoh.
+</p>
+<p class="note">
+    Demi kejelasan, cuplikan kode di bagian ini memanggil
+    {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam
+    kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya
+    adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan
+    lebih detail dalam panduan <a href="{@docRoot}guide/components/loaders.html">
+    Loader</a>. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi
+     lengkap.
+</p>
+<p>
+    Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini:
+</p>
+<ol>
+   <li>
+        Minta izin akses baca untuk penyedia itu.
+   </li>
+   <li>
+        Definisikan kode yang mengirim query ke penyedia.
+   </li>
+</ol>
+<h3 id="RequestPermissions">Meminta izin akses baca</h3>
+<p>
+    Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk
+    penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa
+    Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    dan nama persis izin yang didefinisikan oleh
+    penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta"
+    izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan
+    permintaan ini.
+</p>
+<p>
+    Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta
+    nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam
+    dokumentasi penyedia.
+</p>
+<p>
+    Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian
+    <a href="#Permissions">Izin Penyedia Konten</a>.
+</p>
+<p>
+    Penyedia Kamus Pengguna mendefinisikan izin
+    <code>android.permission.READ_USER_DICTIONARY</code> dalam file manifesnya, sehingga
+    aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini.
+</p>
+<!-- Constructing the query -->
+<h3 id="Query">Membuat query</h3>
+<p>
+    Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini
+    mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna:
+</p>
+<pre class="prettyprint">
+
+// A "projection" defines the columns that will be returned for each row
+String[] mProjection =
+{
+    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
+    UserDictionary.Words.WORD,   // Contract class constant for the word column name
+    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
+};
+
+// Defines a string to contain the selection clause
+String mSelectionClause = null;
+
+// Initializes an array to contain selection arguments
+String[] mSelectionArgs = {""};
+
+</pre>
+<p>
+    Cuplikan berikutnya menampilkan cara menggunakan
+    {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna
+    sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu
+    set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir.
+</p>
+<p>
+    Set kolom yang harus dikembalikan query disebut dengan <strong>proyeksi</strong>
+    (variabel <code>mProjection</code>).
+</p>
+<p>
+    Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan
+    argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean,
+    nama kolom, dan nilai (variabel <code>mSelectionClause</code>). Jika Anda menetapkan
+    parameter <code>?</code> yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai
+    dari larik argumen pemilihan (variabel <code>mSelectionArgs</code>).
+</p>
+<p>
+    Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke
+    <code>null</code>, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan
+    sebuah kata, klausa pemilihan akan diatur ke <code>UserDictionary.Words.WORD + " = ?"</code> dan
+    elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna.
+</p>
+<pre class="prettyprint">
+/*
+ * This defines a one-element String array to contain the selection argument.
+ */
+String[] mSelectionArgs = {""};
+
+// Gets a word from the UI
+mSearchString = mSearchWord.getText().toString();
+
+// Remember to insert code here to check for invalid or malicious input.
+
+// If the word is the empty string, gets everything
+if (TextUtils.isEmpty(mSearchString)) {
+    // Setting the selection clause to null will return all words
+    mSelectionClause = null;
+    mSelectionArgs[0] = "";
+
+} else {
+    // Constructs a selection clause that matches the word that the user entered.
+    mSelectionClause = UserDictionary.Words.WORD + " = ?";
+
+    // Moves the user's input string to the selection arguments.
+    mSelectionArgs[0] = mSearchString;
+
+}
+
+// Does a query against the table and returns a Cursor object
+mCursor = getContentResolver().query(
+    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
+    mProjection,                       // The columns to return for each row
+    mSelectionClause                   // Either null, or the word the user entered
+    mSelectionArgs,                    // Either empty, or the string the user entered
+    mSortOrder);                       // The sort order for the returned rows
+
+// Some providers return null if an error occurs, others throw an exception
+if (null == mCursor) {
+    /*
+     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
+     * call android.util.Log.e() to log this error.
+     *
+     */
+// If the Cursor is empty, the provider found no matches
+} else if (mCursor.getCount() &lt; 1) {
+
+    /*
+     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
+     * an error. You may want to offer the user the option to insert a new row, or re-type the
+     * search term.
+     */
+
+} else {
+    // Insert code here to do something with the results
+
+}
+</pre>
+<p>
+    Query ini analog dengan pernyataan SQL:
+</p>
+<pre>
+SELECT _ID, word, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
+</pre>
+<p>
+    Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak.
+</p>
+<h4 id="Injection">Melindungi dari input merusak</h4>
+<p>
+    Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal
+    ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL.
+</p>
+<p>
+    Perhatikan klausa pemilihan ini:
+</p>
+<pre>
+// Constructs a selection clause by concatenating the user's input to the column name
+String mSelectionClause =  "var = " + mUserInput;
+</pre>
+<p>
+    Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda.
+    Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;"  untuk <code>mUserInput</code>, yang
+    akan menghasilkan klausa pemilihan <code>var = nothing; DROP TABLE *;</code>. Karena
+    klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua
+    tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya
+    <a href="http://en.wikipedia.org/wiki/SQL_injection">injeksi SQL</a>).
+</p>
+<p>
+    Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan <code>?</code> sebagai
+    parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna
+    akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL.
+    Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan
+    penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini:
+</p>
+<pre>
+// Constructs a selection clause with a replaceable parameter
+String mSelectionClause =  "var = ?";
+</pre>
+<p>
+    Buat larik argumen pemilihan seperti ini:
+</p>
+<pre>
+// Defines an array to contain the selection arguments
+String[] selectionArgs = {""};
+</pre>
+<p>
+    Masukkan nilai dalam larik argumen pemilihan seperti ini:
+</p>
+<pre>
+// Sets the selection argument to the user's input
+selectionArgs[0] = mUserInput;
+</pre>
+<p>
+    Sebuah klausa pemilihan yang menggunakan <code>?</code> sebagai parameter yang bisa diganti dan sebuah larik
+    argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak
+    dibuat berdasarkan database SQL.
+</p>
+<!-- Displaying the results -->
+<h3 id="DisplayResults">Menampilkan hasil query</h3>
+<p>
+    Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu
+    menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh
+    proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek
+    {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang
+    dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam
+    hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa
+    properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor}
+    akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat
+    bila {@link android.database.Cursor} berubah, atau keduanya.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Penyedia bisa membatasi akses ke kolom berdasarkan sifat
+    objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada
+    adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan.
+</p>
+<p>
+    Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia
+    akan mengembalikan objek {@link android.database.Cursor} dengan
+    {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong).
+</p>
+<p>
+    Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa
+    memilih untuk menghasilkan <code>null</code>, atau melontarkan {@link java.lang.Exception}.
+</p>
+<p>
+    Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan
+    konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView}
+    melalui {@link android.widget.SimpleCursorAdapter}.
+</p>
+<p>
+    Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat
+    objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor}
+    yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi
+    {@link android.widget.ListView}:
+</p>
+<pre class="prettyprint">
+// Defines a list of columns to retrieve from the Cursor and load into an output row
+String[] mWordListColumns =
+{
+    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
+    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
+};
+
+// Defines a list of View IDs that will receive the Cursor columns for each row
+int[] mWordListItems = { R.id.dictWord, R.id.locale};
+
+// Creates a new SimpleCursorAdapter
+mCursorAdapter = new SimpleCursorAdapter(
+    getApplicationContext(),               // The application's Context object
+    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
+    mCursor,                               // The result from the query
+    mWordListColumns,                      // A string array of column names in the cursor
+    mWordListItems,                        // An integer array of view IDs in the row layout
+    0);                                    // Flags (usually none are needed)
+
+// Sets the adapter for the ListView
+mWordList.setAdapter(mCursorAdapter);
+</pre>
+<p class="note">
+    <strong>Catatan:</strong> Untuk mendukung {@link android.widget.ListView} dengan
+    {@link android.database.Cursor}, kursor harus berisi kolom bernama <code>_ID</code>.
+    Karena itu, query yang ditampilkan sebelumnya mengambil kolom <code>_ID</code> untuk
+    tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya.
+    Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom <code>_ID</code> untuk masing-masing
+    tabelnya.
+</p>
+
+        <!-- Getting data from query results -->
+<h3 id="GettingResults">Mendapatkan data dari hasil query</h3>
+<p>
+    Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya,
+    Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam
+    penyedia lain. Caranya, ulangi baris-baris dalam {@link android.database.Cursor}:
+</p>
+<pre class="prettyprint">
+
+// Determine the column index of the column named "word"
+int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
+
+/*
+ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
+ * an internal error occurs. Other providers may throw an Exception instead of returning null.
+ */
+
+if (mCursor != null) {
+    /*
+     * Moves to the next row in the cursor. Before the first movement in the cursor, the
+     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
+     * exception.
+     */
+    while (mCursor.moveToNext()) {
+
+        // Gets the value from the column.
+        newWord = mCursor.getString(index);
+
+        // Insert code here to process the retrieved word.
+
+        ...
+
+        // end of while loop
+    }
+} else {
+
+    // Insert code here to report an error if the cursor is null or the provider threw an exception.
+}
+</pre>
+<p>
+    Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk
+    mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya
+    menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki
+    metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan
+    tipe data kolom.
+</p>
+
+
+    <!-- Requesting permissions -->
+<h2 id="Permissions">Izin Penyedia Konten</h2>
+<p>
+    Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk
+    mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data
+    yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain
+    meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat
+    izin yang diminta saat menginstal aplikasi.
+</p>
+<p>
+    Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki
+    akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki
+    akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan.
+</p>
+<p>
+    Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin
+    <code>android.permission.READ_USER_DICTIONARY</code> untuk mengambil data darinya.
+    Penyedia memiliki izin <code>android.permission.WRITE_USER_DICTIONARY</code>
+    yang terpisah untuk menyisipkan, memperbarui, atau menghapus data.
+</p>
+<p>
+    Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna
+    harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya,
+    Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager
+    akan membatalkan instalasi.
+</p>
+<p>
+    Elemen
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    berikut meminta akses baca ke Penyedia Kamus Pengguna:
+</p>
+<pre>
+    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
+</pre>
+<p>
+    Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan
+    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
+</p>
+
+
+<!-- Inserting, Updating, and Deleting Data -->
+<h2 id="Modifications">Menyisipkan, Memperbarui, dan Menghapus Data</h2>
+<p>
+    Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara
+    klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data.
+    Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke
+    metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia
+    menangani secara otomatis keamanan dan komunikasi antar-proses.
+</p>
+<h3 id="Inserting">Menyisipkan data</h3>
+<p>
+    Untuk menyisipkan data ke penyedia, Anda memanggil metode
+    {@link android.content.ContentResolver#insert ContentResolver.insert()}.
+ Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu.
+    Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna:
+</p>
+<pre class="prettyprint">
+// Defines a new Uri object that receives the result of the insertion
+Uri mNewUri;
+
+...
+
+// Defines an object to contain the new values to insert
+ContentValues mNewValues = new ContentValues();
+
+/*
+ * Sets the values of each column and inserts the word. The arguments to the "put"
+ * method are "column name" and "value"
+ */
+mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
+mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
+mNewValues.put(UserDictionary.Words.WORD, "insert");
+mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
+
+mNewUri = getContentResolver().insert(
+    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
+    mNewValues                          // the values to insert
+);
+</pre>
+<p>
+    Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang
+    serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki
+    tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom
+    ke <code>null</code> dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}.
+</p>
+<p>
+    Cuplikan ini tidak menambahkan kolom <code>_ID</code>, karena kolom ini dipelihara
+    secara otomatis. Penyedia menetapkan sebuah nilai unik <code>_ID</code> ke setiap baris yang
+    ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel.
+</p>
+<p>
+    URI konten yang dihasilkan dalam <code>newUri</code> akan mengidentifikasi baris yang baru ditambahkan, dengan
+    format berikut:
+</p>
+<pre>
+content://user_dictionary/words/&lt;id_value&gt;
+</pre>
+<p>
+    <code>&lt;id_value&gt;</code> adalah konten <code>_ID</code> untuk baris baru.
+    Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan
+    operasi yang diminta pada baris tersebut.
+</p>
+<p>
+    Untuk mendapatkan nilai <code>_ID</code> dari {@link android.net.Uri} yang dihasilkan, panggil
+    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
+</p>
+<h3 id="Updating">Memperbarui data</h3>
+<p>
+    Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan
+    nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query.
+    Metode klien yang Anda gunakan adalah
+    {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan
+    nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda
+    ingin membersihkan konten kolom, aturlah nilai ke <code>null</code>.
+</p>
+<p>
+    Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke
+    lokal <code>null</code>. Nilai hasil adalah jumlah baris yang diperbarui:
+</p>
+<pre>
+// Defines an object to contain the updated values
+ContentValues mUpdateValues = new ContentValues();
+
+// Defines selection criteria for the rows you want to update
+String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
+String[] mSelectionArgs = {"en_%"};
+
+// Defines a variable to contain the number of updated rows
+int mRowsUpdated = 0;
+
+...
+
+/*
+ * Sets the updated value and updates the selected words.
+ */
+mUpdateValues.putNull(UserDictionary.Words.LOCALE);
+
+mRowsUpdated = getContentResolver().update(
+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
+    mUpdateValues                       // the columns to update
+    mSelectionClause                    // the column to select on
+    mSelectionArgs                      // the value to compare to
+);
+</pre>
+<p>
+    Anda juga harus membersihkan input pengguna bila memanggil
+    {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang
+    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
+</p>
+<h3 id="Deleting">Menghapus data</h3>
+<p>
+    Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris
+    yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus.
+    Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan
+    jumlah baris yang dihapus.
+</p>
+<pre>
+
+// Defines selection criteria for the rows you want to delete
+String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
+String[] mSelectionArgs = {"user"};
+
+// Defines a variable to contain the number of rows deleted
+int mRowsDeleted = 0;
+
+...
+
+// Deletes the words that match the selection criteria
+mRowsDeleted = getContentResolver().delete(
+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
+    mSelectionClause                    // the column to select on
+    mSelectionArgs                      // the value to compare to
+);
+</pre>
+<p>
+    Anda juga harus membersihkan input pengguna bila memanggil
+    {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang
+    hal ini, bacalah bagian <a href="#Injection">Melindungi dari input merusak</a>.
+</p>
+<!-- Provider Data Types -->
+<h2 id="DataTypes">Tipe Data Penyedia</h2>
+<p>
+    Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan
+    teks, namun penyedia juga bisa menawarkan format berikut:
+</p>
+    <ul>
+        <li>
+            integer
+        </li>
+        <li>
+            long integer (long)
+        </li>
+        <li>
+            floating point
+        </li>
+        <li>
+            long floating point (double)
+        </li>
+    </ul>
+<p>
+    Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai
+    larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get"
+    kelas {@link android.database.Cursor}.
+</p>
+<p>
+    Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya.
+    Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan
+    untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak
+    dijelaskan di bagian <a href="#ContractClasses">Kelas-kelas Kontrak</a>).
+    Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType
+    Cursor.getType()}.
+</p>
+<p>
+    Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa
+    menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang
+    disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan
+    tipe MIME saat menggunakan penyedia yang berisi
+    struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data}
+    dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap
+    baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil
+    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
+</p>
+<p>
+    Bagian <a href="#MIMETypeReference">Acuan Tipe MIME</a> menerangkan
+    sintaks tipe MIME baik yang standar maupun custom.
+</p>
+
+
+<!-- Alternative Forms of Provider Access -->
+<h2 id="AltForms">Bentuk-Bentuk Alternatif Akses Penyedia</h2>
+<p>
+    Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi:
+</p>
+<ul>
+    <li>
+        <a href="#Batch">Akses batch</a>: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam
+        kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan
+        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
+    </li>
+    <li>
+        Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah
+        menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan
+        <a href="{@docRoot}guide/components/loaders.html">Loader</a> memperagakan
+        cara melakukannya.
+    </li>
+    <li>
+        <a href="#Intents">Akses data melalui intent</a>: Walaupun tidak bisa mengirim intent
+        ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang
+        biasanya paling lengkap dibekali untuk memodifikasi data penyedia.
+    </li>
+</ul>
+<p>
+    Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut.
+</p>
+<h3 id="Batch">Akses batch</h3>
+<p>
+    Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan
+    baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set
+    operasi lintas batas proses sebagai transaksi (operasi atomik).
+</p>
+<p>
+    Untuk mengakses penyedia dalam "mode batch",
+    buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian
+    kirim larik itu ke penyedia konten dengan
+    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan
+    <em>otoritas</em> penyedia konten ke metode ini, daripada URI konten tertentu.
+    Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja
+    terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch
+    ContentResolver.applyBatch()} menghasilkan satu larik hasil.
+</p>
+<p>
+    Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts}
+    menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi
+    <a href="{@docRoot}resources/samples/ContactManager/index.html">Contacts Manager</a>
+    berisi contoh akses batch dalam file sumber <code>ContactAdder.java</code>-nya
+.
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Menampilkan data dengan aplikasi pembantu</h2>
+<p>
+    Jika aplikasi Anda <em>memang</em> memiliki izin akses, Anda masih mungkin perlu menggunakan
+    intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima
+    intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu.
+    Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri.
+    Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan
+    <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>.
+</p>
+<p>
+    Aplikasi yang Anda kirimi intent tidak harus aplikasi
+    yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari
+    Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW}
+    berisi URI konten untuk gambar kontak itu ke penampil gambar.
+</p>
+</div>
+</div>
+<h3 id="Intents">Akses data melalui intent</h3>
+<p>
+    Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses
+    data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan
+    mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan
+    aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya.
+</p>
+<h4>Mendapatkan akses dengan izin sementara</h4>
+<p>
+    Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki
+    izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan
+    menerima hasil berupa intent berisi izin "URI".
+    Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima
+    izin selesai. Aplikasi yang memiliki izin tetap akan memberikan
+    izin sementara dengan mengatur flag dalam intent yang dihasilkan:
+</p>
+<ul>
+    <li>
+        <strong>Izin baca:</strong>
+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
+    </li>
+    <li>
+        <strong>Izin tulis:</strong>
+        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
+    </li>
+</ul>
+<p class="note">
+    <strong>Catatan:</strong> Flag ini tidak memberikan akses baca atau tulis umum ke penyedia
+    yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri.
+</p>
+<p>
+    Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
+    dari elemen
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+,   serta elemen anak
+<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+    dari elemen
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>.
+ Mekanisme izin URI dijelaskan secara lebih detail dalam panduan
+    <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>,
+    di bagian "Izin URI".
+</p>
+<p>
+    Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak
+    memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan
+    ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti
+    meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua
+    kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol
+    kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut:
+</p>
+<ol>
+    <li>
+        Aplikasi Anda akan mengirim intent berisi tindakan
+        {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts"
+        {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan
+        metode {@link android.app.Activity#startActivityForResult
+        startActivityForResult()}.
+    </li>
+    <li>
+        Karena intent ini cocok dengan filter intent untuk
+        aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan.
+    </li>
+    <li>
+        Dalam aktivitas pemilihan, pengguna memilih sebuah
+        kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil
+        {@link android.app.Activity#setResult setResult(resultcode, intent)}
+        untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten
+        kontak yang dipilih pengguna, dan flag "extras"
+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan
+        izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh
+        URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk
+        mengembalikan kontrol ke aplikasi Anda.
+    </li>
+    <li>
+        Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode
+        {@link android.app.Activity#onActivityResult onActivityResult()}
+        aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam
+        aplikasi People.
+    </li>
+    <li>
+        Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak
+        dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap
+        ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak
+        atau alamat emailnya, kemudian mengirim kartu ucapan elektronik.
+    </li>
+</ol>
+<h4>Menggunakan aplikasi lain</h4>
+<p>
+    Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah
+    mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana.
+</p>
+<p>
+    Misalnya, aplikasi Kalender menerima
+    intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan
+    UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang
+    digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit,
+    cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan
+    {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana.
+</p>
+<!-- Contract Classes -->
+<h2 id="ContractClasses">Kelas-kelas Kontrak</h2>
+<p>
+    Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama
+    kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak
+    disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian
+    membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android
+    memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya.
+</p>
+<p>
+    Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak
+    {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI
+    konten untuk tabel "words" didefinisikan dalam konstanta
+    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
+    Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom,
+    yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa
+    didefinisikan sebagai:
+</p>
+<pre>
+String[] mProjection =
+{
+    UserDictionary.Words._ID,
+    UserDictionary.Words.WORD,
+    UserDictionary.Words.LOCALE
+};
+</pre>
+<p>
+    Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak.
+    Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu
+    subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah
+    kelas kontrak yang berisi konstanta untuk intent dan data intent.
+</p>
+
+
+<!-- MIME Type Reference -->
+<h2 id="MIMETypeReference">Acuan Tipe MIME</h2>
+<p>
+    Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya.
+</p>
+<p>
+    Tipe MIME memiliki format
+</p>
+<pre>
+<em>type</em>/<em>subtype</em>
+</pre>
+<p>
+    Misalnya, tipe MIME <code>text/html</code> yang dikenal luas memiliki tipe <code>text</code> dan
+    subtipe <code>html</code>. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya
+    query dengan URI itu akan menghasilkan teks berisi tag HTML.
+</p>
+<p>
+    String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai
+    <em>tipe</em> dan <em>subtipe</em> yang lebih kompleks. Nilai <em>tipe</em> selalu
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>
+</pre>
+<p>
+    untuk beberapa baris, atau
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>
+</pre>
+<p>
+    untuk satu baris.
+</p>
+<p>
+    <em>Subtipe</em> adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe
+    sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon,
+    aplikasi akan mengatur tipe MIME berikut di baris itu:
+</p>
+<pre>
+vnd.android.cursor.item/phone_v2
+</pre>
+<p>
+    Perhatikan bahwa nilai subtipe adalah sekadar <code>phone_v2</code>.
+</p>
+<p>
+    Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan
+    otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api.
+    Otoritas penyedia adalah <code>com.example.trains</code>, dan berisi tabel-tabel
+    Line1, Line2, dan Line3. Untuk merespons URI konten
+</p>
+<p>
+<pre>
+content://com.example.trains/Line1
+</pre>
+<p>
+    untuk tabel Line1, penyedia menghasilkan tipe MIME
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
+</pre>
+<p>
+     Untuk merespons URI konten
+</p>
+<pre>
+content://com.example.trains/Line2/5
+</pre>
+<p>
+    untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.example.line2
+</pre>
+<p>
+    Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak
+    {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak
+    misalnya, mendefinisikan konstanta
+    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME
+    baris kontak mentah tunggal.
+</p>
+<p>
+    URI konten untuk baris-baris tunggal dijelaskan di bagian
+    <a href="#ContentURIs">URI Konten</a>.
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
new file mode 100644
index 0000000..7fbc613
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/content-provider-creating.jd
@@ -0,0 +1,1214 @@
+page.title=Membuat Penyedia Konten
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+    <li>
+        <a href="#DataStorage">Mendesain Penyimpanan Data</a>
+    </li>
+    <li>
+        <a href="#ContentURI">Mendesain URI Konten</a>
+    </li>
+    <li>
+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>
+        <ol>
+            <li>
+                <a href="#RequiredAccess">Metode-Metode yang Diperlukan</a>
+            </li>
+            <li>
+                <a href="#Query">Mengimplementasikan metode query()</a>
+            </li>
+            <li>
+                <a href="#Insert">Mengimplementasikan metode insert()</a>
+            </li>
+            <li>
+                <a href="#Delete">Mengimplementasikan metode delete()</a>
+            </li>
+            <li>
+                <a href="#Update">Mengimplementasikan metode update()</a>
+            </li>
+            <li>
+                <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>
+        <ol>
+            <li>
+                <a href="#TableMIMETypes">Tipe MIME untuk tabel</a>
+            </li>
+            <li>
+                <a href="#FileMIMETypes">Tipe MIME untuk file</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#ContractClass">Mengimplementasikan Kelas Kontrak</a>
+    </li>
+    <li>
+        <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>
+    </li>
+    <li>
+        <a href="#ProviderElement">Elemen &lt;provider&gt;</a>
+    </li>
+    <li>
+        <a href="#Intents">Intent dan Akses Data</a>
+    </li>
+</ol>
+<h2>Kelas-kelas utama</h2>
+    <ol>
+        <li>
+            {@link android.content.ContentProvider}
+        </li>
+        <li>
+            {@link android.database.Cursor}
+        </li>
+        <li>
+            {@link android.net.Uri}
+        </li>
+    </ol>
+<h2>Contoh-Contoh Terkait</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}resources/samples/NotePad/index.html">
+                Aplikasi contoh Note Pad
+            </a>
+        </li>
+    </ol>
+<h2>Lihat juga</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+            Dasar-Dasar Penyedia Konten</a>
+        </li>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+            Penyedia Kalender</a>
+        </li>
+    </ol>
+</div>
+</div>
+
+
+<p>
+    Penyedia konten mengelola akses ke repository data pusat. Anda mengimplementasikan
+    penyedia sebagai satu atau beberapa kelas dalam aplikasi Android, bersama elemen-elemen dalam
+    file manifes. Salah satu kelas Anda mengimplementasikan subkelas
+    {@link android.content.ContentProvider}, yang merupakan antarmuka antara penyedia Anda dan
+    aplikasi lain. Walaupun penyedia konten dimaksudkan untuk menyediakan data bagi
+    aplikasi lain, Anda tentu saja bisa memiliki aktivitas dalam aplikasi yang memungkinkan pengguna
+    melakukan query dan memodifikasi data yang dikelola oleh penyedia Anda.
+</p>
+<p>
+    Bagian selebihnya dalam topik ini adalah daftar langkah-langkah dasar untuk membangun penyedia konten dan daftar
+    API yang akan digunakan.
+</p>
+
+
+<!-- Before You Start Building -->
+<h2 id="BeforeYouStart">Sebelum Anda Mulai Membangun</h2>
+<p>
+    Sebelum Anda mulai membangun penyedia, lakukanlah hal-hal berikut:
+</p>
+<ol>
+    <li>
+        <strong>Putuskan apakah Anda memerlukan penyedia konten</strong>. Anda perlu membangun sebuah
+        penyedia konten jika ingin menyediakan salah satu atau beberapa dari fitur berikut:
+        <ul>
+            <li>Anda ingin menawarkan data atau file yang kompleks ke aplikasi lain.</li>
+            <li>Anda ingin memungkinkan pengguna menyalin data yang kompleks dari aplikasi Anda ke dalam aplikasi lain.</li>
+            <li>Anda ingin menyediakan saran pencarian custom dengan menggunakan kerangka kerja pencarian.</li>
+        </ul>
+    <p>
+        Anda <em>tidak</em> mengharuskan penyedia untuk menggunakan database SQLite jika hanya digunakan dalam
+        aplikasi sendiri.
+    </p>
+    </li>
+    <li>
+        Jika Anda belum siap melakukannya, bacalah topik
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Dasar-Dasar Penyedia Konten</a> untuk mengetahui selengkapnya tentang penyedia.
+    </li>
+</ol>
+<p>
+    Berikutnya, ikuti langkah-langkah ini untuk membangun penyedia:
+</p>
+<ol>
+    <li>
+        Desain penyimpanan mentah untuk data Anda. Penyedia konten menawarkan data dengan dua cara:
+        <dl>
+            <dt>
+                Data file
+            </dt>
+            <dd>
+                Data yang biasanya masuk ke dalam file, misalnya
+                foto, audio, atau video. Simpan file dalam ruang privat
+                aplikasi Anda. Untuk merespons permintaan file dari aplikasi lain,
+                penyedia Anda bisa menawarkan handle ke file tersebut.
+            </dd>
+            <dt>
+                Data "terstruktur"
+            </dt>
+            <dd>
+                Data yang biasanya masuk ke dalam database, larik, atau struktur serupa.
+                Simpan data dalam bentuk yang kompatibel dengan tabel berisi baris dan kolom. Baris
+                mewakili entitas, misalnya satu orang atau satu barang inventori. Kolom mewakili
+                beberapa data untuk entitas itu, misalnya nama orang atau harga barang. Cara umum untuk
+                menyimpan tipe data ini adalah dalam database SQLite, namun Anda bisa menggunakan tipe
+                penyimpanan apa saja yang persisten. Untuk mengetahui selengkapnya tentang tipe penyimpanan yang tersedia di
+                sistem Android, lihat bagian <a href="#DataStorage">
+                Mendesain Penyimpanan Data</a>.
+            </dd>
+        </dl>
+    </li>
+    <li>
+        Definisikan sebuah implementasi konkret kelas {@link android.content.ContentProvider} dan
+        metode yang diperlukannya. Kelas ini adalah antarmuka antara data Anda dan bagian selebihnya pada
+        sistem Android. Untuk informasi selengkapnya tentang kelas ini, lihat bagian
+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
+    </li>
+    <li>
+        Definisikan string otoritas, semua URI isinya, dan nama-nama kolom penyedia. Jika Anda ingin
+        penyedia aplikasi menangani intent, definisikan juga semua tindakan intent, data ekstra,
+        dan flag. Definisikan juga izin yang akan Anda syaratkan terhadap aplikasi yang ingin
+        mengakses data Anda. Anda harus mempertimbangkan pendefinisian semua nilai ini sebagai konstanta di
+        kelas kontrak terpisah; nantinya, Anda bisa mengekspos kelas ini kepada pengembang lain. Untuk
+        informasi selengkapnya tentang URI konten, lihat
+        bagian <a href="#ContentURI">Mendesain URI Konten</a>.
+        Untuk informasi selengkapnya tentang intent, lihat
+        bagian <a href="#Intents">Intent dan Akses Data</a>.
+    </li>
+    <li>
+        Tambahkan bagian opsional lainnya, seperti data contoh atau implementasi
+        {@link android.content.AbstractThreadedSyncAdapter} yang bisa menyinkronkan data antara
+        penyedia dan data berbasis cloud.
+    </li>
+</ol>
+
+
+<!-- Designing Data Storage -->
+<h2 id="DataStorage">Mendesain Penyimpanan Data</h2>
+<p>
+    Penyedia konten adalah antarmuka ke data yang disimpan dalam format terstruktur. Sebelum membuat
+    antarmuka, Anda harus memutuskan cara menyimpan data. Anda bisa menyimpan data dalam bentuk apa saja yang Anda
+    sukai, kemudian mendesain antarmuka untuk membaca dan menulis data yang diperlukan.
+</p>
+<p>
+    Berikut ini adalah beberapa teknologi penyimpanan data yang tersedia di Android:
+</p>
+<ul>
+    <li>
+        Sistem Android menyertakan API database SQLite yang digunakan penyedia Android sendiri
+        untuk menyimpan data berorientasi tabel. Kelas
+        {@link android.database.sqlite.SQLiteOpenHelper} membantu Anda membuat database, dan kelas
+        {@link android.database.sqlite.SQLiteDatabase} adalah kelas dasar untuk mengakses
+        database.
+        <p>
+            Ingatlah bahwa Anda tidak harus menggunakan database untuk mengimplementasikan repository. Penyedia
+            muncul secara eksternal sebagai satu set tabel, yang serupa dengan sebuah database relasional, namun ini
+            bukan persyaratan untuk implementasi internal penyedia.
+        </p>
+    </li>
+    <li>
+        Untuk menyimpan file data, Android memiliki beragam API berorientasi file.
+        Untuk mengetahui selengkapnya tentang penyimpanan file, bacalah topik
+        <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a>. Jika Anda sedang
+        mendesain penyedia yang menawarkan data yang terkait dengan media seperti musik atau video, Anda bisa
+        memiliki penyedia yang mengombinasikan data tabel dan file.
+    </li>
+    <li>
+        Untuk bekerja dengan data berbasis jaringan, gunakan kelas-kelas dalam {@link java.net} dan
+        {@link android.net}. Anda juga bisa menyinkronkan data berbasis jaringan dengan penyimpanan data lokal
+        seperti database, kemudian menawarkan data sebagai tabel atau file.
+        Aplikasi contoh <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+        Sample Sync Adapter</a> memperagakan tipe sinkronisasi ini.
+    </li>
+</ul>
+<h3 id="DataDesign">
+    Pertimbangan desain data
+</h3>
+<p>
+    Berikut ini adalah beberapa tip untuk mendesain struktur data penyedia:
+</p>
+<ul>
+    <li>
+        Data tabel harus selalu memiliki kolom "kunci utama" yang dipelihara oleh penyedia
+        sebagai nilai numerik unik untuk setiap baris. Anda bisa menggunakan nilai ini untuk menautkan baris ke
+        baris yang terkait dalam tabel lain (dengan menggunakannya sebagai "kunci asing"). Walaupun Anda bisa menggunakan nama
+        apa saja untuk kolom ini, menggunakan {@link android.provider.BaseColumns#_ID BaseColumns._ID} adalah
+        pilihan terbaik, karena menautkan hasil query penyedia dengan
+        {@link android.widget.ListView} mensyaratkan bahwa salah satu kolom yang diambil memiliki nama
+        <code>_ID</code>.
+    </li>
+    <li>
+        Jika Anda ingin untuk menyediakan gambar bitmap atau potongan data berorientasi file lainnya yang berukuran sangat besar, simpanlah
+        data dalam sebuah file kemudian sediakan secara tidak langsung sebagai ganti menyimpannya secara langsung dalam
+        tabel. Jika melakukannya, Anda perlu memberi tahu pengguna penyedia Anda bahwa mereka perlu menggunakan metode file
+        {@link android.content.ContentResolver} untuk mengakses data.
+    </li>
+    <li>
+        Gunakan tipe data Binary Large OBject (BLOB) untuk menyimpan data yang bervariasi ukurannya atau memiliki
+        struktur yang beragam. Misalnya, Anda bisa menggunakan sebuah kolom BLOB untuk menyimpan
+        <a href="http://code.google.com/p/protobuf">buffer protokol</a> atau
+        <a href="http://www.json.org">struktur JSON</a>.
+        <p>
+            Anda juga bisa menggunakan BLOB untuk mengimplementasikan tabel yang <em>tidak bergantung skema</em>. Dalam
+            tipe tabel ini, Anda mendefinisikan kolom kunci utama, kolom tipe MIME, dan satu atau beberapa
+            kolom generik sebagai BLOB. Arti dari data dalam kolom-kolom BLOB ditunjukkan
+            oleh nilai dalam kolom tipe MIME. Cara ini memungkinkan Anda menyimpan berbagai tipe baris dalam
+            tabel yang sama. Tabel "data"
+            {@link android.provider.ContactsContract.Data} Penyedia Kontak adalah contoh tabel yang tidak bergantung skema
+            tersebut.
+        </p>
+    </li>
+</ul>
+<!-- Designing Content URIs -->
+<h2 id="ContentURI">Mendesain URI Konten</h2>
+<p>
+    <strong>URI konten</strong> adalah URI yang mengidentifikasi data dalam penyedia. URI Konten
+    berisi nama simbolis seluruh penyedia (<strong>otoritas</strong>nya) dan sebuah
+    nama yang menunjuk ke tabel atau file (<strong>path</strong>). Bagian id opsional menunjuk ke
+    satu baris dalam tabel. Setiap metode akses data
+    {@link android.content.ContentProvider} memiliki sebuah URI konten sebagai argumen; hal ini memungkinkan Anda
+    menentukan tabel, baris, atau file yang akan diakses.
+</p>
+<p>
+    Dasar-dasar URI konten dijelaskan dalam topik
+    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+    Dasar-Dasar Penyedia Konten</a>.
+</p>
+<h3>Mendesain otoritas</h3>
+<p>
+    Penyedia biasanya memiliki otoritas tunggal, yang berfungsi sebagai nama internal Android-nya. Untuk
+    menghindari konflik dengan penyedia lain, Anda harus menggunakan kepemilikan domain internet (secara terbalik)
+    sebagai basis otoritas penyedia Anda. Karena saran ini juga berlaku untuk
+    nama-nama paket Android, Anda bisa mendefinisikan otoritas penyedia sebagai perluasan dari nama
+    paket yang berisi penyedia. Misalnya, jika nama paket Android Anda adalah
+    <code>com.example.&lt;appname&gt;</code>, Anda harus memberikan penyedia Anda
+    otoritas <code>com.example.&lt;appname&gt;.provider</code>.
+</p>
+<h3>Mendesain struktur path</h3>
+<p>
+    Pengembang biasanya membuat URI konten dari otoritas dengan menambahkan path yang menunjuk ke
+    masing-masing tabel. Misalnya, jika Anda memiliki dua tabel <em>table1</em> dan
+    <em>table2</em>, Anda mengombinasikan otoritas dari contoh sebelumnya untuk menghasilkan
+    URI konten
+    <code>com.example.&lt;appname&gt;.provider/table1</code> dan
+    <code>com.example.&lt;appname&gt;.provider/table2</code>. Path tidak
+    dibatasi pada segmen tunggal, dan tidak harus berupa tabel untuk masing-masing tingkat path.
+</p>
+<h3>Menangani ID URI konten</h3>
+<p>
+    Berdasarkan standar, penyedia menawarkan akses ke satu baris dalam tabel dengan menerima URI konten
+    dengan sebuah nilai ID untuk baris itu di akhir URI. Juga berdasarkan standar, penyedia mencocokkan
+    nilai ID dengan kolom <code>_ID</code> tabel, dan melakukan akses yang diminta terhadap baris
+    yang cocok.
+</p>
+<p>
+    Standar ini memudahkan pola desain umum untuk aplikasi yang mengakses penyedia. Aplikasi
+    melakukan query terhadap penyedia dan menampilkan {@link android.database.Cursor} yang dihasilkan
+    dalam {@link android.widget.ListView} dengan menggunakan {@link android.widget.CursorAdapter}.
+    Definisi {@link android.widget.CursorAdapter} mengharuskan salah satu kolom dalam
+    {@link android.database.Cursor} berupa <code>_ID</code>
+</p>
+<p>
+    Pengguna kemudian mengambil salah satu baris yang ditampilkan dari UI untuk menemukan atau memodifikasi
+    data. Aplikasi mengambil baris yang sesuai dari {@link android.database.Cursor} yang mendukung
+    {@link android.widget.ListView}, mengambil nilai <code>_ID</code> untuk baris ini, menambahkannya ke
+    URI konten, dan mengirim permintaan akses ke penyedia. Penyedia nanti bisa melakukan
+    query atau modifikasi terhadap baris yang persis diambil pengguna.
+</p>
+<h3>Pola URI konten</h3>
+<p>
+    Untuk membantu Anda memilih tindakan yang diambil bagi URI konten yang masuk, API penyedia menyertakan
+    kelas praktis {@link android.content.UriMatcher}, yang memetakan "pola-pola" URI konten ke
+    nilai-nilai integer. Anda bisa menggunakan nilai-nilai integer dalam pernyataan <code>switch</code> yang
+    memilih tindakan yang diinginkan untuk URI konten atau URI yang cocok dengan pola tertentu.
+</p>
+<p>
+    Pola URI konten mencocokkan dengan URI konten menggunakan karakter wildcard:
+</p>
+    <ul>
+        <li>
+            <strong><code>*</code>:</strong> Mencocokkan string yang memiliki karakter yang sah dengan panjang berapa saja.
+        </li>
+        <li>
+            <strong><code>#</code>:</strong> Mencocokkan string karakter numerik dengan panjang berapa saja.
+        </li>
+    </ul>
+<p>
+    Sebagai contoh desain dan pemrograman penanganan URI konten, perhatikan penyedia dengan
+    otoritas <code>com.example.app.provider</code> yang mengenali URI konten berikut
+    yang menunjuk ke tabel-tabel:
+</p>
+<ul>
+    <li>
+        <code>content://com.example.app.provider/table1</code>: Tabel bernama <code>table1</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table2/dataset1</code>: Tabel bernama
+        <code>dataset1</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table2/dataset2</code>: Tabel bernama
+        <code>dataset2</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table3</code>: Tabel bernama <code>table3</code>.
+    </li>
+</ul>
+<p>
+    Penyedia juga mengenali URI konten ini jika baris ID ditambahkan ke URI,
+    misalnya <code>content://com.example.app.provider/table3/1</code> untuk baris yang diidentifikasi oleh
+    <code>1</code> dalam <code>table3</code>.
+</p>
+<p>
+    Pola-pola URI konten berikut akan menjadi mungkin:
+</p>
+<dl>
+    <dt>
+        <code>content://com.example.app.provider/*</code>
+    </dt>
+    <dd>
+        Mencocokkan URI konten di penyedia.
+    </dd>
+    <dt>
+        <code>content://com.example.app.provider/table2/*</code>:
+    </dt>
+    <dd>
+        Mencocokkan URI konten untuk tabel-tabel <code>dataset1</code>
+        dan <code>dataset2</code>, namun tidak mencocokkan URI konten untuk <code>table1</code> atau
+        <code>table3</code>.
+    </dd>
+    <dt>
+        <code>content://com.example.app.provider/table3/#</code>: Mencocokkan URI konten
+        untuk satu baris di <code>table3</code>, misalnya
+        <code>content://com.example.app.provider/table3/6</code> untuk baris yang diidentifikasi oleh
+        <code>6</code>.
+    </dt>
+</dl>
+<p>
+    Cuplikan kode berikut menunjukkan cara kerja metode di {@link android.content.UriMatcher}.
+    Kode ini menangani URI seluruh tabel secara berbeda dengan URI untuk
+    satu baris, menggunakan pola URI konten
+    <code>content://&lt;authority&gt;/&lt;path&gt;</code> untuk tabel, dan
+    <code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code> untuk satu baris.
+</p>
+<p>
+    Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan
+    otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri)
+    match()} menghasilkan nilai integer URI. Pernyataan <code>switch</code>
+    memilih antara melakukan query seluruh tabel dan melakukan query satu record:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider {
+...
+    // Creates a UriMatcher object.
+    private static final UriMatcher sUriMatcher;
+...
+    /*
+     * The calls to addURI() go here, for all of the content URI patterns that the provider
+     * should recognize. For this snippet, only the calls for table 3 are shown.
+     */
+...
+    /*
+     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
+     * in the path
+     */
+    sUriMatcher.addURI("com.example.app.provider", "table3", 1);
+
+    /*
+     * Sets the code for a single row to 2. In this case, the "#" wildcard is
+     * used. "content://com.example.app.provider/table3/3" matches, but
+     * "content://com.example.app.provider/table3 doesn't.
+     */
+    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
+...
+    // Implements ContentProvider.query()
+    public Cursor query(
+        Uri uri,
+        String[] projection,
+        String selection,
+        String[] selectionArgs,
+        String sortOrder) {
+...
+        /*
+         * Choose the table to query and a sort order based on the code returned for the incoming
+         * URI. Here, too, only the statements for table 3 are shown.
+         */
+        switch (sUriMatcher.match(uri)) {
+
+
+            // If the incoming URI was for all of table3
+            case 1:
+
+                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
+                break;
+
+            // If the incoming URI was for a single row
+            case 2:
+
+                /*
+                 * Because this URI was for a single row, the _ID value part is
+                 * present. Get the last path segment from the URI; this is the _ID value.
+                 * Then, append the value to the WHERE clause for the query
+                 */
+                selection = selection + "_ID = " uri.getLastPathSegment();
+                break;
+
+            default:
+            ...
+                // If the URI is not recognized, you should do some error handling here.
+        }
+        // call the code to actually do the query
+    }
+</pre>
+<p>
+    Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan
+    bagian <code>id</code> URI konten. Kelas-kelas {@link android.net.Uri} dan
+    {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai
+    objek {@link android.net.Uri} yang ada dan membuat objek baru.
+</p>
+
+<!-- Implementing the ContentProvider class -->
+<h2 id="ContentProvider">Mengimplementasikan Kelas ContentProvider</h2>
+<p>
+    Instance {@link android.content.ContentProvider} mengelola akses
+    ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk
+    akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil
+    metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses.
+</p>
+<h3 id="RequiredAccess">Metode-metode yang diperlukan</h3>
+<p>
+    Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang
+    harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali
+    {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien
+    yang berupaya mengakses penyedia konten Anda:
+</p>
+<dl>
+    <dt>
+        {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+        query()}
+    </dt>
+    <dd>
+        Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan
+        di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya.
+        Menghasilkan data berupa objek {@link android.database.Cursor}.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
+    </dt>
+    <dd>
+        Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih
+        tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk
+        baris yang baru disisipkan.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+        update()}
+    </dt>
+    <dd>
+        Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris
+        yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
+    </dt>
+    <dd>
+        Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan
+        dihapus. Menghasilkan jumlah baris yang dihapus.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#getType(Uri) getType()}
+    </dt>
+    <dd>
+        Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail
+        di bagian <a href="#MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</a>.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#onCreate() onCreate()}
+    </dt>
+    <dd>
+        Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah
+        membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga
+        objek {@link android.content.ContentResolver} mencoba mengaksesnya.
+    </dd>
+</dl>
+<p>
+    Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan
+    metode-metode {@link android.content.ContentResolver} yang sama namanya.
+</p>
+<p>
+    Implementasi metode-metode ini harus memperhitungkan hal-hal berikut:
+</p>
+<ul>
+    <li>
+        Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()}
+        bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui
+        selengkapnya tentang multi-thread, lihat topik
+        <a href="{@docRoot}guide/components/processes-and-threads.html">
+        Proses dan Thread</a>.
+    </li>
+    <li>
+        Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate()
+        onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan.
+        Bagian <a href="#OnCreate">Mengimplementasikan metode onCreate()</a>
+        membahas hal ini secara lebih detail.
+    </li>
+    <li>
+        Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain
+        tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain
+        menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke
+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan
+        0.
+    </li>
+</ul>
+<h3 id="Query">Mengimplementasikan metode query()</h3>
+<p>
+    Metode
+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+    ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika
+    gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai
+    penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode
+    <code>query()</code> dari kelas {@link android.database.sqlite.SQLiteDatabase}.
+    Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor}
+    yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0.
+    Anda harus mengembalikan <code>null</code> hanya jika terjadi kesalahan internal selama proses query.
+</p>
+<p>
+    Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret
+    {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor}
+    mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini,
+    gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru.
+</p>
+<p>
+    Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception}
+    lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna
+    dalam menangani kesalahan query:
+</p>
+<ul>
+    <li>
+        {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda
+        menerima URI konten yang tidak sah)
+    </li>
+    <li>
+        {@link java.lang.NullPointerException}
+    </li>
+</ul>
+<h3 id="Insert">Mengimplementasikan metode insert()</h3>
+<p>
+    Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu
+    baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}.
+ Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda
+    mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database
+    Anda.
+</p>
+<p>
+    Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai
+    <code>_ID</code> baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan
+    {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
+</p>
+<h3 id="Delete">Mengimplementasikan metode delete()</h3>
+<p>
+    Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
+    tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi
+    bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus
+    dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa
+    memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia.
+</p>
+<h3 id="Update">Mengimplementasikan metode update()</h3>
+<p>
+    Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+    update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh
+    {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan
+    argumen-argumen <code>selection</code> dan <code>selectionArgs</code> yang sama dengan yang digunakan oleh
+    {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan
+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+    ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini.
+</p>
+<h3 id="OnCreate">Mengimplementasikan metode onCreate()</h3>
+<p>
+    Sistem Android memanggil {@link android.content.ContentProvider#onCreate()
+    onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja
+    dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar
+    menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam
+    {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat
+    startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap
+    aplikasi lain.
+</p>
+<p>
+    Misalnya, jika menggunakan database SQLite, Anda bisa membuat
+    sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
+    kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini,
+    saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
+    getWritableDatabase()}, metode ini memanggil metode
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()} secara otomatis.
+</p>
+<p>
+    Dua cuplikan berikut memperagakan interaksi antara
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider
+
+    /*
+     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
+     * in a following snippet.
+     */
+    private MainDatabaseHelper mOpenHelper;
+
+    // Defines the database name
+    private static final String DBNAME = "mydb";
+
+    // Holds the database object
+    private SQLiteDatabase db;
+
+    public boolean onCreate() {
+
+        /*
+         * Creates a new helper object. This method always returns quickly.
+         * Notice that the database itself isn't created or opened
+         * until SQLiteOpenHelper.getWritableDatabase is called
+         */
+        mOpenHelper = new MainDatabaseHelper(
+            getContext(),        // the application context
+            DBNAME,              // the name of the database)
+            null,                // uses the default SQLite cursor
+            1                    // the version number
+        );
+
+        return true;
+    }
+
+    ...
+
+    // Implements the provider's insert method
+    public Cursor insert(Uri uri, ContentValues values) {
+        // Insert code here to determine which table to open, handle error-checking, and so forth
+
+        ...
+
+        /*
+         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
+         *
+         */
+        db = mOpenHelper.getWritableDatabase();
+    }
+}
+</pre>
+<p>
+    Cuplikan berikutnya adalah implementasi
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper:
+</p>
+<pre class="prettyprint">
+...
+// A string that defines the SQL statement for creating a table
+private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
+    "main " +                       // Table's name
+    "(" +                           // The columns in the table
+    " _ID INTEGER PRIMARY KEY, " +
+    " WORD TEXT"
+    " FREQUENCY INTEGER " +
+    " LOCALE TEXT )";
+...
+/**
+ * Helper class that actually creates and manages the provider's underlying data repository.
+ */
+protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
+
+    /*
+     * Instantiates an open helper for the provider's SQLite data repository
+     * Do not do database creation and upgrade here.
+     */
+    MainDatabaseHelper(Context context) {
+        super(context, DBNAME, null, 1);
+    }
+
+    /*
+     * Creates the data repository. This is called when the provider attempts to open the
+     * repository and SQLite reports that it doesn't exist.
+     */
+    public void onCreate(SQLiteDatabase db) {
+
+        // Creates the main table
+        db.execSQL(SQL_CREATE_MAIN);
+    }
+}
+</pre>
+
+
+<!-- Implementing ContentProvider MIME Types -->
+<h2 id="MIMETypes">Mengimplementasikan Tipe MIME Penyedia Konten</h2>
+<p>
+    Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME:
+</p>
+<dl>
+    <dt>
+        {@link android.content.ContentProvider#getType(Uri) getType()}
+    </dt>
+    <dd>
+        Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+    </dt>
+    <dd>
+        Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file.
+    </dd>
+</dl>
+<h3 id="TableMIMETypes">Tipe MIME untuk tabel</h3>
+<p>
+    Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan
+    {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh
+    argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu;
+    dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan
+    polanya.
+</p>
+<p>
+    Untuk tipe data umum misalnya teks, HTML, atau JPEG,
+    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
+    tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web
+    <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>.
+
+</p>
+<p>
+    Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel,
+    {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan
+    tipe MIME dalam format MIME khusus vendor Android:
+</p>
+<ul>
+    <li>
+        Bagian tipe: <code>vnd</code>
+    </li>
+    <li>
+        Bagian subtipe:
+        <ul>
+            <li>
+    Jika pola URI adalah untuk satu baris: <code>android.cursor.<strong>item</strong>/</code>
+            </li>
+            <li>
+    Jika pola URI adalah untuk lebih dari satu baris: <code>android.cursor.<strong>dir</strong>/</code>
+            </li>
+        </ul>
+    </li>
+    <li>
+        Bagian khusus penyedia: <code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
+        <p>
+            Anda menyediakan <code>&lt;name&gt;</code> dan <code>&lt;type&gt;</code>.
+            Nilai <code>&lt;name&gt;</code> harus unik secara global,
+            dan nilai <code>&lt;type&gt;</code> harus unik bagi pola URI
+            yang sesuai. Pilihan tepat untuk <code>&lt;name&gt;</code> adalah nama perusahaan Anda atau
+            sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk
+            <code>&lt;type&gt;</code> adalah string yang mengidentifikasi tabel yang terkait dengan
+            URI.
+        </p>
+
+    </li>
+</ul>
+<p>
+    Misalnya, jika otoritas penyedia adalah
+    <code>com.example.app.provider</code>, dan penyedia mengekspos tabel bernama
+    <code>table1</code>, tipe MIME untuk beberapa baris dalam <code>table1</code> adalah:
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
+</pre>
+<p>
+    Untuk satu baris <code>table1</code>, tipe MIME adalah:
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
+</pre>
+<h3 id="FileMIMETypes">Tipe MIME untuk file</h3>
+<p>
+    Jika penyedia Anda menawarkan file, implementasikan
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
+    Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file
+    yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter
+    tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien.
+</p>
+<p>
+    Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format <code>.jpg</code>,
+    <code>.png</code>, dan <code>.gif</code>.
+    Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+    ContentResolver.getStreamTypes()} dengan string filter <code>image/*</code> (sesuatu yang
+    merupakan "gambar"),
+    maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+    ContentProvider.getStreamTypes()} harus mengembalikan larik:
+</p>
+<pre>
+{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
+</pre>
+<p>
+    Jika aplikasi tertarik pada file <code>.jpg</code>, maka aplikasi bisa memanggil
+    {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+    ContentResolver.getStreamTypes()} dengan string filter <code>*\/jpeg</code>, dan
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+    ContentProvider.getStreamTypes()} harus mengembalikan:
+<pre>
+{&quot;image/jpeg&quot;}
+</pre>
+<p>
+    Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter,
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+    harus mengembalikan <code>null</code>.
+</p>
+
+
+<!--  Implementing a Contract Class -->
+<h2 id="ContractClass">Mengimplementasikan Kelas Kontrak</h2>
+<p>
+    Kelas kontrak adalah kelas <code>public final</code> yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
+metadata lain yang melekat ke penyedia. Kelas
+    membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia
+    bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom,
+    dan seterusnya.
+</p>
+<p>
+    Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya,
+    sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa
+    kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti
+    Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk
+    konstanta.
+</p>
+<p>
+    Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa
+    mengompilasinya secara statis ke dalam aplikasi mereka dari file <code>.jar</code> yang Anda sediakan.
+</p>
+<p>
+    Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh
+    kelas kontrak.
+</p>
+<h2 id="Permissions">Mengimplementasikan Izin Penyedia Konten</h2>
+<p>
+    Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam
+    topik <a href="{@docRoot}guide/topics/security/security.html">Keamanan dan Izin</a>.
+    Topik <a href="{@docRoot}guide/topics/data/data-storage.html">Penyimpanan Data</a> juga
+    menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan.
+    Singkatnya, poin-poin pentingnya adalah:
+</p>
+<ul>
+    <li>
+        Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi
+        aplikasi dan penyedia Anda.
+    </li>
+    <li>
+        Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi
+        aplikasi dan penyedia Anda.
+    </li>
+    <li>
+        Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat <em>publik</em> dan
+        <em>bisa dibaca secara global</em>. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam
+        penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut.
+    </li>
+    <li>
+        Panggilan metode untuk membuka atau membuat file atau database SQLite pada
+        penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda
+        menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya
+        akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam
+        manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam
+        penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah.
+    </li>
+</ul>
+<p>
+    Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus
+    menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya,
+    di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda.
+</p>
+<h3>Mengimplementasikan izin</h3>
+<p>
+    Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah
+    privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya,
+    atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak
+    dari elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+    &lt;provider&gt;</a></code>. Anda bisa mengatur izin yang berlaku pada seluruh penyedia,
+    atau pada tabel tertentu, atau bahkan pada record tertentu, atau ketiganya.
+</p>
+<p>
+    Anda mendefinisikan izin untuk penyedia dengan satu atau beberapa elemen
+    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
+    &lt;permission&gt;</a></code> dalam file manifes. Untuk membuat
+    izin unik bagi penyedia, gunakan scoping (pengaturan lingkup) bergaya Java untuk
+    atribut <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
+    android:name</a></code>. Misalnya, beri nama izin membaca dengan
+    <code>com.example.app.provider.permission.READ_PROVIDER</code>.
+
+</p>
+<p>
+    Daftar berikut menjelaskan lingkup penyedia izin, mulai dengan
+    izin yang berlaku pada seluruh penyedia kemudian menjadi semakin sempit.
+    Izin yang lebih sempit akan didahulukan daripada izin yang berlingkup lebih luas:
+</p>
+<dl>
+    <dt>
+        Izin baca-tulis tunggal tingkat penyedia
+    </dt>
+    <dd>
+        Suatu izin yang mengontrol akses baca-tulis bagi seluruh penyedia, ditetapkan
+        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+        android:permission</a></code> dari
+        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code>.
+    </dd>
+    <dt>
+        Izin baca-tulis terpisah tingkat penyedia
+    </dt>
+    <dd>
+        Satu izin baca dan satu izin tulis untuk seluruh penyedia. Anda menetapkan keduanya
+        dengan atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+        android:readPermission</a></code> dan
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+        android:writePermission</a></code> dari elemen
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code>. Kedua izin akan didahulukan daripada izin yang diharuskan oleh
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+        android:permission</a></code>.
+    </dd>
+    <dt>
+        Izin tingkat path
+    </dt>
+    <dd>
+        Izin baca, tulis, atau baca/tulis untuk URI konten dalam penyedia Anda. Anda menetapkan
+        tiap URI yang ingin dikontrol dengan elemen anak
+        <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
+        &lt;path-permission&gt;</a></code> dari
+        elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code>. Untuk setiap URI konten yang ditetapkan, Anda bisa menetapkan
+        satu izin baca/tulis, satu izin baca, atau satu izin tulis, atau ketiganya. Izin baca dan
+        tulis akan didahulukan daripada izin baca/tulis. Juga,
+        izin tingkat path akan didahulukan daripada izin tingkat penyedia.
+    </dd>
+    <dt>
+        Izin sementara
+    </dt>
+    <dd>
+        Tingkat izin yang memberikan akses sementara ke aplikasi, sekalipun aplikasi itu
+        tidak memiliki izin yang biasanya diminta. Fitur akses
+         sementara mengurangi jumlah izin yang harus diminta aplikasi dalam
+        manifesnya. Bila Anda mengaktifkan izin sementara, satu-satunya aplikasi yang memerlukan
+        izin "permanen" untuk penyedia adalah aplikasi yang mengakses terus-menerus semua
+        data Anda.
+        <p>
+            Perhatikan izin yang Anda perlukan untuk mengimplementasikan penyedia dan aplikasi email, bila Anda
+            ingin memperbolehkan aplikasi penampil gambar dari luar menampilkan lampiran foto dari
+            penyedia Anda. Untuk memberikan akses yang diperlukan kepada penampil gambar tanpa mengharuskan izin,
+            siapkan izin sementara untuk URI konten bagi foto. Desainlah aplikasi email Anda agar
+            bila pengguna ingin menampilkan foto, aplikasi itu akan mengirim intent berisi
+            URI konten foto dan flag izin ke penampil gambar. Penampil gambar nanti bisa
+            melakukan query penyedia email untuk mengambil foto, sekalipun penampil itu tidak
+            memiliki izin baca normal untuk penyedia Anda.
+        </p>
+        <p>
+            Untuk mengaktifkan izin sementara, atur atribut
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+            android:grantUriPermissions</a></code> dari
+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code>, atau tambahkan satu atau beberapa elemen anak
+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+            &lt;grant-uri-permission&gt;</a></code> ke
+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> Anda. Jika menggunakan izin sementara, Anda harus memanggil
+            {@link android.content.Context#revokeUriPermission(Uri, int)
+            Context.revokeUriPermission()} kapan saja Anda menghilangkan dukungan untuk URI konten dari
+            penyedia, dan URI konten dikaitkan dengan izin sementara.
+        </p>
+        <p>
+            Nilai atribut menentukan seberapa banyak penyedia Anda yang dijadikan bisa diakses.
+            Jika atribut diatur ke <code>true</code>, maka sistem akan memberikan
+            izin sementara kepada seluruh penyedia, dengan mengesampingkan izin lain yang diharuskan
+            oleh izin tingkat penyedia atau tingkat path.
+        </p>
+        <p>
+            Jika flag ini diatur ke <code>false</code>, maka Anda harus menambahkan elemen-elemen anak
+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+            &lt;grant-uri-permission&gt;</a></code> ke
+            elemen <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> Anda. Tiap elemen anak menetapkan URI konten atau
+            URI yang telah diberi akses sementara.
+        </p>
+        <p>
+            Untuk mendelegasikan akses sementara ke sebuah aplikasi, intent harus berisi
+            {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} atau flag
+            {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, atau keduanya. Keduanya
+            diatur dengan metode {@link android.content.Intent#setFlags(int) setFlags()}.
+        </p>
+        <p>
+            Jika atribut <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+            android:grantUriPermissions</a></code> tidak ada, atribut ini diasumsikan sebagai
+            <code>false</code>.
+        </p>
+    </dd>
+</dl>
+
+
+
+<!-- The Provider Element -->
+<h2 id="ProviderElement">Elemen &lt;provider&gt;</h2>
+<p>
+    Seperti halnya komponen {@link android.app.Activity} dan {@link android.app.Service},
+    subkelas {@link android.content.ContentProvider}
+    harus didefinisikan dalam file manifes untuk aplikasinya, dengan menggunakan elemen
+    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+    &lt;provider&gt;</a></code>. Sistem Android mendapatkan informasi berikut dari
+    elemen:
+<dl>
+    <dt>
+        Otoritas
+        (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
+        android:authorities}</a>)
+    </dt>
+    <dd>
+        Nama-nama simbolik yang mengidentifikasi seluruh penyedia dalam sistem. Atribut
+        ini dijelaskan lebih detail di bagian
+        <a href="#ContentURI">Mendesain URI Konten</a>.
+    </dd>
+    <dt>
+        Nama kelas penyedia
+        (<code>
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
+        </code>)
+    </dt>
+    <dd>
+        Kelas yang mengimplementasikan {@link android.content.ContentProvider}. Kelas ini
+        dijelaskan lebih detail di bagian
+        <a href="#ContentProvider">Mengimplementasikan Kelas ContentProvider</a>.
+    </dd>
+    <dt>
+        Izin
+    </dt>
+    <dd>
+        Atribut-atribut yang menetapkan izin yang harus dimiliki aplikasi lain untuk mengakses
+        data penyedia:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+                android:grantUriPermssions</a></code>: Flag izin sementara.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+                android:permission</a></code>: Izin baca/tulis tunggal untuk tingkat penyedia.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+                android:readPermission</a></code>: Izin baca untuk tingkat penyedia.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+                android:writePermission</a></code>: Izin tulis untuk tingkat penyedia.
+            </li>
+        </ul>
+        <p>
+            Izin dan atribut-atribut yang sesuai dijelaskan lebih detail
+            di bagian
+            <a href="#Permissions">Mengimplementasikan Izin Penyedia Konten</a>.
+        </p>
+    </dd>
+    <dt>
+        Atribut-atribut startup dan kontrol
+    </dt>
+    <dd>
+        Atribut-atribut ini menentukan cara dan waktu sistem Android memulai penyedia,
+        karakteristik proses penyedia, dan pengaturan runtime lainnya:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
+                android:enabled</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia.
+            </li>
+              <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
+                android:exported</a></code>: Flag yang memperbolehkan aplikasi lain untuk menggunakan penyedia ini.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
+                android:initOrder</a></code>: Urutan yang digunakan untuk memulai penyedia ini,
+                relatif terhadap penyedia lain dalam proses yang sama.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
+                android:multiProcess</a></code>: Flag yang memperbolehkan sistem untuk memulai penyedia
+                dalam proses yang sama dengan proses klien pemanggil.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
+                android:process</a></code>: Nama proses tempat penyedia harus
+                berjalan.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
+                android:syncable</a></code>: Flag yang menunjukkan bahwa data penyedia harus
+                disinkronkan dengan data di server.
+            </li>
+        </ul>
+        <p>
+            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code>.
+
+        </p>
+    </dd>
+    <dt>
+        Atribut-atribut informatif
+    </dt>
+    <dd>
+        Ikon dan label opsional untuk penyedia:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
+                android:icon</a></code>: Sumber daya drawable, berisi ikon untuk penyedia.
+                Ikon ini muncul di sebelah label penyedia dalam daftar aplikasi dalam menu
+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
+                android:label</a></code>: Label informatif yang menjelaskan penyedia atau
+                datanya, atau keduanya. Label ini muncul dalam daftar aplikasi di
+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
+            </li>
+        </ul>
+        <p>
+            Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code>.
+        </p>
+    </dd>
+</dl>
+
+<!-- Intent Access -->
+<h2 id="Intents">Intent dan Akses Data</h2>
+<p>
+    Aplikasi bisa mengakses penyedia konten secara tidak langsung dengan sebuah {@link android.content.Intent}.
+    Aplikasi tidak memanggil satu pun dari metode-metode {@link android.content.ContentResolver} atau
+    {@link android.content.ContentProvider}. Sebagai gantinya, aplikasi mengirim intent yang memulai aktivitas,
+    yang sering kali merupakan bagian dari aplikasi penyedia sendiri. Aktivitas tujuan bertugas
+    mengambil dan menampilkan data dalam UI-nya. Bergantung pada tindakan dalam intent,
+    aktivitas tujuan juga bisa meminta pengguna untuk membuat modifikasi pada data penyedia.
+    Intent juga bisa berisi data "ekstra" yang menampilkan aktivitas tujuan
+    dalam UI; pengguna nanti memiliki pilihan untuk mengubah data ini sebelum menggunakannya untuk mengubah
+    data di penyedia.
+</p>
+<p>
+
+</p>
+<p>
+    Anda mungkin perlu menggunakan akses intent guna membantu memastikan integritas data. Penyedia Anda mungkin bergantung
+    pada data yang disisipkan, diperbarui, dan dihapusnya sesuai dengan logika bisnis yang didefinisikan dengan ketat. Jika
+    demikian halnya, memperbolehkan aplikasi lain mengubah data Anda secara langsung bisa menyebabkan
+    data yang tidak sah. Jika Anda ingin pengembang menggunakan akses intent, pastikan untuk mendokumentasikannya secara saksama.
+    Jelaskan kepada mereka alasan akses intent yang menggunakan UI aplikasi Anda sendiri adalah lebih baik daripada mencoba
+    memodifikasi data dengan kode mereka.
+</p>
+<p>
+    Menangani sebuah intent masuk yang ingin memodifikasi data penyedia Anda tidak berbeda dengan
+    menangani intent lainnya. Anda bisa mengetahui selengkapnya tentang penggunaan intent dengan membaca topik
+    <a href="{@docRoot}guide/components/intents-filters.html">Intent dan Filter Intent</a>.
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
new file mode 100644
index 0000000..2dcd55e
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/content-providers.jd
@@ -0,0 +1,108 @@
+page.title=Penyedia konten
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<!-- In this document -->
+<h2>Topik</h2>
+<ol>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Dasar-Dasar Penyedia Konten</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+        Membuat Penyedia Konten</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Penyedia Kalender</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Penyedia Kontak</a>
+    </li>
+</ol>
+
+    <!-- Related Samples -->
+<h2>Contoh-Contoh Terkait</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}resources/samples/ContactManager/index.html">
+            Aplikasi Contact Manager</a>
+        </li>
+        <li>
+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+        "Kursor (Orang)"
+        </a>
+        </li>
+        <li>
+        <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+        "Kursor (Telepon)"</a>
+        </li>
+        <li>
+            <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+            Contoh Adaptor Sinkronisasi</a>
+        </li>
+    </ol>
+</div>
+</div>
+<p>
+    Penyedia konten mengelola akses ke set data terstruktur. Penyedia ini membungkus
+ data, dan menyediakan mekanisme untuk mendefinisikan keamanan data. Penyedia konten adalah antarmuka
+ standar yang menghubungkan data dalam satu proses dengan kode yang berjalan dalam proses lain.
+</p>
+<p>
+    Bila Anda ingin mengakses data di penyedia konten, Anda menggunakan
+ {@link android.content.ContentResolver} objek dalam
+ {@link android.content.Context} aplikasi untuk berkomunikasi dengan penyedia sebagai klien.
+    Objek {@link android.content.ContentResolver} berkomunikasi dengan objek penyedia, yakni
+ instance kelas yang mengimplementasikan {@link android.content.ContentProvider}. Objek penyedia
+ menerima permintaan data dari klien, melakukan tindakan yang diminta, dan
+ mengembalikan hasilnya.
+</p>
+<p>
+    Anda tidak perlu mengembangkan penyedia sendiri jika tidak bermaksud untuk berbagi data dengan
+ aplikasi lain. Akan tetapi, Anda memerlukan penyedia buatan sendiri untuk menyediakan saran pencarian custom
+ dalam aplikasi Anda sendiri. Anda juga memerlukan penyedia sendiri jika ingin menyalin dan
+menempelkan data atau file yang kompleks dari aplikasi Anda ke aplikasi lain.
+</p>
+<p>
+    Android sendiri berisi penyedia konten yang mengelola data seperti informasi audio, video, gambar, dan
+ kontak pribadi. Anda bisa melihat sebagian informasi ini tercantum dalam dokumentasi
+ acuan untuk paket
+ <code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
+    </code>. Dengan beberapa batasan, semua penyedia ini bisa diakses oleh aplikasi Android
+ apa saja.
+</p><p>
+    Topik-topik berikut menjelaskan penyedia konten secara lebih detail:
+</p>
+<dl>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Dasar-Dasar Penyedia Konten</a></strong>
+    </dt>
+    <dd>
+        Cara mengakses data di penyedia konten bila data disusun dalam tabel.
+    </dd>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+        Membuat Penyedia Konten</a></strong>
+    </dt>
+    <dd>
+        Cara membuat penyedia konten sendiri.
+    </dd>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+        Penyedia Kalender</a></strong>
+    </dt>
+    <dd>
+        Cara mengakses Penyedia Kalender yang merupakan bagian dari platform Android.
+    </dd>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Penyedia Kontak</a></strong>
+    </dt>
+    <dd>
+        Cara mengakses Penyedia Kontak yang merupakan bagian dari platform Android.
+    </dd>
+</dl>
diff --git a/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
new file mode 100644
index 0000000..f857467
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/providers/document-provider.jd
@@ -0,0 +1,916 @@
+page.title=Storage Access Framework
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini
+ <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle">
+        <span class="more">tampilkan maksimal</span>
+        <span class="less" style="display:none">tampilkan minimal</span></a></h2>
+<ol id="toc44" class="hide-nested">
+    <li>
+        <a href="#overview">Ikhtisar</a>
+    </li>
+    <li>
+        <a href="#flow">Arus Kontrol</a>
+    </li>
+    <li>
+        <a href="#client">Menulis Aplikasi Klien</a>
+        <ol>
+        <li><a href="#search">Mencari dokumen</a></li>
+        <li><a href="#process">Memproses hasil</a></li>
+        <li><a href="#metadata">Memeriksa metadata dokumen</a></li>
+        <li><a href="#open">Membuka dokumen</a></li>
+        <li><a href="#create">Membuat dokumen baru</a></li>
+        <li><a href="#delete">Menghapus dokumen</a></li>
+        <li><a href="#edit">Mengedit dokumen</a></li>
+        <li><a href="#permissions">Mempertahankan izin</a></li>
+        </ol>
+    </li>
+    <li><a href="#custom">Menulis Penyedia Dokumen Custom</a>
+        <ol>
+        <li><a href="#manifest">Manifes</a></li>
+        <li><a href="#contract">Kontrak</a></li>
+        <li><a href="#subclass">Subkelas DocumentsProvider</a></li>
+        <li><a href="#security">Keamanan</a></li>
+        </ol>
+    </li>
+
+</ol>
+<h2>Kelas-kelas utama</h2>
+<ol>
+    <li>{@link android.provider.DocumentsProvider}</li>
+    <li>{@link android.provider.DocumentsContract}</li>
+</ol>
+
+<h2>Video</h2>
+
+<ol>
+    <li><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4">
+DevBytes: Android 4.4 Storage Access Framework: Penyedia</a></li>
+     <li><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ">
+DevBytes: Android 4.4 Storage Access Framework: Klien</a></li>
+</ol>
+
+
+<h2>Contoh Kode</h2>
+
+<ol>
+    <li><a href="{@docRoot}samples/StorageProvider/index.html">
+Penyedia Penyimpanan</a></li>
+     <li><a href="{@docRoot}samples/StorageClient/index.html">
+Klien Penyimpanan</a></li>
+</ol>
+
+<h2>Lihat Juga</h2>
+<ol>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Dasar-Dasar Penyedia Konten
+        </a>
+    </li>
+</ol>
+
+</div>
+</div>
+
+
+<p>Android 4.4 (API level 19) memperkenalkan Storage Access Framework (SAF, Kerangka Kerja Akses Penyimpanan). SAF
+ memudahkan pengguna menyusuri dan membuka dokumen, gambar, dan file lainnya
+di semua penyedia penyimpanan dokumen pilihannya. UI standar yang mudah digunakan
+memungkinkan pengguna menyusuri file dan mengakses yang terbaru dengan cara konsisten di antara berbagai aplikasi dan penyedia.</p>
+
+<p>Layanan penyimpanan cloud atau lokal bisa dilibatkan dalam ekosistem ini dengan mengimplementasikan sebuah
+{@link android.provider.DocumentsProvider} yang membungkus layanannya. Aplikasi klien
+yang memerlukan akses ke dokumen sebuah penyedia bisa berintegrasi dengan SAF cukup dengan beberapa
+baris kode.</p>
+
+<p>SAF terdiri dari berikut ini:</p>
+
+<ul>
+<li><strong>Penyedia dokumen</strong>&mdash;Penyedia konten yang memungkinkan
+layanan penyimpanan (seperti Google Drive) untuk menampilkan file yang dikelolanya. Penyedia dokumen
+diimplementasikan sebagai subkelas dari kelas {@link android.provider.DocumentsProvider}.
+Skema penyedia dokumen berdasarkan hierarki file biasa,
+walaupun cara penyedia dokumen Anda secara fisik menyimpan data adalah terserah Anda.
+Platform Android terdiri dari beberapa penyedia dokumen bawaan, seperti
+Downloads, Images, dan Videos.</li>
+
+<li><strong>Aplikasi klien</strong>&mdash;Aplikasi custom yang memanggil intent
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan/atau
+{@link android.content.Intent#ACTION_CREATE_DOCUMENT} dan menerima
+file yang dihasilkan penyedia dokumen.</li>
+
+<li><strong>Picker</strong>&mdash;UI sistem yang memungkinkan pengguna mengakses dokumen dari semua
+penyedia dokumen yang memenuhi kriteria pencarian aplikasi klien.</li>
+</ul>
+
+<p>Beberapa fitur yang disediakan oleh SAF adalah sebagai berikut:</p>
+<ul>
+<li>Memungkinkan pengguna menyusuri konten dari semua penyedia dokumen, bukan hanya satu aplikasi.</li>
+<li>Memungkinkan aplikasi Anda memiliki akses jangka panjang dan tetap ke
+ dokumen yang dimiliki oleh penyedia dokumen. Melalui akses ini pengguna bisa menambah, mengedit,
+ menyimpan, dan menghapus file pada penyedia.</li>
+<li>Mendukung banyak akun pengguna dan akar jangka pendek seperti penyedia penyimpanan
+USB, yang hanya muncul jika drive itu dipasang. </li>
+</ul>
+
+<h2 id ="overview">Ikhtisar</h2>
+
+<p>SAF berpusat di seputar penyedia konten yang merupakan
+subkelas dari kelas {@link android.provider.DocumentsProvider}. Dalam <em>penyedia dokumen</em>, data
+distrukturkan sebagai hierarki file biasa:</p>
+<p><img src="{@docRoot}images/providers/storage_datamodel.png" alt="data model" /></p>
+<p class="img-caption"><strong>Gambar 1.</strong> Model data penyedia dokumen. Root menunjuk ke satu Document,
+yang nanti memulai pemekaran seluruh pohon.</p>
+
+<p>Perhatikan yang berikut ini:</p>
+<ul>
+
+<li>Setiap penyedia dokumen melaporkan satu atau beberapa
+"akar" yang merupakan titik awal penyusuran pohon dokumen.
+Masing-masing akar memiliki sebuah {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} yang unik,
+dan menunjuk ke satu dokumen (satu direktori)
+yang mewakili konten di bawah akar itu.
+Akar sengaja dibuat dinamis untuk mendukung kasus penggunaan seperti multiakun,
+perangkat penyimpanan USB jangka pendek, atau masuk/keluar pengguna.</li>
+
+<li>Di bawah tiap akar terdapat satu dokumen. Dokumen itu menunjuk ke dokumen-dokumen 1-ke-<em>N</em>,
+yang nanti masing-masing bisa menunjuk ke dokumen 1-ke-<em>N</em>. </li>
+
+<li>Tiap backend penyimpanan memunculkan
+masing-masing file dan direktori dengan mengacunya lewat sebuah
+{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang unik.
+ID dokumen harus unik dan tidak berubah setelah dibuat, karena ID ini digunakan untuk
+URI persisten yang diberikan pada saat reboot perangkat.</li>
+
+
+<li>Dokumen bisa berupa file yang bisa dibuka (dengan tipe MIME tertentu), atau
+direktori yang berisi dokumen tambahan (dengan tipe MIME
+{@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR}).</li>
+
+<li>Tiap dokumen bisa mempunyai kemampuan berbeda, sebagaimana yang dijelaskan oleh
+{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS}.
+Misalnya, {@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE},
+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}, dan
+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL}.
+{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang sama bisa
+dimasukkan dalam beberapa direktori.</li>
+</ul>
+
+<h2 id="flow">Arus Kontrol</h2>
+<p>Seperti dinyatakan di atas, model data penyedia dokumen dibuat berdasarkan hierarki file
+biasa. Akan tetapi, Anda bisa menyimpan secara fisik data dengan cara apa pun yang disukai,
+selama data bisa diakses melalui API {@link android.provider.DocumentsProvider}. Misalnya, Anda
+bisa menggunakan penyimpanan cloud berbasis tag untuk data Anda.</p>
+
+<p>Gambar 2 menampilkan contoh cara aplikasi foto bisa menggunakan SAF
+untuk mengakses data tersimpan:</p>
+<p><img src="{@docRoot}images/providers/storage_dataflow.png" alt="app" /></p>
+
+<p class="img-caption"><strong>Gambar 2.</strong> Arus Storage Access Framework</p>
+
+<p>Perhatikan yang berikut ini:</p>
+<ul>
+
+<li>Di SAF, penyedia dan klien tidak berinteraksi
+secara langsung. Klien meminta izin untuk berinteraksi
+dengan file (yakni, membaca, mengedit, membuat, atau menghapus file).</li>
+
+<li>Interaksi dimulai bila sebuah aplikasi (dalam contoh ini adalah aplikasi foto) mengeluarkan intent
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} atau {@link android.content.Intent#ACTION_CREATE_DOCUMENT}. Intent bisa berisi filter
+untuk mempersempit kriteria&mdash;misalnya, "beri saya semua file yang bisa dibuka
+yang memiliki tipe MIME 'gambar'".</li>
+
+<li>Setelah intent dibuat, picker sistem akan pergi ke setiap penyedia yang terdaftar
+dan menunjukkan kepada pengguna akar konten yang cocok.</li>
+
+<li>Picker memberi pengguna antarmuka standar untuk mengakses dokumen,
+walaupun penyedia dokumen dasar bisa sangat berbeda. Misalnya, gambar 2
+menunjukkan penyedia Google Drive, penyedia USB, dan penyedia cloud.</li>
+</ul>
+
+<p>Gambar 3 menunjukkan picker yang di digunakan pengguna mencari gambar telah memilih
+akun Google Drive:</p>
+
+<p><img src="{@docRoot}images/providers/storage_picker.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
+
+<p class="img-caption"><strong>Gambar 3.</strong> Picker</p>
+
+<p>Bila pengguna memilih Google Drive, gambar-gambar akan ditampilkan, seperti yang ditampilkan dalam
+gambar 4. Dari titik itu, pengguna bisa berinteraksi dengan gambar dengan cara apa pun
+yang didukung oleh penyedia dan aplikasi klien.
+
+<p><img src="{@docRoot}images/providers/storage_photos.png" width="340" alt="picker" style="border:2px solid #ddd" /></p>
+
+<p class="img-caption"><strong>Gambar 4.</strong> Gambar</p>
+
+<h2 id="client">Menulis Aplikasi Klien</h2>
+
+<p>Pada Android 4.3 dan yang lebih rendah, jika Anda ingin aplikasi mengambil file dari
+aplikasi lain, aplikasi Anda harus memanggil intent seperti {@link android.content.Intent#ACTION_PICK}
+atau {@link android.content.Intent#ACTION_GET_CONTENT}. Pengguna nanti harus memilih
+satu aplikasi yang akan digunakan untuk mengambil file dan aplikasi yang dipilih harus menyediakan antarmuka pengguna
+bagi untuk menyusuri dan mengambil dari file yang tersedia. </p>
+
+<p>Pada Android 4.4 dan yang lebih tinggi, Anda mempunyai opsi tambahan dalam menggunakan intent
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT},
+yang menampilkan UI picker yang dikontrol oleh sistem yang memungkinkan pengguna
+menyusuri semua file yang disediakan aplikasi lain. Dari satu UI ini, pengguna
+bisa mengambil file dari aplikasi apa saja yang didukung.</p>
+
+<p>{@link android.content.Intent#ACTION_OPEN_DOCUMENT}
+tidak dimaksudkan untuk menjadi pengganti {@link android.content.Intent#ACTION_GET_CONTENT}.
+Yang harus Anda gunakan bergantung pada kebutuhan aplikasi:</p>
+
+<ul>
+<li>Gunakan {@link android.content.Intent#ACTION_GET_CONTENT} jika Anda ingin aplikasi
+cuma membaca/mengimpor data. Dengan pendekatan ini, aplikasi akan mengimpor salinan data,
+misalnya file gambar.</li>
+
+<li>Gunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT} jika Anda ingin aplikasi
+memiliki akses jangka panjang dan jangka pendek ke dokumen yang dimiliki oleh penyedia
+dokumen. Contohnya adalah aplikasi pengeditan foto yang memungkinkan pengguna mengedit
+gambar yang tersimpan dalam penyedia dokumen. </li>
+
+</ul>
+
+
+<p>Bagian ini menjelaskan cara menulis aplikasi klien berdasarkan
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan
+intent {@link android.content.Intent#ACTION_CREATE_DOCUMENT}.</p>
+
+
+<h3 id="search">Mencari dokumen</h3>
+
+<p>
+Cuplikan berikut menggunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
+untuk mencari penyedia dokumen yang
+berisi file gambar:</p>
+
+<pre>private static final int READ_REQUEST_CODE = 42;
+...
+/**
+ * Fires an intent to spin up the &quot;file chooser&quot; UI and select an image.
+ */
+public void performFileSearch() {
+
+    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file
+    // browser.
+    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+
+    // Filter to only show results that can be &quot;opened&quot;, such as a
+    // file (as opposed to a list of contacts or timezones)
+    intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+    // Filter to show only images, using the image MIME data type.
+    // If one wanted to search for ogg vorbis files, the type would be &quot;audio/ogg&quot;.
+    // To search for all documents available via installed storage providers,
+    // it would be &quot;*/*&quot;.
+    intent.setType(&quot;image/*&quot;);
+
+    startActivityForResult(intent, READ_REQUEST_CODE);
+}</pre>
+
+<p>Perhatikan yang berikut ini:</p>
+<ul>
+<li>Saat aplikasi mengeluarkan intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
+, aplikasi akan menjalankan picker yang menampilkan semua penyedia dokumen yang cocok.</li>
+
+<li>Menambahkan kategori {@link android.content.Intent#CATEGORY_OPENABLE} ke
+intent akan menyaring hasil agar hanya menampilkan dokumen yang bisa dibuka, seperti file gambar.</li>
+
+<li>Pernyataan {@code intent.setType("image/*")} menyaring lebih jauh agar hanya
+menampilkan dokumen yang memiliki tipe data MIME gambar.</li>
+</ul>
+
+<h3 id="results">Memproses Hasil</h3>
+
+<p>Setelah pengguna memilih dokumen di picker,
+{@link android.app.Activity#onActivityResult onActivityResult()} akan dipanggil.
+URI yang menunjuk ke dokumen yang dipilih dimasukkan dalam parameter {@code resultData}
+. Ekstrak URI dengan {@link android.content.Intent#getData getData()}.
+Setelah mendapatkannya, Anda bisa menggunakannya untuk mengambil dokumen yang diinginkan pengguna. Misalnya
+:</p>
+
+<pre>&#64;Override
+public void onActivityResult(int requestCode, int resultCode,
+        Intent resultData) {
+
+    // The ACTION_OPEN_DOCUMENT intent was sent with the request code
+    // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the
+    // response to some other intent, and the code below shouldn't run at all.
+
+    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+        // The document selected by the user won't be returned in the intent.
+        // Instead, a URI to that document will be contained in the return intent
+        // provided to this method as a parameter.
+        // Pull that URI using resultData.getData().
+        Uri uri = null;
+        if (resultData != null) {
+            uri = resultData.getData();
+            Log.i(TAG, "Uri: " + uri.toString());
+            showImage(uri);
+        }
+    }
+}
+</pre>
+
+<h3 id="metadata">Memeriksa metadata dokumen</h3>
+
+<p>Setelah Anda memiliki URI untuk dokumen, Anda akan mendapatkan akses ke metadatanya. Cuplikan
+ini memegang metadata sebuah dokumen yang disebutkan oleh URI, dan mencatatnya:</p>
+
+<pre>public void dumpImageMetaData(Uri uri) {
+
+    // The query, since it only applies to a single document, will only return
+    // one row. There's no need to filter, sort, or select fields, since we want
+    // all fields for one document.
+    Cursor cursor = getActivity().getContentResolver()
+            .query(uri, null, null, null, null, null);
+
+    try {
+    // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
+    // &quot;if there's anything to look at, look at it&quot; conditionals.
+        if (cursor != null &amp;&amp; cursor.moveToFirst()) {
+
+            // Note it's called &quot;Display Name&quot;.  This is
+            // provider-specific, and might not necessarily be the file name.
+            String displayName = cursor.getString(
+                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+            Log.i(TAG, &quot;Display Name: &quot; + displayName);
+
+            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
+            // If the size is unknown, the value stored is null.  But since an
+            // int can't be null in Java, the behavior is implementation-specific,
+            // which is just a fancy term for &quot;unpredictable&quot;.  So as
+            // a rule, check if it's null before assigning to an int.  This will
+            // happen often:  The storage API allows for remote files, whose
+            // size might not be locally known.
+            String size = null;
+            if (!cursor.isNull(sizeIndex)) {
+                // Technically the column stores an int, but cursor.getString()
+                // will do the conversion automatically.
+                size = cursor.getString(sizeIndex);
+            } else {
+                size = &quot;Unknown&quot;;
+            }
+            Log.i(TAG, &quot;Size: &quot; + size);
+        }
+    } finally {
+        cursor.close();
+    }
+}
+</pre>
+
+<h3 id="open-client">Membuka dokumen</h3>
+
+<p>Setelah mendapatkan URI dokumen, Anda bisa membuka dokumen atau melakukan apa saja
+yang diinginkan padanya.</p>
+
+<h4>Bitmap</h4>
+
+<p>Berikut ini adalah contoh cara membuka {@link android.graphics.Bitmap}:</p>
+
+<pre>private Bitmap getBitmapFromUri(Uri uri) throws IOException {
+    ParcelFileDescriptor parcelFileDescriptor =
+            getContentResolver().openFileDescriptor(uri, "r");
+    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
+    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
+    parcelFileDescriptor.close();
+    return image;
+}
+</pre>
+
+<p>Perhatikan bahwa Anda tidak boleh melakukan operasi ini pada thread UI. Lakukan hal ini di latar belakang
+, dengan menggunakan {@link android.os.AsyncTask}. Setelah membuka bitmap, Anda
+bisa menampilkannya dalam {@link android.widget.ImageView}.
+</p>
+
+<h4>Mendapatkan InputStream</h4>
+
+<p>Berikut ini adalah contoh cara mendapatkan {@link java.io.InputStream} dari URI. Dalam cuplikan ini
+, baris-baris file dibaca ke dalam sebuah string:</p>
+
+<pre>private String readTextFromUri(Uri uri) throws IOException {
+    InputStream inputStream = getContentResolver().openInputStream(uri);
+    BufferedReader reader = new BufferedReader(new InputStreamReader(
+            inputStream));
+    StringBuilder stringBuilder = new StringBuilder();
+    String line;
+    while ((line = reader.readLine()) != null) {
+        stringBuilder.append(line);
+    }
+    fileInputStream.close();
+    parcelFileDescriptor.close();
+    return stringBuilder.toString();
+}
+</pre>
+
+<h3 id="create">Membuat dokumen baru</h3>
+
+<p>Aplikasi Anda bisa membuat dokumen baru dalam penyedia dokumen dengan menggunakan intent
+{@link android.content.Intent#ACTION_CREATE_DOCUMENT}
+. Untuk membuat file, Anda memberikan satu tipe MIME dan satu nama file pada intent, dan
+menjalankannya dengan kode permintaan yang unik. Selebihnya akan diurus untuk Anda:</p>
+
+
+<pre>
+// Here are some examples of how you might call this method.
+// The first parameter is the MIME type, and the second parameter is the name
+// of the file you are creating:
+//
+// createFile("text/plain", "foobar.txt");
+// createFile("image/png", "mypicture.png");
+
+// Unique request code.
+private static final int WRITE_REQUEST_CODE = 43;
+...
+private void createFile(String mimeType, String fileName) {
+    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+
+    // Filter to only show results that can be &quot;opened&quot;, such as
+    // a file (as opposed to a list of contacts or timezones).
+    intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+    // Create a file with the requested MIME type.
+    intent.setType(mimeType);
+    intent.putExtra(Intent.EXTRA_TITLE, fileName);
+    startActivityForResult(intent, WRITE_REQUEST_CODE);
+}
+</pre>
+
+<p>Setelah membuat dokumen baru, Anda bisa mendapatkan URI-nya dalam
+{@link android.app.Activity#onActivityResult onActivityResult()}, sehingga Anda
+bisa terus menulis ke dokumen itu.</p>
+
+<h3 id="delete">Menghapus dokumen</h3>
+
+<p>Jika Anda memiliki URI dokumen dan
+{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS}
+ dokumen berisi
+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE},
+Anda bisa menghapus dokumen tersebut. Misalnya:</p>
+
+<pre>
+DocumentsContract.deleteDocument(getContentResolver(), uri);
+</pre>
+
+<h3 id="edit">Mengedit dokumen</h3>
+
+<p>Anda bisa menggunakan SAF untuk mengedit dokumen teks langsung di tempatnya.
+Cuplikan ini memicu
+intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan menggunakan
+kategori {@link android.content.Intent#CATEGORY_OPENABLE} untuk menampilkan
+dokumen yang bisa dibuka saja. Ini akan menyaring lebih jauh untuk menampilkan file teks saja:</p>
+
+<pre>
+private static final int EDIT_REQUEST_CODE = 44;
+/**
+ * Open a file for writing and append some text to it.
+ */
+ private void editDocument() {
+    // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's
+    // file browser.
+    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+
+    // Filter to only show results that can be &quot;opened&quot;, such as a
+    // file (as opposed to a list of contacts or timezones).
+    intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+    // Filter to show only text files.
+    intent.setType(&quot;text/plain&quot;);
+
+    startActivityForResult(intent, EDIT_REQUEST_CODE);
+}
+</pre>
+
+<p>Berikutnya, dari {@link android.app.Activity#onActivityResult onActivityResult()}
+(lihat <a href="#results">Memproses hasil</a>) Anda bisa memanggil kode untuk mengedit.
+Cuplikan berikut mendapatkan {@link java.io.FileOutputStream}
+dari {@link android.content.ContentResolver}. Secara default, snipet menggunakan mode “tulis”.
+Inilah praktik terbaik untuk meminta jumlah akses minimum yang Anda perlukan, jadi jangan meminta
+baca/tulis jika yang Anda perlukan hanyalah tulis:</p>
+
+<pre>private void alterDocument(Uri uri) {
+    try {
+        ParcelFileDescriptor pfd = getActivity().getContentResolver().
+                openFileDescriptor(uri, "w");
+        FileOutputStream fileOutputStream =
+                new FileOutputStream(pfd.getFileDescriptor());
+        fileOutputStream.write(("Overwritten by MyCloud at " +
+                System.currentTimeMillis() + "\n").getBytes());
+        // Let the document provider know you're done by closing the stream.
+        fileOutputStream.close();
+        pfd.close();
+    } catch (FileNotFoundException e) {
+        e.printStackTrace();
+    } catch (IOException e) {
+        e.printStackTrace();
+    }
+}</pre>
+
+<h3 id="permissions">Mempertahankan izin</h3>
+
+<p>Bila aplikasi Anda membuka file untuk membaca atau menulis, sistem akan memberi
+aplikasi Anda izin URI untuk file itu. Pemberian ini berlaku hingga perangkat pengguna di-restart.
+Namun anggaplah aplikasi Anda adalah aplikasi pengeditan gambar, dan Anda ingin pengguna bisa
+mengakses 5 gambar terakhir yang dieditnya, langsung dari aplikasi Anda. Jika perangkat pengguna telah
+di-restart, maka Anda harus mengirim pengguna kembali ke picker sistem untuk menemukan
+file, hal ini jelas tidak ideal.</p>
+
+<p>Untuk mencegah terjadinya hal ini, Anda bisa mempertahankan izin yang diberikan
+sistem ke aplikasi Anda. Secara efektif, aplikasi Anda akan "mengambil" pemberian izin URI yang bisa dipertahankan
+yang ditawarkan oleh sistem. Hal ini memberi pengguna akses kontinu ke file
+melalui aplikasi Anda, sekalipun perangkat telah di-restart:</p>
+
+
+<pre>final int takeFlags = intent.getFlags()
+            &amp; (Intent.FLAG_GRANT_READ_URI_PERMISSION
+            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+// Check for the freshest data.
+getContentResolver().takePersistableUriPermission(uri, takeFlags);</pre>
+
+<p>Ada satu langkah akhir. Anda mungkin telah menyimpan
+URI terbaru yang diakses aplikasi, namun URI itu mungkin tidak lagi valid,&mdash;aplikasi lain
+mungkin telah menghapus atau memodifikasi dokumen. Karena itu, Anda harus selalu memanggil
+{@code getContentResolver().takePersistableUriPermission()} untuk memeriksa
+data terbaru.</p>
+
+<h2 id="custom">Menulis Penyedia Dokumen Custom</h2>
+
+<p>
+Jika Anda sedang mengembangkan aplikasi yang menyediakan layanan penyimpanan untuk file (misalnya
+layanan penyimpanan cloud), Anda bisa menyediakan file melalui
+SAF dengan menulis penyedia dokumen custom.  Bagian ini menjelaskan
+caranya.</p>
+
+
+<h3 id="manifest">Manifes</h3>
+
+<p>Untuk mengimplementasikan penyedia dokumen custom, tambahkan yang berikut ini ke manifes aplikasi
+Anda:</p>
+<ul>
+
+<li>Target berupa API level 19 atau yang lebih tinggi.</li>
+
+<li>Elemen <code>&lt;provider&gt;</code> yang mendeklarasikan penyedia penyimpanan custom
+Anda. </li>
+
+<li>Nama penyedia Anda, yaitu nama kelasnya, termasuk nama paket.
+Misalnya: <code>com.example.android.storageprovider.MyCloudProvider</code>.</li>
+
+<li>Nama otoritas Anda, yaitu nama paket Anda (dalam contoh ini,
+<code>com.example.android.storageprovider</code>) plus tipe penyedia konten
+(<code>documents</code>). Misalnya, {@code com.example.android.storageprovider.documents}.</li>
+
+<li>Atribut <code>android:exported</code> yang diatur ke <code>&quot;true&quot;</code>.
+Anda harus mengekspor penyedia sehingga aplikasi lain bisa membacanya.</li>
+
+<li>Atribut <code>android:grantUriPermissions</code> yang diatur ke
+<code>&quot;true&quot;</code>. Pengaturan ini memungkinkan sistem memberi aplikasi lain akses
+ke konten dalam penyedia Anda. Untuk pembahasan cara mempertahankan pemberian bagi
+dokumen tertentu, lihat <a href="#permissions">Mempertahankan izin</a>.</li>
+
+<li>Izin {@code MANAGE_DOCUMENTS}. Secara default, penyedia tersedia
+bagi siapa saja. Menambahkan izin ini akan membatasi penyedia Anda pada sistem.
+Pembatasan ini penting untuk keamanan.</li>
+
+<li>Atribut {@code android:enabled} yang diatur ke nilai boolean didefinisikan dalam file
+sumber daya. Tujuan atribut ini adalah menonaktifkan penyedia pada perangkat yang menjalankan Android 4.3 atau yang lebih rendah.
+Misalnya, {@code android:enabled="@bool/atLeastKitKat"}. Selain
+memasukkan atribut ini dalam manifes, Anda perlu melakukan hal-hal berikut:
+<ul>
+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
+baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;false&lt;/bool&gt;</pre></li>
+
+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
+baris ini: <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;true&lt;/bool&gt;</pre></li>
+</ul></li>
+
+<li>Sebuah filter intent berisi tindakan
+{@code android.content.action.DOCUMENTS_PROVIDER}, agar penyedia Anda
+muncul dalam picker saat sistem mencari penyedia.</li>
+
+</ul>
+<p>Berikut ini adalah kutipan contoh manifes berisi penyedia yang:</p>
+
+<pre>&lt;manifest... &gt;
+    ...
+    &lt;uses-sdk
+        android:minSdkVersion=&quot;19&quot;
+        android:targetSdkVersion=&quot;19&quot; /&gt;
+        ....
+        &lt;provider
+            android:name=&quot;com.example.android.storageprovider.MyCloudProvider&quot;
+            android:authorities=&quot;com.example.android.storageprovider.documents&quot;
+            android:grantUriPermissions=&quot;true&quot;
+            android:exported=&quot;true&quot;
+            android:permission=&quot;android.permission.MANAGE_DOCUMENTS&quot;
+            android:enabled=&quot;&#64;bool/atLeastKitKat&quot;&gt;
+            &lt;intent-filter&gt;
+                &lt;action android:name=&quot;android.content.action.DOCUMENTS_PROVIDER&quot; /&gt;
+            &lt;/intent-filter&gt;
+        &lt;/provider&gt;
+    &lt;/application&gt;
+
+&lt;/manifest&gt;</pre>
+
+<h4 id="43">Mendukung perangkat yang menjalankan Android 4.3 dan yang lebih rendah</h4>
+
+<p>Intent
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} hanya tersedia
+pada perangkat yang menjalankan Android 4.4 dan yang lebih tinggi.
+Jika ingin aplikasi Anda mendukung {@link android.content.Intent#ACTION_GET_CONTENT}
+untuk mengakomodasi perangkat yang menjalankan Android 4.3 dan yang lebih rendah, Anda harus
+menonaktifkan filter inten {@link android.content.Intent#ACTION_GET_CONTENT} dalam
+manifes untuk perangkat yang menjalankan Android 4.4 atau yang lebih tinggi. Penyedia
+dokumen dan {@link android.content.Intent#ACTION_GET_CONTENT} harus dianggap
+saling eksklusif. Jika Anda mendukung keduanya sekaligus, aplikasi Anda akan
+muncul dua kali dalam UI picker sistem, yang menawarkan dua cara mengakses
+data tersimpan Anda. Hal ini akan membingungkan pengguna.</p>
+
+<p>Berikut ini adalah cara yang disarankan untuk menonaktifkan
+filter intent {@link android.content.Intent#ACTION_GET_CONTENT} untuk perangkat
+yang menjalankan Android versi 4.4 atau yang lebih tinggi:</p>
+
+<ol>
+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
+baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;true&lt;/bool&gt;</pre></li>
+
+<li>Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
+baris ini: <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;false&lt;/bool&gt;</pre></li>
+
+<li>Tambahkan
+<a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">alias
+aktivitas</a> untuk menonaktifkan filter intent {@link android.content.Intent#ACTION_GET_CONTENT}
+bagi versi 4.4 (API level 19) dan yang lebih tinggi. Misalnya:
+
+<pre>
+&lt;!-- This activity alias is added so that GET_CONTENT intent-filter
+     can be disabled for builds on API level 19 and higher. --&gt;
+&lt;activity-alias android:name=&quot;com.android.example.app.MyPicker&quot;
+        android:targetActivity=&quot;com.android.example.app.MyActivity&quot;
+        ...
+        android:enabled=&quot;@bool/atMostJellyBeanMR2&quot;&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.intent.action.GET_CONTENT&quot; /&gt;
+        &lt;category android:name=&quot;android.intent.category.OPENABLE&quot; /&gt;
+        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
+        &lt;data android:mimeType=&quot;image/*&quot; /&gt;
+        &lt;data android:mimeType=&quot;video/*&quot; /&gt;
+    &lt;/intent-filter&gt;
+&lt;/activity-alias&gt;
+</pre>
+</li>
+</ol>
+<h3 id="contract">Kontrak</h3>
+
+<p>Biasanya bila Anda menulis penyedia konten custom, salah satu tugas adalah
+mengimplementasikan kelas kontrak, seperti dijelaskan dalam panduan pengembang
+<a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContractClass">
+Penyedia Konten</a>. Kelas kontrak adalah kelas {@code public final}
+yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
+metadata lain yang berkenaan dengan penyedia. SAF
+menyediakan kelas-kelas kontrak ini untuk Anda, jadi Anda tidak perlu menulisnya
+sendiri:</p>
+
+<ul>
+   <li>{@link android.provider.DocumentsContract.Document}</li>
+   <li>{@link android.provider.DocumentsContract.Root}</li>
+</ul>
+
+<p>Misalnya, berikut ini adalah kolom-kolom yang bisa Anda hasilkan di kursor bila
+penyedia dokumen Anda membuat query dokumen atau akar:</p>
+
+<pre>private static final String[] DEFAULT_ROOT_PROJECTION =
+        new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES,
+        Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+        Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
+        Root.COLUMN_AVAILABLE_BYTES,};
+private static final String[] DEFAULT_DOCUMENT_PROJECTION = new
+        String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE,
+        Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED,
+        Document.COLUMN_FLAGS, Document.COLUMN_SIZE,};
+</pre>
+
+<h3 id="subclass">Subkelas DocumentsProvider</h3>
+
+<p>Langkah berikutnya dalam menulis penyedia dokumen custom adalah menjadikan
+kelas abstrak sebagai subkelas {@link android.provider.DocumentsProvider}. Setidaknya, Anda perlu
+ mengimplementasikan metode berikut:</p>
+
+<ul>
+<li>{@link android.provider.DocumentsProvider#queryRoots queryRoots()}</li>
+
+<li>{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}</li>
+
+<li>{@link android.provider.DocumentsProvider#queryDocument queryDocument()}</li>
+
+<li>{@link android.provider.DocumentsProvider#openDocument openDocument()}</li>
+</ul>
+
+<p>Hanya inilah metode yang diwajibkan kepada Anda secara ketat untuk diimplementasikan, namun ada
+banyak lagi yang mungkin Anda inginkan. Lihat {@link android.provider.DocumentsProvider}
+untuk detailnya.</p>
+
+<h4 id="queryRoots">Mengimplementasikan queryRoots</h4>
+
+<p>Implementasi {@link android.provider.DocumentsProvider#queryRoots
+queryRoots()} oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua
+direktori akar penyedia dokumen, dengan menggunakan kolom-kolom yang didefinisikan dalam
+{@link android.provider.DocumentsContract.Root}.</p>
+
+<p>Dalam cuplikan berikut, parameter {@code projection} mewakili bidang-bidang
+tertentu yang ingin didapatkan kembali oleh pemanggil. Cuplikan ini membuat kursor baru
+dan menambahkan satu baris ke satu akar&mdash; kursor, satu direktori level atas, seperti
+Downloads atau Images.  Kebanyakan penyedia hanya mempunyai satu akar. Anda bisa mempunyai lebih dari satu,
+misalnya, jika ada banyak akun pengguna. Dalam hal itu, cukup tambahkan sebuah
+baris kedua ke kursor.</p>
+
+<pre>
+&#64;Override
+public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+
+    // Create a cursor with either the requested fields, or the default
+    // projection if "projection" is null.
+    final MatrixCursor result =
+            new MatrixCursor(resolveRootProjection(projection));
+
+    // If user is not logged in, return an empty root cursor.  This removes our
+    // provider from the list entirely.
+    if (!isUserLoggedIn()) {
+        return result;
+    }
+
+    // It's possible to have multiple roots (e.g. for multiple accounts in the
+    // same app) -- just add multiple cursor rows.
+    // Construct one row for a root called &quot;MyCloud&quot;.
+    final MatrixCursor.RowBuilder row = result.newRow();
+    row.add(Root.COLUMN_ROOT_ID, ROOT);
+    row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary));
+
+    // FLAG_SUPPORTS_CREATE means at least one directory under the root supports
+    // creating documents. FLAG_SUPPORTS_RECENTS means your application's most
+    // recently used documents will show up in the &quot;Recents&quot; category.
+    // FLAG_SUPPORTS_SEARCH allows users to search all documents the application
+    // shares.
+    row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE |
+            Root.FLAG_SUPPORTS_RECENTS |
+            Root.FLAG_SUPPORTS_SEARCH);
+
+    // COLUMN_TITLE is the root title (e.g. Gallery, Drive).
+    row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title));
+
+    // This document id cannot change once it's shared.
+    row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir));
+
+    // The child MIME types are used to filter the roots and only present to the
+    //  user roots that contain the desired type somewhere in their file hierarchy.
+    row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir));
+    row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace());
+    row.add(Root.COLUMN_ICON, R.drawable.ic_launcher);
+
+    return result;
+}</pre>
+
+<h4 id="queryChildDocuments">Mengimplementasikan queryChildDocuments</h4>
+
+<p>Implementasi
+{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}
+oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua file dalam
+direktori yang ditentukan, dengan menggunakan kolom-kolom yang didefinisikan dalam
+{@link android.provider.DocumentsContract.Document}.</p>
+
+<p>Metode ini akan dipanggil bila Anda memilih akar aplikasi dalam picker UI.
+Metode mengambil dokumen anak dari direktori di bawah akar.  Metode ini bisa dipanggil pada level apa saja dalam
+hierarki file, bukan hanya akar. Cuplikan ini
+membuat kursor baru dengan kolom-kolom yang diminta, lalu menambahkan informasi tentang
+setiap anak langsung dalam direktori induk ke kursor.
+Satu anak bisa berupa gambar, direktori lain&mdash;file apa saja:</p>
+
+<pre>&#64;Override
+public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
+                              String sortOrder) throws FileNotFoundException {
+
+    final MatrixCursor result = new
+            MatrixCursor(resolveDocumentProjection(projection));
+    final File parent = getFileForDocId(parentDocumentId);
+    for (File file : parent.listFiles()) {
+        // Adds the file's display name, MIME type, size, and so on.
+        includeFile(result, null, file);
+    }
+    return result;
+}
+</pre>
+
+<h4 id="queryDocument">Mengimplementasikan queryDocument</h4>
+
+<p>Implementasi
+{@link android.provider.DocumentsProvider#queryDocument queryDocument()}
+oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke file yang disebutkan,
+dengan menggunakan kolom-kolom yang didefinisikan dalam {@link android.provider.DocumentsContract.Document}.
+</p>
+
+<p>Metode {@link android.provider.DocumentsProvider#queryDocument queryDocument()}
+menghasilkan informasi yang sama yang diteruskan dalam
+{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()},
+namun untuk file tertentu:</p>
+
+
+<pre>&#64;Override
+public Cursor queryDocument(String documentId, String[] projection) throws
+        FileNotFoundException {
+
+    // Create a cursor with the requested projection, or the default projection.
+    final MatrixCursor result = new
+            MatrixCursor(resolveDocumentProjection(projection));
+    includeFile(result, documentId, null);
+    return result;
+}
+</pre>
+
+<h4 id="openDocument">Mengimplementasikan openDocument</h4>
+
+<p>Anda harus mengimplementasikan {@link android.provider.DocumentsProvider#openDocument
+openDocument()} untuk menghasilkan {@link android.os.ParcelFileDescriptor} yang mewakili
+file yang disebutkan. Aplikasi lain bisa menggunakan {@link android.os.ParcelFileDescriptor}
+yang dihasilkan untuk mengalirkan data. Sistem memanggil metode ini setelah pengguna memilih file
+dan aplikasi klien meminta akses ke file itu dengan memanggil
+{@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.
+Misalnya:</p>
+
+<pre>&#64;Override
+public ParcelFileDescriptor openDocument(final String documentId,
+                                         final String mode,
+                                         CancellationSignal signal) throws
+        FileNotFoundException {
+    Log.v(TAG, &quot;openDocument, mode: &quot; + mode);
+    // It's OK to do network operations in this method to download the document,
+    // as long as you periodically check the CancellationSignal. If you have an
+    // extremely large file to transfer from the network, a better solution may
+    // be pipes or sockets (see ParcelFileDescriptor for helper methods).
+
+    final File file = getFileForDocId(documentId);
+
+    final boolean isWrite = (mode.indexOf('w') != -1);
+    if(isWrite) {
+        // Attach a close listener if the document is opened in write mode.
+        try {
+            Handler handler = new Handler(getContext().getMainLooper());
+            return ParcelFileDescriptor.open(file, accessMode, handler,
+                        new ParcelFileDescriptor.OnCloseListener() {
+                &#64;Override
+                public void onClose(IOException e) {
+
+                    // Update the file with the cloud server. The client is done
+                    // writing.
+                    Log.i(TAG, &quot;A file with id &quot; +
+                    documentId + &quot; has been closed!
+                    Time to &quot; +
+                    &quot;update the server.&quot;);
+                }
+
+            });
+        } catch (IOException e) {
+            throw new FileNotFoundException(&quot;Failed to open document with id &quot;
+            + documentId + &quot; and mode &quot; + mode);
+        }
+    } else {
+        return ParcelFileDescriptor.open(file, accessMode);
+    }
+}
+</pre>
+
+<h3 id="security">Keamanan</h3>
+
+<p>Anggaplah penyedia dokumen Anda sebuah layanan penyimpanan cloud yang dilindungi kata sandi
+dan Anda ingin memastikan bahwa pengguna sudah login sebelum Anda mulai berbagi file mereka.
+Apakah yang harus dilakukan aplikasi Anda jika pengguna tidak login?  Solusinya adalah menghasilkan
+akar nol dalam implementasi {@link android.provider.DocumentsProvider#queryRoots
+queryRoots()} Anda. Yakni, sebuah kursor akar kosong:</p>
+
+<pre>
+public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+...
+    // If user is not logged in, return an empty root cursor.  This removes our
+    // provider from the list entirely.
+    if (!isUserLoggedIn()) {
+        return result;
+}
+</pre>
+
+<p>Langkah lainnya adalah memanggil {@code getContentResolver().notifyChange()}.
+Ingat {@link android.provider.DocumentsContract}?  Kita menggunakannya untuk membuat
+URI ini. Cuplikan berikut memberi tahu sistem untuk membuat query akar penyedia dokumen Anda
+kapan saja status login pengguna berubah. Jika pengguna tidak
+login, panggilan ke {@link android.provider.DocumentsProvider#queryRoots queryRoots()} akan menghasilkan
+kursor kosong, seperti yang ditampilkan di atas. Cara ini akan memastikan bahwa dokumen penyedia hanya
+tersedia jika pengguna login ke penyedia itu.</p>
+
+<pre>private void onLoginButtonClick() {
+    loginOrLogout();
+    getContentResolver().notifyChange(DocumentsContract
+            .buildRootsUri(AUTHORITY), null);
+}
+</pre>
\ No newline at end of file
diff --git a/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
new file mode 100644
index 0000000..6774557
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/resources/accessing-resources.jd
@@ -0,0 +1,337 @@
+page.title=Mengakses Sumber Daya
+parent.title=Sumber Daya Aplikasi
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Tampilan Cepat</h2>
+  <ul>
+    <li>Sumber daya bisa diacu dari kode dengan menggunakan integer dari {@code R.java}, seperti
+{@code R.drawable.myimage}</li>
+    <li>Sumber daya bisa diacu dari sumber daya dengan menggunakan sintaks XML khusus, seperti {@code
+&#64;drawable/myimage}</li>
+    <li>Anda juga bisa mengakses sumber daya aplikasi Anda dengan berbagai metode di
+{@link android.content.res.Resources}</li>
+  </ul>
+
+  <h2>Kelas-Kelas Utama</h2>
+  <ol>
+    <li>{@link android.content.res.Resources}</li>
+  </ol>
+
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#ResourcesFromCode">Mengakses Sumber Daya dari Kode</a></li>
+    <li><a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>
+      <ol>
+        <li><a href="#ReferencesToThemeAttributes">Mengacu atribut gaya</a></li>
+      </ol>
+    </li>
+    <li><a href="#PlatformResources">Mengakses Sumber Daya Platform</a></li>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
+  </ol>
+</div>
+</div>
+
+
+
+
+<p>Setelah Anda menyediakan sumber daya dalam aplikasi Anda (yang dibicarakan di <a href="providing-resources.html">Menyediakan Sumber Daya</a>), Anda bisa menerapkannya dengan
+mengacu ID sumber dayanya. Semua ID sumber daya didefinisikan di kelas {@code R} proyek Anda, yang
+dihasilkan oleh alat {@code aapt} secara otomatis.</p>
+
+<p>Bila aplikasi Anda dikompilasi, {@code aapt} akan membuat kelas {@code R}, yang berisi
+ID sumber daya untuk semua sumber daya dalam direktori {@code
+res/} Anda. Untuk masing-masing tipe sumber daya, ada subkelas {@code R} (misalnya,
+{@code R.drawable} untuk semua sumber daya yang bisa ditarik), dan untuk masing-masing sumber daya dari tipe itu, ada satu integer statis
+ (misalnya, {@code R.drawable.icon}). Integer ini adalah ID sumber daya yang bisa Anda gunakan
+untuk mengambil sumber daya Anda.</p>
+
+<p>Walaupun kelas {@code R} adalah tempat menyebutkan ID sumber daya, Anda tidak perlu
+melihat ke sana untuk menemukan ID sumber daya. ID sumber daya selalu terdiri dari:</p>
+<ul>
+  <li><em>Tipe sumber daya</em>: Masing-masing sumber daya dikelompokkan menjadi "tipe", misalnya {@code
+string}, {@code drawable}, dan {@code layout}. Untuk mengetahui selengkapnya tentang berbagai tipe, lihat <a href="available-resources.html">Tipe Sumber Daya</a>.
+  </li>
+  <li><em>Nama sumber daya</em>, bisa berupa: nama file,
+tidak termasuk ekstensi; atau nilai dalam atribut {@code android:name} XML, jika
+sumber daya itu sebuah nilai sederhana (misalnya sebuah string).</li>
+</ul>
+
+<p>Ada dua cara untuk mengakses sumber daya:</p>
+<ul>
+  <li><strong>Dalam kode:</strong> Menggunakan integer statis dari subkelas dari kelas {@code R}
+, misalnya:
+    <pre class="classic no-pretty-print">R.string.hello</pre>
+    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Ada banyak
+API Android yang bisa mengakses sumber daya Anda bila Anda menyediakan ID sumber daya dengan format ini. Lihat
+<a href="#ResourcesFromCode">Mengakses Sumber Daya dalam Kode</a>.</p>
+  </li>
+  <li><strong>Dalam XML:</strong> Menggunakan sebuah sintaks XML khusus yang juga berkaitan dengan
+ID sumber daya yang didefinisikan dalam kelas {@code R}, misalnya:
+    <pre class="classic no-pretty-print">&#64;string/hello</pre>
+    <p>{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Anda bisa menggunakan
+sintaks ini dalam sumber daya XML di mana saja Anda ingin menyediakan sebuah nilai dalam sebuah sumber daya. Lihat <a href="#ResourcesFromXml">Mengakses Sumber Daya dari XML</a>.</p>
+  </li>
+</ul>
+
+
+
+<h2 id="ResourcesFromCode">Mengakses Sumber Daya dalam Kode </h2>
+
+<p>Anda bisa menggunakan sumber daya dalam kode dengan menyalurkan ID sumber daya sebagai sebuah parameter metode. Misalnya,
+ Anda bisa mengatur sebuah {@link android.widget.ImageView} agar menggunakan sumber daya{@code res/drawable/myimage.png}
+dengan menggunakan {@link android.widget.ImageView#setImageResource(int) setImageResource()}:</p>
+<pre>
+ImageView imageView = (ImageView) findViewById(R.id.myimageview);
+imageView.setImageResource(<strong>R.drawable.myimage</strong>);
+</pre>
+
+<p>Anda juga bisa mengambil tiap sumber daya dengan menggunakan berbagai metode di {@link
+android.content.res.Resources}, di mana Anda bisa mendapatkan instance
+ {@link android.content.Context#getResources()}.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Akses ke File Asli</h2>
+
+<p>Walaupun tidak lazim, Anda mungkin perlu mengakses file dan direktori asli Anda. Jika demikian, maka
+menyimpan file Anda di {@code res/} tidak akan berhasil, karena satu-satunya cara untuk membaca sebuah sumber daya dari
+{@code res/} adalah dengan ID sumber daya. Sebagai gantinya, Anda bisa menyimpan sumber daya dalam direktori
+{@code assets/}.</p>
+<p>File yang tersimpan di direktori {@code assets/} <em>tidak</em> diberi ID
+sumber daya, sehingga Anda tidak bisa mengacunya melalui kelas {@code R} atau dari sumber daya XML. Sebagai gantinya, Anda bisa melakukan
+query file di direktori {@code assets/} seperti sebuah sistem file biasa dan membaca data mentah dengan menggunakan
+{@link android.content.res.AssetManager}.</p>
+<p>Akan tetapi, jika yang Anda butuhkan hanya kemampuan membaca data mentah (misalnya sebuah file video atau audio),
+maka simpanlah file itu di direktori {@code res/raw/} dan baca aliran byte dengan menggunakan {@link
+android.content.res.Resources#openRawResource(int) openRawResource()}.</p>
+
+</div>
+</div>
+
+
+<h3>Sintaks</h3>
+
+<p>Inilah sintaks untuk mengacu sumber daya dalam kode:</p>
+
+<pre class="classic no-pretty-print">
+[<em>&lt;package_name&gt;</em>.]R.<em>&lt;resource_type&gt;</em>.<em>&lt;resource_name&gt;</em>
+</pre>
+
+<ul>
+  <li><em> {@code &lt;package_name&gt;}</em>adalah nama paket yang di dalamnya terdapat sumber daya (tidak
+dibutuhkan bila mengacu sumber daya dari paket Anda sendiri).</li>
+  <li><em>{@code &lt;resource_type&gt;}</em> adalah subkelas {@code R} untuk tipe sumber daya.</li>
+  <li><em>{@code &lt;resource_name&gt;}</em> bisa berupa nama file sumber daya
+tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
+sederhana).</li>
+</ul>
+<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
+informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
+
+
+<h3>Kasus penggunaan</h3>
+
+<p>Ada banyak metode yang menerima parameter ID sumber daya dan Anda bisa mengambil sumber daya dengan menggunakan
+metode di {@link android.content.res.Resources}. Anda bisa mengambil instance {@link
+android.content.res.Resources} dengan {@link android.content.Context#getResources
+Context.getResources()}.</p>
+
+
+<p>Berikut adalah beberapa contoh cara mengakses sumber daya dalam kode:</p>
+
+<pre>
+// Load a background for the current screen from a drawable resource
+{@link android.app.Activity#getWindow()}.{@link
+android.view.Window#setBackgroundDrawableResource(int)
+setBackgroundDrawableResource}(<strong>R.drawable.my_background_image</strong>) ;
+
+// Set the Activity title by getting a string from the Resources object, because
+//  this method requires a CharSequence rather than a resource ID
+{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence)
+setTitle}(getResources().{@link android.content.res.Resources#getText(int)
+getText}(<strong>R.string.main_title</strong>));
+
+// Load a custom layout for the current screen
+{@link android.app.Activity#setContentView(int)
+setContentView}(<strong>R.layout.main_screen</strong>);
+
+// Set a slide in animation by getting an Animation from the Resources object
+mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation)
+setInAnimation}(AnimationUtils.loadAnimation(this,
+        <strong>R.anim.hyperspace_in</strong>));
+
+// Set the text on a TextView object using a resource ID
+TextView msgTextView = (TextView) findViewById(<strong>R.id.msg</strong>);
+msgTextView.{@link android.widget.TextView#setText(int)
+setText}(<strong>R.string.hello_message</strong>);
+</pre>
+
+
+<p class="caution"><strong>Perhatian:</strong> Anda tidak boleh memodifikasi file {@code
+R.java} secara manual&mdash;, ini dihasilkan oleh alat {@code aapt} bila proyek Anda telah
+dikompilasi. Perubahan apa pun akan ditimpa bila nanti Anda mengompilasi.</p>
+
+
+
+<h2 id="ResourcesFromXml">Mengakses Sumber Daya dari XML</h2>
+
+<p>Anda bisa mendefinisikan nilai untuk beberapa atribut dan elemen XML dengan menggunakan
+acuan ke sumber daya yang ada. Anda akan sering melakukannya saat membuat file layout, untuk
+memasok string dan gambar bagi widget Anda.</p>
+
+<p>Misalnya, jika Anda menambahkan sebuah {@link android.widget.Button} ke layout, Anda harus menggunakan
+sebuah <a href="string-resource.html">sumber daya string</a> bagi teks tombolnya:</p>
+
+<pre>
+&lt;Button
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:text="<strong>@string/submit</strong>" /&gt;
+</pre>
+
+
+<h3>Sintaks</h3>
+
+<p>Berikut adalah sintaks untuk mengacu sumber daya di sumber daya XML:</p>
+
+<pre class="classic no-pretty-print">
+&#64;[<em>&lt;package_name&gt;</em>:]<em>&lt;resource_type&gt;</em>/<em>&lt;resource_name&gt;</em>
+</pre>
+
+<ul>
+  <li>{@code &lt;package_name&gt;} adalah nama paket yang di dalamnya terdapat sumber daya (tidak
+dibutuhkan bila mengacu sumber daya dari paket yang sama)</li>
+  <li>{@code &lt;resource_type&gt;} adalah subkelas
+{@code R} untuk tipe sumber daya</li>
+  <li>{@code &lt;resource_name&gt;} bisa berupa nama file sumber daya
+tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai
+sederhana).</li>
+</ul>
+
+<p>Lihat <a href="available-resources.html">Tipe Sumber Daya</a> untuk
+informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.</p>
+
+
+<h3>Kasus penggunaan</h3>
+
+<p>Dalam beberapa kasus, Anda harus menggunakan sumber daya untuk suatu nilai dalam XML (misalnya, untuk menerapkan gambar yang bisa ditarik
+pada widget), namun Anda juga bisa menggunakan sumber daya di XML mana saja yang menerima nilai sederhana. Misalnya, jika
+Anda mempunyai file sumber daya berikut yang berisi <a href="more-resources.html#Color">sumber daya warna</a> dan <a href="string-resource.html">sumber daya string</a>:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+   &lt;color name="opaque_red">#f00&lt;/color>
+   &lt;string name="hello">Hello!&lt;/string>
+&lt;/resources>
+</pre>
+
+<p>Anda bisa menggunakan sumber daya ini dalam file layout berikut untuk mengatur warna teks dan
+string teks:</p>
+
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+    android:layout_width=&quot;fill_parent&quot;
+    android:layout_height=&quot;fill_parent&quot;
+    android:textColor=&quot;<strong>&#64;color/opaque_red</strong>&quot;
+    android:text=&quot;<strong>&#64;string/hello</strong>&quot; /&gt;
+</pre>
+
+<p>Dalam hal ini, Anda tidak perlu menyebutkan nama paket dalam sumber daya acuan karena
+sumber daya berasal dari paket Anda sendiri. Untuk
+mengacu sumber daya sistem, Anda perlu memasukkan nama paketnya. Misalnya:</p>
+
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+    android:layout_width=&quot;fill_parent&quot;
+    android:layout_height=&quot;fill_parent&quot;
+    android:textColor=&quot;<strong>&#64;android:color/secondary_text_dark</strong>&quot;
+    android:text=&quot;&#64;string/hello&quot; /&gt;
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Anda harus menggunakan sumber daya string sepanjang
+waktu, sehingga aplikasi Anda bisa dilokalkan untuk bahasa lain.
+Untuk informasi tentang cara menciptakan
+sumber daya alternatif (seperti string lokal), lihat <a href="providing-resources.html#AlternativeResources">Menyediakan Sumber Daya Alternatif
+</a>. Untuk panduan lengkap melokalkan aplikasi Anda ke bahasa lain,
+lihat <a href="localization.html">Pelokalan</a>.</p>
+
+<p>Anda bahkan bisa menggunakan sumber daya dalam XML untuk membuat alias. Misalnya, Anda bisa membuat
+sumber daya yang bisa ditarik yang merupakan alias bagi sumber daya yang bisa ditarik lainnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/other_drawable" />
+</pre>
+
+<p>Hal ini terdengar berlebihan, namun bisa sangat berguna saat menggunakan sumber daya alternatif. Baca selengkapnya tentang
+<a href="providing-resources.html#AliasResources">Membuat sumber daya alias</a>.</p>
+
+
+
+<h3 id="ReferencesToThemeAttributes">Mengacu atribut gaya</h3>
+
+<p>Sumber daya atribut gaya memungkinkan Anda mengacu nilai
+suatu atribut dalam tema yang diterapkan saat ini. Dengan mengacu sebuah atribut gaya memungkinkan Anda
+menyesuaikan tampilan elemen UI dengan mengatur gayanya agar cocok dengan beragam variasi standar yang dipasok oleh
+tema saat ini, sebagai ganti memasok nilai yang ditanamkan (hard-coded). Mengacu sebuah atribut gaya
+pada dasarnya adalah "gunakan gaya yang didefinisikan oleh atribut ini, dalam tema saat ini".</p>
+
+<p>Untuk mengacu sebuah atribut gaya, sintaks namanya hampir sama dengan format sumber daya normal
+, namun sebagai ganti simbol @ ({@code @}), gunakan sebuah tanda tanya ({@code ?}), dan
+porsi tipe sumber daya bersifat opsional. Sebagai contoh:</p>
+
+<pre class="classic">
+?[<em>&lt;package_name&gt;</em>:][<em>&lt;resource_type&gt;</em>/]<em>&lt;resource_name&gt;</em>
+</pre>
+
+<p>Misalnya, begini cara Anda mengacu suatu atribut untuk mengatur warna teks agar cocok dengan
+warna teks "utama" tema sistem:</p>
+
+<pre>
+&lt;EditText id=&quot;text&quot;
+    android:layout_width=&quot;fill_parent&quot;
+    android:layout_height=&quot;wrap_content&quot;
+    android:textColor=&quot;<strong>?android:textColorSecondary</strong>&quot;
+    android:text=&quot;&#64;string/hello_world&quot; /&gt;
+</pre>
+
+<p>Di sini, atribut {@code android:textColor} menyebutkan nama atribut gaya
+dalam tema saat ini. Android kini menggunakan nilai yang diterapkan pada atribut gaya {@code android:textColorSecondary}
+sebagai nilai untuk {@code android:textColor} dalam widget ini. Karena alat sumber daya
+mengetahui bahwa atribut sumber daya diharapkan dalam konteks ini,
+maka Anda tidak perlu menyatakan tipenyanya secara eksplisit (yang akan berupa
+<code>?android:attr/textColorSecondary</code>)&mdash;Anda bisa mengecualikan tipe {@code attr}.</p>
+
+
+
+
+<h2 id="PlatformResources">Mengakses Sumber Daya Platform</h2>
+
+<p>Android berisi sejumlah sumber daya standar, seperti gaya, tema, dan layout. Untuk
+mengakses semua sumber daya ini, tetapkan acuan sumber daya Anda dengan nama paket
+<code>android</code>. Misalnya, Android menyediakan sumber daya layout yang bisa Anda gunakan untuk
+item daftar dalam{@link android.widget.ListAdapter}:</p>
+
+<pre>
+{@link android.app.ListActivity#setListAdapter(ListAdapter)
+setListAdapter}(new {@link
+android.widget.ArrayAdapter}&lt;String&gt;(this, <strong>android.R.layout.simple_list_item_1</strong>, myarray));
+</pre>
+
+<p>Dalam contoh ini, {@link android.R.layout#simple_list_item_1} adalah sumber daya layout yang didefinisikan oleh
+platform untuk item di {@link android.widget.ListView}. Anda bisa menggunakannya sebagai ganti menciptakan
+layout sendiri untuk item daftar. Untuk informasi selengkapnya, lihat panduan pengembang
+<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>.</p>
+
diff --git a/docs/html-intl/intl/id/guide/topics/resources/overview.jd b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
new file mode 100644
index 0000000..def4932
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/resources/overview.jd
@@ -0,0 +1,103 @@
+page.title=Ikhtisar Sumber Daya
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Topik</h2>
+  <ol>
+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
+    <li><a href="runtime-changes.html">Menangani Perubahan Runtime</a></li>
+    <li><a href="localization.html">Pelokalan</a></li>
+  </ol>
+
+  <h2>Acuan</h2>
+  <ol>
+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
+  </ol>
+</div>
+</div>
+
+
+<p>Anda harus selalu mengeksternalkan sumber daya seperti gambar dan string dari kode
+aplikasi, agar Anda bisa memeliharanya secara independen. Mengeksternalkan
+sumber daya juga membuat Anda dapat menyediakan sumber daya alternatif yang mendukung konfigurasi
+perangkat tertentu seperti bahasa atau ukuran layar yang berbeda, yang semakin penting
+seiring semakin banyak tersedianya perangkat berbasis Android dengan konfigurasi berbeda. Untuk
+memberikan kompatibilitas dengan konfigurasi berbeda, Anda harus menata sumber daya dalam
+direktori {@code res/} proyek Anda, menggunakan berbagai subdirektori yang mengelompokkan sumber daya menurut tipe
+dan konfigurasinya.</p>
+
+<div class="figure" style="width:429px">
+<img src="{@docRoot}images/resources/resource_devices_diagram1.png" height="167" alt="" />
+<p class="img-caption">
+<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan layout default
+(aplikasi tidak menyediakan layout alternatif).</p>
+</div>
+
+<div class="figure" style="width:429px">
+<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
+<p class="img-caption">
+<strong>Gambar 2.</strong> Dua perangkat berbeda, masing-masing menggunakan layout berbeda yang tersedia untuk
+ukuran layar berbeda.</p>
+</div>
+
+<p>Bagi setiap tipe sumber daya, Anda bisa menetapkan sumber daya <em>default</em> dan sumber daya
+<em>alternatif</em> untuk aplikasi Anda:</p>
+<ul>
+  <li>Sumber daya default adalah sumber daya yang harus digunakan apa pun
+konfigurasi perangkatnya atau jika tidak ada sumber daya alternatif yang sesuai
+dengan konfigurasi saat ini.</li>
+  <li>Sumber daya alternatif adalah sumber daya yang Anda desain untuk digunakan dengan
+konfigurasi tertentu. Untuk menetapkan bahwa satu kelompok sumber daya ditujukan bagi konfigurasi tertentu,
+tambahkan qualifier konfigurasi yang sesuai ke nama direktori.</li>
+</ul>
+
+<p>Misalnya, walaupun layout
+UI default Anda disimpan dalam direktori {@code res/layout/}, Anda dapat menetapkan layout berbeda
+untuk digunakan saat layar dalam orientasi lanskap, dengan menyimpannya dalam direktori {@code res/layout-land/}
+. Android secara otomatis memberlakukan sumber daya yang sesuai dengan mencocokkan konfigurasi perangkat
+saat ini dengan nama direktori sumber daya.</p>
+
+<p>Gambar 1 mengilustrasikan cara sistem memberlakukan layout yang sama untuk
+dua perangkat berbeda saat sumber daya alternatif tidak tersedia. Gambar 2 menunjukkan
+aplikasi yang sama saat menambahkan sumber daya layout alternatif untuk layar yang lebih besar.</p>
+
+<p>Dokumen-dokumen berikut berisi panduan lengkap mengenai cara menata sumber daya aplikasi,
+menetapkan sumber daya alternatif, mengaksesnya dalam aplikasi, dan banyak lagi:</p>
+
+<dl>
+  <dt><strong><a href="providing-resources.html">Menyediakan Sumber Daya</a></strong></dt>
+  <dd>Jenis sumber daya yang dapat Anda sediakan dalam aplikasi, tempat menyimpannya, dan cara membuat sumber daya
+alternatif untuk konfigurasi perangkat tertentu.</dd>
+  <dt><strong><a href="accessing-resources.html">Mengakses Sumber Daya</a></strong></dt>
+  <dd>Cara menggunakan sumber daya yang telah Anda sediakan, baik dengan mengacunya dari kode
+aplikasi Anda atau dari sumber daya XML lainnya.</dd>
+  <dt><strong><a href="runtime-changes.html">Menangani Perubahan Runtime</a></strong></dt>
+  <dd>Cara mengelola perubahan konfigurasi yang terjadi saat Aktivitas Anda berjalan.</dd>
+  <dt><strong><a href="localization.html">Pelokalan</a></strong></dt>
+  <dd>Panduan dari pengalaman untuk melokalkan aplikasi menggunakan sumber daya alternatif. Walaupun ini
+hanya satu penggunaan tertentu dari sumber daya alternatif, hal ini sangat penting dalam meraih pengguna lebih
+banyak.</dd>
+  <dt><strong><a href="available-resources.html">Tipe Sumber Daya</a></strong></dt>
+  <dd>Acuan dari berbagai tipe sumber daya yang dapat Anda sediakan, menjelaskan elemen-elemen XML,
+atribut, dan sintaksnya. Misalnya, acuan ini menunjukkan kepada Anda cara membuat sumber daya untuk
+menu aplikasi, drawable, animasi, dan lainnya.</dd>
+</dl>
+
+<!--
+<h2>Raw Assets</h2>
+
+<p>An alternative to saving files in {@code res/} is to save files in the {@code
+assets/} directory. This should only be necessary if you need direct access to original files and
+directories by name. Files saved in the {@code assets/} directory will not be given a resource
+ID, so you can't reference them through the {@code R} class or from XML resources. Instead, you can
+query data in the {@code assets/} directory like an ordinary file system, search through the
+directory and
+read raw data using {@link android.content.res.AssetManager}. For example, this can be more useful
+when dealing with textures for a game. However, if you only need to read raw data from a file
+(such as a video or audio file), then you should save files into the {@code res/raw/} directory and
+then read a stream of bytes using {@link android.content.res.Resources#openRawResource(int)}. This
+is uncommon, but if you need direct access to original files in {@code assets/}, refer to the {@link
+android.content.res.AssetManager} documentation.</p>
+-->
diff --git a/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
new file mode 100644
index 0000000..9bccd24
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/resources/providing-resources.jd
@@ -0,0 +1,1094 @@
+page.title=Menyediakan Sumber Daya
+parent.title=Sumber Daya Aplikasi
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Tampilan Cepat</h2>
+  <ul>
+    <li>Berbagai tipe sumber daya termasuk dalam subdirektori {@code res/}</li>
+    <li>Sumber daya alternatif menyediakan file sumber daya dengan konfigurasi tertentu</li>
+    <li>Sertakan selalu sumber daya default agar aplikasi Anda tidak bergantung pada
+konfigurasi perangkat tertentu</li>
+  </ul>
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#ResourceTypes">Mengelompokkan Tipe Sumber Daya</a></li>
+    <li><a href="#AlternativeResources">Menyediakan Sumber Daya Alternatif</a>
+      <ol>
+        <li><a href="#QualifierRules">Aturan penamaan qualifier</a></li>
+        <li><a href="#AliasResources">Membuat sumber daya alias</a></li>
+      </ol>
+    </li>
+    <li><a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</a></li>
+    <li><a href="#BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</a></li>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
+    <li><a href="available-resources.html">Tipe Sumber Daya</a></li>
+    <li><a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
+Layar</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Anda harus selalu mengeksternalkan sumber daya aplikasi seperti gambar dan string dari kode
+, agar Anda bisa memeliharanya secara independen. Anda juga harus menyediakan sumber daya alternatif untuk
+konfigurasi perangkat tertentu, dengan mengelompokkannya dalam direktori sumber daya bernama khusus. Saat
+runtime, Android menggunakan sumber daya yang sesuai berdasarkan konfigurasi saat ini. Misalnya, Anda mungkin
+ingin menyediakan layout UI berbeda bergantung pada ukuran layar atau string berbeda bergantung pada
+pengaturan bahasa.</p>
+
+<p>Setelah mengeksternalkan sumber daya aplikasi, Anda dapat mengaksesnya menggunakan
+ID sumber daya yang dibuat dalam kelas {@code R} proyek Anda. Cara menggunakan
+sumber daya dalam aplikasi dibahas dalam <a href="accessing-resources.html">Mengakses
+Sumber Daya</a>. Dokumen ini menampilkan cara mengelompokkan sumber daya
+dalam proyek Android Anda dan menyediakan sumber daya alternatif untuk konfigurasi perangkat tertentu.</p>
+
+
+<h2 id="ResourceTypes">Mengelompokkan Tipe Sumber Daya</h2>
+
+<p>Anda harus menempatkan setiap tipe sumber daya dalam subdirektori spesifik pada direktori
+{@code res/} proyek. Misalnya, inilah hierarki file untuk proyek sederhana:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+    src/  <span style="color:black">
+        MyActivity.java  </span>
+    res/
+        drawable/  <span style="color:black">
+            graphic.png  </span>
+        layout/  <span style="color:black">
+            main.xml
+            info.xml</span>
+        mipmap/  <span style="color:black">
+            icon.png </span>
+        values/  <span style="color:black">
+            strings.xml  </span>
+</pre>
+
+<p>Seperti yang Anda lihat dalam contoh ini, direktori {@code res/} berisi semua sumber daya (dalam
+subdirektori): sumber daya gambar, dua sumber daya layout, direktori {@code mipmap/} untuk ikon
+launcher, dan satu file sumber daya string. Nama direktori
+sumber daya penting dan dijelaskan dalam tabel 1.</p>
+
+<p class="note"><strong>Catatan:</strong> Untuk informasi selengkapnya tentang menggunakan folder mipmap, lihat
+<a href="{@docRoot}tools/projects/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</p>
+
+<p class="table-caption" id="table1"><strong>Tabel 1.</strong> Direktori sumber daya
+didukung dalam direktori proyek {@code res/}.</p>
+
+<table>
+  <tr>
+    <th scope="col">Direktori</th>
+    <th scope="col">Tipe Sumber Daya</th>
+  </tr>
+
+  <tr>
+    <td><code>animator/</code></td>
+    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/prop-animation.html">animasi
+properti</a>.</td>
+  </tr>
+
+  <tr>
+    <td><code>anim/</code></td>
+    <td>File XML yang mendefinisikan <a href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">animasi
+tween</a>. (Animasi properti juga dapat disimpan dalam direktori ini, namun
+direktori {@code animator/} lebih disukai bagi animasi properti agar kedua tipe
+ini dapat dibedakan.)</td>
+  </tr>
+
+  <tr>
+    <td><code>color/</code></td>
+    <td>File XML yang mendefinisikan daftar status warna. Lihat <a href="color-list-resource.html">Sumber Daya
+Daftar Status Warna</a></td>
+  </tr>
+
+  <tr>
+    <td><code>drawable/</code></td>
+
+    <td><p>File bitmap ({@code .png}, {@code .9.png}, {@code .jpg}, {@code .gif}) atau file XML yang
+dikompilasi menjadi subtipe sumber daya drawable berikut:</p>
+      <ul>
+        <li>File bitmap</li>
+        <li>Nine-Patches (bitmap yang dapat diubah ukurannya)</li>
+        <li>Daftar status</li>
+        <li>Bentuk</li>
+        <li>Drawable animasi</li>
+        <li>Drawable lainnya</li>
+      </ul>
+      <p>Lihat <a href="drawable-resource.html">Sumber Daya Drawable</a>.</p>
+    </td>
+  </tr>
+
+  <tr>
+    <td><code>mipmap/</code></td>
+    <td>File drawable untuk densitas ikon launcher yang berbeda. Untuk informasi selengkapnya tentang
+ mengelola ikon launcher dengan folder {@code mipmap/}, lihat
+<a href="{@docRoot}tools/project/index.html#mipmap">Mengelola Ikhtisar Proyek</a>.</td>
+  </tr>
+
+  <tr>
+    <td><code>layout/</code></td>
+    <td>File XML yang mendefinisikan layout antarmuka pengguna.
+        Lihat <a href="layout-resource.html">Sumber Daya Layout</a>.</td>
+  </tr>
+
+  <tr>
+    <td><code>menu/</code></td>
+    <td>File XML yang mendefinisikan menu aplikasi, seperti Menu Opsi, Menu Konteks, atau Sub
+Menu. Lihat <a href="menu-resource.html">Sumber Daya Menu</a>.</td>
+  </tr>
+
+  <tr>
+    <td><code>raw/</code></td>
+    <td><p>File tak didukung yang akan disimpan dalam bentuk mentah. Untuk membuka sumber daya ini dengan
+{@link java.io.InputStream} mentah, panggil {@link android.content.res.Resources#openRawResource(int)
+Resources.openRawResource()} dengan ID sumber daya, yaitu {@code R.raw.<em>filename</em>}.</p>
+      <p>Akan tetapi, jika Anda butuh akses ke nama file asli dan hierarki file, Anda bisa mempertimbangkan
+untuk menyimpan beberapa sumber daya dalam direktori {@code
+assets/} (sebagai ganti {@code res/raw/}). File dalam {@code assets/} tidak diberi
+ID sumber daya, jadi Anda bisa membacanya hanya dengan menggunakan {@link android.content.res.AssetManager}.</p></td>
+  </tr>
+
+  <tr>
+    <td><code>values/</code></td>
+    <td><p>File XML yang berisi nilai-nilai sederhana, seperti string, integer, dan warna.</p>
+      <p>Walaupun file sumber daya XML dalam subdirektori {@code res/} lainnya mendefinisikan satu sumber daya
+berdasarkan nama file XML, file dalam direktori {@code values/} menggambarkan beberapa sumber daya.
+Untuk file dalam direktori ini, setiap anak elemen {@code &lt;resources&gt;} mendefinisikan satu sumber
+daya. Misalnya, elemen {@code &lt;string&gt;} membuat sumber daya
+{@code R.string} dan elemen {@code &lt;color&gt;} membuat sumber daya {@code R.color}
+.</p>
+      <p>Karena setiap sumber daya didefinisikan dengan elemen XML-nya sendiri, Anda bisa bebas menamai file
+ini dan menempatkan tipe sumber daya berbeda dalam satu file. Akan tetapi, agar jelas, Anda mungkin
+perlu menempatkan tipe sumber daya unik dalam file berbeda. Misalnya, berikut ini adalah beberapa ketentuan
+penamaan file untuk sumber daya yang dapat Anda buat dalam direktori ini:</p>
+      <ul>
+        <li>arrays.xml untuk larik sumber daya tipe (<a href="more-resources.html#TypedArray">larik bertipe</a>).</li>
+        <li>colors.xml untuk <a href="more-resources.html#Color">nilai warna</a></li>
+        <li>dimens.xml untuk <a href="more-resources.html#Dimension">nilai dimensi</a>.</li>
+        <li>strings.xml untuk <a href="string-resource.html">nilai
+string</a>.</li>
+        <li>styles.xml untuk <a href="style-resource.html">gaya</a>.</li>
+      </ul>
+      <p>Lihat <a href="string-resource.html">Sumber Daya String</a>,
+        <a href="style-resource.html">Sumber Daya Gaya</a>, dan
+        <a href="more-resources.html">Tipe Sumber Daya Lainnya</a>.</p>
+    </td>
+  </tr>
+
+  <tr>
+    <td><code>xml/</code></td>
+    <td>File XML tak didukung yang bisa dibaca saat runtime dengan memanggil {@link
+android.content.res.Resources#getXml(int) Resources.getXML()}. Berbagai file konfigurasi XML
+harus disimpan di sini, seperti <a href="{@docRoot}guide/topics/search/searchable-config.html">konfigurasi yang dapat dicari</a>.
+<!-- or preferences configuration. --></td>
+  </tr>
+</table>
+
+<p class="caution"><strong>Perhatian:</strong> Jangan menyimpan file sumber daya secara langsung dalam
+direktori {@code res/}&mdash; karena akan menyebabkan kesalahan compiler.</p>
+
+<p>Untuk informasi selengkapnya tentang tipe sumber daya tertentu, lihat dokumentasi <a href="available-resources.html">Tipe Sumber Daya</a>.</p>
+
+<p>Sumber daya yang disimpan dalam subdirektori yang didefinisikan dalam tabel 1 adalah sumber daya
+"default" Anda. Berarti sumber daya ini mendefinisikan desain default dan konten untuk aplikasi Anda.
+Akan tetapi, beberapa tipe perangkat berbasis Android mungkin memanggil tipe sumber daya yang berbeda.
+Misalnya, jika perangkat memiliki layar yang lebih besar daripada layar normal, maka Anda harus
+menyediakan sumber daya layout berbeda yang memanfaatkan ruang layar yang lebih besar. Atau, jika perangkat
+memiliki pengaturan bahasa berbeda, maka Anda harus menyediakan sumber daya string berbeda yang menerjemahkan teks dalam
+antarmuka pengguna Anda. Untuk menyediakan sumber daya berbeda ini bagi
+konfigurasi perangkat yang berbeda, Anda harus menyediakan sumber daya alternatif, selain sumber
+daya default.</p>
+
+
+<h2 id="AlternativeResources">Menyediakan Sumber Daya Alternatif</h2>
+
+
+<div class="figure" style="width:429px">
+<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" />
+<p class="img-caption">
+<strong>Gambar 1.</strong> Dua perangkat berbeda, masing-masing menggunakan sumber daya layout berbeda.</p>
+</div>
+
+<p>Hampir setiap aplikasi harus menyediakan sumber daya alternatif untuk mendukung konfigurasi
+perangkat tertentu. Misalnya, Anda harus menyertakan sumber daya drawable alternatif untuk densitas layar
+berbeda dan sumber daya string alternatif untuk bahasa yang berbeda. Saat runtime, Android
+akan mendeteksi konfigurasi perangkat aktif dan memuat
+sumber daya yang sesuai untuk aplikasi Anda.</p>
+
+<p>Untuk menyebutkan alternatif konfigurasi tertentu untuk satu set sumber daya:</p>
+<ol>
+  <li>Buat direktori baru dalam {@code res/} yang dinamai dalam bentuk {@code
+<em>&lt;resources_name&gt;</em>-<em>&lt;config_qualifier&gt;</em>}.
+    <ul>
+      <li><em>{@code &lt;resources_name&gt;}</em> adalah nama direktori dari sumber daya default
+terkait (didefinisikan dalam tabel 1).</li>
+      <li><em>{@code &lt;qualifier&gt;}</em> adalah nama yang menetapkan konfigurasi individu
+yang akan digunakan sumber daya ini (didefinisikan dalam tabel 2).</li>
+    </ul>
+    <p>Anda bisa menambahkan lebih dari satu <em>{@code &lt;qualifier&gt;}</em>. Pisahkan masing-masing
+dengan tanda hubung.</p>
+    <p class="caution"><strong>Perhatian:</strong> Saat menambahkan beberapa qualifier, Anda
+harus menempatkannya dalam urutan yang sama dengan yang tercantum dalam tabel 2. Jika urutan qualifier
+salah, sumber daya akan diabaikan.</p>
+  </li>
+  <li>Simpan masing-masing sumber daya alternatif dalam direktori baru ini. File sumber daya harus dinamai
+sama persis dengan file sumber daya default.</li>
+</ol>
+
+<p>Misalnya, berikut ini beberapa sumber daya default dan sumber daya alternatif:</p>
+
+<pre class="classic no-pretty-print">
+res/
+    drawable/   <span style="color:black">
+        icon.png
+        background.png    </span>
+    drawable-hdpi/  <span style="color:black">
+        icon.png
+        background.png  </span>
+</pre>
+
+<p>Qualifier {@code hdpi} menunjukkan bahwa sumber daya dalam direktori itu diperuntukkan bagi perangkat dengan
+layar densitas tinggi. Gambar di masing-masing direktori drawable memiliki ukuran untuk densitas layar
+tertentu, namun nama filenya persis
+sama. Dengan demikian, ID sumber daya yang Anda gunakan untuk mengacu gambar {@code icon.png} atau @code
+background.png} selalu sama, namun Android memilih
+versi masing-masing sumber daya yang paling cocok dengan perangkat saat ini, dengan membandingkan informasi konfigurasi
+perangkat dengan qualifier dalam nama direktori sumber daya.</p>
+
+<p>Android mendukung beberapa qualifier konfigurasi dan Anda dapat
+menambahkan beberapa qualifier ke satu nama direktori, dengan memisahkan setiap qualifier dengan tanda hubung. Tabel 2
+berisi daftar qualifier konfigurasi yang valid, dalam urutan prioritas&mdash;jika Anda menggunakan beberapa
+qualifier sebagai direktori sumber daya, Anda harus menambahkannya ke nama direktori sesuai urutan
+yang tercantum dalam tabel.</p>
+
+
+<p class="table-caption" id="table2"><strong>Tabel 2.</strong> Nama-nama
+qualifier konfigurasi.</p>
+<table>
+    <tr>
+        <th>Konfigurasi</th>
+        <th>Nilai-nilai Qualifier</th>
+        <th>Keterangan</th>
+    </tr>
+    <tr id="MccQualifier">
+      <td>MCC dan MNC</td>
+      <td>Contoh:<br/>
+        <code>mcc310</code><br/>
+        <code><nobr>mcc310-mnc004</nobr></code><br/>
+        <code>mcc208-mnc00</code><br/>
+        dll.
+      </td>
+      <td>
+        <p>Kode negara seluler (MCC), bisa diikuti dengan kode jaringan seluler (MNC)
+ dari kartu SIM dalam perangkat. Misalnya, <code>mcc310</code> adalah AS untuk operator mana saja,
+ <code>mcc310-mnc004</code> adalah AS untuk Verizon, dan <code>mcc208-mnc00</code> Prancis untuk
+Orange.</p>
+        <p>Jika perangkat menggunakan koneksi radio (ponsel GSM), nilai-nilai MCC dan MNC berasal
+dari kartu SIM.</p>
+        <p>Anda juga dapat menggunakan MNC saja (misalnya, untuk menyertakan sumber daya legal
+spesifik untuk negara itu di aplikasi Anda). Jika Anda perlu menetapkan hanya berdasarkan bahasa, maka gunakan qualifier
+<em>bahasa dan wilayah</em> sebagai gantinya (akan dibahas nanti). Jika Anda memutuskan untuk menggunakan qualifier MCC dan
+MNC, Anda harus melakukannya dengan hati-hati dan menguji apakah qualifier itu berjalan sesuai harapan.</p>
+        <p>Lihat juga bidang konfigurasi {@link
+android.content.res.Configuration#mcc}, dan {@link
+android.content.res.Configuration#mnc}, yang masing-masing menunjukkan kode negara seluler saat ini
+dan kode jaringan seluler.</p>
+      </td>
+    </tr>
+    <tr id="LocaleQualifier">
+      <td>Bahasa dan wilayah</td>
+      <td>Contoh:<br/>
+        <code>en</code><br/>
+        <code>fr</code><br/>
+        <code>en-rUS</code><br/>
+        <code>fr-rFR</code><br/>
+        <code>fr-rCA</code><br/>
+        dll.
+      </td>
+      <td><p>Bahasa didefinisikan oleh kode bahasa dua huruf <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
+639-1</a>, bisa juga diikuti dengan kode wilayah
+dua huruf <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
+3166-1-alpha-2</a> (diawali dengan huruf kecil "{@code r}").
+        </p><p>
+        Kode <em>tidak</em> membedakan huruf besar atau kecil; awalan {@code r} akan digunakan untuk
+membedakan bagian wilayah.
+        Anda tidak bisa menetapkan wilayah saja.</p>
+        <p>Ini bisa berubah selama masa pakai
+aplikasi Anda jika pengguna mengubah bahasanya dalam pengaturan sistem. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang
+bagaimana hal ini dapat memengaruhi aplikasi Anda selama runtime.</p>
+        <p>Lihat <a href="localization.html">Pelokalan</a> untuk panduan lengkap melokalkan
+aplikasi Anda ke bahasa lain.</p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#locale} yang menunjukkan
+bahasa setempat yang digunakan saat ini.</p>
+      </td>
+    </tr>
+    <tr id="LayoutDirectionQualifier">
+      <td>Arah Layout</td>
+      <td><code>ldrtl</code><br/>
+        <code>ldltr</code><br/>
+      </td>
+      <td><p>Arah layout aplikasi Anda. {@code ldrtl} berarti "arah layout dari kanan ke kiri".
+ {@code ldltr} berarti "arah layout dari kiri ke kanan" dan merupakan nilai implisit default.
+      </p>
+      <p>Ini bisa berlaku untuk sumber daya mana pun seperti layout, drawable, atau nilai-nilai.
+      </p>
+      <p>Misalnya, jika Anda ingin memberikan beberapa layout khusus untuk bahasa Arab dan beberapa
+layout umum untuk setiap bahasa lainnya yang menggunakan "kanan-ke-kiri" lainnya (seperti bahasa Persia atau Ibrani) maka Anda akan memiliki:
+      </p>
+<pre class="classic no-pretty-print">
+res/
+    layout/   <span style="color:black">
+        main.xml  </span>(Default layout)
+    layout-ar/  <span style="color:black">
+        main.xml  </span>(Specific layout for Arabic)
+    layout-ldrtl/  <span style="color:black">
+        main.xml  </span>(Any "right-to-left" language, except
+                  for Arabic, because the "ar" language qualifier
+                  has a higher precedence.)
+</pre>
+        <p class="note"><strong>Catatan:</strong> Untuk mengaktifkan fitur
+layout kanan-ke-kiri untuk aplikasi, Anda harus mengatur <a href="{@docRoot}guide/topics/manifest/application-element.html#supportsrtl">{@code
+        supportsRtl}</a> ke {@code "true"} dan mengatur <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> ke 17 atau yang lebih tinggi.</p>
+        <p><em>Ditambahkan dalam API level 17.</em></p>
+      </td>
+    </tr>
+    <tr id="SmallestScreenWidthQualifier">
+      <td>smallestWidth</td>
+      <td><code>sw&lt;N&gt;dp</code><br/><br/>
+        Contoh:<br/>
+        <code>sw320dp</code><br/>
+        <code>sw600dp</code><br/>
+        <code>sw720dp</code><br/>
+        dll.
+      </td>
+      <td>
+        <p>Ukuran dasar layar, sebagaimana yang ditunjukkan oleh dimensi terpendek dari area layar
+yang tersedia. Secara spesifik, smallestWidth perangkat adalah yang terpendek dari
+tinggi dan lebar layar yang tersedia (Anda dapat menganggapnya sebagai "lebar terkecil yang memungkinkan" untuk layar). Anda bisa
+menggunakan qualifier ini untuk memastikan bahwa, apa pun orientasi layar saat ini, aplikasi
+Anda memiliki paling tidak {@code &lt;N&gt;} dps dari lebar yang tersedia untuk UI-nya.</p>
+        <p>Misalnya, jika layout mengharuskan dimensi layar terkecilnya setiap saat paling tidak
+600 dp, maka Anda dapat menggunakan qualifer ini untuk membuat sumber daya layout, {@code
+res/layout-sw600dp/}. Sistem akan menggunakan sumber daya ini hanya bila dimensi layar terkecil yang
+tersedia paling tidak 600 dp, tanpa mempertimbangkan apakah sisi 600 dp adalah tinggi atau
+lebar yang dipersepsikan pengguna. SmallestWidth adalah karakteristik ukuran layar tetap dari perangkat; <strong>smallestWidth
+perangkat tidak berubah saat orientasi layar berubah</strong>.</p>
+        <p>SmallestWidth perangkat memperhitungkan dekorasi layar dan UI sistem. Misalnya
+, jika perangkat memiliki beberapa elemen UI persisten pada layar yang menghitung ruang di sepanjang
+sumbu smallestWidth, sistem akan mendeklarasikan smallestWidth lebih kecil daripada ukuran layar sebenarnya,
+karena itu adalah piksel layar yang tidak tersedia untuk UI Anda. Sehingga nilai yang Anda
+gunakan haruslah merupakan dimensi terkecil sebenarnya yang <em>dibutuhkan oleh layout Anda</em> (biasanya, nilai ini adalah
+"lebar terkecil" yang didukung layout Anda, apa pun orientasi layar saat ini).</p>
+        <p>Sebagian nilai yang mungkin Anda gunakan untuk ukuran layar umum:</p>
+        <ul>
+          <li>320, untuk perangkat berkonfigurasi layar seperti:
+            <ul>
+              <li>240x320 ldpi (handset QVGA)</li>
+              <li>320x480 mdpi (handset)</li>
+              <li>480x800 hdpi (handset densitas tinggi)</li>
+            </ul>
+          </li>
+          <li>480, untuk layar seperti 480x800 mdpi (tablet/handset).</li>
+          <li>600, untuk layar seperti 600x1024 mdpi (tablet 7").</li>
+          <li>720, untuk layar seperti 720x1280 mdpi (tablet 10").</li>
+        </ul>
+        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda untuk
+qualifier smallestWidth terkecil, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
+smallestWidth perangkat. </p>
+        <p><em>Ditambahkan dalam API level 13.</em></p>
+        <p>Lihat juga atribut <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html#requiresSmallest">{@code
+android:requiresSmallestWidthDp}</a>, yang mendeklarasikan smallestWidth minimum yang
+kompatibel dengan aplikasi Anda, dan bidang konfigurasi {@link
+android.content.res.Configuration#smallestScreenWidthDp}, yang menyimpan nilai
+smallestWidth perangkat.</p>
+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
+Multi Layar</a>.</p>
+      </td>
+    </tr>
+    <tr id="ScreenWidthQualifier">
+      <td>Lebar yang tersedia</td>
+      <td><code>w&lt;N&gt;dp</code><br/><br/>
+        Contoh:<br/>
+        <code>w720dp</code><br/>
+        <code>w1024dp</code><br/>
+        dll.
+      </td>
+      <td>
+        <p>Menetapkan lebar layar minimum yang tersedia, di unit {@code dp} yang
+menggunakan sumber daya&mdash;yang didefinisikan oleh nilai <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
+ akan berubah bila orientasi
+berubah antara lanskap dan potret agar cocok dengan lebar sebenarnya saat ini.</p>
+        <p>Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
+ untuk konfigurasi ini, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi)
+ lebar layar perangkat saat ini.  Nilai
+di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
+elemen UI persisten di tepi kiri atau kanan, layar
+menggunakan nilai lebar yang lebih kecil daripada ukuran layar sebenarnya, yang memperhitungkan
+elemen UI ini dan mengurangi ruang aplikasi yang tersedia.</p>
+        <p><em>Ditambahkan dalam API level 13.</em></p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenWidthDp}
+ yang menyimpan lebar layar saat ini.</p>
+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
+Multi Layar</a>.</p>
+      </td>
+    </tr>
+    <tr id="ScreenHeightQualifier">
+      <td>Tinggi yang tersedia</td>
+      <td><code>h&lt;N&gt;dp</code><br/><br/>
+        Contoh:<br/>
+        <code>h720dp</code><br/>
+        <code>h1024dp</code><br/>
+        dll.
+      </td>
+      <td>
+        <p>Menetapkan tinggi layar minimum yang tersedia, dalam satuan "dp" yang harus digunakan
+sumber daya &mdash;bersama nilai yang didefinisikan oleh <code>&lt;N&gt;</code>.  Nilai konfigurasi ini
+ akan berubah saat orientasi
+berubah antara lanskap dan potret agar cocok dengan tinggi sebenarnya saat ini.</p>
+        <p>Bila aplikasi menyediakan beberapa direktori sumber daya dengan nilai yang berbeda
+ untuk konfigurasi ini, sistem akan menggunakan nilai yang terdekat dengan (tanpa melebihi)
+ tinggi layar perangkat saat ini.  Nilai
+di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa
+elemen UI persisten di tepi atas atau bawah, layar akan
+menggunakan nilai tinggi yang lebih kecil daripada ukuran layar sebenarnya, memperhitungkan
+elemen UI ini dan mengurangi ruang aplikasi yang tersedia.  Dekorasi
+layar yang tidak tetap (misalnya baris status (status-bar) telepon yang bisa
+disembunyikan saat layar penuh) di sini <em>tidak</em> diperhitungkan, demikian pula
+dekorasi jendela seperti baris judul (title-bar)atau baris tindakan (action-bar), jadi aplikasi harus disiapkan
+untuk menangani ruang yang agak lebih kecil daripada yang ditetapkan.
+        <p><em>Ditambahkan dalam API level 13.</em></p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenHeightDp}
+ yang menyimpan lebar layar saat ini.</p>
+        <p>Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan
+qualifier ini, lihat panduan pengembang <a href="{@docRoot}guide/practices/screens_support.html">Mendukung
+Multi Layar</a>.</p>
+      </td>
+    </tr>
+    <tr id="ScreenSizeQualifier">
+      <td>Ukuran layar</td>
+      <td>
+        <code>small</code><br/>
+        <code>normal</code><br/>
+        <code>large</code><br/>
+        <code>xlarge</code>
+      </td>
+      <td>
+        <ul class="nolist">
+        <li>{@code small}: Layar yang berukuran serupa dengan
+layar QVGA densitas rendah. Ukuran layout minimum untuk layar kecil
+adalah sekitar 320x426 satuan dp.  Misalnya QVGA densitas rendah
+dan VGA densitas tinggi.</li>
+        <li>{@code normal}: Layar yang berukuran serupa dengan
+layar HVGA densitas sedang. Ukuran layout minimum untuk
+layar normal adalah sekitar 320x470 satuan dp.  Contoh layar seperti itu adalah
+WQVGA densitas rendah, HVGA densitas sedang, WVGA
+     densitas tinggi.</li>
+        <li>{@code large}: Layar yang berukuran serupa dengan
+layar VGA densitas sedang.
+        Ukuran layout minimum untuk layar besar adalah sekitar 480x640 satuan dp.
+        Misalnya layar VGA dan WVGA densitas sedang.</li>
+        <li>{@code xlarge}: Layar yang jauh lebih besar dari layar HVGA
+densitas sedang tradisional. Ukuran layout minimum untuk
+layar ekstra besar adalah sekitar 720x960 satuan dp.  Perangkat dengan layar ekstra besar
+seringkali terlalu besar untuk dibawa dalam saku dan kemungkinan besar
+ berupa perangkat bergaya tablet. <em>Ditambahkan dalam API level 9.</em></li>
+        </ul>
+        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier ukuran tidak berarti bahwa
+sumber daya <em>hanya</em> untuk layar ukuran itu saja. Jika Anda tidak menyediakan sumber
+daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
+mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
+        <p class="caution"><strong>Perhatian:</strong> Jika semua sumber daya Anda menggunakan
+qualifier yang berukuran <em>lebih besar</em> daripada layar saat ini, sistem <strong>tidak</strong> akan menggunakannya dan aplikasi
+Anda akan crash saat runtime (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code
+xlarge}, namun perangkat memiliki ukuran layar normal).</p>
+        <p><em>Ditambahkan dalam API level 4.</em></p>
+
+        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
+Layar</a> untuk informasi selengkapnya.</p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
+ yang menunjukkan apakah layar berukuran kecil, normal, atau
+besar.</p>
+      </td>
+    </tr>
+    <tr id="ScreenAspectQualifier">
+      <td>Aspek layar</td>
+      <td>
+        <code>long</code><br/>
+        <code>notlong</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code long}: Layar panjang, seperti WQVGA, WVGA, FWVGA</li>
+          <li>{@code notlong}: Layar tidak panjang, seperti QVGA, HVGA, dan VGA</li>
+        </ul>
+        <p><em>Ditambahkan dalam API level 4.</em></p>
+        <p>Ini berdasarkan sepenuhnya pada rasio aspek layar (layar "panjang" lebih lebar). Ini
+tidak ada kaitannya dengan orientasi layar.</p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout},
+ yang menunjukkan apakah layar panjang.</p>
+      </td>
+    </tr>
+    <tr id="OrientationQualifier">
+      <td>Orientasi layar</td>
+      <td>
+        <code>port</code><br/>
+        <code>land</code>  <!-- <br/>
+        <code>square</code>  -->
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code port}: Perangkat dalam orientasi potret (vertikal)</li>
+          <li>{@code land}: Perangkat dalam orientasi lanskap (horizontal)</li>
+          <!-- Square mode is currently not used. -->
+        </ul>
+        <p>Ini bisa berubah selama masa pakai aplikasi Anda jika pengguna memutar
+layar. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
+ informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#orientation},
+yang menunjukkan orientasi perangkat saat ini.</p>
+      </td>
+    </tr>
+    <tr id="UiModeQualifier">
+      <td>Mode UI</td>
+      <td>
+        <code>car</code><br/>
+        <code>desk</code><br/>
+        <code>television</code><br/>
+        <code>appliance</code>
+        <code>watch</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code car}: Perangkat sedang menampilkan di dudukan perangkat di mobil</li>
+          <li>{@code desk}: Perangkat sedang menampilkan di dudukan perangkat di meja</li>
+          <li>{@code television}: Perangkat sedang menampilkan di televisi, yang menyediakan
+pengalaman "sepuluh kaki" dengan UI-nya pada layar besar yang berada jauh dari pengguna,
+terutama diorientasikan seputar DPAD atau
+interaksi non-pointer lainnya</li>
+          <li>{@code appliance}: Perangkat berlaku sebagai
+alat, tanpa tampilan</li>
+          <li>{@code watch}: Perangkat memiliki tampilan dan dikenakan di pergelangan tangan</li>
+        </ul>
+        <p><em>Ditambahkan dalam API level 8, televisi ditambahkan dalam API 13, jam ditambahkan dalam API 20.</em></p>
+        <p>Untuk informasi tentang cara aplikasi merespons saat perangkat dimasukkan
+ke dalam atau dilepaskan dari dudukannya, bacalah <a href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Menentukan
+dan Memantau Kondisi dan Tipe Dudukan</a>.</p>
+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menempatkan perangkat di
+dudukannya. Anda dapat mengaktifkan atau menonaktifkan sebagian mode ini menggunakan {@link
+android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
+informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
+      </td>
+    </tr>
+    <tr id="NightQualifier">
+      <td>Mode malam</td>
+      <td>
+        <code>night</code><br/>
+        <code>notnight</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code night}: Waktu malam</li>
+          <li>{@code notnight}: Waktu siang</li>
+        </ul>
+        <p><em>Ditambahkan dalam API level 8.</em></p>
+        <p>Ini bisa berubah selama masa pakai aplikasi jika mode malam dibiarkan dalam
+mode otomatis (default), dalam hal ini perubahan mode berdasarkan pada waktu hari.  Anda dapat mengaktifkan
+atau menonaktifkan mode ini menggunakan {@link android.app.UiModeManager}. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana hal ini memengaruhi
+aplikasi Anda selama runtime.</p>
+      </td>
+    </tr>
+    <tr id="DensityQualifier">
+      <td>Densitas piksel layar (dpi)</td>
+      <td>
+        <code>ldpi</code><br/>
+        <code>mdpi</code><br/>
+        <code>hdpi</code><br/>
+        <code>xhdpi</code><br/>
+        <code>xxhdpi</code><br/>
+        <code>xxxhdpi</code><br/>
+        <code>nodpi</code><br/>
+        <code>tvdpi</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code ldpi}: Layar densitas rendah; sekitar 120 dpi.</li>
+          <li>{@code mdpi}: Layar densitas sedang (pada HVGA tradisional); sekitar 160 dpi.
+</li>
+          <li>{@code hdpi}: Layar densitas tinggi; sekitar 240 dpi.</li>
+          <li>{@code xhdpi}: Layar densitas ekstra tinggi; sekitar 320 dpi. <em>Ditambahkan dalam API
+Level 8.</em></li>
+          <li>{@code xxhdpi}: Layar densitas ekstra-ekstra-tinggi; sekitar 480 dpi. <em>Ditambahkan dalam API
+Level 16.</em></li>
+          <li>{@code xxxhdpi}: Densitas ekstra-ekstra-ekstra-tinggi (hanya ikon launcher,
+lihat <a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">catatan</a>
+ dalam <em>Mendukung Beberapa Layar</em>); sekitar 640 dpi. <em>Ditambahkan dalam API
+Level 18.</em></li>
+          <li>{@code nodpi}: Ini bisa digunakan untuk sumber daya bitmap yang tidak ingin Anda
+skalakan agar sama dengan densitas perangkat.</li>
+          <li>{@code tvdpi}: Layar antara mdpi dan hdpi; sekitar 213 dpi. Ini
+tidak dianggap sebagai kelompok densitas "utama". Sebagian besar ditujukan untuk televisi dan kebanyakan
+aplikasi tidak memerlukannya &mdash;asalkan sumber daya mdpi dan hdpi cukup untuk sebagian besar aplikasi dan
+sistem akan menskalakan sebagaimana mestinya. Qualifier ini diperkenalkan pada API level 13.</li>
+        </ul>
+        <p>Terdapat rasio skala 3:4:6:8:12:16 antara enam densitas utama (dengan mengabaikan densitas
+tvdpi). Jadi bitmap 9x9 di ldpi adalah 12x12 di mdpi, 18x18 di hdpi, 24x24 di xhdpi dan seterusnya.
+</p>
+        <p>Jika Anda memutuskan bahwa sumber daya gambar tidak terlihat cukup baik di televisi
+atau perangkat tertentu lainnya dan ingin mencoba sumber daya tvdpi, faktor skalanya adalah 1,33*mdpi. Misalnya,
+gambar 100px x 100px untuk layar mdpi harus 133px x 133px untuk tvdpi.</p>
+        <p class="note"><strong>Catatan:</strong> Menggunakan qualifier densitas tidak berarti bahwa
+sumber daya <em>hanya</em> untuk layar dengan ukuran itu saja. Jika Anda tidak menyediakan sumber
+daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya
+mana saja yang <a href="#BestMatch">paling cocok</a>.</p>
+        <p>Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
+Layar</a> untuk informasi selengkapnya tentang cara menangani densitas layar yang berbeda dan cara Android
+menurunkan skala bitmap Anda agar sesuai dengan densitas saat ini.</p>
+       </td>
+    </tr>
+    <tr id="TouchscreenQualifier">
+      <td>Tipe layar sentuh</td>
+      <td>
+        <code>notouch</code><br/>
+        <code>finger</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code notouch}: Perangkat tidak memiliki layar sentuh.</li>
+          <li>{@code finger}: Perangkat memiliki layar sentuh yang dimaksudkan untuk
+digunakan melalui interaksi dengan jari pengguna.</li>
+        </ul>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#touchscreen}, yang
+menunjukkan tipe layar sentuh pada perangkat.</p>
+      </td>
+    </tr>
+    <tr id="KeyboardAvailQualifier">
+      <td>Ketersediaan keyboard</td>
+      <td>
+        <code>keysexposed</code><br/>
+        <code>keyshidden</code><br/>
+        <code>keyssoft</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code keysexposed}: Perangkat menyediakan keyboard. Jika perangkat mengaktifkan
+keyboard perangkat lunak (kemungkinan), ini dapat digunakan bahkan saat keyboard fisik
+<em>tidak</em> diekspos kepada pengguna, meskipun perangkat tidak memiliki keyboard fisik. Jika keyboard
+perangkat lunak tidak disediakan atau dinonaktifkan, maka ini hanya digunakan bila
+keyboard fisik diekspos.</li>
+          <li>{@code keyshidden}: Perangkat memiliki keyboard fisik yang tersedia
+tetapi tersembunyi <em>dan</em> perangkat <em>tidak</em> mengaktifkan keyboard perangkat lunak.</li>
+          <li>{@code keyssoft}: Perangkat mengaktifkan keyboard perangkat lunak,
+baik itu terlihat maupun tidak.</li>
+        </ul>
+        <p>Jika Anda menyediakan sumber daya <code>keysexposed</code>, namun bukan sumber daya <code>keyssoft</code>
+, sistem akan menggunakan sumber daya <code>keysexposed</code> baik keyboard
+terlihat atau tidak, asalkan sistem telah mengaktifkan keyboard perangkat lunak.</p>
+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna membuka keyboard
+fisik. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk informasi tentang bagaimana
+hal ini memengaruhi aplikasi Anda selama runtime.</p>
+        <p>Lihat juga bidang konfigurasi {@link
+android.content.res.Configuration#hardKeyboardHidden} dan {@link
+android.content.res.Configuration#keyboardHidden}, yang menunjukkan visibilitas
+keyboard fisik dan visibilitas segala jenis keyboard (termasuk keyboard perangkat lunak), masing-masing.</p>
+      </td>
+    </tr>
+    <tr id="ImeQualifier">
+      <td>Metode input teks utama</td>
+      <td>
+        <code>nokeys</code><br/>
+        <code>qwerty</code><br/>
+        <code>12key</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code nokeys}: Perangkat tidak memiliki tombol fisik untuk input teks.</li>
+          <li>{@code qwerty}: Perangkat memiliki keyboard fisik qwerty, baik terlihat maupun tidak pada
+pengguna
+.</li>
+          <li>{@code 12key}: Perangkat memiliki keyboard fisik 12 tombol, baik terlihat maupun tidak
+pada pengguna.</li>
+        </ul>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#keyboard},
+yang menunjukkan metode utama input teks yang tersedia.</p>
+      </td>
+    </tr>
+    <tr id="NavAvailQualifier">
+      <td>Ketersediaan tombol navigasi</td>
+      <td>
+        <code>navexposed</code><br/>
+        <code>navhidden</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code navexposed}: Tombol navigasi tersedia bagi pengguna.</li>
+          <li>{@code navhidden}: Tombol navigasi tidak tersedia (misalnya di balik penutup yang
+ditutup).</li>
+        </ul>
+        <p>Ini bisa berubah selama masa pakai aplikasi jika pengguna menyingkap tombol
+navigasi. Lihat <a href="runtime-changes.html">Menangani Perubahan Runtime</a> untuk
+informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime.</p>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigationHidden}, yang menunjukkan
+apakah tombol navigasi disembunyikan.</p>
+      </td>
+    </tr>
+    <tr id="NavigationQualifier">
+      <td>Metode navigasi non-sentuh utama</td>
+      <td>
+        <code>nonav</code><br/>
+        <code>dpad</code><br/>
+        <code>trackball</code><br/>
+        <code>wheel</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code nonav}: Perangkat tidak memiliki fasilitas navigasi selain menggunakan
+layar sentuh.</li>
+          <li>{@code dpad}: Perangkat memiliki pad pengarah (directional pad / d-pad) untuk navigasi.</li>
+          <li>{@code trackball}: Perangkat memiliki trackball untuk navigasi.</li>
+          <li>{@code wheel}: Perangkat memiliki roda pengarah (directional wheel) untuk navigasi (tidak umum).</li>
+        </ul>
+        <p>Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigation},
+yang menunjukkan tipe metode navigasi yang tersedia.</p>
+      </td>
+    </tr>
+<!-- DEPRECATED
+    <tr>
+      <td>Screen dimensions</td>
+      <td>Examples:<br/>
+        <code>320x240</code><br/>
+        <code>640x480</code><br/>
+        etc.
+      </td>
+      <td>
+        <p>The larger dimension must be specified first. <strong>This configuration is deprecated
+and should not be used</strong>. Instead use "screen size," "wider/taller screens," and "screen
+orientation" described above.</p>
+      </td>
+    </tr>
+-->
+    <tr id="VersionQualifier">
+      <td>Versi Platform (level API)</td>
+      <td>Contoh:<br/>
+        <code>v3</code><br/>
+        <code>v4</code><br/>
+        <code>v7</code><br/>
+        dll.</td>
+      <td>
+        <p>Level API yang didukung perangkat. Misalnya, <code>v1</code> untuk API level
+1 (perangkat dengan Android 1.0 atau yang lebih tinggi) dan <code>v4</code> untuk API level 4 (perangkat dengan Android
+1.6 atau yang lebih tinggi). Lihat dokumen <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Level API Android</a> untuk informasi selengkapnya
+tentang nilai-nilai ini.</p>
+      </td>
+    </tr>
+</table>
+
+
+<p class="note"><strong>Catatan:</strong> Sebagian qualifier konfigurasi telah ditambahkan sejak Android
+1.0, jadi tidak semua versi Android mendukung semua qualifier. Menggunakan qualifier baru secara implisit
+akan menambahkan qualifier versi platform sehingga perangkat yang lebih lama pasti mengabaikannya. Misalnya, menggunakan qualifier
+<code>w600dp</code> secara otomatis akan menyertakan qualifier <code>v13</code>, karena
+qualifier lebar yang tersedia baru di API level 13. Untuk menghindari masalah, selalu sertakan satu set
+sumber daya default (satu set sumber daya <em>tanpa qualifier</em>). Untuk informasi selengkapnya, lihat
+bagian tentang <a href="#Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan
+Sumber Daya</a>.</p>
+
+
+
+<h3 id="QualifierRules">Aturan penamaan qualifier</h3>
+
+<p>Inilah beberapa aturan tentang penggunaan nama qualifier konfigurasi:</p>
+
+<ul>
+    <li>Anda bisa menetapkan beberapa qualifier untuk satu set sumber daya, yang dipisahkan dengan tanda hubung. Misalnya,
+<code>drawable-en-rUS-land</code> berlaku untuk perangkat bahasa Inggris-AS dalam orientasi
+lanskap.</li>
+    <li>Qualifier harus dalam urutan seperti yang tercantum dalam <a href="#table2">tabel 2</a>.
+Misalnya:
+      <ul>
+        <li>Salah: <code>drawable-hdpi-port/</code></li>
+        <li>Benar: <code>drawable-port-hdpi/</code></li>
+      </ul>
+    </li>
+    <li>Direktori sumber daya alternatif tidak bisa digunakan. Misalnya, Anda tidak bisa memiliki
+<code>res/drawable/drawable-en/</code>.</li>
+    <li>Nilai tidak membedakan huruf besar maupun kecil.  Compiler sumber daya mengubah nama direktori
+menjadi huruf kecil sebelum pemrosesan untuk menghindari masalah pada sistem file yang membedakan
+huruf kecil dan besar. Setiap penggunaan huruf besar dalam nama hanyalah demi keterbacaan.</li>
+    <li>Hanya didukung satu nilai untuk setiap tipe qualifier. Misalnya, jika Anda ingin menggunakan
+file drawable yang sama untuk Spanyol dan Prancis, Anda <em>tidak bisa</em> memiliki direktori bernama
+<code>drawable-rES-rFR/</code>. Sebagai gantinya, Anda perlu dua direktori sumber daya, seperti
+<code>drawable-rES/</code> dan <code>drawable-rFR/</code>, berisi file yang sesuai.
+Akan tetapi, Anda tidak harus benar-benar menggandakan file yang sama di kedua lokasi. Sebagai gantinya, Anda
+bisa membuat alias ke satu sumber daya. Lihat <a href="#AliasResources">Membuat
+sumber daya alias</a> di bawah ini.</li>
+</ul>
+
+<p>Setelah Anda menyimpan sumber daya alternatif ke dalam direktori yang diberi nama dengan
+qualifier ini, Android secara otomatis menerapkan sumber daya dalam
+aplikasi Anda berdasarkan pada konfigurasi perangkat saat ini. Setiap kali sumber daya diminta, Android akan memeriksa direktori sumber daya
+alternatif berisi file sumber daya yang diminta, lalu <a href="#BestMatch">mencari sumber daya yang
+paling cocok</a>(dibahas di bawah). Jika tidak ada sumber daya alternatif yang cocok
+dengan konfigurasi perangkat tertentu, Android akan menggunakan sumber daya default terkait (set
+sumber daya untuk tipe sumber daya tertentu yang tidak termasuk qualifier
+konfigurasi).</p>
+
+
+
+<h3 id="AliasResources">Membuat sumber daya alias</h3>
+
+<p>Bila memiliki sumber daya yang ingin Anda gunakan untuk lebih dari satu konfigurasi
+perangkat (namun tidak ingin menyediakannya sebagai sumber daya default), Anda tidak perlu menempatkan sumber daya
+yang sama di lebih dari satu direktori sumber daya alternatif. Sebagai gantinya, (dalam beberapa kasus) Anda bisa membuat
+sumber daya alternatif
+yang berfungsi sebagai alias untuk sumber daya yang disimpan dalam direktori sumber daya default.</p>
+
+<p class="note"><strong>Catatan:</strong> Tidak semua sumber daya menawarkan mekanisme yang memungkinkan Anda
+membuat alias ke sumber daya lain. Khususnya, animasi, menu, raw, dan
+sumber daya lain yang tidak ditetapkan dalam direktori {@code xml/} tidak menawarkan fitur ini.</p>
+
+<p>Misalnya, bayangkan Anda memiliki ikon aplikasi {@code icon.png}, dan membutuhkan versi uniknya
+untuk lokal berbeda. Akan tetapi, dua lokal, bahasa Inggris-Kanada dan bahasa Prancis-Kanada, harus menggunakan
+versi yang sama. Anda mungkin berasumsi bahwa Anda perlu menyalin gambar
+yang sama ke dalam direktori sumber daya baik untuk bahasa Inggris-Kanada maupun bahasa Prancis-Kanada, namun
+bukan demikian. Sebagai gantinya, Anda bisa menyimpan gambar yang sama-sama digunakan sebagai {@code icon_ca.png} (nama
+apa saja selain {@code icon.png}) dan memasukkannya
+dalam direktori default {@code res/drawable/}. Lalu buat file {@code icon.xml} dalam {@code
+res/drawable-en-rCA/} dan {@code res/drawable-fr-rCA/} yang mengacu ke sumber daya {@code icon_ca.png}
+yang menggunakan elemen {@code &lt;bitmap&gt;}. Hal ini memungkinkan Anda menyimpan satu versi saja dari
+file PNG dan dua file XML kecil yang menunjuk ke sana. (Contoh file XML ditampilkan di bawah.)</p>
+
+
+<h4>Drawable</h4>
+
+<p>Untuk membuat alias ke drawable yang ada, gunakan elemen {@code &lt;bitmap&gt;}.
+Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/icon_ca" />
+</pre>
+
+<p>Jika Anda menyimpan file ini sebagai {@code icon.xml} (dalam direktori sumber daya alternatif, seperti
+{@code res/drawable-en-rCA/}), maka file akan dikompilasi menjadi sumber daya yang dapat Anda acu
+sebagai {@code R.drawable.icon}, namun sebenarnya merupakan alias untuk sumber daya {@code
+R.drawable.icon_ca} (yang disimpan dalam {@code res/drawable/}).</p>
+
+
+<h4>Layout</h4>
+
+<p>Untuk membuat alias ke layout yang ada, gunakan elemen {@code &lt;include&gt;},
+yang dibungkus dalam {@code &lt;merge&gt;}. Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;merge>
+    &lt;include layout="@layout/main_ltr"/>
+&lt;/merge>
+</pre>
+
+<p>Jika Anda menyimpan file ini sebagai {@code main.xml}, file akan dikompilasi menjadi sumber daya yang dapat Anda acu
+sebagai {@code R.layout.main}, namun sebenarnya merupakan alias untuk sumber daya {@code R.layout.main_ltr}
+.</p>
+
+
+<h4>String dan nilai-nilai sederhana lainnya</h4>
+
+<p>Untuk membuat alias ke string yang ada, cukup gunakan ID sumber daya
+dari string yang diinginkan sebagai nilai untuk string baru. Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;string name="hello">Hello&lt;/string>
+    &lt;string name="hi">@string/hello&lt;/string>
+&lt;/resources>
+</pre>
+
+<p>Sumber daya {@code R.string.hi} sekarang merupakan alias untuk {@code R.string.hello}.</p>
+
+<p> <a href="{@docRoot}guide/topics/resources/more-resources.html">Nilai sederhana lainnya</a> sama
+cara kerjanya. Misalnya, sebuah warna:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;color name="yellow">#f00&lt;/color>
+    &lt;color name="highlight">@color/red&lt;/color>
+&lt;/resources>
+</pre>
+
+
+
+
+<h2 id="Compatibility">Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya</h2>
+
+<p>Agar aplikasi Anda mendukung beberapa konfigurasi perangkat,
+Anda harus selalu menyediakan sumber daya default untuk setiap tipe sumber daya yang menggunakan aplikasi Anda.</p>
+
+<p>Misalnya, jika aplikasi Anda mendukung beberapa bahasa, sertakan selalu direktori {@code
+values/} (tempat string Anda disimpan) <em>tanpa</em> <a href="#LocaleQualifier">qualifier bahasa dan wilayah</a>. Jika sebaliknya Anda menempatkan semua file
+string dalam direktori yang memiliki qualifier bahasa dan wilayah, maka aplikasi Anda akan crash saat berjalan
+pada perangkat yang telah diatur ke bahasa yang tidak didukung string Anda. Namun asalkan Anda menyediakan sumber daya default
+{@code values/}, aplikasi akan berjalan lancar (meskipun pengguna
+tidak memahami bahasa itu&mdash;, ini lebih baik daripada crash).</p>
+
+<p>Demikian pula, jika Anda menyediakan sumber daya layout berbeda berdasarkan orientasi layar, Anda harus
+memilih satu orientasi sebagai default. Misalnya, sebagai ganti menyediakan sumber daya dalam {@code
+layout-land/} untuk lanskap dan {@code layout-port/} untuk potret, biarkan salah satu sebagai default, seperti
+{@code layout/} untuk lanskap dan {@code layout-port/} untuk potret.</p>
+
+<p>Sumber daya default perlu disediakan bukan hanya karena aplikasi mungkin berjalan pada
+konfigurasi yang belum Anda antisipasi, namun juga karena versi baru Android terkadang menambahkan
+qualifier konfigurasi yang tidak didukung oleh versi lama. Jika Anda menggunakan qualifier sumber daya baru,
+namun mempertahankan kompatibilitas kode dengan versi Android yang lebih lama, maka saat versi lama
+Android menjalankan aplikasi, aplikasi itu akan crash jika Anda tidak menyediakan sumber daya default, aplikasi
+tidak bisa menggunakan sumber daya yang dinamai dengan qualifier baru. Misalnya, jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+minSdkVersion}</a> Anda diatur ke 4, dan Anda memenuhi syarat semua sumber daya drawable dengan menggunakan <a href="#NightQualifier">mode malam</a> ({@code night} atau {@code notnight}, yang ditambahkan di API
+Level 8), maka perangkat API level 4 tidak bisa mengakses sumber daya drawable dan akan crash. Dalam hal
+ini, Anda mungkin ingin {@code notnight} menjadi sumber daya default, jadi Anda harus mengecualikan
+qualifier itu agar sumber daya drawable Anda ada dalam {@code drawable/} atau {@code drawable-night/}.</p>
+
+<p>Jadi, agar bisa menyediakan kompatibilitas perangkat terbaik, sediakan selalu sumber daya
+default untuk sumber daya yang diperlukan aplikasi Anda untuk berjalan dengan benar. Selanjutnya buatlah sumber daya
+alternatif untuk konfigurasi perangkat tertentu dengan menggunakan qualifier konfigurasi.</p>
+
+<p>Ada satu eksepsi untuk aturan ini: Jika <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> aplikasi Anda adalah 4 atau
+lebih, Anda <em>tidak</em> memerlukan sumber daya drawable default saat menyediakan sumber daya
+drawable alternatif dengan qualifier <a href="#DensityQualifier">densitas layar</a>. Tanpa sumber daya
+drawable default sekali pun, Android bisa menemukan yang paling cocok di antara densitas layar alternatif dan menskalakan
+bitmap sesuai kebutuhan. Akan tetapi, demi pengalaman terbaik pada semua jenis perangkat, Anda harus
+menyediakan drawable alternatif untuk ketiga tipe densitas.</p>
+
+
+
+<h2 id="BestMatch">Cara Android Menemukan Sumber Daya yang Paling Cocok</h2>
+
+<p>Saat Anda meminta sumber daya yang Anda berikan alternatifnya, Android akan memilih
+sumber daya alternatif yang akan digunakan saat runtime, bergantung pada konfigurasi perangkat saat ini. Untuk
+mendemonstrasikan cara Android memilih sumber daya alternatif, anggaplah direktori drawable berikut
+masing-masing berisi versi berbeda dari gambar yang sama:</p>
+
+<pre class="classic no-pretty-print">
+drawable/
+drawable-en/
+drawable-fr-rCA/
+drawable-en-port/
+drawable-en-notouch-12key/
+drawable-port-ldpi/
+drawable-port-notouch-12key/
+</pre>
+
+<p>Dan anggaplah yang berikut ini merupakan konfigurasi perangkatnya:</p>
+
+<p style="margin-left:1em;">
+Lokal = <code>en-GB</code> <br/>
+Orientasi layar = <code>port</code> <br/>
+Densitas piksel layar = <code>hdpi</code> <br/>
+Tipe layar sentuh = <code>notouch</code> <br/>
+Metode input teks utama = <code>12key</code>
+</p>
+
+<p>Dengan membandingkan konfigurasi perangkat dengan sumber daya alternatif yang tersedia, Android akan memilih
+drawable dari {@code drawable-en-port}.</p>
+
+<p>Sistem akan menentukan keputusannya mengenai sumber daya yang akan digunakan dengan logika
+berikut:</p>
+
+
+<div class="figure" style="width:371px">
+<img src="{@docRoot}images/resources/res-selection-flowchart.png" alt="" height="471" />
+<p class="img-caption"><strong>Gambar 2.</strong> Bagan alur cara Android menemukan
+sumber daya yang paling cocok.</p>
+</div>
+
+
+<ol>
+  <li>Menghapus file sumber daya yang bertentangan dengan konfigurasi perangkat.
+    <p>Direktori <code>drawable-fr-rCA/</code> dihapus karena bertentangan
+dengan lokal <code>en-GB</code>.</p>
+<pre class="classic no-pretty-print">
+drawable/
+drawable-en/
+<strike>drawable-fr-rCA/</strike>
+drawable-en-port/
+drawable-en-notouch-12key/
+drawable-port-ldpi/
+drawable-port-notouch-12key/
+</pre>
+<p class="note"><strong>Eksepsi:</strong> Densitas piksel layar adalah satu qualifier yang
+tidak dihapus karena bertentangan. Meskipun densitas layar perangkat adalah hdpi,
+<code>drawable-port-ldpi/</code> tidak dihapus karena setiap densitas layar
+dianggap cocok untuk saat ini. Informasi selengkapnya tersedia dalam dokumen <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
+Layar</a>.</p></li>
+
+  <li>Pilih qualifier berkedudukan tertinggi (berikutnya) dalam daftar (<a href="#table2">tabel 2</a>).
+(Mulai dengan MCC, lalu pindah ke bawah.) </li>
+  <li>Apakah salah satu direktori sumber daya menyertakan qualifier ini?  </li>
+    <ul>
+      <li>Jika Tidak, kembali ke langkah 2 dan lihat qualifier berikutnya. (Dalam contoh,
+jawabannya adalah "tidak" hingga qualifier bahasa tercapai.)</li>
+      <li>Jika Ya, lanjutkan ke langkah 4.</li>
+    </ul>
+  </li>
+
+  <li>Hapus direktori sumber daya yang tidak menyertakan qualifier ini. Dalam contoh, sistem
+menghapus semua direktori yang tidak menyertakan qualifier bahasa:</li>
+<pre class="classic no-pretty-print">
+<strike>drawable/</strike>
+drawable-en/
+drawable-en-port/
+drawable-en-notouch-12key/
+<strike>drawable-port-ldpi/</strike>
+<strike>drawable-port-notouch-12key/</strike>
+</pre>
+<p class="note"><strong>Eksepsi:</strong> Jika qualifier yang dimaksud adalah densitas piksel layar,
+Android akan memilih opsi yang paling cocok dengan densitas layar perangkat.
+Secara umum, Android lebih suka menurunkan skala gambar asli yang lebih besar daripada menaikkan skala
+atas gambar asli yang lebih kecil. Lihat <a href="{@docRoot}guide/practices/screens_support.html">Mendukung Beberapa
+Layar</a>.</p>
+  </li>
+
+  <li>Kembali dan ulangi langkah 2, 3, dan 4 hingga tersisa satu direktori. Dalam contoh ini, orientasi
+layar adalah qualifier berikutnya yang memiliki kecocokan.
+Jadi, sumber daya yang tidak menetapkan orientasi layar akan dihapus:
+<pre class="classic no-pretty-print">
+<strike>drawable-en/</strike>
+drawable-en-port/
+<strike>drawable-en-notouch-12key/</strike>
+</pre>
+<p>Direktori yang tersisa adalah {@code drawable-en-port}.</p>
+  </li>
+</ol>
+
+<p>Meskipun prosedur dijalankan untuk setiap sumber daya yang diminta, sistem akan mengoptimalkan beberapa aspek
+lebih lanjut. Satu optimalisasi tersebut adalah bahwa setelah konfigurasi perangkat diketahui, sistem mungkin
+akan menghapus sumber daya alternatif yang sama sekali tidak cocok. Misalnya, jika bahasa konfigurasi
+adalah bahasa Inggris ("en"), maka setiap direktori sumber daya yang memiliki qualifier bahasa akan diatur ke
+selain bahasa Inggris tidak akan pernah disertakan dalam pool sumber daya yang diperiksa (meskipun
+direktori sumber daya <em>tanpa</em> qualifier bahasa masih disertakan).</p>
+
+<p>Saat memilih sumber daya berdasarkan qualifier ukuran layar, sistem akan menggunakan
+sumber daya yang didesain untuk layar yang lebih kecil daripada layar saat ini jika tidak ada sumber daya yang lebih cocok
+(misalnya, layar ukuran besar akan menggunakan sumber daya layar ukuran normal jika diperlukan). Akan tetapi,
+jika satu-satunya sumber daya yang tersedia <em>lebih besar</em> daripada layar saat ini, sistem
+<strong>tidak</strong> akan menggunakannya dan aplikasi Anda akan crash jika tidak ada sumber daya lain yang cocok dengan konfigurasi
+perangkat (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code xlarge},
+namun perangkat memiliki ukuran layar normal).</p>
+
+<p class="note"><strong>Catatan:</strong> <em>Kedudukan</em> qualifier (dalam <a href="#table2">tabel 2</a>) lebih penting
+daripada jumlah qualifier yang benar-benar pas dengan perangkat. Misalnya, dalam langkah 4 di atas, pilihan
+terakhir pada daftar berisi tiga qualifier yang bebar-benar cocok dengan perangkat (orientasi, tipe
+layar sentuh, dan metode input), sementara <code>drawable-en</code> hanya memiliki satu parameter yang cocok
+(bahasa). Akan tetapi, bahasa memiliki kedudukan lebih tinggi dari pada qualifier lainnya, sehingga
+<code>drawable-port-notouch-12key</code> tidak masuk.</p>
+
+<p>Untuk mengetahui selengkapnya tentang cara menggunakan sumber daya dalam aplikasi, lanjutkan ke <a href="accessing-resources.html">Mengakses Sumber Daya</a>.</p>
diff --git a/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
new file mode 100644
index 0000000..09ad60c
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/resources/runtime-changes.jd
@@ -0,0 +1,281 @@
+page.title=Menangani Perubahan Runtime
+page.tags=aktivitas,daur hidup
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</a></li>
+    <li><a href="#HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</a>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="providing-resources.html">Menyediakan Sumber Daya</a></li>
+    <li><a href="accessing-resources.html">Mengakses Sumber Daya</a></li>
+    <li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Perubahan
+ Orientasi Layar yang Lebih Cepat</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Sebagian konfigurasi perangkat bisa berubah selama runtime
+(seperti orientasi layar, ketersediaan keyboard, dan bahasa). Saat perubahan demikian terjadi,
+Android akan me-restart
+{@link android.app.Activity} yang berjalan ({@link android.app.Activity#onDestroy()} dipanggil, diikuti oleh {@link
+android.app.Activity#onCreate(Bundle) onCreate()}). Perilaku restart didesain untuk membantu
+aplikasi Anda beradaptasi dengan konfigurasi baru melalui pemuatan kembali aplikasi Anda secara otomatis dengan
+sumber daya alternatif sumber yang sesuai dengan konfigurasi perangkat baru.</p>
+
+<p>Untuk menangani restart dengan benar, aktivitas Anda harus mengembalikan
+statusnya seperti semula melalui <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup
+aktivitas</a> normal, dalam hal ini Android akan memanggil
+{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} sebelum menghentikan
+aktivitas Anda sehingga Anda dapat menyimpan data mengenai status aplikasi. Selanjutnya Anda bisa mengembalikan status
+selama {@link android.app.Activity#onCreate(Bundle) onCreate()} atau {@link
+android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.</p>
+
+<p>Untuk menguji bahwa aplikasi me-restart sendiri dengan status tak berubah, Anda harus
+memanggil perubahan konfigurasi (seperti mengubah orientasi layar) saat melakukan berbagai
+tugas dalam aplikasi. Aplikasi Anda harus dapat me-restart setiap saat tanpa kehilangan
+data pengguna atau status untuk menangani kejadian seperti perubahan konfigurasi atau bila pengguna menerima panggilan telepon
+masuk lalu kembali ke aplikasi setelah proses
+aplikasi Anda dimusnahkan. Untuk mengetahui cara mengembalikan status aktivitas, bacalah tentang <a href="{@docRoot}guide/components/activities.html#Lifecycle">Daur hidup aktivitas</a>.</p>
+
+<p>Akan tetapi, Anda mungkin menemui situasi ketika me-restart aplikasi dan
+mengembalikan data dalam jumlah besar malah menjadi mahal dan menghasilkan pengalaman pengguna yang buruk. Dalam situasi
+demikian, Anda memiliki dua opsi lain:</p>
+
+<ol type="a">
+  <li><a href="#RetainingAnObject">Mempertahankan objek selama perubahan konfigurasi</a>
+  <p>Izinkan aktivitas Anda me-restart saat konfigurasi berubah, namun bawa objek
+berstatus (stateful) ke instance baru aktivitas Anda.</p>
+
+  </li>
+  <li><a href="#HandlingTheChange">Menangani sendiri perubahan konfigurasi</a>
+  <p>Cegah sistem me-restart aktivitas selama perubahan konfigurasi
+tertentu, namun terima callback saat konfigurasi benar-benar berubah, agar Anda bisa memperbarui
+aktivitas secara manual bila diperlukan.</p>
+  </li>
+</ol>
+
+
+<h2 id="RetainingAnObject">Mempertahankan Objek Selama Perubahan Konfigurasi</h2>
+
+<p>Jika me-restart aktivitas mengharuskan pemulihan seperangkat data dalam jumlah besar, menghubungkan kembali koneksi
+jaringan, atau melakukan operasi intensif lainnya, maka restart penuh karena perubahan konfigurasi mungkin
+menjadi pengalaman pengguna yang lambat. Selain itu, Anda mungkin tidak bisa sepenuhnya mengembalikan status
+aktivitas dengan {@link android.os.Bundle} yang disimpan sistem untuk Anda dengan callback {@link
+android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()}&mdash;itu tidaklah
+didesain untuk membawa objek besar (seperti bitmap) dan data di dalamnya harus diserialkan kemudian
+dinon-serialkan, yang bisa menghabiskan banyak memori dan membuat perubahan konfigurasi menjadi lambat. Dalam situasi
+demikian, Anda bisa meringankan beban memulai kembali aktivitas Anda dengan mempertahankan {@link
+android.app.Fragment} saat aktivitas Anda di-restart karena perubahan konfigurasi. Fragmen ini
+bisa berisi acuan ke objek stateful yang ingin Anda pertahankan.</p>
+
+<p>Bila sistem Android menghentikan aktivitas Anda karena perubahan konfigurasi, fragmen
+aktivitas yang telah ditandai untuk dipertahankan tidak akan dimusnahkan. Anda dapat menambahkan fragmen tersebut ke
+aktivitas untuk mempertahankan objek stateful.</p>
+
+<p>Untuk mempertahankan objek stateful dalam fragmen selama perubahan konfigurasi runtime:</p>
+
+<ol>
+  <li>Perluas kelas {@link android.app.Fragment} dan deklarasikan referensi ke objek stateful
+Anda.</li>
+  <li>Panggil {@link android.app.Fragment#setRetainInstance(boolean)} saat fragmen dibuat.
+      </li>
+  <li>Tambahkan fragmen ke aktivitas.</li>
+  <li>Gunakan {@link android.app.FragmentManager} untuk mengambil fragmen saat aktivitas
+di-restart.</li>
+</ol>
+
+<p>Misalnya, definisikan fragmen sebagai berikut:</p>
+
+<pre>
+public class RetainedFragment extends Fragment {
+
+    // data object we want to retain
+    private MyDataObject data;
+
+    // this method is only called once for this fragment
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // retain this fragment
+        setRetainInstance(true);
+    }
+
+    public void setData(MyDataObject data) {
+        this.data = data;
+    }
+
+    public MyDataObject getData() {
+        return data;
+    }
+}
+</pre>
+
+<p class="caution"><strong>Perhatian:</strong> Meskipun bisa menyimpan objek apa saja, Anda
+sama sekali tidak boleh meneruskan objek yang terkait dengan {@link android.app.Activity}, seperti {@link
+android.graphics.drawable.Drawable}, {@link android.widget.Adapter}, {@link android.view.View}
+atau objek lainnya mana pun yang terkait dengan {@link android.content.Context}. Jika Anda melakukannya, hal tersebut akan
+membocorkan semua tampilan dan sumber daya instance aktivitas semula. (Sumber daya yang bocor
+berarti bahwa aplikasi Anda tetap menyimpannya dan tidak bisa dijadikan kumpulan sampah, sehingga bisa banyak
+memori yang hilang.)</p>
+
+<p>Selanjutnya gunakan {@link android.app.FragmentManager} untuk menambahkan fragmen ke aktivitas.
+Anda bisa memperoleh objek data dari fragmen saat aktivitas memulai kembali selama perubahan
+konfigurasi runtime. Misalnya, definisikan aktivitas Anda sebagai berikut:</p>
+
+<pre>
+public class MyActivity extends Activity {
+
+    private RetainedFragment dataFragment;
+
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        // find the retained fragment on activity restarts
+        FragmentManager fm = getFragmentManager();
+        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
+
+        // create the fragment and data the first time
+        if (dataFragment == null) {
+            // add the fragment
+            dataFragment = new DataFragment();
+            fm.beginTransaction().add(dataFragment, “data”).commit();
+            // load the data from the web
+            dataFragment.setData(loadMyData());
+        }
+
+        // the data is available in dataFragment.getData()
+        ...
+    }
+
+    &#64;Override
+    public void onDestroy() {
+        super.onDestroy();
+        // store the data in the fragment
+        dataFragment.setData(collectMyLoadedData());
+    }
+}
+</pre>
+
+<p>Dalam contoh ini, {@link android.app.Activity#onCreate(Bundle) onCreate()} menambahkan fragmen
+atau mengembalikan referensinya. {@link android.app.Activity#onCreate(Bundle) onCreate()} juga
+menyimpan objek stateful dalam instance fragmen.
+{@link android.app.Activity#onDestroy() onDestroy()} akan memperbarui objek stateful dalam
+instance fragmen yang dipertahankan.</p>
+
+
+
+
+
+<h2 id="HandlingTheChange">Menangani Sendiri Perubahan Konfigurasi</h2>
+
+<p>Jika aplikasi Anda tidak memerlukan pembaruan sumber daya selama perubahan konfigurasi
+tertentu <em>dan</em> Anda memiliki keterbatasan kinerja yang mengharuskan Anda untuk
+menghindari restart aktivitas, maka Anda bisa mendeklarasikan agar aktivitas Anda menangani sendiri perubahan
+konfigurasinya, sehingga mencegah sistem me-restart aktivitas.</p>
+
+<p class="note"><strong>Catatan:</strong> Menangani sendiri perubahan konfigurasi bisa jauh lebih
+mempersulit penggunaan sumber daya alternatif, karena sistem tidak menerapkannya secara otomatis
+untuk Anda. Teknik ini harus dianggap sebagai usaha terakhir bila Anda harus menghindari restart
+karena perubahan konfigurasi dan tidak disarankan untuk sebagian besar aplikasi.</p>
+
+<p>Untuk mendeklarasikan agar aktivitas Anda menangani perubahan konfigurasi, edit elemen <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> yang sesuai
+dalam file manifes Anda agar menyertakan atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
+android:configChanges}</a> dengan nilai yang mewakili konfigurasi yang ingin
+ditangani. Nilai yang memungkinkan tercantum dalam dokumentasi untuk atribut <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
+android:configChanges}</a> (nilai paling sering digunakan adalah {@code "orientation"} untuk
+mencegah restart saat orientasi layar berubah dan {@code "keyboardHidden"} untuk mencegah
+restart saat ketersediaan keyboard berubah).  Anda dapat mendeklarasikan beberapa nilai konfigurasi
+dalam atribut dengan memisahkannya menggunakan karakter pipa {@code |}.</p>
+
+<p>Misalnya, kode manifes berikut menyatakan aktivitas yang menangani
+perubahan orientasi layar maupun perubahan ketersediaan keyboard:</p>
+
+<pre>
+&lt;activity android:name=".MyActivity"
+          android:configChanges="orientation|keyboardHidden"
+          android:label="@string/app_name">
+</pre>
+
+<p>Sekarang, bila salah satu konfigurasi ini berubah, {@code MyActivity} tidak akan me-restart.
+Sebagai gantinya, {@code MyActivity} akan menerima panggilan ke {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Metode ini
+meneruskan objek {@link android.content.res.Configuration} yang menetapkan
+konfigurasi perangkat baru. Dengan membaca bidang-bidang dalam {@link android.content.res.Configuration},
+Anda dapat menentukan konfigurasi baru dan membuat perubahan yang sesuai dengan memperbarui
+sumber daya yang digunakan dalam antarmuka. Pada saat
+metode ini dipanggil, objek {@link android.content.res.Resources} aktivitas Anda akan diperbarui untuk
+mengembalikan sumber daya berdasarkan konfigurasi baru, jadi Anda bisa dengan mudah
+me-reset elemen UI tanpa membuat sistem me-restart aktivitas Anda.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Mulai Android 3.2 (API level 13), <strong>
+"ukuran layar" juga berubah</strong> bila perangkat beralih orientasi antara potret
+dan lanskap. Jadi jika Anda tidak ingin runtime di-restart karena perubahan orientasi saat mengembangkan
+API level 13 atau yang lebih tinggi (sebagaimana dideklarasikan oleh atribut <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> dan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+), Anda harus menyertakan nilai {@code "screenSize"} selain nilai {@code
+"orientation"}. Yaitu Anda harus mendeklarasikan {@code
+android:configChanges="orientation|screenSize"}. Akan tetapi, jika aplikasi Anda menargetkan API level
+12 atau yang lebih rendah, maka aktivitas Anda akan selalu menangani sendiri perubahan konfigurasi ini (perubahan
+konfigurasi ini tidak me-restart aktivitas Anda, bahkan saat berjalan pada perangkat Android 3.2 atau yang lebih tinggi).</p>
+
+<p>Misalnya, implementasi {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} berikut akan
+memeriksa orientasi perangkat saat ini:</p>
+
+<pre>
+&#64;Override
+public void onConfigurationChanged(Configuration newConfig) {
+    super.onConfigurationChanged(newConfig);
+
+    // Checks the orientation of the screen
+    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
+    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
+        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
+    }
+}
+</pre>
+
+<p>Objek {@link android.content.res.Configuration} mewakili semua konfigurasi
+saat ini, tidak hanya konfigurasi yang telah berubah. Seringkali Anda tidak perlu memperhatikan dengan persis bagaimana
+konfigurasi berubah dan cukup menetapkan kembali semua sumber daya yang memberikan alternatif untuk
+konfigurasi sedang ditangani. Misalnya, karena objek {@link
+android.content.res.Resources} sekarang diperbarui, Anda dapat me-reset
+setiap {@link android.widget.ImageView} dengan {@link android.widget.ImageView#setImageResource(int)
+setImageResource()}
+dan sumber daya yang sesuai untuk konfigurasi baru yang digunakan (seperti dijelaskan dalam <a href="providing-resources.html#AlternateResources">Menyediakan Sumber Daya</a>).</p>
+
+<p>Perhatikan bahwa nilai-nilai dari bidang {@link
+android.content.res.Configuration} adalah integer yang sesuai dengan konstanta spesifik
+dari kelas {@link android.content.res.Configuration}. Untuk dokumentasi tentang konstanta
+yang harus digunakan di setiap bidang, lihat bidang yang sesuai dalam referensi {@link
+android.content.res.Configuration}.</p>
+
+<p class="note"><strong>Ingatlah:</strong> Saat mendeklarasikan aktivitas untuk menangani perubahan
+konfigurasi, Anda bertanggung jawab untuk me-reset setiap elemen yang alternatifnya Anda berikan. Jika Anda
+mendeklarasikan aktivitas untuk menangani perubahan orientasi dan memiliki gambar yang harus berubah
+antara lanskap dan potret, Anda harus menetapkan kembali setiap sumber daya elemen selama {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.</p>
+
+<p>Jika Anda tidak perlu memperbarui aplikasi berdasarkan perubahan
+konfigurasi ini, sebagai gantinya Anda bisa saja <em>tidak</em> mengimplementasikan {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Dalam
+hal ini, semua sumber daya yang digunakan sebelum perubahan konfigurasi akan tetap digunakan
+dan Anda hanya menghindari restart aktivitas. Akan tetapi, aplikasi Anda harus selalu
+bisa dimatikan dan di-restart dengan status sebelumnya tetap utuh, sehingga Anda jangan menganggap teknik
+ini sebagai jalan keluar untuk mempertahankan status selama daur hidup aktivitas normal. Tidak hanya
+karena ada perubahan konfigurasi lainnya yang tidak bisa Anda cegah untuk me-restart aplikasi, namun
+juga karena Anda harus menangani kejadian seperti saat pengguna meninggalkan aplikasi dan
+dimusnahkan sebelum pengguna kembali ke aplikasi.</p>
+
+<p>Untuk informasi selengkapnya tentang perubahan konfigurasi yang bisa Anda tangani dalam aktivitas, lihat dokumentasi <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
+android:configChanges}</a> dan kelas {@link android.content.res.Configuration}
+.</p>
diff --git a/docs/html-intl/intl/id/guide/topics/ui/controls.jd b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
new file mode 100644
index 0000000..3ebf48b
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/controls.jd
@@ -0,0 +1,90 @@
+page.title=Kontrol Input
+parent.title=Antarmuka Pengguna
+parent.link=index.html
+@jd:body
+
+<div class="figure" style="margin:0">
+  <img src="{@docRoot}images/ui/ui-controls.png" alt="" style="margin:0" />
+</div>
+
+<p>Kontrol input adalah komponen interaktif dalam antarmuka pengguna aplikasi Anda. Android menyediakan
+aneka ragam kontrol yang bisa Anda gunakan dalam UI, seperti tombol, bidang teks, bilah pencarian,
+kotak cek, tombol zoom, tombol toggle, dan masih banyak lagi.</p>
+
+<p>Menambahkan sebuah kontrol input ke UI adalah semudah menambahkan satu elemen XML ke <a href="{@docRoot}guide/topics/ui/declaring-layout.html">layout XML</a>. Misalnya, inilah sebuah
+layout dengan satu bidang teks dan satu tombol:</p>
+
+<pre style="clear:right">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="horizontal">
+    &lt;EditText android:id="@+id/edit_message"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:hint="@string/edit_message" />
+    &lt;Button android:id="@+id/button_send"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/button_send"
+        android:onClick="sendMessage" />
+&lt;/LinearLayout>
+</pre>
+
+<p>Tiap kontrol input mendukung satu set kejadian input sehingga Anda bisa menangani berbagai kejadian seperti saat
+pengguna memasukkan teks atau menyentuh tombol.</p>
+
+
+<h2 id="CommonControls">Kontrol Umum</h2>
+<p>Berikut adalah daftar beberapa kontrol umum yang bisa Anda gunakan dalam aplikasi. Ikuti tautan ini untuk mengetahui
+selengkapnya tentang penggunaannya masing-masing.</p>
+
+<p class="note"><strong>Catatan:</strong> Android menyediakan beberapa kontrol lain yang tidak tercantum
+di sini. Telusuri paket {@link android.widget} untuk mengetahui selengkapnya. Jika aplikasi Anda memerlukan
+semacam kontrol input tertentu, Anda bisa membangun <a href="{@docRoot}guide/topics/ui/custom-components.html">komponen custom</a> sendiri.</p>
+
+<table>
+    <tr>
+        <th scope="col">Tipe Kontrol</th>
+        <th scope="col">Keterangan</th>
+	<th scope="col">Kelas Terkait</th>
+    </tr>
+    <tr>
+        <td><a href="controls/button.html">Tombol</a></td>
+        <td>Tombol tekan yang bisa ditekan, atau diklik, oleh pengguna untuk melakukan suatu tindakan.</td>
+	<td>{@link android.widget.Button Button} </td>
+    </tr>
+    <tr>
+        <td><a href="controls/text.html">Bidang teks</a></td>
+        <td>Bidang teks yang bisa diedit. Anda bisa menggunakan widget <code>AutoCompleteTextView</code> untuk membuat widget entri teks yang menyediakan saran pelengkapan otomatis</td>
+	<td>{@link android.widget.EditText EditText}, {@link android.widget.AutoCompleteTextView}</td>
+    </tr>
+    <tr>
+        <td><a href="controls/checkbox.html">Kotak cek</a></td>
+        <td>Switch aktif/nonaktif yang bisa diubah oleh pengguna. Anda harus menggunakan kotak cek saat menampilkan sekumpulan opsi yang bisa dipilih pengguna dan bila keduanya mungkin terjadi bersamaan.</td>
+	<td>{@link android.widget.CheckBox CheckBox} </td>
+    </tr>
+    <tr>
+        <td><a href="controls/radiobutton.html">Tombol radio</a></td>
+        <td>Mirip dengan kotak cek, hanya saja cuma satu opsi yang bisa dipilih dalam kumpulan tersebut.</td>
+	<td>{@link android.widget.RadioGroup RadioGroup}
+	<br>{@link android.widget.RadioButton RadioButton} </td>
+    </tr>
+    <tr>
+        <td><a href="controls/togglebutton.html" style="white-space:nowrap">Tombol toggle</a></td>
+        <td>Tombol aktif/nonaktif dengan indikator cahaya.</td>
+	<td>{@link android.widget.ToggleButton ToggleButton} </td>
+    </tr>
+    <tr>
+        <td><a href="controls/spinner.html">Spinner</a></td>
+        <td>Daftar tarik-turun yang memungkinkan pengguna memilih salah satu dari serangkaian nilai.</td>
+	<td>{@link android.widget.Spinner Spinner} </td>
+    </tr>
+    <tr>
+        <td><a href="controls/pickers.html">Picker</a></td>
+        <td>Dialog bagi pengguna untuk memilih satu nilai dari satu kumpulan dengan menggunakan tombol naik/turun atau dengan gerakan mengusap. Gunakan widget <code>DatePicker</code>code&gt; untuk memasukkan nilai tanggal (bulan, hari, tahun) atau widget <code>TimePicker</code> untuk memasukkan nilai waktu (jam, menit, AM/PM), yang akan diformat secara otomatis untuk lokasi pengguna tersebut.</td>
+	<td>{@link android.widget.DatePicker}, {@link android.widget.TimePicker}</td>
+    </tr>
+</table>
diff --git a/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
new file mode 100644
index 0000000..1c8a0d6
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/declaring-layout.jd
@@ -0,0 +1,492 @@
+page.title=Layout
+page.tags=view,viewgroup
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#write">Tulis XML</a></li>
+  <li><a href="#load">Muat Sumber Daya XML</a></li>
+  <li><a href="#attributes">Atribut</a>
+    <ol>
+      <li><a href="#id">ID</a></li>
+      <li><a href="#layout-params">Parameter Layout</a></li>
+    </ol>
+  </li>
+  <li><a href="#Position">Posisi Layout</a></li>
+  <li><a href="#SizePaddingMargins">Ukuran, Pengisi, dan Margin</a></li>
+  <li><a href="#CommonLayouts">Layout Umum</a></li>
+  <li><a href="#AdapterViews">Membangun Layout dengan Adaptor</a>
+    <ol>
+      <li><a href="#FillingTheLayout">Mengisi tampilan adaptor dengan data</a></li>
+      <li><a href="#HandlingUserSelections">Menangani kejadian klik</a></li>
+    </ol>
+  </li>
+</ol>
+
+  <h2>Kelas-kelas utama</h2>
+  <ol>
+    <li>{@link android.view.View}</li>
+    <li>{@link android.view.ViewGroup}</li>
+    <li>{@link android.view.ViewGroup.LayoutParams}</li>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="{@docRoot}training/basics/firstapp/building-ui.html">Membangun Antarmuka Pengguna
+Sederhana</a></li> </div>
+</div>
+
+<p>Layout mendefinisikan struktur visual untuk antarmuka pengguna, seperti UI sebuah <a href="{@docRoot}guide/components/activities.html">aktivitas</a> atau <a href="{@docRoot}guide/topics/appwidgets/index.html">widget aplikasi</a>.
+Anda dapat mendeklarasikan layout dengan dua cara:</p>
+<ul>
+<li><strong>Deklarasikan elemen UI dalam XML</strong>. Android menyediakan sebuah kosakata XML
+sederhana yang sesuai dengan kelas dan subkelas View, seperti halnya untuk widget dan layout.</li>
+<li><strong>Buat instance elemen layout saat runtime</strong>. Aplikasi Anda
+bisa membuat objek View dan ViewGroup (dan memanipulasi propertinya) lewat program. </li>
+</ul>
+
+<p>Kerangka kerja Android memberi Anda fleksibilitas untuk menggunakan salah satu atau kedua metode ini guna mendeklarasikan dan mengelola UI aplikasi Anda. Misalnya, Anda bisa mendeklarasikan layout default aplikasi Anda dalam XML, termasuk elemen-elemen layar yang akan muncul di dalamnya dan di propertinya. Anda nanti bisa menambahkan kode dalam aplikasi yang akan memodifikasi status objek layar, termasuk yang dideklarasikan dalam XML, saat runtime. </p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+  <ul>
+  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
+  Plugin for Eclipse</a> menawarkan preview layout XML &mdash;
+ Anda dengan file XML yang dibuka, pilih tab <strong>Layout</strong>.</li>
+  <li>Anda juga harus mencoba alat
+  <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a>,
+ untuk merunut layout &mdash; alat ini akan menampilkan nilai-nilai properti layout,
+  menggambar bentuk kerangka dengan indikator pengisi/margin, dan tampilan yang dirender penuh selagi
+  Anda merunut pada emulator atau perangkat.</li>
+  <li>Alat <a href="{@docRoot}tools/debugging/debugging-ui.html#layoutopt">layoutopt</a> memungkinkan
+  Anda menganalisis layout dan hierarki dengan untuk mengetahui ketidakefisienan atau masalah lainnya.</li>
+</div>
+</div>
+
+<p>Keuntungan mendeklarasikan UI dalam XML adalah karena hal ini memungkinkan Anda memisahkan penampilan aplikasi dari kode yang mengontrol perilakunya dengan lebih baik. Keterangan UI Anda bersifat eksternal bagi kode aplikasi Anda, yang berarti bahwa Anda bisa memodifikasi atau menyesuaikannya tanpa harus memodifikasi dan mengompilasi ulang kode sumber. Misalnya, Anda bisa membuat layout XML untuk berbagai orientasi layar, berbagai ukuran layar perangkat, dan berbagai bahasa. Selain itu, mendeklarasikan layout dalam XML akan mempermudah Anda memvisualisasikan struktur UI, sehingga lebih mudah merunut masalahnya. Karena itu, dokumen ini berfokus pada upaya mengajari Anda cara mendeklarasikan layout dalam XML. Jika Anda
+tertarik dalam membuat instance objek View saat runtime, lihat referensi kelas {@link android.view.ViewGroup} dan
+{@link android.view.View}.</p>
+
+<p>Secara umum, kosakata XML untuk mendeklarasikan elemen UI mengikuti dengan sangat mirip struktur serta penamaan kelas dan metode, dengan nama elemen dipadankan dengan nama kelas dan nama atribut dipadankan dengan metode. Sebenarnya, pemadanan ini kerap kali begitu jelas sehingga Anda bisa menebak atribut XML yang berpadanan dengan sebuah metode kelas, atau menebak kelas yang berpadanan dengan sebuah elemen XML. Akan tetapi, perhatikan bahwa tidak semua kosakata identik. Dalam beberapa kasus, ada sedikit perbedaan penamaan. Misalnya
+, elemen EditText memiliki atribut <code>text</code> yang berpadanan dengan
+<code>EditText.setText()</code>. </p>
+
+<p class="note"><strong>Tip:</strong> Ketahui selengkapnya berbagai tipe layout dalam <a href="{@docRoot}guide/topics/ui/layout-objects.html">Objek
+Layout Umum</a>. Ada juga sekumpulan tutorial tentang cara membangun berbagai layout dalam panduan tutorial
+<a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>.</p>
+
+<h2 id="write">Tulis XML</h2>
+
+<p>Dengan menggunakan kosakata XML Android, Anda bisa mendesain secara cepat layout UI dan elemen layar yang dimuatnya, sama dengan cara membuat halaman web dalam HTML &mdash; dengan serangkaian elemen tersarang. </p>
+
+<p>Tiap file layout harus berisi persis satu elemen akar, yang harus berupa sebuah objek View atau ViewGroup. Setelah mendefinisikan elemen akar, Anda bisa menambahkan objek atau widget layout tambahan sebagai elemen anak untuk membangun hierarki View yang mendefinisikan layout Anda secara bertahap. Misalnya, inilah layout XML yang menggunakan {@link android.widget.LinearLayout}
+vertikal untuk menyimpan {@link android.widget.TextView} dan {@link android.widget.Button}:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+    &lt;TextView android:id="@+id/text"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:text="Hello, I am a TextView" />
+    &lt;Button android:id="@+id/button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Hello, I am a Button" />
+&lt;/LinearLayout>
+</pre>
+
+<p>Setelah Anda mendeklarasikan layout dalam XML, simpanlah file dengan ekstensi <code>.xml</code>,
+dalam direktori <code>res/layout/</code> proyek Android, sehingga nanti bisa dikompilasi dengan benar. </p>
+
+<p>Informasi selengkapnya tentang sintaks untuk file XML layout tersedia dalam dokumen <a href="{@docRoot}guide/topics/resources/layout-resource.html">Sumber Daya Layout</a>.</p>
+
+<h2 id="load">Muat Sumber Daya XML</h2>
+
+<p>Saat mengompilasi aplikasi, masing-masing file layout XML akan dikompilasi dalam sebuah sumber daya
+{@link android.view.View}. Anda harus memuat sumber daya layout dari kode aplikasi, dalam implementasi
+callback {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}.
+Lakukan dengan memanggil <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
+dengan meneruskan acuan ke sumber daya layout berupa:
+<code>R.layout.<em>layout_file_name</em></code>.
+Misalnya, jika XML layout Anda disimpan sebagai <code>main_layout.xml</code>, Anda akan memuatnya
+untuk Activity seperti ini:</p>
+<pre>
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.main_layout);
+}
+</pre>
+
+<p>Metode callback <code>onCreate()</code> dalam Activity dipanggil oleh kerangka kerja Android saat
+Activity Anda dijalankan (lihat diskusi tentang daur hidup, dalam dokumen
+<a href="{@docRoot}guide/components/activities.html#Lifecycle">Aktivitas</a>
+).</p>
+
+
+<h2 id="attributes">Atribut</h2>
+
+<p>Setiap objek View dan ViewGroup mendukung variasi atribut XML-nya sendiri.
+Sebagian atribut bersifat spesifik untuk objek View (misalnya, TextView mendukung atribut <code>textSize</code>
+), namun atribut ini juga diwarisi oleh sembarang objek View yang dapat memperluas kelas ini.
+Sebagian atribut bersifat umum untuk semua objek View, karena diwarisi dari kelas View akar (seperti
+atribut <code>id</code>). Dan, atribut lain dianggap sebagai "parameter layout" yaitu
+atribut yang menjelaskan orientasi layout tertentu dari objek View, seperti yang didefinisikan oleh objek ViewGroup induk
+dari objek itu.</p>
+
+<h3 id="id">ID</h3>
+
+<p>Objek View apa saja dapat memiliki ID integer yang dikaitkan dengannya, untuk mengidentifikasi secara unik View dalam pohon.
+Bila aplikasi dikompilasi, ID ini akan diacu sebagai integer, namun ID biasanya
+ditetapkan dalam file XML layout sebagai string, dalam atribut <code>id</code>.
+Ini atribut XML yang umum untuk semua objek View
+(yang didefinisikan oleh kelas {@link android.view.View}) dan Anda akan sering sekali menggunakannya.
+Sintaks untuk ID dalam tag XML adalah:</p>
+<pre>android:id="&#64;+id/my_button"</pre>
+
+<p>Simbol "at" (@) pada awal string menunjukkan parser XML harus mengurai dan memperluas
+ID string selebihnya dan mengenalinya sebagai ID sumber daya. Simbol tanda tambah (+) berarti ini nama sumber daya baru yang harus
+dibuat dan ditambahkan ke sumber daya kita (dalam file <code>R.java</code>). Ada sejumlah sumber daya ID lain yang
+ditawarkan oleh kerangka kerja Android. Saat mengacu sebuah ID sumber daya Android, Anda tidak memerlukan simbol tanda tambah,
+namun harus menambahkan namespace paket <code>android</code>, sehingga:</p>
+<pre>android:id="&#64;android:id/empty"</pre>
+<p>Dengan namespace paket <code>android</code> yang tersedia, kita sekarang mengacu ID dari kelas sumber daya <code>android.R</code>
+, daripada kelas sumber daya lokal.</p>
+
+<p>Untuk membuat tampilan dan mengacunya dari aplikasi, pola yang umum adalah:</p>
+<ol>
+  <li>Mendefinisikan tampilan/widget dalam file layout dan memberinya ID unik:
+<pre>
+&lt;Button android:id="&#64;+id/my_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="&#64;string/my_button_text"/>
+</pre>
+  </li>
+  <li>Kemudian buat instance objek tampilan dan tangkap instance itu dari layout
+(biasanya dalam metode <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code>):
+<pre>
+Button myButton = (Button) findViewById(R.id.my_button);
+</pre>
+  </li>
+</ol>
+<p>Mendefinisikan ID untuk objek tampilan adalah penting saat membuat {@link android.widget.RelativeLayout}.
+Dalam layout relatif, tampilan saudara bisa mendefinisikan layout secara relatif terhadap tampilan saudara lainnya,
+yang diacu melalui ID unik.</p>
+<p>ID tidak perlu unik di seluruh pohon, namun harus
+unik di bagian pohon yang Anda cari (yang mungkin sering kali seluruh pohon, jadi lebih baik
+benar-benar unik bila memungkinkan).</p>
+
+
+<h3 id="layout-params">Parameter Layout</h3>
+
+<p>Atribut layout XML bernama <code>layout_<em>something</em></code> mendefinisikan
+parameter layout View yang cocok untuk ViewGroup tempatnya berada.</p>
+
+<p>Setiap kelas ViewGroup mengimplementasikan kelas tersarang yang memperluas {@link
+android.view.ViewGroup.LayoutParams}. Subkelas ini
+berisi tipe properti yang mendefinisikan ukuran dan posisi masing-masing tampilan anak, sebagaimana
+mestinya untuk grup tampilan. Seperti yang bisa Anda lihat dalam gambar 1,
+grup tampilan induk mendefinisikan parameter layout untuk masing-masing tampilan anak (termasuk grup tampilan anak).</p>
+
+<img src="{@docRoot}images/layoutparams.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Visualisasi hierarki tampilan dengan parameter layout
+yang dikaitkan dengan tiap tampilan.</p>
+
+<p>Perhatikan bahwa setiap subkelas LayoutParams memiliki sintaksnya sendiri untuk menetapkan
+nilai-nilai. Tiap elemen anak harus mendefinisikan LayoutParams yang semestinya bagi induknya,
+meskipun elemen itu bisa juga mendefinisikan LayoutParams untuk anak-anaknya sendiri. </p>
+
+<p>Semua grup tampilan berisi lebar dan tinggi (<code>layout_width</code> dan
+<code>layout_height</code>), dan masing-masing tampilan harus mendefinisikannya. Banyak
+LayoutParams yang juga menyertakan margin dan border opsional. <p>
+
+<p>Anda bisa menetapkan lebar dan tinggi dengan ukuran persis, meskipun Anda mungkin
+tidak ingin sering-sering melakukannya. Lebih sering, Anda akan menggunakan salah satu konstanta ini untuk
+mengatur lebar atau tinggi: </p>
+
+<ul>
+  <li><var>wrap_content</var> memberi tahu tampilan Anda agar menyesuaikan sendiri ukurannya dengan dimensi
+yang dibutuhkan oleh isinya.</li>
+  <li><var>match_parent</var> (bernama <var>fill_parent</var> sebelum API Level 8)
+memberi tahu tampilan Anda agar menjadi sebesar yang diperbolehkan oleh grup tampilan induknya.</li>
+</ul>
+
+<p>Secara umum, menetapkan lebar dan tinggi layout dengan satuan mutlak seperti
+piksel tidaklah disarankan. Melainkan dengan menggunakan ukuran relatif seperti
+satuan piksel yang tidak bergantung pada kerapatan (<var>dp</var>), <var>wrap_content</var>, atau
+<var>match_parent</var>, adalah sebuah pendekatan yang lebih baik, karena membantu memastikan bahwa
+aplikasi Anda akan ditampilkan dengan benar pada berbagai ukuran layar perangkat.
+Tipe ukuran yang diterima didefinisikan dalam dokumen
+<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">
+Sumber Daya yang Tersedia</a>.</p>
+
+
+<h2 id="Position">Posisi Layout</h2>
+   <p>
+   Geometri tampilan adalah persegi panjang. Sebuah tampilan memiliki lokasi,
+   yang dinyatakan berupa sepasang koordinat <em>kiri</em> dan <em>atas</em>, dan
+   dua dimensi, yang dinyatakan berupa lebar dan tinggi. Satuan untuk lokasi
+   dan dimensi adalah piksel.
+   </p>
+
+   <p>
+   Lokasi tampilan dapat diambil dengan memanggil metode
+   {@link android.view.View#getLeft()} dan {@link android.view.View#getTop()}. Metode terdahulu menghasilkan koordinat kiri, atau X,
+   persegi panjang yang mewakili tampilan. Metode selanjutnya menghasilkan koordinat
+   atas, atau Y, persegi panjang yang mewakili tampilan. Kedua metode ini
+   menghasilkan lokasi tampilan relatif terhadap induknya. Misalnya,
+   bila <code>getLeft()</code> menghasilkan 20, berarti tampilan berlokasi 20 piksel ke
+   kanan dari tepi kiri induk langsungnya.
+   </p>
+
+   <p>
+   Selain itu, beberapa metode praktis ditawarkan untuk menghindari komputasi yang tidak perlu,
+   yakni {@link android.view.View#getRight()} dan {@link android.view.View#getBottom()}.
+   Kedua metode ini menghasilkan koordinat tepi kanan dan bawah
+   persegi panjang yang mewakili tampilan. Misalnya, memanggil {@link android.view.View#getRight()}
+   serupa dengan komputasi berikut: <code>getLeft() + getWidth()</code>.
+   </p>
+
+
+<h2 id="SizePaddingMargins">Ukuran, Pengisi, dan Margin</h2>
+   <p>
+   Ukuran tampilan dinyatakan dengan lebar dan tinggi. Tampilan sebenarnya
+   memiliki dua pasang nilai lebar dan tinggi.
+   </p>
+
+   <p>
+   Sepasang pertama disebut <em>lebar terukur</em> dan
+   <em>tinggi terukur</em>. Dimensi ini mendefinisikan seberapa besar tampilan yang diinginkan
+   dalam induknya. Dimensi
+   terukur bisa diperoleh dengan memanggil {@link android.view.View#getMeasuredWidth()}
+   dan {@link android.view.View#getMeasuredHeight()}.
+   </p>
+
+   <p>
+   Sepasang kedua cukup disebut dengan <em>lebar</em> dan <em>tinggi</em>, atau
+   kadang-kadang <em>lebar penggambaran</em> dan <em>tinggi penggambaran</em>. Dimensi-dimensi ini
+   mendefinisikan ukuran tampilan sebenarnya pada layar, saat digambar dan
+   setelah layout. Nilai-nilai ini mungkin, namun tidak harus, berbeda dengan
+   lebar dan tinggi terukur. Lebar dan tinggi bisa diperoleh dengan memanggil
+   {@link android.view.View#getWidth()} dan {@link android.view.View#getHeight()}.
+   </p>
+
+   <p>
+   Untuk mengukur dimensinya, tampilan akan memperhitungkan pengisinya (padding). Pengisi
+   dinyatakan dalam piksel untuk bagian kiri, atas, kanan, dan bawah tampilan.
+   Pengisi bisa digunakan untuk meng-offset isi tampilan dengan
+   piksel dalam jumlah tertentu. Misalnya, pengisi kiri sebesar 2 akan mendorong isi tampilan sebanyak
+   2 piksel ke kanan dari tepi kiri. Pengisi bisa diatur menggunakan
+   metode {@link android.view.View#setPadding(int, int, int, int)} dan diketahui dengan memanggil
+   {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
+   {@link android.view.View#getPaddingRight()}, dan {@link android.view.View#getPaddingBottom()}.
+   </p>
+
+   <p>
+   Meskipun bisa mendefinisikan pengisi, tampilan tidak menyediakan dukungan untuk
+   margin. Akan tetapi, grup tampilan menyediakan dukungan tersebut. Lihat
+   {@link android.view.ViewGroup} dan
+   {@link android.view.ViewGroup.MarginLayoutParams} untuk informasi lebih jauh.
+   </p>
+
+   <p>Untuk informasi selengkapnya tentang dimensi, lihat
+   <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Nilai-Nilai Dimensi</a>.
+   </p>
+
+
+
+
+
+
+<style type="text/css">
+div.layout {
+  float:left;
+  width:200px;
+  margin:0 0 20px 20px;
+}
+div.layout.first {
+  margin-left:0;
+  clear:left;
+}
+</style>
+
+
+
+
+<h2 id="CommonLayouts">Layout Umum</h2>
+
+<p>Tiap subkelas dari kelas {@link android.view.ViewGroup} menyediakan cara unik untuk menampilkan
+tampilan yang Anda sarangkan di dalamnya. Di bawah ini adalah beberapa tipe layout lebih umum yang dibuat
+ke dalam platform Android.</p>
+
+<p class="note"><strong>Catatan:</strong> Walaupun Anda bisa menyarangkan satu atau beberapa layout dalam
+layout lain untuk mendapatkan desain UI, Anda harus berusaha menjaga hierarki layout sedangkal
+mungkin. Layout Anda akan digambar lebih cepat jika memiliki layout tersarang yang lebih sedikit (hierarki tampilan yang melebar
+lebih baik daripada hierarki tampilan yang dalam).</p>
+
+<!--
+<h2 id="framelayout">FrameLayout</h2>
+<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout
+object. It's basically a blank space on your screen that you can
+later fill with a single object &mdash; for example, a picture that you'll swap in and out.
+All child elements of the FrameLayout are pinned to the top left corner of the screen; you cannot
+specify a different location for a child view. Subsequent child views will simply be drawn over
+previous ones,
+partially or totally obscuring them (unless the newer object is transparent).
+</p>
+-->
+
+
+<div class="layout first">
+  <h4><a href="layout/linear.html">Layout Linier</a></h4>
+  <a href="layout/linear.html"><img src="{@docRoot}images/ui/linearlayout-small.png" alt="" /></a>
+  <p>Layout yang mengatur anak-anaknya menjadi satu baris horizontal atau vertikal. Layout ini
+  akan membuat scrollbar jika panjang jendela melebihi panjang layar.</p>
+</div>
+
+<div class="layout">
+  <h4><a href="layout/relative.html">Layout Relatif</a></h4>
+  <a href="layout/relative.html"><img src="{@docRoot}images/ui/relativelayout-small.png" alt="" /></a>
+  <p>Memungkinkan Anda menentukan lokasi objek anak relatif terhadap satu sama lain (anak A di
+kiri anak B) atau terhadap induk (disejajarkan dengan atas induknya).</p>
+</div>
+
+<div class="layout">
+  <h4><a href="{@docRoot}guide/webapps/webview.html">Tampilan Web</a></h4>
+  <a href="{@docRoot}guide/webapps/webview.html"><img src="{@docRoot}images/ui/webview-small.png" alt="" /></a>
+  <p>Menampilkan halaman web.</p>
+</div>
+
+
+
+
+<h2 id="AdapterViews" style="clear:left">Membangun Layout dengan Adaptor</h2>
+
+<p>Bila isi layout bersifat dinamis atau tidak dipastikan sebelumnya, Anda bisa menggunakan layout yang menjadi
+subkelas {@link android.widget.AdapterView} untuk mengisi layout dengan tampilan saat runtime.
+Subkelas dari kelas {@link android.widget.AdapterView} menggunakan {@link android.widget.Adapter} untuk
+mengikat data ke layoutnya. {@link android.widget.Adapter} berfungsi sebagai penghubung antara sumber data
+dan layout{@link android.widget.AdapterView}&mdash;{@link android.widget.Adapter}
+menarik data (dari suatu sumber seperti larik (array) atau query database) dan mengubah setiap entri
+menjadi tampilan yang bisa ditambahkan ke dalam layout {@link android.widget.AdapterView}.</p>
+
+<p>Layout umum yang didukung oleh adaptor meliputi:</p>
+
+<div class="layout first">
+  <h4><a href="layout/listview.html">Tampilan Daftar</a></h4>
+  <a href="layout/listview.html"><img src="{@docRoot}images/ui/listview-small.png" alt="" /></a>
+  <p>Menampilkan daftar kolom tunggal yang bergulir.</p>
+</div>
+
+<div class="layout">
+  <h4><a href="layout/gridview.html">Tampilan Petak</a></h4>
+  <a href="layout/gridview.html"><img src="{@docRoot}images/ui/gridview-small.png" alt="" /></a>
+  <p>Menampilkan petak bergulir yang terdiri atas kolom dan baris.</p>
+</div>
+
+
+
+<h3 id="FillingTheLayout" style="clear:left">Mengisi tampilan adaptor dengan data</h3>
+
+<p>Anda bisa mengisi {@link android.widget.AdapterView} seperti {@link android.widget.ListView} atau
+{@link android.widget.GridView} dengan mengikat instance {@link android.widget.AdapterView} ke
+{@link android.widget.Adapter}, yang akan mengambil data dari sumber eksternal dan membuat {@link
+android.view.View} yang mewakili tiap entri data.</p>
+
+<p>Android menyediakan beberapa subkelas {@link android.widget.Adapter} yang berguna untuk
+menarik berbagai jenis data dan membangun tampilan untuk {@link android.widget.AdapterView}. Dua
+ adaptor yang paling umum adalah:</p>
+
+<dl>
+  <dt>{@link android.widget.ArrayAdapter}</dt>
+    <dd>Gunakan adaptor ini bila sumber data Anda berupa larik. Secara default, {@link
+android.widget.ArrayAdapter} akan membuat tampilan untuk tiap elemen larik dengan memanggil {@link
+java.lang.Object#toString()} pada tiap elemen dan menempatkan isinya dalam {@link
+android.widget.TextView}.
+      <p>Misalnya, jika Anda memiliki satu larik string yang ingin ditampilkan dalam {@link
+android.widget.ListView}, buatlah {@link android.widget.ArrayAdapter} baru dengan konstruktor
+untuk menentukan layout setiap string dan larik string:</p>
+<pre>
+ArrayAdapter&lt;String> adapter = new ArrayAdapter&lt;String>(this,
+        android.R.layout.simple_list_item_1, myStringArray);
+</pre>
+<p>Argumen-argumen untuk konstruktor ini adalah:</p>
+<ul>
+  <li>{@link android.content.Context} aplikasi Anda</li>
+  <li>Layout yang berisi {@link android.widget.TextView} untuk tiap string dalam larik</li>
+  <li>Larik string</li>
+</ul>
+<p>Kemudian tinggal panggil
+{@link android.widget.ListView#setAdapter setAdapter()} pada {@link android.widget.ListView} Anda:</p>
+<pre>
+ListView listView = (ListView) findViewById(R.id.listview);
+listView.setAdapter(adapter);
+</pre>
+
+      <p>Untuk menyesuaikan penampilan setiap item, Anda bisa mengesampingkan metode {@link
+java.lang.Object#toString()} bagi objek dalam larik Anda. Atau, untuk membuat tampilan tiap
+elemen selain {@link android.widget.TextView} (misalnya, jika Anda menginginkan
+{@link android.widget.ImageView} bagi setiap item larik), perluas kelas {@link
+android.widget.ArrayAdapter} dan kesampingkan {@link android.widget.ArrayAdapter#getView
+getView()} agar memberikan tipe tampilan yang Anda inginkan bagi tiap item.</p>
+
+</dd>
+
+  <dt>{@link android.widget.SimpleCursorAdapter}</dt>
+    <dd>Gunakan adaptor ini bila data Anda berasal dari {@link android.database.Cursor}. Saat
+menggunakan {@link android.widget.SimpleCursorAdapter}, Anda harus menentukan layout yang akan digunakan untuk tiap
+baris dalam {@link android.database.Cursor} dan di kolom mana di {@link android.database.Cursor}
+harus memasukkan tampilan layout. Misalnya, jika Anda ingin untuk membuat daftar
+nama orang dan nomor telepon, Anda bisa melakukan query yang menghasilkan {@link
+android.database.Cursor} yang berisi satu baris untuk tiap orang dan kolom-kolom untuk nama dan
+nomor. Selanjutnya Anda membuat larik string yang menentukan kolom dari {@link
+android.database.Cursor} yang Anda inginkan dalam layout untuk setiap hasil dan larik integer yang menentukan
+tampilan yang sesuai untuk menempatkan masing-masing kolom:</p>
+<pre>
+String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
+                        ContactsContract.CommonDataKinds.Phone.NUMBER};
+int[] toViews = {R.id.display_name, R.id.phone_number};
+</pre>
+<p>Bila Anda membuat instance {@link android.widget.SimpleCursorAdapter}, teruskan layout yang akan digunakan untuk
+setiap hasil, {@link android.database.Cursor} yang berisi hasil tersebut, dan dua larik ini:</p>
+<pre>
+SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
+        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
+ListView listView = getListView();
+listView.setAdapter(adapter);
+</pre>
+<p>{@link android.widget.SimpleCursorAdapter} kemudian membuat tampilan untuk tiap baris dalam
+{@link android.database.Cursor} dengan layout yang disediakan dengan memasukkan setiap item {@code
+fromColumns} ke dalam tampilan {@code toViews} yang sesuai.</p></dd>
+</dl>
+
+
+<p>Jika, selama aplikasi berjalan, Anda mengubah data sumber yang dibaca oleh
+adaptor, maka Anda harus memanggil {@link android.widget.ArrayAdapter#notifyDataSetChanged()}. Hal ini akan
+memberi tahu tampilan yang bersangkutan bahwa data telah berubah dan tampilan harus memperbarui dirinya sendiri.</p>
+
+
+
+<h3 id="HandlingUserSelections">Menangani kejadian klik</h3>
+
+<p>Anda bisa merespons kejadian klik pada setiap item dalam {@link android.widget.AdapterView} dengan
+menerapkan antarmuka {@link android.widget.AdapterView.OnItemClickListener}. Misalnya:</p>
+
+<pre>
+// Create a message handling object as an anonymous class.
+private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
+    public void onItemClick(AdapterView parent, View v, int position, long id) {
+        // Do something in response to the click
+    }
+};
+
+listView.setOnItemClickListener(mMessageClickedHandler);
+</pre>
+
+
+
diff --git a/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
new file mode 100644
index 0000000..06a25ac
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/dialogs.jd
@@ -0,0 +1,798 @@
+page.title=Dialog
+page.tags=alertdialog,dialogfragment
+
+@jd:body
+
+
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#DialogFragment">Membuat Fragmen Dialog</a></li>
+  <li><a href="#AlertDialog">Membuat Dialog Peringatan</a>
+    <ol>
+      <li><a href="#AddingButtons">Menambahkan tombol</a></li>
+      <li><a href="#AddingAList">Menambahkan daftar</a></li>
+      <li><a href="#CustomLayout">Membuat Layout Custom</a></li>
+    </ol>
+  </li>
+  <li><a href="#PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</a></li>
+  <li><a href="#ShowingADialog">Menampilkan Dialog</a></li>
+  <li><a href="#FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</a>
+    <ol>
+      <li><a href="#ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</a></li>
+    </ol>
+  </li>
+  <li><a href="#DismissingADialog">Menutup Dialog</a></li>
+</ol>
+
+    <h2>Kelas-kelas utama</h2>
+    <ol>
+      <li>{@link android.app.DialogFragment}</li>
+      <li>{@link android.app.AlertDialog}</li>
+    </ol>
+
+    <h2>Lihat juga</h2>
+    <ol>
+      <li><a href="{@docRoot}design/building-blocks/dialogs.html">Panduan desain dialog</a></li>
+      <li><a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a> (dialog Tanggal/Waktu)</li>
+    </ol>
+  </div>
+</div>
+
+<p>Dialog adalah jendela kecil yang meminta pengguna untuk
+membuat keputusan atau memasukkan informasi tambahan. Dialog tidak mengisi layar dan
+biasanya digunakan untuk kejadian modal yang mengharuskan pengguna untuk melakukan tindakan sebelum bisa melanjutkan.</p>
+
+<div class="note design">
+<p><strong>Desain Dialog</strong></p>
+  <p>Untuk informasi tentang cara mendesain dialog, termasuk saran
+  untuk bahasa, bacalah panduan Desain <a href="{@docRoot}design/building-blocks/dialogs.html">dialog</a>.</p>
+</div>
+
+<img src="{@docRoot}images/ui/dialogs.png" />
+
+<p>Kelas {@link android.app.Dialog} adalah kelas basis untuk dialog, namun Anda
+harus menghindari pembuatan instance {@link android.app.Dialog} secara langsung.
+Sebagai gantinya, gunakan salah satu subkelas berikut:</p>
+<dl>
+  <dt>{@link android.app.AlertDialog}</dt>
+  <dd>Dialog yang bisa menampilkan judul, hingga tiga tombol, daftar
+    item yang dapat dipilih, atau layout custom.</dd>
+  <dt>{@link android.app.DatePickerDialog} atau {@link android.app.TimePickerDialog}</dt>
+  <dd>Dialog berisi UI yang sudah didefinisikan dan memungkinkan pengguna memilih tanggal atau waktu.</dd>
+</dl>
+
+<div class="sidebox">
+<h2>Hindari ProgressDialog</h2>
+<p>Android menyertakan kelas dialog lain yang disebut
+{@link android.app.ProgressDialog} yang menampilkan dialog berisi progress-bar. Akan tetapi, jika Anda
+perlu menunjukkan kemajuan pemuatan ataupun kemajuan yang tidak pasti, maka Anda harus mengikuti
+panduan desain untuk <a href="{@docRoot}design/building-blocks/progress.html">Kemajuan &amp;
+Aktivitas</a> dan menggunakan {@link android.widget.ProgressBar} dalam layout Anda.</p>
+</div>
+
+<p>Kelas-kelas ini mendefinisikan gaya dan struktur dialog Anda, namun Anda harus
+menggunakan {@link android.support.v4.app.DialogFragment} sebagai kontainer dialog Anda.
+Kelas {@link android.support.v4.app.DialogFragment} menyediakan semua kontrol yang Anda
+perlukan untuk membuat dialog dan mengelola penampilannya, sebagai ganti memanggil metode
+pada objek {@link android.app.Dialog}.</p>
+
+<p>Menggunakan {@link android.support.v4.app.DialogFragment} untuk mengelola dialog
+akan memastikan bahwa kelas itu menangani kejadian daur hidup
+dengan benar seperti ketika pengguna menekan tombol <em>Back</em> atau memutar layar. Kelas {@link
+android.support.v4.app.DialogFragment} juga memungkinkan Anda menggunakan ulang dialog UI sebagai
+komponen yang bisa ditanamkan dalam UI yang lebih besar, persis seperti {@link
+android.support.v4.app.Fragment} tradisional (seperti saat Anda ingin dialog UI muncul berbeda
+pada layar besar dan kecil).</p>
+
+<p>Bagian-bagian berikutnya dalam panduan ini akan menjelaskan cara menggunakan {@link
+android.support.v4.app.DialogFragment} yang dikombinasikan dengan objek {@link android.app.AlertDialog}
+. Jika Anda ingin membuat picker tanggal atau waktu, Anda harus membaca panduan
+<a href="{@docRoot}guide/topics/ui/controls/pickers.html">Picker</a>.</p>
+
+<p class="note"><strong>Catatan:</strong>
+Karena kelas {@link android.app.DialogFragment} mulanya ditambahkan pada
+Android 3.0 (API level 11), dokumen ini menjelaskan cara menggunakan kelas {@link
+android.support.v4.app.DialogFragment} yang disediakan bersama <a href="{@docRoot}tools/support-library/index.html">Pustaka Dukungan</a>. Dengan menambahkan pustaka ini
+ke aplikasi, Anda bisa menggunakan {@link android.support.v4.app.DialogFragment} dan berbagai
+API lain pada perangkat yang menjalankan Android 1.6 atau yang lebih tinggi. Jika versi minimum yang didukung aplikasi Anda
+adalah API level 11 atau yang lebih tinggi, maka Anda bisa menggunakan versi kerangka kerja {@link
+android.app.DialogFragment}, namun ketahuilah bahwa tautan dalam dokumen ini adalah untuk API
+pustaka dukungan. Saat menggunakan pustaka dukungan,
+pastikan Anda mengimpor kelas <code>android.support.v4.app.DialogFragment</code>
+dan <em>bukan</em> <code>android.app.DialogFragment</code>.</p>
+
+
+<h2 id="DialogFragment">Membuat Fragmen Dialog</h2>
+
+<p>Anda bisa menghasilkan beragam rancangan dialog&mdash;termasuk
+layout custom dan desain yang dijelaskan dalam panduan desain <a href="{@docRoot}design/building-blocks/dialogs.html">Dialog</a>
+&mdash;dengan memperluas
+{@link android.support.v4.app.DialogFragment} dan membuat {@link android.app.AlertDialog}
+dalam metode callback {@link android.support.v4.app.DialogFragment#onCreateDialog
+onCreateDialog()}.</p>
+
+<p>Misalnya, berikut ini sebuah {@link android.app.AlertDialog} dasar yang dikelola dalam
+{@link android.support.v4.app.DialogFragment}:</p>
+
+<pre>
+public class FireMissilesDialogFragment extends DialogFragment {
+    &#64;Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Use the Builder class for convenient dialog construction
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setMessage(R.string.dialog_fire_missiles)
+               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int id) {
+                       // FIRE ZE MISSILES!
+                   }
+               })
+               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int id) {
+                       // User cancelled the dialog
+                   }
+               });
+        // Create the AlertDialog object and return it
+        return builder.create();
+    }
+}
+</pre>
+
+<div class="figure" style="width:290px;margin:0 0 0 20px">
+<img src="{@docRoot}images/ui/dialog_buttons.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong>
+Dialog dengan satu pesan dan dua tombol tindakan.</p>
+</div>
+
+<p>Sekarang, bila Anda membuat instance kelas ini dan memanggil {@link
+android.support.v4.app.DialogFragment#show show()} pada objek itu, dialog akan muncul seperti
+yang ditampilkan dalam gambar 1.</p>
+
+<p>Bagian berikutnya menjelaskan lebih jauh tentang penggunaan API {@link android.app.AlertDialog.Builder}
+untuk membuat dialog.</p>
+
+<p>Bergantung pada seberapa rumit dialog tersebut, Anda bisa menerapkan berbagai metode callback lain
+dalam {@link android.support.v4.app.DialogFragment}, termasuk semua
+<a href="{@docRoot}guide/components/fragments.html#Lifecycle">metode daur hidup fragmen</a> dasar.
+
+
+
+
+
+<h2 id="AlertDialog">Membuat Dialog Peringatan</h2>
+
+
+<p>Kelas {@link android.app.AlertDialog} memungkinkan Anda membuat berbagai desain dialog dan
+seringkali satu-satunya kelas dialog yang akan Anda perlukan.
+Seperti yang ditampilkan dalam gambar 2, ada tiga area pada dialog peringatan:</p>
+
+<div class="figure" style="width:311px;margin-top:0">
+<img src="{@docRoot}images/ui/dialogs_regions.png" alt="" style="margin-bottom:0" />
+<p class="img-caption"><strong>Gambar 2.</strong> Layout dialog.</p>
+</div>
+
+<ol>
+<li><b>Judul</b>
+  <p>Area ini opsional dan hanya boleh digunakan bila area konten
+  ditempati oleh pesan terperinci, daftar, atau layout custom. Jika Anda perlu menyatakan
+  pesan atau pertanyaan sederhana (seperti dialog dalam gambar 1), Anda tidak memerlukan judul.</li>
+<li><b>Area konten</b>
+  <p>Area ini bisa menampilkan pesan, daftar, atau layout custom lainnya.</p></li>
+<li><b>Tombol tindakan</b>
+  <p>Tidak boleh ada lebih dari tiga tombol tindakan dalam sebuah dialog.</p></li>
+</ol>
+
+<p>Kelas {@link android.app.AlertDialog.Builder}
+ menyediakan API yang memungkinkan Anda membuat {@link android.app.AlertDialog}
+dengan jenis konten ini, termasuk layout custom.</p>
+
+<p>Untuk membuat {@link android.app.AlertDialog}:</p>
+
+<pre>
+<b>// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor</b>
+AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+<b>// 2. Chain together various setter methods to set the dialog characteristics</b>
+builder.setMessage(R.string.dialog_message)
+       .setTitle(R.string.dialog_title);
+
+<b>// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()}</b>
+AlertDialog dialog = builder.create();
+</pre>
+
+<p>Topik-topik selanjutnya menampilkan cara mendefinisikan berbagai atribut dialog dengan menggunakan
+kelas {@link android.app.AlertDialog.Builder}.</p>
+
+
+
+
+<h3 id="AddingButtons">Menambahkan tombol</h3>
+
+<p>Untuk menambahkan tombol tindakan seperti dalam gambar 2,
+panggil metode {@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} dan
+{@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()}:</p>
+
+<pre style="clear:right">
+AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+// Add the buttons
+builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+           public void onClick(DialogInterface dialog, int id) {
+               // User clicked OK button
+           }
+       });
+builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+           public void onClick(DialogInterface dialog, int id) {
+               // User cancelled the dialog
+           }
+       });
+// Set other dialog properties
+...
+
+// Create the AlertDialog
+AlertDialog dialog = builder.create();
+</pre>
+
+<p>Metode <code>set...Button()</code> mengharuskan adanya judul bagi tombol (disediakan
+oleh suatu <a href="{@docRoot}guide/topics/resources/string-resource.html">sumber daya string</a>) dan
+{@link android.content.DialogInterface.OnClickListener} yang mendefinisikan tindakan yang diambil
+bila pengguna menekan tombol.</p>
+
+<p>Ada tiga macam tombol tindakan yang Anda bisa tambahkan:</p>
+<dl>
+  <dt>Positif</dt>
+  <dd>Anda harus menggunakan tipe ini untuk menerima dan melanjutkan tindakan (tindakan "OK").</dd>
+  <dt>Negatif</dt>
+  <dd>Anda harus menggunakan tipe ini untuk membatalkan tindakan.</dd>
+  <dt>Netral</dt>
+  <dd>Anda harus menggunakan tipe ini bila pengguna mungkin tidak ingin melanjutkan tindakan,
+  namun tidak ingin membatalkan. Tipe ini muncul antara tombol positif dan
+tombol negatif. Misalnya, tindakan bisa berupa "Ingatkan saya nanti".</dd>
+</dl>
+
+<p>Anda hanya bisa menambahkan salah satu tipe tombol ke {@link
+android.app.AlertDialog}. Artinya, Anda tidak bisa memiliki lebih dari satu tombol "positif".</p>
+
+
+
+<div class="figure" style="width:290px;margin:0 0 0 40px">
+<img src="{@docRoot}images/ui/dialog_list.png" alt="" />
+<p class="img-caption"><strong>Gambar 3.</strong>
+Dialog dengan satu judul dan daftar.</p>
+</div>
+
+<h3 id="AddingAList">Menambahkan daftar</h3>
+
+<p>Ada tiga macam daftar yang tersedia pada API {@link android.app.AlertDialog}:</p>
+<ul>
+<li>Daftar pilihan tunggal biasa</li>
+<li>Daftar pilihan tunggal persisten (tombol radio)</li>
+<li>Daftar pilihan ganda persisten (kotak cek)</li>
+</ul>
+
+<p>Untuk membuat daftar pilihan tunggal seperti dalam gambar 3,
+gunakan metode {@link android.app.AlertDialog.Builder#setItems setItems()}:</p>
+
+<pre style="clear:right">
+&#64;Override
+public Dialog onCreateDialog(Bundle savedInstanceState) {
+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+    builder.setTitle(R.string.pick_color)
+           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
+               public void onClick(DialogInterface dialog, int which) {
+               // The 'which' argument contains the index position
+               // of the selected item
+           }
+    });
+    return builder.create();
+}
+</pre>
+
+<p>Karena daftar muncul dalam area konten dialog,
+dialog tidak bisa menampilkan pesan dan daftar sekaligus dan Anda harus menetapkan judul untuk
+dialog dengan {@link android.app.AlertDialog.Builder#setTitle setTitle()}.
+Untuk menentukan item daftar, panggil {@link
+android.app.AlertDialog.Builder#setItems setItems()}, dengan meneruskan larik.
+Atau, Anda bisa menetapkan daftar menggunakan {@link
+android.app.AlertDialog.Builder#setAdapter setAdapter()}. Hal ini memungkinkan Anda mendukung daftar
+dengan data dinamis (seperti dari database) dengan menggunakan {@link android.widget.ListAdapter}.</p>
+
+<p>Jika Anda memilih untuk mendukung daftar dengan {@link android.widget.ListAdapter},
+selalu gunakan sebuah {@link android.support.v4.content.Loader} agar konten dimuat
+secara asinkron. Hal ini dijelaskan lebih jauh dalam panduan
+<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Membuat Layout
+dengan Adaptor</a> dan <a href="{@docRoot}guide/components/loaders.html">Loader</a>
+.</p>
+
+<p class="note"><strong>Catatan:</strong> Secara default, menyentuh sebuah item daftar akan menutup dialog,
+kecuali Anda menggunakan salah satu daftar pilihan persisten berikut ini.</p>
+
+<div class="figure" style="width:290px;margin:-30px 0 0 40px">
+<img src="{@docRoot}images/ui/dialog_checkboxes.png" />
+<p class="img-caption"><strong>Gambar 4.</strong>
+Daftar item pilihan ganda.</p>
+</div>
+
+
+<h4 id="Checkboxes">Menambahkan daftar pilihan ganda atau pilihan tunggal persisten</h4>
+
+<p>Untuk menambahkan daftar item pilihan ganda (kotak cek) atau
+item pilihan tunggal (tombol radio), gunakan masing-masing metode
+{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String,
+DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()}, atau
+{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
+setSingleChoiceItems()}.</p>
+
+<p>Misalnya, berikut ini cara membuat daftar pilihan ganda seperti
+yang ditampilkan dalam gambar 4 yang menyimpan item
+yang dipilih dalam {@link java.util.ArrayList}:</p>
+
+<pre style="clear:right">
+&#64;Override
+public Dialog onCreateDialog(Bundle savedInstanceState) {
+    mSelectedItems = new ArrayList();  // Where we track the selected items
+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+    // Set the dialog title
+    builder.setTitle(R.string.pick_toppings)
+    // Specify the list array, the items to be selected by default (null for none),
+    // and the listener through which to receive callbacks when items are selected
+           .setMultiChoiceItems(R.array.toppings, null,
+                      new DialogInterface.OnMultiChoiceClickListener() {
+               &#64;Override
+               public void onClick(DialogInterface dialog, int which,
+                       boolean isChecked) {
+                   if (isChecked) {
+                       // If the user checked the item, add it to the selected items
+                       mSelectedItems.add(which);
+                   } else if (mSelectedItems.contains(which)) {
+                       // Else, if the item is already in the array, remove it
+                       mSelectedItems.remove(Integer.valueOf(which));
+                   }
+               }
+           })
+    // Set the action buttons
+           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+               &#64;Override
+               public void onClick(DialogInterface dialog, int id) {
+                   // User clicked OK, so save the mSelectedItems results somewhere
+                   // or return them to the component that opened the dialog
+                   ...
+               }
+           })
+           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+               &#64;Override
+               public void onClick(DialogInterface dialog, int id) {
+                   ...
+               }
+           });
+
+    return builder.create();
+}
+</pre>
+
+<p>Walaupun daftar tradisional maupun daftar dengan tombol radio
+menyediakan tindakan "pilihan tunggal", Anda harus menggunakan {@link
+android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener)
+setSingleChoiceItems()} jika ingin mempertahankan pilihan pengguna.
+Yakni, jika nanti membuka dialog lagi untuk menunjukkan pilihan pengguna,
+maka Anda perlu membuat daftar dengan tombol radio.</p>
+
+
+
+
+
+<h3 id="CustomLayout">Membuat Layout Custom</h3>
+
+<div class="figure" style="width:290px;margin:-30px 0 0 40px">
+<img src="{@docRoot}images/ui/dialog_custom.png" alt="" />
+<p class="img-caption"><strong>Gambar 5.</strong> Layout dialog custom.</p>
+</div>
+
+<p>Jika Anda menginginkan layout custom dalam dialog, buatlah layout dan tambahkan ke
+{@link android.app.AlertDialog} dengan memanggil {@link
+android.app.AlertDialog.Builder#setView setView()} pada objek {@link
+android.app.AlertDialog.Builder} Anda.</p>
+
+<p>Secara default, layout custom akan mengisi jendela dialog, namun Anda masih bisa
+menggunakan metode {@link android.app.AlertDialog.Builder} untuk menambahkan tombol dan judul.</p>
+
+<p>Misalnya, berikut ini adalah file layout untuk dialog dalam Gambar 5:</p>
+
+<p style="clear:right" class="code-caption">res/layout/dialog_signin.xml</p>
+<pre>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    &lt;ImageView
+        android:src="@drawable/header_logo"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:scaleType="center"
+        android:background="#FFFFBB33"
+        android:contentDescription="@string/app_name" />
+    &lt;EditText
+        android:id="@+id/username"
+        android:inputType="textEmailAddress"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginLeft="4dp"
+        android:layout_marginRight="4dp"
+        android:layout_marginBottom="4dp"
+        android:hint="@string/username" />
+    &lt;EditText
+        android:id="@+id/password"
+        android:inputType="textPassword"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:layout_marginLeft="4dp"
+        android:layout_marginRight="4dp"
+        android:layout_marginBottom="16dp"
+        android:fontFamily="sans-serif"
+        android:hint="@string/password"/>
+&lt;/LinearLayout>
+</pre>
+
+<p class="note"><strong>Tip:</strong> Secara default, bila Anda telah mengatur sebuah elemen {@link android.widget.EditText}
+agar menggunakan tipe input {@code "textPassword"}, keluarga font akan diatur ke spasi tunggal, sehingga
+Anda harus mengubah keluarga font ke {@code "sans-serif"} sehingga kedua bidang teks menggunakan
+gaya font yang cocok.</p>
+
+<p>Untuk memekarkan layout dalam {@link android.support.v4.app.DialogFragment} Anda,
+ambillah {@link android.view.LayoutInflater} dengan
+{@link android.app.Activity#getLayoutInflater()} dan panggil
+{@link android.view.LayoutInflater#inflate inflate()}, dengan parameter pertama
+adalah ID sumber daya layout dan parameter kedua adalah tampilan induk untuk layout.
+Selanjutnya Anda bisa memanggil {@link android.app.AlertDialog#setView setView()}
+untuk menempatkan layout dalam dialog.</p>
+
+<pre>
+&#64;Override
+public Dialog onCreateDialog(Bundle savedInstanceState) {
+    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+    // Get the layout inflater
+    LayoutInflater inflater = getActivity().getLayoutInflater();
+
+    // Inflate and set the layout for the dialog
+    // Pass null as the parent view because its going in the dialog layout
+    builder.setView(inflater.inflate(R.layout.dialog_signin, null))
+    // Add action buttons
+           .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
+               &#64;Override
+               public void onClick(DialogInterface dialog, int id) {
+                   // sign in the user ...
+               }
+           })
+           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+               public void onClick(DialogInterface dialog, int id) {
+                   LoginDialogFragment.this.getDialog().cancel();
+               }
+           });
+    return builder.create();
+}
+</pre>
+
+<div class="note">
+<p><strong>Tip:</strong> Jika Anda menginginkan dialog custom,
+Anda bisa menampilkan {@link android.app.Activity} sebagai dialog
+daripada menggunakan API {@link android.app.Dialog}. Cukup buat satu aktivitas dan mengatur temanya ke
+{@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog}
+di elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a>:</p>
+
+<pre>
+&lt;activity android:theme="&#64;android:style/Theme.Holo.Dialog" >
+</pre>
+<p>Demikian saja. Aktivitas sekarang ditampilkan dalam jendela dialog, sebagai ganti layar penuh.</p>
+</div>
+
+
+
+<h2 id="PassingEvents">Meneruskan Kejadian Kembali ke Host Dialog</h2>
+
+<p>Bila pengguna menyentuh salah satu tombol tindakan dialog atau memilih satu item dari daftarnya,
+{@link android.support.v4.app.DialogFragment} Anda bisa melakukan sendiri tindakan yang diperlukan
+, namun sering kali Anda perlu mengirim kejadian itu ke aktivitas atau fragmen yang
+membuka dialog. Caranya, definisikan antarmuka dengan sebuah metode untuk masing-masing tipe kejadian klik.
+Lalu implementasikan antarmuka itu dalam komponen host yang akan
+menerima kejadian tindakan dari dialog.</p>
+
+<p>Misalnya, berikut ini adalah {@link android.support.v4.app.DialogFragment} yang mendefinisikan
+antarmuka yang akan digunakan untuk mengirim kembali suatu kejadian ke aktivitas host:</p>
+
+<pre>
+public class NoticeDialogFragment extends DialogFragment {
+
+    /* The activity that creates an instance of this dialog fragment must
+     * implement this interface in order to receive event callbacks.
+     * Each method passes the DialogFragment in case the host needs to query it. */
+    public interface NoticeDialogListener {
+        public void onDialogPositiveClick(DialogFragment dialog);
+        public void onDialogNegativeClick(DialogFragment dialog);
+    }
+
+    // Use this instance of the interface to deliver action events
+    NoticeDialogListener mListener;
+
+    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
+    &#64;Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        // Verify that the host activity implements the callback interface
+        try {
+            // Instantiate the NoticeDialogListener so we can send events to the host
+            mListener = (NoticeDialogListener) activity;
+        } catch (ClassCastException e) {
+            // The activity doesn't implement the interface, throw exception
+            throw new ClassCastException(activity.toString()
+                    + " must implement NoticeDialogListener");
+        }
+    }
+    ...
+}
+</pre>
+
+<p>Aktivitas yang menjadi host dialog tersebut akan membuat instance dialog
+dengan konstruktor fragmen dialog dan menerima kejadian dialog
+melalui implementasi antarmuka {@code NoticeDialogListener}:</p>
+
+<pre>
+public class MainActivity extends FragmentActivity
+                          implements NoticeDialogFragment.NoticeDialogListener{
+    ...
+
+    public void showNoticeDialog() {
+        // Create an instance of the dialog fragment and show it
+        DialogFragment dialog = new NoticeDialogFragment();
+        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
+    }
+
+    // The dialog fragment receives a reference to this Activity through the
+    // Fragment.onAttach() callback, which it uses to call the following methods
+    // defined by the NoticeDialogFragment.NoticeDialogListener interface
+    &#64;Override
+    public void onDialogPositiveClick(DialogFragment dialog) {
+        // User touched the dialog's positive button
+        ...
+    }
+
+    &#64;Override
+    public void onDialogNegativeClick(DialogFragment dialog) {
+        // User touched the dialog's negative button
+        ...
+    }
+}
+</pre>
+
+<p>Karena aktivitas host mengimplementasikan {@code NoticeDialogListener}&mdash;yang
+diberlakukan oleh metode callback {@link android.support.v4.app.Fragment#onAttach onAttach()}
+di atas,&mdash;fragmen dialog bisa menggunakan
+metode callback antarmuka untuk mengirimkan kejadian klik ke aktivitas:</p>
+
+<pre>
+public class NoticeDialogFragment extends DialogFragment {
+    ...
+
+    &#64;Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Build the dialog and set up the button click handlers
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setMessage(R.string.dialog_fire_missiles)
+               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int id) {
+                       // Send the positive button event back to the host activity
+                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
+                   }
+               })
+               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int id) {
+                       // Send the negative button event back to the host activity
+                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);
+                   }
+               });
+        return builder.create();
+    }
+}
+</pre>
+
+
+
+<h2 id="ShowingADialog">Menampilkan Dialog</h2>
+
+<p>Bila Anda ingin menampilkan dialog, buatlah instance {@link
+android.support.v4.app.DialogFragment} dan panggil {@link android.support.v4.app.DialogFragment#show
+show()}, dengan meneruskan {@link android.support.v4.app.FragmentManager} dan nama tag
+untuk fragmen dialognya.</p>
+
+<p>Anda bisa mendapatkan {@link android.support.v4.app.FragmentManager} dengan memanggil
+{@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} dari
+ {@link android.support.v4.app.FragmentActivity} atau {@link
+android.support.v4.app.Fragment#getFragmentManager()} dari {@link
+android.support.v4.app.Fragment}. Misalnya:</p>
+
+<pre>
+public void confirmFireMissiles() {
+    DialogFragment newFragment = new FireMissilesDialogFragment();
+    newFragment.show(getSupportFragmentManager(), "missiles");
+}
+</pre>
+
+<p>Argumen kedua, {@code "missiles"}, adalah nama tag unik yang digunakan sistem untuk menyimpan
+dan memulihkan status fragmen bila diperlukan. Tag ini juga memungkinkan Anda mendapatkan handle ke
+fragmen dengan memanggil {@link android.support.v4.app.FragmentManager#findFragmentByTag
+findFragmentByTag()}.</p>
+
+
+
+
+<h2 id="FullscreenDialog">Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam</h2>
+
+<p>Anda mungkin memiliki desain UI yang di dalamnya Anda ingin UI muncul sebagai dialog dalam beberapa
+situasi, namun sebagai layar penuh atau fragmen tertanam dalam situasi lain (mungkin bergantung pada apakah
+perangkat memiliki layar besar atau layar kecil). Kelas {@link android.support.v4.app.DialogFragment}
+menawarkan fleksibilitas ini karena masih bisa berperilaku sebagai {@link
+android.support.v4.app.Fragment} yang bisa ditanamkan.</p>
+
+<p>Akan tetapi, dalam hal ini Anda tidak bisa menggunakan {@link android.app.AlertDialog.Builder AlertDialog.Builder}
+atau objek {@link android.app.Dialog} lain untuk membangun dialog. Jika
+Anda ingin {@link android.support.v4.app.DialogFragment}
+bisa ditanamkan, Anda harus mendefinisikan dialog UI dalam layout, lalu memuat layout itu dalam metode callback
+{@link android.support.v4.app.DialogFragment#onCreateView
+onCreateView()}.</p>
+
+<p>Berikut ini adalah contoh {@link android.support.v4.app.DialogFragment} yang bisa muncul sebagai
+dialog maupun fragmen yang bisa ditanamkan (menggunakan layout bernama <code>purchase_items.xml</code>):</p>
+
+<pre>
+public class CustomDialogFragment extends DialogFragment {
+    /** The system calls this to get the DialogFragment's layout, regardless
+        of whether it's being displayed as a dialog or an embedded fragment. */
+    &#64;Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        // Inflate the layout to use as dialog or embedded fragment
+        return inflater.inflate(R.layout.purchase_items, container, false);
+    }
+
+    /** The system calls this only when creating the layout in a dialog. */
+    &#64;Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // The only reason you might override this method when using onCreateView() is
+        // to modify any dialog characteristics. For example, the dialog includes a
+        // title by default, but your custom layout might not need it. So here you can
+        // remove the dialog title, but you must call the superclass to get the Dialog.
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        return dialog;
+    }
+}
+</pre>
+
+<p>Dan berikut ini adalah beberapa kode yang memutuskan apakah akan menampilkan fragmen sebagai dialog
+atau UI layar penuh, berdasarkan ukuran layar:</p>
+
+<pre>
+public void showDialog() {
+    FragmentManager fragmentManager = getSupportFragmentManager();
+    CustomDialogFragment newFragment = new CustomDialogFragment();
+
+    if (mIsLargeLayout) {
+        // The device is using a large layout, so show the fragment as a dialog
+        newFragment.show(fragmentManager, "dialog");
+    } else {
+        // The device is smaller, so show the fragment fullscreen
+        FragmentTransaction transaction = fragmentManager.beginTransaction();
+        // For a little polish, specify a transition animation
+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+        // To make it fullscreen, use the 'content' root view as the container
+        // for the fragment, which is always the root view for the activity
+        transaction.add(android.R.id.content, newFragment)
+                   .addToBackStack(null).commit();
+    }
+}
+</pre>
+
+<p>Untuk informasi selengkapnya tentang melakukan transaksi fragmen, lihat panduan
+<a href="{@docRoot}guide/components/fragments.html">Fragmen</a>.</p>
+
+<p>Dalam contoh ini, nilai boolean <code>mIsLargeLayout</code> menentukan apakah perangkat saat ini
+harus menggunakan desain layout besar aplikasi (dan dengan demikian menampilkan fragmen ini sebagai dialog, bukan
+layar penuh). Cara terbaik untuk mengatur jenis boolean ini adalah mendeklarasikan
+<a href="{@docRoot}guide/topics/resources/more-resources.html#Bool">nilai sumber daya boolean</a>
+dengan nilai <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">sumber daya alternatif</a> untuk berbagai ukuran layar. Misalnya, berikut ini adalah dua
+versi sumber daya boolean untuk berbagai ukuran layar:</p>
+
+<p class="code-caption">res/values/bools.xml</p>
+<pre>
+&lt;!-- Default boolean values -->
+&lt;resources>
+    &lt;bool name="large_layout">false&lt;/bool>
+&lt;/resources>
+</pre>
+
+<p class="code-caption">res/values-large/bools.xml</p>
+<pre>
+&lt;!-- Large screen boolean values -->
+&lt;resources>
+    &lt;bool name="large_layout">true&lt;/bool>
+&lt;/resources>
+</pre>
+
+<p>Selanjutnya Anda bisa menetapkan nilai {@code mIsLargeLayout} selama
+metode {@link android.app.Activity#onCreate onCreate()} aktivitas:</p>
+
+<pre>
+boolean mIsLargeLayout;
+
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_main);
+
+    mIsLargeLayout = getResources().getBoolean(R.bool.large_layout);
+}
+</pre>
+
+
+
+<h3 id="ActivityAsDialog">Menampilkan aktivitas sebagai dialog pada layar besar</h3>
+
+<p>Sebagai ganti menampilkan dialog berupa UI layar penuh saat di layar kecil, Anda bisa memperoleh
+hasil yang sama dengan menampilkan {@link android.app.Activity} sebagai dialog saat di
+layar besar. Pendekatan yang Anda pilih bergantung pada desain aplikasi, namun
+menampilkan aktivitas sebagai dialog sering kali berguna bila aplikasi Anda sudah didesain untuk
+layar kecil dan Anda ingin meningkatkan pengalaman pada tablet dengan menampilkan aktivitas berjangka pendek
+sebagai dialog.</p>
+
+<p>Untuk menampilkan aktivitas sebagai dialog hanya saat di layar besar,
+terapkan tema {@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge}
+ pada elemen manifes <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a>:</p>
+
+<pre>
+&lt;activity android:theme="&#64;android:style/Theme.Holo.DialogWhenLarge" >
+</pre>
+
+<p>Untuk informasi selengkapnya tentang mengatur gaya aktivitas Anda dengan tema, lihat panduan <a href="{@docRoot}guide/topics/ui/themes.html">Gaya dan Tema</a>.</p>
+
+
+
+<h2 id="DismissingADialog">Menutup Dialog</h2>
+
+<p>Bila pengguna menyentuh salah satu tombol tindakan yang dibuat dengan
+{@link android.app.AlertDialog.Builder}, sistem akan menutup dialog untuk Anda.</p>
+
+<p>Sistem juga menutup dialog bila pengguna menyentuh sebuah item dalam daftar dialog, kecuali
+bila daftar itu menggunakan tombol radio atau kotak cek. Jika tidak, Anda bisa menutup dialog secara manual
+dengan memanggil {@link android.support.v4.app.DialogFragment#dismiss()} pada {@link
+android.support.v4.app.DialogFragment} Anda.</p>
+
+<p>Jika Anda perlu melakukan
+tindakan tertentu saat dialog menghilang, Anda bisa menerapkan metode {@link
+android.support.v4.app.DialogFragment#onDismiss onDismiss()} dalam {@link
+android.support.v4.app.DialogFragment} Anda.</p>
+
+<p>Anda juga bisa <em>membatalkan</em> dialog. Ini merupakan kejadian khusus yang menunjukkan bahwa pengguna
+secara eksplisit meninggalkan dialog tanpa menyelesaikan tugas. Hal ini terjadi jika pengguna menekan tombol
+<em>Back</em>, menyentuh layar di luar area dialog,
+atau jika Anda secara eksplisit memanggil {@link android.app.Dialog#cancel()} pada {@link
+android.app.Dialog} (seperti saat merespons tombol "Cancel" dalam dialog).</p>
+
+<p>Seperti yang ditampilkan dalam contoh di atas, Anda bisa merespons kejadian batal dengan menerapkan
+{@link android.support.v4.app.DialogFragment#onCancel onCancel()} dalam kelas {@link
+android.support.v4.app.DialogFragment} Anda.</p>
+
+<p class="note"><strong>Catatan:</strong> Sistem akan memanggil
+{@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} pada tiap kejadian yang
+memanggil callback {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Akan tetapi,
+jika Anda memanggil {@link android.app.Dialog#dismiss Dialog.dismiss()} atau {@link
+android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()},
+sistem akan memanggil {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} <em>namun
+bukan</em> {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Jadi biasanya Anda harus
+memanggil {@link android.support.v4.app.DialogFragment#dismiss dismiss()} bila pengguna menekan tombol
+<em>positif</em> dalam dialog untuk menghilangkan tampilan dialog.</p>
+
+
diff --git a/docs/html-intl/intl/id/guide/topics/ui/menus.jd b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
new file mode 100644
index 0000000..1ee0244
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/menus.jd
@@ -0,0 +1,1031 @@
+page.title=Menu
+parent.title=Antarmuka Pengguna
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#xml">Mendefinisikan Menu dalam XML</a></li>
+  <li><a href="#options-menu">Membuat Menu Opsi</a>
+    <ol>
+      <li><a href="#RespondingOptionsMenu">Menangani kejadian klik</a></li>
+      <li><a href="#ChangingTheMenu">Mengubah item menu saat runtime</a></li>
+    </ol>
+  </li>
+  <li><a href="#context-menu">Membuat Menu Kontekstual</a>
+    <ol>
+      <li><a href="#FloatingContextMenu">Membuat menu konteks mengambang</a></li>
+      <li><a href="#CAB">Menggunakan mode tindakan kontekstual</a></li>
+    </ol>
+  </li>
+  <li><a href="#PopupMenu">Membuat Menu Popup</a>
+    <ol>
+      <li><a href="#PopupEvents">Menangani kejadian klik</a></li>
+    </ol>
+  </li>
+  <li><a href="#groups">Membuat Grup Menu</a>
+    <ol>
+      <li><a href="#checkable">Menggunakan item menu yang bisa diberi tanda cek</a></li>
+    </ol>
+  </li>
+  <li><a href="#intents">Menambahkan Item Menu Berdasarkan Intent</a>
+    <ol>
+      <li><a href="#AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</a></li>
+    </ol>
+  </li>
+</ol>
+
+  <h2>Kelas-kelas utama</h2>
+  <ol>
+    <li>{@link android.view.Menu}</li>
+    <li>{@link android.view.MenuItem}</li>
+    <li>{@link android.view.ContextMenu}</li>
+    <li>{@link android.view.ActionMode}</li>
+  </ol>
+
+  <h2>Lihat juga</h2>
+  <ol>
+    <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a></li>
+    <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a></li>
+    <li><a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Ucapkan
+Selamat Tinggal pada Tombol Menu</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Menu adalah komponen antarmuka pengguna yang lazim dalam banyak tipe aplikasi. Untuk menyediakan pengalaman pengguna yang sudah akrab
+dan konsisten, Anda harus menggunakan API {@link android.view.Menu} untuk menyajikan
+tindakan dan opsi lain dalam aktivitas kepada pengguna.</p>
+
+<p>Mulai dengan Android 3.0 (API level 11), perangkat berbasis Android tidak perlu lagi
+menyediakan tombol <em>Menu</em> tersendiri. Dengan perubahan ini, aplikasi Android harus bermigrasi dari
+dependensi pada panel menu 6 item biasa, dan sebagai ganti menyediakan action-bar untuk menyajikan
+berbagai tindakan pengguna yang lazim.</p>
+
+<p>Walaupun desain dan pengalaman pengguna untuk sebagian item menu telah berubah, semantik untuk mendefinisikan
+serangkaian tindakan dan opsi masih berdasarkan pada API {@link android.view.Menu}. Panduan ini
+menampilkan cara membuat tiga tipe dasar penyajian menu atau tindakan pada semua
+versi Android:</p>
+
+<dl>
+  <dt><strong>Menu opsi dan action-bar</strong></dt>
+    <dd><a href="#options-menu">Menu opsi</a> adalah kumpulan item menu utama untuk suatu
+aktivitas. Inilah tempat Anda harus menempatkan tindakan yang berdampak global pada aplikasi, seperti
+"Cari", "Tulis email", dan "Pengaturan".
+  <p>Jika Anda mengembangkan aplikasi untuk Android 2.3 atau yang lebih rendah, pengguna bisa
+menampilkan panel menu opsi dengan menekan tombol <em>Menu</em>.</p>
+  <p>Pada Android 3.0 dan yang lebih tinggi, item menu opsi disajikan melalui <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a> sebagai kombinasi item tindakan
+di layar dan opsi overflow. Mulai dengan Android 3.0, tombol <em>Menu</em> dihilangkan (sebagian
+perangkat
+tidak memilikinya), sehingga Anda harus bermigrasi ke penggunaan action-bar untuk menyediakan akses ke tindakan dan
+opsi lainnya.</p>
+  <p>Lihat bagian tentang <a href="#options-menu">Membuat Menu Opsi</a>.</p>
+    </dd>
+
+  <dt><strong>Menu konteks dan mode tindakan kontekstual</strong></dt>
+
+   <dd>Menu konteks adalah <a href="#FloatingContextMenu">menu mengambang</a> yang muncul saat
+pengguna mengklik lama pada suatu elemen. Menu ini menyediakan tindakan yang memengaruhi konten atau
+bingkai konteks yang dipilih.
+  <p>Saat mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, sebagai gantinya Anda harus menggunakan <a href="#CAB">mode tindakan kontekstual</a> untuk memungkinkan tindakan pada konten yang dipilih. Mode ini menampilkan
+item tindakan yang memengaruhi konten yang dipilih dalam baris di bagian atas layar dan memungkinkan pengguna
+memilih beberapa item sekaligus.</p>
+  <p>Lihat bagian tentang <a href="#context-menu">Membuat Menu Kontekstual</a>.</p>
+</dd>
+
+  <dt><strong>Menu popup</strong></dt>
+    <dd>Menu popup menampilkan daftar item secara vertikal yang dipasang pada tampilan yang
+memanggil menu. Ini cocok untuk menyediakan kelebihan tindakan yang terkait dengan konten tertentu atau
+untuk menyediakan opsi bagi bagian kedua dari suatu perintah. Tindakan di menu popup
+<strong>tidak</strong> boleh memengaruhi secara langsung konten yang bersangkutan&mdash;yang diperuntukkan bagi
+tindakan kontekstual. Melainkan, menu popup adalah untuk tindakan tambahan yang terkait dengan wilayah konten dalam
+aktivitas Anda.
+  <p>Lihat bagian tentang <a href="#PopupMenu">Membuat Menu Popup</a>.</p>
+</dd>
+</dl>
+
+
+
+<h2 id="xml">Mendefinisikan Menu dalam XML</h2>
+
+<p>Untuk semua tipe menu, Android menyediakan sebuah format XML standar untuk mendefinisikan item menu.
+Sebagai ganti membuat menu dalam kode aktivitas, Anda harus mendefinisikan menu dan semua itemnya dalam
+<a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a> XML. Anda kemudian bisa
+memekarkan sumber daya menu (memuatnya sebagai objek {@link android.view.Menu}) dalam aktivitas atau
+fragmen.</p>
+
+<p>Menggunakan sumber daya menu adalah praktik yang baik karena beberapa alasan:</p>
+<ul>
+  <li>Memvisualisasikan struktur menu dalam XML menjadi lebih mudah.</li>
+  <li>Cara ini memisahkan konten untuk menu dari kode perilaku aplikasi Anda.</li>
+  <li>Cara ini memungkinkan Anda membuat konfigurasi menu alternatif untuk berbagai versi platform,
+ukuran layar, dan konfigurasi lainnya dengan memanfaatkan kerangka kerja <a href="{@docRoot}guide/topics/resources/index.html">sumber daya aplikasi</a>.</li>
+</ul>
+
+<p>Untuk mendefinisikan menu, buatlah sebuah file XML dalam direktori <code>res/menu/</code>
+proyek dan buat menu dengan elemen-elemen berikut:</p>
+<dl>
+  <dt><code>&lt;menu></code></dt>
+    <dd>Mendefinisikan {@link android.view.Menu}, yang merupakan sebuah kontainer untuk item menu. Elemen
+<code>&lt;menu></code> harus menjadi simpul akar untuk file dan bisa menampung salah satu atau beberapa dari elemen
+<code>&lt;item></code> dan <code>&lt;group></code>.</dd>
+
+  <dt><code>&lt;item></code></dt>
+    <dd>Membuat {@link android.view.MenuItem}, yang mewakili satu item menu. Elemen ini
+bisa berisi elemen <code>&lt;menu></code> tersarang guna untuk membuat submenu.</dd>
+
+  <dt><code>&lt;group></code></dt>
+    <dd>Kontainer opsional tak terlihat untuk elemen-elemen {@code &lt;item&gt;}. Kontainer ini memungkinkan Anda
+mengelompokkan item menu untuk berbagi properti seperti status aktif dan visibilitas. Untuk informasi
+selengkapnya, lihat bagian tentang <a href="#groups">Membuat Grup Menu</a>.</dd>
+</dl>
+
+
+<p>Berikut ini adalah contoh menu bernama <code>game_menu.xml</code>:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/new_game"
+          android:icon="@drawable/ic_new_game"
+          android:title="@string/new_game"
+          android:showAsAction="ifRoom"/&gt;
+    &lt;item android:id="@+id/help"
+          android:icon="@drawable/ic_help"
+          android:title="@string/help" /&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>Elemen <code>&lt;item></code> mendukung beberapa atribut yang bisa Anda gunakan untuk mendefinisikan penampilan dan perilaku
+item. Item menu di atas mencakup atribut berikut:</p>
+
+<dl>
+  <dt>{@code android:id}</dt>
+    <dd>ID sumber daya unik bagi item, yang memungkinkan aplikasi mengenali item
+bila pengguna memilihnya.</dd>
+  <dt>{@code android:icon}</dt>
+    <dd>Acuan ke drawable untuk digunakan sebagai ikon item.</dd>
+  <dt>{@code android:title}</dt>
+    <dd>Acuan ke string untuk digunakan sebagai judul item.</dd>
+  <dt>{@code android:showAsAction}</dt>
+    <dd>Menetapkan waktu dan cara item ini muncul sebagai item tindakan di <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>.</dd>
+</dl>
+
+<p>Ini adalah atribut-atribut terpenting yang harus Anda gunakan, namun banyak lagi yang tersedia.
+Untuk informasi tentang semua atribut yang didukung, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
+
+<p>Anda bisa menambahkan submenu ke sebuah item di menu (kecuali submenu) apa saja dengan menambahkan elemen {@code &lt;menu&gt;}
+sebagai anak {@code &lt;item&gt;}. Submenu berguna saat aplikasi Anda memiliki banyak
+fungsi yang bisa ditata ke dalam topik-topik, seperti item dalam sebuah baris menu aplikasi PC (File,
+Edit, Lihat, dsb.). Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/file"
+          android:title="@string/file" &gt;
+        &lt;!-- "file" submenu --&gt;
+        &lt;menu&gt;
+            &lt;item android:id="@+id/create_new"
+                  android:title="@string/create_new" /&gt;
+            &lt;item android:id="@+id/open"
+                  android:title="@string/open" /&gt;
+        &lt;/menu&gt;
+    &lt;/item&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>Untuk menggunakan menu dalam aktivitas, Anda perlu memekarkan sumber daya menu (mengonversi sumber daya XML
+menjadi objek yang bisa diprogram) dengan menggunakan {@link android.view.MenuInflater#inflate(int,Menu)
+MenuInflater.inflate()}. Di bagian berikut, Anda akan melihat cara memekarkan menu untuk tiap
+tipe menu.</p>
+
+
+
+<h2 id="options-menu">Membuat Menu Opsi</h2>
+
+<div class="figure" style="width:200px;margin:0">
+  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
+  <p class="img-caption"><strong>Gambar 1.</strong> Menu opsi di
+Browser, pada Android 2.3.</p>
+</div>
+
+<p>Menu opsi adalah tempat Anda harus menyertakan tindakan dan opsi lain yang relevan dengan
+konteks aktivitas saat ini, seperti "Cari", "Tulis email", dan "Pengaturan".</p>
+
+<p>Tempat item dalam menu opsi muncul di layar bergantung pada versi aplikasi yang Anda
+kembangkan:</p>
+
+<ul>
+  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 2.3.x (API level 10) atau
+yang lebih rendah</strong>, konten menu opsi muncul pada bagian bawah layar bila pengguna
+menekan tombol <em>Menu</em>, seperti yang ditampilkan dalam gambar 1. Bila dibuka, bagian yang terlihat pertama adalah
+menu
+ikon, yang menampung hingga enam item menu. Jika menu Anda menyertakan lebih dari enam item, Android akan meletakkan
+item keenam dan sisanya ke dalam menu kelebihan, yang bisa dibuka pengguna dengan memilih
+<em>More</em>.</li>
+
+  <li>Jika Anda mengembangkan aplikasi untuk <strong>Android 3.0 (API level 11) dan
+yang lebih tinggi</strong>, item menu opsi tersedia dalam <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Secara default, sistem
+meletakkan semua item dalam kelebihan tindakan, yang bisa ditampilkan pengguna dengan ikon kelebihan tindakan di
+sisi kanan action-bar (atau dengan menekan tombol <em>Menu</em> perangkat, jika tersedia). Untuk
+mengaktifkan
+akses cepat ke tindakan penting, Anda bisa mempromosikan beberapa item agar muncul pada action-bar dengan menambahkan
+{@code android:showAsAction="ifRoom"} ke elemen-elemen {@code &lt;item&gt;} yang bersangkutan (lihat gambar
+2). <p>Untuk informasi selengkapnya tentang item tindakan dan perilaku action-bar lainnya, lihat panduan <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>. </p>
+<p class="note"><strong>Catatan:</strong> Sekalipun Anda <em>tidak</em> mengembangkan aplikasi untuk Android 3.0 atau
+yang lebih tinggi, Anda bisa membuat layout action-bar sendiri untuk mendapatkan efek serupa. Untuk contoh cara
+mendukung versi Android yang lebih lama dengan action-bar, lihat contoh <a href="{@docRoot}resources/samples/ActionBarCompat/index.html">Kompatibilitas Action-Bar</a>
+.</p>
+</li>
+</ul>
+
+<img src="{@docRoot}images/ui/actionbar.png" alt="" />
+<p class="img-caption"><strong>Gambar 2.</strong> Action-bar dari aplikasi <a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a>, yang menampilkan
+tab-tab navigasi dan item tindakan kamera (plus tombol kelebihan tindakan).</p>
+
+<p>Anda bisa mendeklarasikan item untuk menu opsi dari subkelas {@link android.app.Activity}
+atau subkelas {@link android.app.Fragment}. Jika aktivitas maupun fragmen Anda
+mendeklarasikan item menu opsi, keduanya akan dikombinasikan dalam UI. Item aktivitas akan muncul
+lebih dahulu, diikuti oleh item tiap fragmen sesuai dengan urutan penambahan fragmen ke
+aktivitas. Jika perlu, Anda bisa menyusun ulang item menu dengan atribut {@code android:orderInCategory}
+dalam setiap {@code &lt;item&gt;} yang perlu Anda pindahkan.</p>
+
+<p>Untuk menetapkan menu opsi suatu aktivitas, kesampingkan {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragmen-fragmen menyediakan
+callback {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} sendiri). Dalam metode ini
+, Anda bisa memekarkan sumber daya menu (<a href="#xml">yang didefinisikan dalam XML</a>) menjadi {@link
+android.view.Menu} yang disediakan dalam callback. Misalnya:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
+    inflater.inflate(R.menu.game_menu, menu);
+    return true;
+}
+</pre>
+
+<p>Anda juga bisa menambahkan item menu dengan menggunakan {@link android.view.Menu#add(int,int,int,int)
+add()} dan mengambil item dengan {@link android.view.Menu#findItem findItem()} untuk merevisi propertinya
+dengan API {@link android.view.MenuItem}.</p>
+
+<p>Jika Anda mengembangkan aplikasi untuk Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} untuk membuat menu opsi
+bila pengguna membuka menu untuk pertama kali. Jika Anda mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi,
+sistem akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} saat
+memulai aktivitas, untuk menampilkan item menu pada action-bar.</p>
+
+
+
+<h3 id="RespondingOptionsMenu">Menangani kejadian klik</h3>
+
+<p>Bila pengguna memilih item dari menu opsi (termasuk item tindakan dalam action-bar),
+sistem akan memanggil metode {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} aktivitas Anda. Metode ini meneruskan {@link android.view.MenuItem} yang dipilih. Anda
+bisa mengidentifikasi item dengan memanggil {@link android.view.MenuItem#getItemId()}, yang menghasilkan
+ID unik untuk item menu itu (yang didefinisikan oleh atribut {@code android:id} dalam sumber daya menu atau dengan
+integer yang diberikan ke metode {@link android.view.Menu#add(int,int,int,int) add()}). Anda bisa mencocokkan
+ID ini dengan item menu yang diketahui untuk melakukan tindakan yang sesuai. Misalnya:</p>
+
+<pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    // Handle item selection
+    switch (item.getItemId()) {
+        case R.id.new_game:
+            newGame();
+            return true;
+        case R.id.help:
+            showHelp();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
+
+<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu
+, Anda harus memanggil implementasi superkelas {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (implementasi default
+menghasilkan false).</p>
+
+<p>Jika aktivitas Anda menyertakan fragmen, sistem akan memanggil lebih dahulu {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} untuk aktivitas, kemudian
+untuk setiap fragmen (sesuai dengan urutan penambahan fragmen) hingga satu fragmen mengembalikan
+{@code true} atau semua fragmen telah dipanggil.</p>
+
+<p class="note"><strong>Tip:</strong> Android 3.0 menambahkan kemampuan mendefinisikan perilaku on-click
+untuk item menu dalam XML, dengan menggunakan atribut {@code android:onClick}. Nilai atribut
+harus berupa nama metode yang didefinisikan aktivitas dengan menggunakan menu. Metode
+harus bersifat publik dan menerima satu parameter {@link android.view.MenuItem}&mdash;bila sistem
+memanggilnya, metode ini akan meneruskan item menu yang dipilih. Untuk informasi selengkapnya dan contoh, lihat dokumen <a href="{@docRoot}guide/topics/resources/menu-resource.html">Sumber Daya Menu</a>.</p>
+
+<p class="note"><strong>Tip:</strong> Jika aplikasi Anda berisi banyak aktivitas dan
+sebagian menyediakan menu opsi yang sama, pertimbangkan untuk membuat
+aktivitas yang tidak mengimplementasikan apa-apa kecuali metode {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} dan {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()}. Kemudian perluas kelas ini untuk setiap aktivitas yang harus menggunakan
+menu opsi yang sama. Dengan begini, Anda bisa mengelola satu set kode untuk menangani tindakan menu
+dan setiap kelas turunan mewarisi perilaku menu.
+Jika ingin menambahkan item menu ke salah satu aktivitas turunan,
+kesampingkan {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} dalam aktivitas itu. Panggil {@code super.onCreateOptionsMenu(menu)} agar
+item menu asli dibuat, kemudian tambahkan item menu yang baru dengan {@link
+android.view.Menu#add(int,int,int,int) menu.add()}. Anda juga bisa mengesampingkan
+perilaku superkelas untuk setiap item menu.</p>
+
+
+<h3 id="ChangingTheMenu">Mengubah item menu saat runtime</h3>
+
+<p>Setelah sistem memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()}, sistem akan mempertahankan instance {@link android.view.Menu} yang Anda tempatkan dan
+tidak akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
+lagi kecuali menu diinvalidkan karena suatu alasan. Akan tetapi, Anda harus menggunakan {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} hanya untuk membuat
+status menu awal dan tidak untuk membuat perubahan selama daur hidup aktivitas.</p>
+
+<p>Jika Anda ingin mengubah menu opsi berdasarkan
+kejadian yang terjadi selama daur hidup aktivitas, Anda bisa melakukannya dalam metode
+{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}. Metode ini
+meneruskan objek {@link android.view.Menu} sebagaimana adanya saat ini sehingga Anda bisa mengubahnya,
+seperti menambah, menghapus, atau menonaktifkan item. (Fragmen juga menyediakan callback {@link
+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()}.)</p>
+
+<p>Pada Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link
+android.app.Activity#onPrepareOptionsMenu(Menu)
+onPrepareOptionsMenu()} setiap kali pengguna membuka menu opsi (menekan tombol <em>Menu</em>
+).</p>
+
+<p>Pada Android 3.0 dan yang lebih tinggi, menu opsi dianggap sebagai selalu terbuka saat item menu
+ditampilkan pada action-bar. Bila ada kejadian dan Anda ingin melakukan pembaruan menu, Anda harus
+memanggil {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} untuk meminta
+sistem memanggil {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
+
+<p class="note"><strong>Catatan:</strong>
+Anda tidak boleh mengubah item dalam menu opsi berdasarkan {@link android.view.View} yang saat ini
+difokus. Saat dalam mode sentuh (bila pengguna tidak sedang menggunakan trackball atau d-pad), tampilan
+tidak bisa mengambil fokus, sehingga Anda tidak boleh menggunakan fokus sebagai dasar untuk mengubah
+item dalam menu opsi. Jika Anda ingin menyediakan item menu yang peka konteks pada {@link
+android.view.View}, gunakan <a href="#context-menu">Menu Konteks</a>.</p>
+
+
+
+
+<h2 id="context-menu">Membuat Menu Kontekstual</h2>
+
+<div class="figure" style="width:420px;margin-top:-1em">
+  <img src="{@docRoot}images/ui/menu-context.png" alt="" />
+  <p class="img-caption"><strong>Gambar 3.</strong> Cuplikan layar menu konteks mengambang (kiri)
+dan action-bar kontekstual (kanan).</p>
+</div>
+
+<p>Menu kontekstual menawarkan tindakan yang memengaruhi item atau bingkai konteks tertentu dalam UI. Anda
+bisa menyediakan menu konteks untuk setiap tampilan, tetapi menu ini paling sering digunakan untuk item pada {@link
+android.widget.ListView}, {@link android.widget.GridView}, atau kumpulan tampilan lainnya yang bisa digunakan
+pengguna untuk melakukan tindakan langsung pada setiap item.</p>
+
+<p>Ada dua cara menyediakan tindakan kontekstual:</p>
+<ul>
+  <li>Dalam <a href="#FloatingContextMenu">menu konteks mengambang</a>. Menu muncul sebagai
+daftar item menu mengambang (serupa dengan dialog) bila pengguna mengklik lama (menekan dan
+menahan) pada tampilan yang mendeklarasikan dukungan bagi menu konteks. Pengguna bisa melakukan
+tindakan kontekstual pada satu item untuk setiap kalinya.</li>
+
+  <li>Dalam <a href="#CAB">mode tindakan kontekstual</a>. Mode ini adalah implementasi sistem
+{@link android.view.ActionMode} yang menampilkan <em>action-bar kontekstual</em> di bagian atas
+layar dengan item tindakan yang memengaruhi item(-item) yang dipilih. Bila mode ini aktif, pengguna
+bisa melakukan tindakan pada beberapa item sekaligus (jika aplikasi Anda mengizinkannya).</li>
+</ul>
+
+<p class="note"><strong>Catatan:</strong> Mode tindakan kontekstual tersedia pada Android 3.0 (API
+level 11) dan yang lebih tinggi dan merupakan teknik yang lebih disukai untuk menampilkan tindakan kontekstual bila
+tersedia. Jika aplikasi Anda mendukung versi yang lebih rendah daripada 3.0, maka Anda harus mundur ke
+menu konteks mengambang pada perangkat-perangkat itu.</p>
+
+
+<h3 id="FloatingContextMenu">Membuat menu konteks mengambang</h3>
+
+<p>Untuk menyediakan menu konteks mengambang:</p>
+<ol>
+  <li>Daftarkan {@link android.view.View} ke menu konteks yang harus dikaitkan dengan
+memanggil {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} dan teruskan
+{@link android.view.View} ke menu itu.
+  <p>Jika aktivitas Anda menggunakan {@link android.widget.ListView} atau {@link android.widget.GridView} dan
+Anda ingin setiap item untuk menyediakan menu konteks yang sama, daftarkan semua item ke menu konteks dengan
+meneruskan {@link android.widget.ListView} atau {@link android.widget.GridView} ke {@link
+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
+</li>
+
+  <li>Implementasikan metode {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+dalam {@link android.app.Activity} atau {@link android.app.Fragment} Anda.
+  <p>Bila tampilan yang terdaftar menerima kejadian klik-lama, sistem akan memanggil metode {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+Anda. Inilah tempat Anda mendefinisikan item menu, biasanya dengan memekarkan sumber daya menu. Misalnya:
+</p>
+<pre>
+&#64;Override
+public void onCreateContextMenu(ContextMenu menu, View v,
+                                ContextMenuInfo menuInfo) {
+    super.onCreateContextMenu(menu, v, menuInfo);
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.context_menu, menu);
+}
+</pre>
+
+<p>{@link android.view.MenuInflater} memungkinkan Anda untuk memekarkan menu konteks <a href="{@docRoot}guide/topics/resources/menu-resource.html">sumber daya menu</a>. Parameter metode callback
+menyertakan {@link android.view.View}
+yang dipilih pengguna dan objek {@link android.view.ContextMenu.ContextMenuInfo} yang menyediakan
+informasi tambahan tentang item yang dipilih. Jika aktivitas Anda memiliki beberapa tampilan yang masing-masingnya menyediakan
+menu konteks berbeda, Anda bisa menggunakan parameter ini untuk menentukan menu konteks yang harus
+dimekarkan.</p>
+</li>
+
+<li>Implementasikan {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}.
+  <p>Bila pengguna memilih item menu, sistem akan memanggil metode ini sehingga Anda bisa melakukan
+tindakan yang sesuai. Misalnya:</p>
+
+<pre>
+&#64;Override
+public boolean onContextItemSelected(MenuItem item) {
+    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+    switch (item.getItemId()) {
+        case R.id.edit:
+            editNote(info.id);
+            return true;
+        case R.id.delete:
+            deleteNote(info.id);
+            return true;
+        default:
+            return super.onContextItemSelected(item);
+    }
+}
+</pre>
+
+<p>Metode {@link android.view.MenuItem#getItemId()} melakukan query ID untuk
+item menu yang dipilih, yang harus Anda tetapkan ke setiap item menu dalam XML dengan menggunakan atribut {@code
+android:id}, seperti yang ditampilkan di bagian tentang <a href="#xml">Mendefinisikan Menu dalam
+XML</a>.</p>
+
+<p>Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu,
+Anda harus meneruskan item menu ke implementasi superkelas. Jika aktivitas Anda menyertakan fragmen,
+aktivitas akan menerima callback ini lebih dahulu. Dengan memanggil superkelas bila tidak ditangani, sistem
+meneruskan kejadian ke metode callback di setiap fragmen, satu per satu (sesuai dengan urutan
+penambahan fragmen) hingga {@code true} atau {@code false} dikembalikan. (Implementasi default
+untuk {@link android.app.Activity} dan {@code android.app.Fragment} mengembalikan {@code
+false}, sehingga Anda harus selalu memanggil superkelas bila tidak ditangani.)</p>
+</li>
+</ol>
+
+
+<h3 id="CAB">Menggunakan mode tindakan kontekstual</h3>
+
+<p>Mode tindakan kontekstual adalah implementasi sistem {@link android.view.ActionMode} yang
+memfokuskan interaksi pengguna pada upaya melakukan tindakan kontekstual. Bila seorang
+pengguna mengaktifkan mode ini dengan memilih item, <em>action-bar kontekstual</em> akan muncul di bagian atas
+layar untuk menampilkan tindakan yang bisa dilakukan pengguna pada item yang dipilih saat ini. Selagi mode ini
+diaktifkan, pengguna bisa memilih beberapa item (jika Anda mengizinkan), membatalkan pilihan item, dan melanjutkan
+penelusuran dalam aktivitas (sebanyak yang ingin Anda izinkan). Mode tindakan dinonaktifkan
+dan action-bar kontekstual menghilang bila pengguna membatalkan pilihan semua item, menekan tombol BACK,
+atau memilih tindakan <em>Done</em> di sisi kiri action-bar.</p>
+
+<p class="note"><strong>Catatan:</strong> Action-bar kontekstual tidak harus
+terkait dengan <a href="{@docRoot}guide/topics/ui/actionbar.html">action-bar</a>. Action-bar ini beroperasi
+secara independen, walaupun action-bar kontekstual secara visual mengambil alih
+posisi action-bar.</p>
+
+<p>Jika Anda mengembangkan aplikasi untuk Android 3.0 (API level 11) atau yang lebih tinggi, Anda
+biasanya harus menggunakan mode tindakan kontekstual untuk menampilkan tindakan kontekstual, sebagai ganti <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p>
+
+<p>Untuk tampilan yang menyediakan tindakan kontekstual, Anda biasanya harus memanggil mode tindakan kontekstual
+pada salah satu dari dua kejadian (atau keduanya):</p>
+<ul>
+  <li>Pengguna mengklik-lama pada tampilan.</li>
+  <li>Pengguna memilih kotak cek atau komponen UI yang serupa dalam tampilan.</li>
+</ul>
+
+<p>Cara aplikasi memanggil mode tindakan kontekstual dan mendefinisikan perilaku setiap
+tindakan bergantung pada desain Anda. Pada dasarnya ada dua desain:</p>
+<ul>
+  <li>Untuk tindakan kontekstual pada tampilan individual dan tak didukung.</li>
+  <li>Untuk tindakan kontekstual batch pada grup item dalam {@link
+android.widget.ListView} atau {@link android.widget.GridView} (memungkinkan pengguna memilih beberapa
+item dan melakukan tindakan pada semua item itu).</li>
+</ul>
+
+<p>Bagian berikut ini menjelaskan penyiapan yang diperlukan untuk setiap skenario.</p>
+
+
+<h4 id="CABforViews">Mengaktifkan mode tindakan kontekstual untuk tampilan individual</h4>
+
+<p>Jika Anda ingin memanggil mode tindakan kontekstual hanya bila pengguna memilih
+tampilan tertentu, Anda harus:</p>
+<ol>
+  <li>Mengimplementasikan antarmuka {@link android.view.ActionMode.Callback}. Dalam metode callback-nya, Anda
+bisa menetapkan tindakan untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan
+menangani kejadian daur hidup lainnya untuk mode tindakan itu.</li>
+  <li>Memanggil {@link android.app.Activity#startActionMode startActionMode()} bila Anda ingin menampilkan
+action-bar (seperti saat pengguna mengklik-lama pada tampilan).</li>
+</ol>
+
+<p>Misalnya:</p>
+
+<ol>
+  <li>Implementasikan antarmuka {@link android.view.ActionMode.Callback ActionMode.Callback}:
+<pre>
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
+
+    // Called when the action mode is created; startActionMode() was called
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate a menu resource providing context menu items
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context_menu, menu);
+        return true;
+    }
+
+    // Called each time the action mode is shown. Always called after onCreateActionMode, but
+    // may be called multiple times if the mode is invalidated.
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        return false; // Return false if nothing is done
+    }
+
+    // Called when the user selects a contextual menu item
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_share:
+                shareCurrentItem();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    // Called when the user exits the action mode
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        mActionMode = null;
+    }
+};
+</pre>
+
+<p>Perhatikan bahwa kejadian callback ini hampir persis sama dengan callback untuk <a href="#options-menu">menu opsi</a>, hanya saja setiap callback ini juga meneruskan objek {@link
+android.view.ActionMode} yang terkait dengan kejadian. Anda bisa menggunakan API {@link
+android.view.ActionMode} untuk membuat berbagai perubahan pada CAB, seperti merevisi judul dan
+subjudul dengan {@link android.view.ActionMode#setTitle setTitle()} dan {@link
+android.view.ActionMode#setSubtitle setSubtitle()} (berguna untuk menunjukkan jumlah item
+yang dipilih).</p>
+
+<p>Juga perhatikan bahwa contoh di atas mengatur variabel {@code mActionMode} ke nol bila
+mode tindakan dimusnahkan. Dalam langkah berikutnya, Anda akan melihat cara variabel diinisialisasi dan kegunaan menyimpan
+variabel anggota dalam aktivitas atau fragmen.</p>
+</li>
+
+  <li>Panggil {@link android.app.Activity#startActionMode startActionMode()} untuk mengaktifkan
+mode tindakan kontekstual bila sesuai, seperti saat merespons klik-lama pada {@link
+android.view.View}:</p>
+
+<pre>
+someView.setOnLongClickListener(new View.OnLongClickListener() {
+    // Called when the user long-clicks on someView
+    public boolean onLongClick(View view) {
+        if (mActionMode != null) {
+            return false;
+        }
+
+        // Start the CAB using the ActionMode.Callback defined above
+        mActionMode = getActivity().startActionMode(mActionModeCallback);
+        view.setSelected(true);
+        return true;
+    }
+});
+</pre>
+
+<p>Bila Anda memanggil {@link android.app.Activity#startActionMode startActionMode()}, sistem akan mengembalikan
+{@link android.view.ActionMode} yang dibuat. Dengan menyimpannya dalam variabel anggota, Anda bisa
+membuat perubahan ke action-bar kontekstual sebagai respons terhadap kejadian lainnya. Dalam contoh di atas,
+{@link android.view.ActionMode} digunakan untuk memastikan bahwa instance {@link android.view.ActionMode}
+tidak dibuat kembali jika sudah aktif, dengan memeriksa apakah anggota bernilai nol sebelum memulai
+mode tindakan.</p>
+</li>
+</ol>
+
+
+
+<h4 id="CABforListView">Mengaktifkan tindakan kontekstual batch dalam ListView atau GridView</h4>
+
+<p>Jika Anda memiliki sekumpulan item dalam {@link android.widget.ListView} atau {@link
+android.widget.GridView} (atau ekstensi {@link android.widget.AbsListView} lainnya) dan ingin
+mengizinkan pengguna melakukan tindakan batch, Anda harus:</p>
+
+<ul>
+  <li>Mengimplementasikan antarmuka {@link android.widget.AbsListView.MultiChoiceModeListener} dan mengaturnya
+untuk grup tampilan dengan {@link android.widget.AbsListView#setMultiChoiceModeListener
+setMultiChoiceModeListener()}. Dalam metode callback listener, Anda bisa menetapkan tindakan
+untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan menangani callback lainnya
+yang diwarisi dari antarmuka {@link android.view.ActionMode.Callback}.</li>
+
+  <li>Panggil {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} dengan argumen {@link
+android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}.</li>
+</ul>
+
+<p>Misalnya:</p>
+
+<pre>
+ListView listView = getListView();
+listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
+
+    &#64;Override
+    public void onItemCheckedStateChanged(ActionMode mode, int position,
+                                          long id, boolean checked) {
+        // Here you can do something when items are selected/de-selected,
+        // such as update the title in the CAB
+    }
+
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        // Respond to clicks on the actions in the CAB
+        switch (item.getItemId()) {
+            case R.id.menu_delete:
+                deleteSelectedItems();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate the menu for the CAB
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context, menu);
+        return true;
+    }
+
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        // Here you can make any necessary updates to the activity when
+        // the CAB is removed. By default, selected items are deselected/unchecked.
+    }
+
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        // Here you can perform updates to the CAB due to
+        // an {@link android.view.ActionMode#invalidate} request
+        return false;
+    }
+});
+</pre>
+
+<p>Demikian saja. Kini bila pengguna memilih item dengan klik-lama, sistem akan memanggil metode {@link
+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
+dan menampilkan action-bar kontekstual bersama tindakan yang ditetapkan. Saat
+action-bar kontekstual terlihat, pengguna bisa memilih item tambahan.</p>
+
+<p>Dalam beberapa kasus di mana tindakan kontekstual menyediakan item tindakan umum, Anda mungkin
+ingin menambahkan kotak cek atau elemen UI serupa yang memungkinkan pengguna memilih item, karena pengguna
+mungkin tidak menemukan perilaku klik-lama. Bila pengguna memilih kotak cek itu, Anda
+bisa memanggil mode tindakan kontekstual dengan mengatur item daftar yang bersangkutan ke
+status diberi tanda cek dengan {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
+
+
+
+
+<h2 id="PopupMenu">Membuat Menu Popup</h2>
+
+<div class="figure" style="width:220px">
+<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
+<p><strong>Gambar 4.</strong> Menu popup dalam aplikasi Gmail, dikaitkan pada
+tombol kelebihan di sudut kanan atas.</p>
+</div>
+
+<p>{@link android.widget.PopupMenu} adalah menu modal yang dikaitkan pada {@link android.view.View}.
+Menu ini muncul di bawah tampilan jangkar jika ada ruang, atau di atas tampilan jika tidak ada. Menu ini berguna untuk:</p>
+<ul>
+  <li>Menyediakan menu bergaya kelebihan (overflow) untuk tindakan yang <em>berkaitan dengan</em> konten tertentu (seperti
+header email Gmail, yang ditampilkan dalam gambar 4).
+    <p class="note"><strong>Catatan:</strong> Ini tidak sama dengan menu konteks, yang umumnya
+untuk tindakan yang <em>memengaruhi</em> konten yang dipilih. Untuk tindakan yang memengaruhi
+konten yang dipilih, gunakan <a href="#CAB">mode tindakan kontekstual</a> atau <a href="#FloatingContextMenu">menu konteks mengambang</a>.</p></li>
+  <li>Menyediakan bagian kedua dari kalimat perintah (seperti tombol bertanda "Tambah"
+yang menghasilkan menu popup dengan berbagai opsi "Tambah").</li>
+  <li>Menyediakan daftar menurun yang serupa dengan {@link android.widget.Spinner} yang tidak mempertahankan
+pilihan persisten.</li>
+</ul>
+
+
+<p class="note"><strong>Catatan:</strong> {@link android.widget.PopupMenu} tersedia dengan API
+level 11 dan yang lebih tinggi.</p>
+
+<p>Jika Anda <a href="#xml">mendefinisikan menu dalam XML</a>, berikut ini adalah cara Anda menampilkan menu popup:</p>
+<ol>
+  <li>Buat instance {@link android.widget.PopupMenu} bersama konstruktornya, yang mengambil
+aplikasi saat ini {@link android.content.Context} dan {@link android.view.View} yang akan menjadi tempat mengaitkan
+menu.</li>
+  <li>Gunakan {@link android.view.MenuInflater} untuk memekarkan sumber daya menu Anda ke dalam objek {@link
+android.view.Menu} yang dikembalikan oleh {@link
+android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. Pada API level 14 ke atas, Anda bisa menggunakan
+{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} sebagai gantinya.</li>
+  <li>Panggil {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
+</ol>
+
+<p>Misalnya, berikut ini adalah tombol dengan atribut {@link android.R.attr#onClick android:onClick}
+yang menampilkan menu popup:</p>
+
+<pre>
+&lt;ImageButton
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:src="@drawable/ic_overflow_holo_dark"
+    android:contentDescription="@string/descr_overflow_button"
+    android:onClick="showPopup" />
+</pre>
+
+<p>Aktivitas nanti bisa menampilkan menu popup seperti ini:</p>
+
+<pre>
+public void showPopup(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+    MenuInflater inflater = popup.getMenuInflater();
+    inflater.inflate(R.menu.actions, popup.getMenu());
+    popup.show();
+}
+</pre>
+
+<p>Dalam API level 14 dan yang lebih tinggi, Anda bisa menggabungkan dua baris yang memekarkan menu dengan {@link
+android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
+
+<p>Menu akan menghilang bila pengguna memilih item atau menyentuh di luar
+area menu. Anda bisa mendengarkan kejadian menghilangkan dengan menggunakan {@link
+android.widget.PopupMenu.OnDismissListener}.</p>
+
+<h3 id="PopupEvents">Menangani kejadian klik</h3>
+
+<p>Untuk melakukan suatu
+tindakan bila pengguna memilih item menu, Anda harus mengimplementasikan antarmuka {@link
+android.widget.PopupMenu.OnMenuItemClickListener} dan mendaftarkannya pada {@link
+android.widget.PopupMenu} dengan memanggil {@link android.widget.PopupMenu#setOnMenuItemClickListener
+setOnMenuItemclickListener()}. Bila pengguna memilih item, sistem akan memanggil callback {@link
+android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} dalam
+antarmuka Anda.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+public void showMenu(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+
+    // This activity implements OnMenuItemClickListener
+    popup.setOnMenuItemClickListener(this);
+    popup.inflate(R.menu.actions);
+    popup.show();
+}
+
+&#64;Override
+public boolean onMenuItemClick(MenuItem item) {
+    switch (item.getItemId()) {
+        case R.id.archive:
+            archive(item);
+            return true;
+        case R.id.delete:
+            delete(item);
+            return true;
+        default:
+            return false;
+    }
+}
+</pre>
+
+
+<h2 id="groups">Membuat Grup Menu</h2>
+
+<p>Grup menu adalah sekumpulan item menu yang sama-sama memiliki ciri (trait) tertentu. Dengan grup, Anda
+bisa:</p>
+<ul>
+  <li>Menampilkan atau menyembunyikan semua item dengan {@link android.view.Menu#setGroupVisible(int,boolean)
+setGroupVisible()}</li>
+  <li>Mengaktifkan atau mennonaktifkan semua item dengan {@link android.view.Menu#setGroupEnabled(int,boolean)
+setGroupEnabled()}</li>
+  <li>Menetapkan apakah semua item bisa diberi tanda cek dengan {@link
+android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()}</li>
+</ul>
+
+<p>Anda bisa membuat grup dengan menyarangkan elemen-elemen {@code &lt;item&gt;} dalam elemen {@code &lt;group&gt;}
+dalam sumber daya menu atau dengan menetapkan ID grup dengan metode {@link
+android.view.Menu#add(int,int,int,int) add()}.</p>
+
+<p>Berikut ini adalah contoh sumber daya menu yang berisi sebuah grup:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;item android:id="@+id/menu_save"
+          android:icon="@drawable/menu_save"
+          android:title="@string/menu_save" /&gt;
+    &lt;!-- menu group --&gt;
+    &lt;group android:id="@+id/group_delete"&gt;
+        &lt;item android:id="@+id/menu_archive"
+              android:title="@string/menu_archive" /&gt;
+        &lt;item android:id="@+id/menu_delete"
+              android:title="@string/menu_delete" /&gt;
+    &lt;/group&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>Item yang berada dalam grup akan muncul pada level yang sama dengan item pertama&mdash;ketiga item
+dalam menu adalah bersaudara. Akan tetapi, Anda bisa memodifikasi ciri kedua
+item dalam grup dengan mengacu ID grup dan menggunakan metode yang tercantum di atas. Sistem
+juga tidak akan memisahkan item yang telah dikelompokkan. Misalnya, jika Anda mendeklarasikan {@code
+android:showAsAction="ifRoom"} untuk tiap item, item tersebut akan muncul dalam
+action-bar atau dalam kelebihan tindakan.</p>
+
+
+<h3 id="checkable">Menggunakan item menu yang bisa diberi tanda cek</h3>
+
+<div class="figure" style="width:200px">
+  <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
+  <p class="img-caption"><strong>Gambar 5.</strong> Cuplikan layar submenu dengan
+item yang bisa diberi tanda cek.</p>
+</div>
+
+<p>Menu bisa digunakan sebagai antarmuka untuk mengaktifkan dan menonaktifkan opsi, menggunakan kotak cek untuk
+opsi mandiri, atau tombol radio untuk grup
+opsi yang saling eksklusif. Gambar 5 menampilkan submenu dengan item yang bisa diberi tanda cek dengan
+tombol radio.</p>
+
+<p class="note"><strong>Catatan:</strong> Item menu dalam Icon Menu (dari menu opsi) tidak bisa
+menampilkan kotak cek atau tombol radio. Jika Anda memilih untuk membuat item dalam Icon Menu yang bisa diberi tanda cek,
+Anda harus menandai status diberi tanda cek secara manual dengan menukar ikon dan/atau teks
+tiap kali statusnya berubah.</p>
+
+<p>Anda bisa mendefinisikan perilaku yang bisa diberi tanda cek untuk tiap item menu dengan menggunakan atribut {@code
+android:checkable} dalam elemen {@code &lt;item&gt;}, atau untuk seluruh grup dengan
+atribut {@code android:checkableBehavior} dalam elemen {@code &lt;group&gt;}. Misalnya
+, semua item dalam grup menu ini bisa diberi tanda cek dengan tombol radio:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+    &lt;group android:checkableBehavior="single"&gt;
+        &lt;item android:id="@+id/red"
+              android:title="@string/red" /&gt;
+        &lt;item android:id="@+id/blue"
+              android:title="@string/blue" /&gt;
+    &lt;/group&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>Atribut {@code android:checkableBehavior} menerima:
+<dl>
+  <dt>{@code single}</dt>
+    <dd>Hanya satu item dari grup ini yang bisa diberi tanda cek (tombol radio)</dd>
+  <dt>{@code all}</dt>
+    <dd>Semua item bisa diberi tanda cek (kotak cek)</dd>
+  <dt>{@code none}</dt>
+    <dd>Tidak ada item yang bisa diberi tanda cek</dd>
+</dl>
+
+<p>Anda bisa menerapkan status diberi tanda cek default pada suatu item dengan menggunakan atribut {@code android:checked} dalam
+elemen {@code &lt;item&gt;} dan mengubahnya dalam kode dengan metode {@link
+android.view.MenuItem#setChecked(boolean) setChecked()}.</p>
+
+<p>Bila item yang bisa diberi tanda cek dipilih, sistem akan memanggil metode callback setiap item yang dipilih
+(seperti {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). Di sinilah
+Anda harus mengatur status kotak cek itu, karena kotak cek atau tombol radio tidak
+mengubah statusnya secara otomatis. Anda bisa melakukan query status saat ini suatu item (seperti sebelum
+pengguna memilihnya) dengan {@link android.view.MenuItem#isChecked()} kemudian mengatur status diberi tanda cek dengan
+{@link android.view.MenuItem#setChecked(boolean) setChecked()}. Misalnya:</p>
+
+<pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    switch (item.getItemId()) {
+        case R.id.vibrate:
+        case R.id.dont_vibrate:
+            if (item.isChecked()) item.setChecked(false);
+            else item.setChecked(true);
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
+
+<p>Jika Anda tidak mengatur status diberi tanda cek dengan cara ini, maka status item (kotak cek atau
+tombol radio) yang terlihat tidak akan
+berubah bila pengguna memilihnya. Bila Anda telah mengatur status, aktivitas akan menjaga status diberi tanda cek
+suatu item sehingga bila nanti pengguna membuka menu, status diberi tanda cek yang Anda
+atur akan terlihat.</p>
+
+<p class="note"><strong>Catatan:</strong>
+Item menu yang bisa diberi tanda cek dimaksudkan untuk digunakan hanya atas dasar per sesi dan tidak disimpan setelah
+aplikasi dimusnahkan. Jika Anda memiliki pengaturan aplikasi yang ingin disimpan untuk pengguna,
+Anda harus menyimpan data dengan menggunakan <a href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
+
+
+
+<h2 id="intents">Menambahkan Item Menu Berdasarkan Intent</h2>
+
+<p>Kadang-kadang Anda ingin supaya item menu menjalankan aktivitas dengan menggunakan {@link android.content.Intent}
+(baik aktivitas berada dalam aplikasi Anda maupun di aplikasi lain). Bila Anda mengetahui intent
+yang ingin digunakan dan memiliki item menu tertentu yang harus memulai intent, Anda bisa mengeksekusi
+intent dengan {@link android.app.Activity#startActivity(Intent) startActivity()} selama
+metode callback bila-item-dipilih yang sesuai (seperti callback {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}).</p>
+
+<p>Akan tetapi, jika Anda tidak yakin apakah perangkat pengguna
+berisi aplikasi yang menangani intent, maka menambahkan item menu yang memanggilnya bisa mengakibatkan
+item menu tidak berfungsi, karena intent tidak bisa diterjemahkan menjadi
+aktivitas. Untuk mengatasi hal ini, Android memungkinkan Anda menambahkan item menu secara dinamis ke menu
+bila Android menemukan aktivitas pada perangkat yang menangani intent Anda.</p>
+
+<p>Untuk menambahkan item menu berdasarkan aktivitas tersedia yang menerima intent:</p>
+<ol>
+  <li>Definisikan
+intent dengan kategori {@link android.content.Intent#CATEGORY_ALTERNATIVE} dan/atau
+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE}, plus kebutuhan lainnya.</li>
+  <li>Panggil {@link
+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+Menu.addIntentOptions()}. Android kemudian akan mencari setiap aplikasi yang bisa melakukan intent
+dan menambahkannya ke menu Anda.</li>
+</ol>
+
+<p>Jika tidak ada aplikasi terinstal
+yang memenuhi intent, maka tidak ada item menu yang ditambahkan.</p>
+
+<p class="note"><strong>Catatan:</strong>
+{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} digunakan untuk menangani
+elemen yang saat ini dipilih pada layar. Jadi, metode hanya digunakan saat membuat Menu dalam {@link
+android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
+onCreateContextMenu()}.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu){
+    super.onCreateOptionsMenu(menu);
+
+    // Create an Intent that describes the requirements to fulfill, to be included
+    // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
+    Intent intent = new Intent(null, dataUri);
+    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
+
+    // Search and populate the menu with acceptable offering applications.
+    menu.addIntentOptions(
+         R.id.intent_group,  // Menu group to which new items will be added
+         0,      // Unique item ID (none)
+         0,      // Order for the items (none)
+         this.getComponentName(),   // The current activity name
+         null,   // Specific items to place first (none)
+         intent, // Intent created above that describes our requirements
+         0,      // Additional flags to control items (none)
+         null);  // Array of MenuItems that correlate to specific items (none)
+
+    return true;
+}</pre>
+
+<p>Untuk setiap aktivitas yang diketahui menyediakan filter intent yang cocok dengan intent yang didefinisikan, item menu
+akan ditambahkan, menggunakan nilai dalam filter intent <code>android:label</code> sebagai
+judul item menu dan ikon aplikasi sebagai ikon item menu. Metode
+{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()} mengembalikan jumlah item menu yang ditambahkan.</p>
+
+<p class="note"><strong>Catatan:</strong> Bila Anda memanggil {@link
+android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()}, metode ini akan mengesampingkan setiap dan semua item menu menurut grup menu yang ditetapkan dalam argumen
+pertama.</p>
+
+
+<h3 id="AllowingToAdd">Memungkinkan aktivitas Anda ditambahkan ke menu lain</h3>
+
+<p>Anda juga bisa menawarkan layanan aktivitas Anda pada aplikasi lainnya, sehingga
+aplikasi Anda bisa disertakan dalam menu aplikasi lain (membalik peran yang dijelaskan di atas).</p>
+
+<p>Agar bisa dimasukkan dalam menu aplikasi lain, Anda perlu mendefinisikan
+filter intent seperti biasa, tetapi pastikan menyertakan nilai-nilai {@link android.content.Intent#CATEGORY_ALTERNATIVE}
+dan/atau {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} untuk
+kategori filter intent. Misalnya:</p>
+<pre>
+&lt;intent-filter label="&#64;string/resize_image">
+    ...
+    &lt;category android:name="android.intent.category.ALTERNATIVE" />
+    &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
+    ...
+&lt;/intent-filter>
+</pre>
+
+<p>Baca selengkapnya tentang penulisan filter intent dalam dokumen
+<a href="/guide/components/intents-filters.html">Intent dan Filter Intent</a>.</p>
+
+<p>Untuk contoh aplikasi yang menggunakan teknik ini, lihat contoh kode
+<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">Note
+Pad</a>.</p>
diff --git a/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
new file mode 100644
index 0000000..5e7b3d9
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/multi-window.jd
@@ -0,0 +1,589 @@
+page.title=Dukungan Multi-Jendela
+page.metaDescription=Dukungan baru di Android N untuk menampilkan lebih dari satu aplikasi sekaligus.
+page.keywords="multi-window", "android N", "split screen", "free-form"
+
+@jd:body
+
+<div id="tb-wrapper">
+  <div id="tb">
+    <h2>Dalam dokumen ini</h2>
+      <ol>
+        <li><a href="#overview">Ringkasan</a></li>
+        <li><a href="#lifecycle">Daur Hidup Multi-Jendela</a></li>
+        <li><a href="#configuring">Mengonfigurasi Aplikasi Anda untuk Mode
+              Multi-Jendela</a></li>
+        <li><a href="#running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</a></li>
+        <li><a href="#testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</a></li>
+      </ol>
+    <h2>Lihat Juga</h2>
+      <ol>
+        <li><a class="external-link" href="https://github.com/googlesamples/android-MultiWindowPlayground">Aplikasi contoh Playground
+          Multi-Jendela</a></li>
+        <li><a class="external-link" href="https://medium.com/google-developers/5-tips-for-preparing-for-multi-window-in-android-n-7bed803dda64">Lima Tip untuk Mempersiapkan Multi-Jendela di Android N</a></li>
+      </ol>
+  </div>
+</div>
+
+<p>
+  Android N menambahkan dukungan untuk menampilkan lebih dari satu aplikasi
+  sekaligus. Pada perangkat genggam, dua aplikasi bisa berjalan berdampingan atau
+  atas-bawah dalam mode <em>layar terbagi</em>. Pada perangkat TV, aplikasi bisa
+  menggunakan mode <em>gambar-dalam-gambar</em> untuk melanjutkan pemutaran video selagi pengguna
+  berinteraksi dengan aplikasi lain.
+</p>
+
+<p>
+  Jika Anda membangun aplikasi Anda dengan N Preview SDK, Anda bisa mengonfigurasi cara aplikasi
+  menangani tampilan multi-jendela. Misalnya, Anda bisa menetapkan dimensi
+  minimum yang diizinkan aktivitas Anda. Anda juga bisa menonaktifkan tampilan multi-jendela untuk
+   aplikasi, sehingga memastikan sistem hanya menampilkan aplikasi Anda dalam mode
+  layar penuh.
+</p>
+
+<h2 id="overview">Ringkasan</h2>
+
+<p>
+  Android N memungkinkan beberapa aplikasi berbagi layar sekaligus. Misalnya,
+  pengguna bisa membagi layar, melihat halaman web di sisi kiri
+  sambil menulis email di sisi kanan. Pengalaman pengguna bergantung pada
+  perangkat:
+</p>
+
+<ul>
+  <li>Perangkat genggam yang menjalankan Android N menawarkan mode
+  layar terbagi. Di mode ini, sistem mengisi layar dengan dua aplikasi, menampilkannya secara
+  berdampingan atau atas-bawah. Pengguna bisa menyeret garis pembagi
+   yang memisahkan keduanya untuk membuat satu aplikasi lebih besar dan yang lainnya lebih kecil.
+  </li>
+
+  <li>Pada Nexus Player yang menjalankan Android N, aplikasi bisa menempatkan diri
+  dalam <a href="picture-in-picture.html">mode gambar-dalam-gambar</a>, yang memungkinkannya
+  untuk terus menampilkan materi selagi pengguna menjelajahi atau berinteraksi dengan
+   aplikasi lain.
+  </li>
+
+  <li>Produsen perangkat berukuran lebih besar bisa memilih untuk mengaktifkan mode
+ bentuk bebas, di mana pengguna bisa bebas mengubah ukuran setiap aktivitas. Jika
+  produsen mengaktifkan fitur ini, perangkat akan menawarkan mode bentuk bebas sebagai tambahan
+  untuk mode layar terbagi.
+  </li>
+</ul>
+
+<img src="{@docRoot}images/android-7.0/mw-splitscreen.png" alt="" width="650" srcset="{@docRoot}images/android-7.0/mw-splitscreen.png 1x,
+    {@docRoot}images/android-7.0/mw-splitscreen_2x.png 2x," id="img-split-screen" />
+<p class="img-caption">
+  <strong>Gambar 1.</strong> Dua aplikasi berjalan berdampingan dalam mode layar terbagi.
+</p>
+
+<p>
+  Pengguna bisa beralih ke mode multi-jendela dengan cara berikut:
+</p>
+
+<ul>
+  <li>Jika pengguna membuka <a href="{@docRoot}guide/components/recents.html">layar
+  Ringkasan</a> dan menekan lama pada
+  judul aktivitas, mereka bisa menyeret aktivitas itu ke bagian yang disorot pada layar
+  untuk menempatkan aktivitas dalam mode multi-jendela.
+  </li>
+
+  <li>Jika pengguna menekan lama pada tombol Ringkasan, perangkat akan menempatkan
+   aktivitas saat ini dalam mode multi-jendela, dan membuka layar Ringkasan guna
+  memungkinkan pengguna memilih aktivitas lain untuk berbagi layar.
+  </li>
+</ul>
+
+<p>
+  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">seret dan
+  lepas</a> data dari aktivitas satu ke aktivitas lain sewaktu aktivitas berbagi
+  layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam aktivitas
+  tunggal.)
+</p>
+
+<h2 id="lifecycle">Daur Hidup Multi-Jendela</h2>
+
+<p>
+  Mode multi-jendela tidak mengubah <a href="{@docRoot}training/basics/activity-lifecycle/index.html">daur hidup
+  aktivitas</a>.
+</p>
+
+<p>
+  Dalam mode multi-jendela, hanya aktivitas yang paling sering digunakan pengguna
+  yang akan aktif pada waktu tertentu. Aktivitas ini dianggap <em>teratas</em>.
+  Semua aktivitas lainnya dalam keadaan berhenti sementara, sekalipun terlihat.
+  Akan tetapi, sistem memberikan aktivitas, yang berhenti-sementara-namun-terlihat ini, prioritas lebih tinggi
+   daripada aktivitas yang tidak terlihat. Jika pengguna berinteraksi dengan salah satu
+  aktivitas yang berhenti sementara, aktivitas tersebut akan dilanjutkan kembali, dan aktivitas
+  teratas sebelumnya akan dihentikan sementara.
+</p>
+
+<p class="note">
+  <strong>Catatan:</strong> Dalam mode multi-jendela, aplikasi bisa berada dalam keadaan berhenti sementara
+  dan masih terlihat oleh pengguna. Sebuah aplikasi mungkin perlu melanjutkan aktivitasnya
+   bahkan saat berhenti sementara. Misalnya, aplikasi pemutar video yang ada dalam
+   mode berhenti sementara namun terlihat harus tetap menampilkan videonya. Karena alasan
+  ini, kami menyarankan aktivitas yang memutar video <em>tidak</em> menghentikan sementara video
+   dalam handler {@link android.app.Activity#onPause onPause()} mereka.
+  Sebagai gantinya, aktivitas itu harus menghentikan sementara video di {@link android.app.Activity#onStop
+  onStop()}, dan melanjutkan pemutaran di {@link android.app.Activity#onStart
+  onStart()}.
+</p>
+
+<p>
+  Bila pengguna menempatkan aplikasi dalam mode multi-jendela, sistem akan memberi tahu
+   aktivitas tersebut mengenai perubahan konfigurasi, sebagaimana ditetapkan dalam <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
+  Waktu Proses</a>. Hal ini juga terjadi ketika pengguna mengubah skala aplikasi, atau menempatkan kembali aplikasi
+  ke mode layar penuh.
+  Pada dasarnya, perubahan ini memiliki implikasi daur hidup aktivitas yang sama
+  seperti saat sistem memberi tahu aplikasi bahwa perangkat telah beralih
+  dari mode potret ke mode lanskap, kecuali dimensi perangkat
+  telah berubah sebagai ganti bertukar posisi. Seperti yang dibahas di <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Menangani Perubahan
+  Waktu Proses</a>, aktivitas Anda bisa menangani perubahan konfigurasi itu sendiri, atau
+   mengizinkan sistem memusnahkan aktivitas dan membuatnya kembali dengan dimensi
+  baru.
+</p>
+
+<p>
+  Jika pengguna mengubah ukuran jendela dan membuat dimensinya lebih besar, sistem
+   akan mengubah ukuran aktivitas untuk menyesuaikan dengan tindakan pengguna dan mengeluarkan <a href="{@docRoot}guide/topics/resources/runtime-changes.html">perubahan waktu proses</a>
+  bila diperlukan. Jika aplikasi tertinggal dibandingkan gambar di area yang baru diekspos,
+  sistem untuk sementara mengisi area tersebut dengan warna yang ditetapkan oleh atribut {@link
+  android.R.attr#windowBackground windowBackground} atau dengan atribut gaya
+  <code>windowBackgroundFallback</code> secara default.
+</p>
+
+<h2 id="configuring">Mengonfigurasi Aplikasi Anda untuk Mode Multi-Jendela</h2>
+
+<p>
+  Jika aplikasi Anda menargetkan Android N, Anda bisa mengonfigurasi bagaimana dan
+  apakah aktivitas aplikasi Anda mendukung tampilan multi-jendela. Anda bisa menyetel
+  atribut dalam manifes untuk mengontrol ukuran dan layoutnya.
+  Setelan atribut aktivitas root berlaku pada semua aktivitas
+   dalam tumpukan tugasnya. Misalnya, jika aktivitas root memiliki
+  <code>android:resizeableActivity</code> yang disetel ke true, maka semua aktivitas
+  dalam tumpukan tugas bisa diubah ukurannya.
+</p>
+
+<p class="note">
+  <strong>Catatan:</strong> Jika Anda membangun aplikasi multi-orientasi dengan versi
+  SDK lebih rendah dari Android N, dan pengguna menggunakan aplikasi
+   dalam mode multi-jendela, sistem akan mengubah ukuran aplikasi secara paksa. Sistem akan menampilkan kotak
+  dialog yang memperingatkan pengguna bahwa aplikasi mungkin berperilaku tidak terduga. Sistem
+   <em>tidak</em> mengubah ukuran aplikasi yang berorientasi tetap; jika
+  pengguna berusaha membuka  aplikasi berorientasi tetap saat mode multi-jendela,
+  aplikasi akan menggunakan seluruh layar.
+</p>
+
+<h4 id="resizeableActivity">android:resizeableActivity</h4>
+<p>
+  Setel atribut ini dalam manifes <code>&lt;activity&gt;</code> Anda atau simpul
+  <code>&lt;application&gt;</code> untuk mengaktifkan atau menonaktifkan tampilan
+   multi-jendela:
+</p>
+
+<pre>
+android:resizeableActivity=["true" | "false"]
+</pre>
+
+<p>
+  Jika atribut ini disetel ke true, aktivitas bisa dijalankan di
+  mode layar terbagi dan mode bentuk bebas. Jika atribut ini disetel ke false, aktivitas
+  tidak akan mendukung mode multi-jendela. Jika nilai ini false, dan pengguna
+  berusaha memulai aktivitas dalam mode multi-jendela, aktivitas akan menggunakan
+   layar penuh.
+</p>
+
+<p>
+  Jika aplikasi Anda menargetkan Android N, namun Anda tidak menetapkan nilai
+  untuk atribut ini, nilai atribut default adalah true.
+</p>
+
+<h4 id="supportsPictureInPicture">android:supportsPictureInPicture</h4>
+
+<p>
+  Setel atribut ini dalam simpul <code>&lt;activity&gt;</code> manifes Anda untuk
+  menunjukkan apakah aktivitas mendukung tampilan gambar-dalam-gambar. Atribut ini
+  diabaikan jika <code>android:resizeableActivity</code> bernilai false.
+</p>
+
+<pre>
+android:supportsPictureInPicture=["true" | "false"]
+</pre>
+
+<h3 id="layout">Atribut layout</h3>
+
+<p>
+  Dengan Android N, elemen manifes <code>&lt;layout&gt;</code>
+  mendukung beberapa atribut yang memengaruhi cara aktivitas berperilaku dalam
+  mode multi-jendela:
+</p>
+
+<dl>
+  <dt>
+    <code>android:defaultWidth</code>
+  </dt>
+
+  <dd>
+    Lebar default aktivitas saat dijalankan dalam mode bentuk bebas.
+  </dd>
+
+  <dt>
+    <code>android:defaultHeight</code>
+  </dt>
+
+  <dd>
+    Tinggi default aktivitas saat dijalankan dalam mode bentuk bebas.
+  </dd>
+
+  <dt>
+    <code>android:gravity</code>
+  </dt>
+
+  <dd>
+    Penempatan awal dari aktivitas saat dibuka dalam mode bentuk bebas. Lihat referensi
+    {@link android.view.Gravity} untuk mengetahui nilai yang cocok.
+  </dd>
+
+  <dt>
+    <code>android:minimalHeight</code>, <code>android:minimalWidth</code>
+  </dt>
+
+  <dd>
+    Tinggi dan lebar minimum untuk aktivitas dalam mode layar terbagi
+    dan mode bentuk bebas. Jika pengguna memindahkan pembagi dalam mode layar terbagi
+    untuk membuat aktivitas lebih kecil dari minimum yang ditetapkan, sistem akan memangkas
+   aktivitas sesuai dengan ukuran yang diminta pengguna.
+  </dd>
+</dl>
+
+<p>
+  Misalnya, kode berikut menampilkan cara menetapkan ukuran dan lokasi default
+  aktivitas, dan ukuran minimumnya, bila aktivitas ditampilkan dalam
+   mode bentuk bebas:
+</p>
+
+<pre>
+&lt;activity android:name=".MyActivity"&gt;
+    &lt;layout android:defaultHeight="500dp"
+          android:defaultWidth="600dp"
+          android:gravity="top|end"
+          android:minimalHeight="450dp"
+          android:minimalWidth="300dp" /&gt;
+&lt;/activity&gt;
+</pre>
+
+<h2 id="running">Menjalankan Aplikasi Anda dalam Mode Multi-Jendela</h2>
+
+<p>
+  Android N menawarkan fungsionalitas baru untuk mendukung aplikasi yang bisa berjalan
+  dalam mode multi-jendela.
+</p>
+
+<h3 id="disabled-features">Fitur yang dinonaktifkan dalam mode multi-jendela</h3>
+
+<p>
+  Fitur tertentu akan dinonaktifkan atau diabaikan bila perangkat berada dalam mode
+  multi-jendela, karena dianggap tidak logis bagi suatu aktivitas yang mungkin berbagi
+  layar perangkat dengan aktivitas atau aplikasi lainnya. Fitur tersebut meliputi:
+
+<ul>
+  <li>Beberapa opsi penyesuaian di <a href="{@docRoot}training/system-ui/index.html">System UI</a>
+  dinonaktifkan; misalnya, aplikasi tidak bisa menyembunyikan bilah status
+  jika tidak berjalan dalam mode layar penuh.
+  </li>
+
+  <li>Sistem akan mengabaikan perubahan pada atribut <code><a href=
+  "{@docRoot}guide/topics/manifest/activity-element.html#screen"
+  >android:screenOrientation</a></code>.
+  </li>
+</ul>
+
+<h3 id="change-notification">Pemberitahuan perubahan multi-jendela dan melakukan kueri</h3>
+
+<p>
+  Metode baru berikut telah ditambahkan ke kelas {@link android.app.Activity}
+  untuk mendukung tampilan multi-jendela. Untuk mengetahui detail tentang setiap
+  metode, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
+ Preview SDK</a>.
+</p>
+
+<dl>
+  <dt>
+    <code>Activity.isInMultiWindowMode()</code>
+  </dt>
+
+  <dd>
+    Panggil untuk mengetahui apakah aktivitas berada dalam mode multi-jendela.
+  </dd>
+
+  <dt>
+    <code>Activity.isInPictureInPictureMode()</code>
+  </dt>
+
+  <dd>
+    Panggil untuk mengetahui apakah aktivitas berada dalam mode gambar-dalam-gambar.
+
+    <p class="note">
+      <strong>Catatan:</strong> Mode gambar-dalam-gambar adalah kasus khusus pada
+      mode multi-jendela. Jika <code>myActivity.isInPictureInPictureMode()</code>
+     mengembalikan nilai true, maka <code>myActivity.isInMultiWindowMode()</code> juga
+      mengembalikan nilai true.
+    </p>
+  </dd>
+
+  <dt>
+    <code>Activity.onMultiWindowModeChanged()</code>
+  </dt>
+
+  <dd>
+    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
+    mode multi-jendela. Sistem akan meneruskan ke metode sebuah nilai true jika
+   aktivitas tersebut memasuki mode multi-jendela, dan nilai false jika aktivitas
+     tersebut meninggalkan mode multi-jendela.
+  </dd>
+
+  <dt>
+    <code>Activity.onPictureInPictureModeChanged()</code>
+  </dt>
+
+  <dd>
+    Sistem akan memanggil metode ini bila aktivitas masuk atau keluar dari
+    mode gambar-dalam-gambar. Sistem akan meneruskan ke metode sebuah nilai true jika
+   aktivitas tersebut memasuki mode gambar-dalam-gambar, dan nilai false jika aktivitas
+     tersebut meninggalkan mode gambar-dalam-gambar.
+  </dd>
+</dl>
+
+<p>
+  Ada juga versi {@link android.app.Fragment} untuk setiap
+  metode ini, misalnya <code>Fragment.isInMultiWindowMode()</code>.
+</p>
+
+<h3 id="entering-pip">Memasuki mode gambar-dalam-gambar</h3>
+
+<p>
+  Untuk menempatkan aktivitas dalam mode gambar-dalam-gambar, panggil metode baru
+  <code>Activity.enterPictureInPictureMode()</code>. Metode ini tidak berpengaruh jika
+   perangkat tidak mendukung mode gambar-dalam-gambar. Untuk informasi selengkapnya,
+   lihat dokumentasi <a href="picture-in-picture.html">Gambar-dalam-Gambar</a>.
+</p>
+
+<h3 id="launch">Meluncurkan Aktivitas Baru dalam Mode Multi-Jendela</h3>
+
+<p>
+  Bila meluncurkan aktivitas baru, Anda bisa memberi petunjuk pada sistem bahwa aktivitas
+  baru harus ditampilkan bersebelahan dengan aktivitas yang sedang aktif, jika memungkinkan. Caranya,
+  gunakan flag
+  <code>Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT</code>. Meneruskan
+  flag ini akan meminta perilaku berikut:
+</p>
+
+<ul>
+  <li>Jika perangkat berada dalam mode layar terbagi, sistem akan berupaya membuat
+  aktivitas baru di sebelah aktivitas yang meluncurkannya, sehingga kedua aktivitas tersebut
+  berbagi layar. Tidak ada jaminan sistem mampu melakukannya, namun sistem akan
+  membuat aktivitas bersebelahan jika memungkinkan.
+  </li>
+
+  <li>Jika perangkat tidak berada dalam mode layar terbagi, flag ini tidak akan berpengaruh.
+  </li>
+</ul>
+
+<p>
+  Jika perangkat dalam mode bentuk bebas dan Anda menjalankan aktivitas baru, Anda bisa
+  menetapkan dimensi aktivitas baru dan lokasi layar dengan memanggil
+  <code>ActivityOptions.setLaunchBounds()</code>. Metode ini tidak berpengaruh jika
+  perangkat tidak berada dalam mode multi-jendela.
+</p>
+
+<p class="note">
+  <strong>Catatan:</strong> Jika Anda meluncurkan aktivitas dalam tumpukan tugas, aktivitas
+  tersebut akan menggantikan aktivitas pada layar, dengan mewarisi semua
+   properti multi-jendelanya. Jika Anda ingin meluncurkan aktivitas baru sebagai jendela
+  terpisah dalam mode multi-jendela, Anda harus meluncurkannya dalam tumpukan tugas baru.
+</p>
+
+<h3 id="dnd">Mendukung seret dan lepas</h3>
+
+<p>
+  Pengguna bisa <a href="{@docRoot}guide/topics/ui/drag-drop.html">menyeret dan
+  melepas</a> data dari satu aktivitas ke aktivitas yang lain selagi kedua aktivitas
+  berbagi layar. (Sebelumnya, pengguna hanya bisa menyeret dan melepas data dalam
+   aktivitas tunggal.) Karena alasan ini, Anda mungkin perlu menambahkan fungsionalitas
+  seret dan lepas ke aplikasi jika aplikasi saat ini belum mendukungnya.
+</p>
+
+<p>
+  N Preview SDK menambahkan paket <a href="{@docRoot}reference/android/view/package-summary.html"><code>android.view</code></a>
+  untuk mendukung seret dan lepas lintas-aplikasi. Untuk mengetahui detail tentang kelas dan metode
+  berikut, lihat <a href="{@docRoot}preview/setup-sdk.html#docs-dl">Referensi N
+  Preview SDK</a>.
+</p>
+
+<dl>
+  <dt>
+    <code>android.view.DropPermissions</code>
+  </dt>
+
+  <dd>
+    Objek token bertanggung jawab menetapkan izin yang diberikan kepada aplikasi
+    yang menerima pelepasan tersebut.
+  </dd>
+
+  <dt>
+    <code>View.startDragAndDrop()</code>
+  </dt>
+
+  <dd>
+    Alias baru untuk {@link android.view.View#startDrag View.startDrag()}. Untuk
+    mengaktifkan seret dan lepas lintas-aktivitas, teruskan flag baru
+    <code>View.DRAG_FLAG_GLOBAL</code>. Jika Anda perlu memberikan izin URI ke
+    aktivitas penerima, teruskan flag baru,
+    <code>View.DRAG_FLAG_GLOBAL_URI_READ</code> atau
+    <code>View.DRAG_FLAG_GLOBAL_URI_WRITE</code>, sebagaimana mestinya.
+  </dd>
+
+  <dt>
+    <code>View.cancelDragAndDrop()</code>
+  </dt>
+
+  <dd>
+    Membatalkan operasi seret yang sedang berlangsung. Hanya bisa dipanggil oleh
+    aplikasi yang menghasilkan operasi seret.
+  </dd>
+
+  <dt>
+    <code>View.updateDragShadow()</code>
+  </dt>
+
+  <dd>
+    Menggantikan bayangan penyeretan untuk operasi seret yang sedang berlangsung. Hanya
+    bisa dipanggil oleh aplikasi yang menghasilkan operasi seret.
+  </dd>
+
+  <dt>
+    <code>Activity.requestDropPermissions()</code>
+  </dt>
+
+  <dd>
+    Meminta izin untuk URI materi yang diteruskan dengan {@link
+    android.content.ClipData} yang terdapat dalam {@link android.view.DragEvent}.
+  </dd>
+</dl>
+
+<h2 id="testing">Menguji Dukungan Multi-Jendela Aplikasi Anda</h2>
+
+<p>
+  Apakah Anda memperbarui aplikasi untuk Android N atau tidak, Anda harus
+  verifikasi bagaimana perilakunya di mode multi-jendela saat pengguna mencoba untuk menjalankannya
+  dalam mode multi-jendela pada perangkat yang menjalankan Android N.
+</p>
+
+<h3 id="configuring">Mengonfigurasi Perangkat Pengujian</h3>
+
+<p>
+  Jika Anda pasang Android N pada perangkat, mode
+  layar terbagi secara otomatis didukung.
+</p>
+
+<h3 id="test-non-n">Jika aplikasi Anda tidak dibangun dengan N Preview SDK</h3>
+
+<p>
+  Jika Anda tidak membangun aplikasi dengan N Preview SDK dan pengguna berupaya menggunakan
+  aplikasi dalam mode multi-jendela, sistem secara paksa akan mengubah ukuran aplikasi kecuali jika aplikasi
+  mendeklarasikan orientasi tetap.
+</p>
+
+<p>
+  Jika aplikasi Anda tidak mendeklarasikan orientasi tetap, Anda harus meluncurkan aplikasi
+  pada perangkat yang menjalankan Android N dan berupaya menempatkan aplikasi tersebut dalam
+  mode layar terbagi. Verifikasi pengalaman pengguna
+  bisa diterima bila aplikasi secara paksa diubah ukurannya.
+</p>
+
+<p>
+  Jika aplikasi mendeklarasikan orientasi tetap, Anda harus berupaya menempatkan aplikasi dalam
+  mode multi-jendela. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
+  mode layar penuh.
+</p>
+
+<h3 id="test-mw">Jika Anda mendukung mode multi-jendela</h3>
+
+<p>
+  Jika Anda membuat aplikasi Anda dengan N Preview SDK dan belum menonaktifkan
+  dukungan multi-jendela, verifikasi perilaku berikut dalam mode layar terbagi
+   dan mode bentuk bebas.
+</p>
+
+<ul>
+  <li>Luncurkan aplikasi dalam mode layar penuh, kemudian beralih ke mode multi-jendela dengan
+   menekan lama pada tombol Ringkasan. Verifikasi apakah aplikasi beralih dengan benar.
+  </li>
+
+  <li>Jalankan aplikasi secara langsung dalam mode multi-jendela, dan verifikasi aplikasi
+  diluncurkan dengan benar. Anda bisa meluncurkan aplikasi dalam mode multi-jendela dengan menekan
+  tombol Ringkasan, kemudian menekan lama baris judul pada aplikasi Anda dan menyeretnya
+  ke salah satu area yang disorot di layar.
+  </li>
+
+  <li>Ubah ukuran aplikasi Anda dalam mode layar terbagi dengan menyeret garis pembagi.
+  Verifikasi apakah aplikasi mengubah ukuran tanpa mogok, dan apakah elemen UI yang diperlukan
+  terlihat.
+  </li>
+
+  <li>Jika Anda telah menetapkan dimensi minimum aplikasi, cobalah untuk mengubah ukuran
+  aplikasi di bawah dimensi tersebut. Verifikasi apakah Anda tidak bisa mengubah ukuran aplikasi menjadi
+  lebih kecil dari minimum yang ditetapkan.
+  </li>
+
+  <li>Melalui semua pengujian, verifikasi apakah kinerja aplikasi Anda bisa diterima. Misalnya,
+  verifikasi apakah tidak ada jeda yang terlalu lama untuk memperbarui UI setelah
+  aplikasi diubah ukurannya.
+  </li>
+</ul>
+
+<h4 id="test-checklist">Daftar periksa pengujian</h4>
+
+<p>
+  Untuk verifikasi kinerja aplikasi Anda dalam mode multi-jendela, cobalah operasi
+  berikut. Anda harus mencoba semua operasi ini dalam mode layar terbagi dan
+   dan mode multi-jendela, kecuali jika dinyatakan berbeda.
+</p>
+
+<ul>
+  <li>Masuki dan tinggalkan mode multi-jendela.
+  </li>
+
+  <li>Beralih dari aplikasi Anda ke aplikasi lain, dan verifikasi apakah aplikasi berperilaku
+   sebagaimana mestinya saat terlihat namun tidak aktif. Misalnya, jika aplikasi Anda
+   sedang memutar video, verifikasi apakah video terus diputar selagi pengguna
+  berinteraksi dengan aplikasi lain.
+  </li>
+
+  <li>Dalam mode layar terbagi, cobalah menggeser garis pembagi untuk membuat aplikasi
+  Anda menjadi lebih besar dan lebih kecil. Coba operasi ini dalam konfigurasi berdampingan dan
+  atas-bawah. Verifikasi apakah aplikasi tidak mogok,
+  fungsionalitas penting bisa terlihat, dan operasi mengubah ukuran tidak memakan waktu terlalu
+  lama.
+  </li>
+
+  <li>Lakukan beberapa operasi ubah ukuran berturut-turut dalam waktu cepat. Verifikasi apakah
+  aplikasi Anda tidak mogok atau mengalami kebocoran memori. Untuk informasi tentang memeriksa penggunaan memori
+  aplikasi Anda, lihat <a href="{@docRoot}tools/debugging/debugging-memory.html">
+  Menyelidiki Penggunaan RAM Anda</a>.
+  </li>
+
+  <li>Gunakan aplikasi secara normal di sejumlah konfigurasi jendela yang berbeda, dan
+  verifikasi apakah aplikasi berperilaku sebagaimana mestinya. Verifikasi apakah teks terbaca, dan apakah
+  elemen UI tidak terlalu kecil untuk interaksi.
+  </li>
+</ul>
+
+<h3 id="test-disabled-mw">Jika Anda telah menonaktifkan dukungan multi-jendela</h3>
+
+<p>
+  Jika Anda menonaktifkan dukungan multi-jendela dengan menyetel
+  <code>android:resizableActivity="false"</code>, Anda harus menjalankan aplikasi pada
+  perangkat yang menjalankan Android N dan berusaha menempatkan aplikasi dalam
+  mode bentuk bebas dan mode layar terbagi. Verifikasi apakah saat Anda melakukannya, aplikasi tetap berada dalam
+  mode layar penuh.
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
new file mode 100644
index 0000000..bb48b80
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/notifiers/notifications.jd
@@ -0,0 +1,979 @@
+page.title=Pemberitahuan
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#Design">Pertimbangan Desain</a></li>
+  <li><a href="#CreateNotification">Membuat Pemberitahuan</a>
+    <ol>
+      <li><a href="#Required">Isi pemberitahuan yang diperlukan</a></li>
+      <li><a href="#Optional">Isi dan pengaturan pemberitahuan opsional</a></li>
+      <li><a href="#Actions">Tindakan pemberitahuan</a></li>
+      <li><a href="#Priority">Prioritas pemberitahuan</a></li>
+      <li><a href="#SimpleNotification">Membuat pemberitahuan sederhana</a></li>
+      <li><a href="#ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</a></li>
+      <li><a href="#Compatibility">Menangani kompatibilitas</a></li>
+    </ol>
+  </li>
+  <li><a href="#Managing">Mengelola Pemberitahuan</a>
+    <ol>
+      <li><a href="#Updating">Memperbarui pemberitahuan</a></li>
+      <li><a href="#Removing">Menghapus pemberitahuan</a></li>
+    </ol>
+  </li>
+  <li><a href="#NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</a>
+    <ol>
+      <li><a href="#DirectEntry">Menyiapkan PendingIntent aktivitas biasa</a></li>
+      <li><a href="#ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</a></li>
+    </ol>
+  </li>
+  <li><a href="#Progress">Menampilkan Kemajuan dalam Pemberitahuan</a>
+    <ol>
+      <li><a href="#FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</a></li>
+      <li><a href="#ActivityIndicator">Menampilkan indikator aktivitas berlanjut</a></li>
+    </ol>
+  </li>
+  <li><a href="#metadata">Metadata Pemberitahuan</a></li>
+  <li><a href="#Heads-up">Pemberitahuan Pendahuluan</a></li>
+  <li><a href="#lockscreenNotification">Pemberitahuan Layar Kunci</a></li>
+    <ol>
+      <li><a href="#visibility">Mengatur Visibilitas</a></li>
+      <li><a href="#controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</a></li>
+    </ol>
+  <li><a href="#CustomNotification">Layout Pemberitahuan Custom</a></li>
+</ol>
+
+    <h2>Kelas-kelas utama</h2>
+    <ol>
+        <li>{@link android.app.NotificationManager}</li>
+        <li>{@link android.support.v4.app.NotificationCompat}</li>
+    </ol>
+    <h2>Video</h2>
+    <ol>
+        <li>
+            <a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&amp;feature=player_detailpage#t=1672s">
+            Pemberitahuan di 4.1</a>
+        </li>
+    </ol>
+<h2>Lihat juga</h2>
+<ol>
+    <li>
+        <a href="{@docRoot}design/patterns/notifications.html">Desain Android: Pemberitahuan</a>
+    </li>
+</ol>
+</div>
+</div>
+<p>
+    Pemberitahuan adalah pesan yang bisa Anda tampilkan kepada pengguna di luar
+    UI normal aplikasi. Bila Anda memberi tahu sistem untuk mengeluarkan pemberitahuan, pemberitahuan akan muncul lebih dahulu sebagai ikon dalam
+    <strong>area pemberitahuan</strong>. Untuk melihat detail pemberitahuan, pengguna membuka
+    <strong>laci pemberitahuan</strong>. Baik area pemberitahuan maupun laci pemberitahuan
+    adalah area-area yang dikontrol sistem yang bisa dilihat pengguna kapan saja.
+</p>
+<img id="figure1" src="{@docRoot}images/ui/notifications/notification_area.png" height="" alt="" />
+<p class="img-caption">
+    <strong>Gambar 1.</strong> Pemberitahuan di area pemberitahuan.
+</p>
+<img id="figure2" src="{@docRoot}images/ui/notifications/notification_drawer.png" width="280px" alt="" />
+<p class="img-caption">
+    <strong>Gambar 2.</strong> Pemberitahuan di laci pemberitahuan.
+</p>
+
+<p class="note"><strong>Catatan:</strong> Kecuali disebutkan, panduan ini mengacu pada
+kelas {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}
+dalam <a href="{@docRoot}tools/support-library/index.html">Support Library</a> versi 4.
+Kelas {@link android.app.Notification.Builder Notification.Builder} telah ditambahkan pada Android
+3.0 (API level 11).</p>
+
+<h2 id="Design">Pertimbangan Desain</h2>
+
+<p>Pemberitahuan, sebagai bagian penting dari antarmuka pengguna Android, memiliki panduan desainnya sendiri.
+Perubahan desain materi yang diperkenalkan dalam Android 5.0 (API level 21) adalah sangat
+penting, dan Anda harus meninjau pelatihan <a href="{@docRoot}training/material/index.html">Desain Bahan</a>
+untuk informasi selengkapnya. Untuk mengetahui cara mendesain pemberitahuan dan interaksinya, bacalah panduan desain
+<a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.</p>
+
+<h2 id="CreateNotification">Membuat Pemberitahuan</h2>
+
+<p>Anda menetapkan informasi dan tindakan UI bagi pemberitahuan dalam
+objek {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
+Untuk membuat pemberitahuan itu sendiri, panggil
+{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()},
+yang akan mengembalikan objek {@link android.app.Notification} berisi spesifikasi Anda. Untuk mengeluarkan
+pemberitahuan, Anda meneruskan objek {@link android.app.Notification} ke sistem dengan memanggil
+{@link android.app.NotificationManager#notify NotificationManager.notify()}.</p>
+
+<h3 id="Required">Isi pemberitahuan yang diperlukan</h3>
+<p>
+    Objek {@link android.app.Notification} <em>harus</em> berisi yang berikut ini:
+</p>
+<ul>
+    <li>
+        Ikon kecil, yang diatur dengan
+        {@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()}
+    </li>
+    <li>
+        Judul, yang diatur dengan
+        {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}
+    </li>
+    <li>
+        Teks detail, yang diatur dengan
+        {@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()}
+    </li>
+</ul>
+<h3 id="Optional">Isi dan pengaturan pemberitahuan opsional</h3>
+<p>
+    Semua isi dan pengaturan pemberitahuan lainnya bersifat opsional. Untuk mengetahui selengkapnya tentang semua itu,
+    lihat dokumentasi acuan untuk {@link android.support.v4.app.NotificationCompat.Builder}.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Actions">Tindakan pemberitahuan</h3>
+<p>
+    Walaupun bersifat opsional, Anda harus menambahkan setidaknya satu tindakan pada pemberitahuan.
+    Tindakan memungkinkan pengguna beralih langsung dari pemberitahuan ke
+    {@link android.app.Activity} dalam aplikasi Anda, tempat pengguna bisa melihat satu atau beberapa kejadian
+    atau melakukan pekerjaan lebih jauh.
+</p>
+<p>
+    Pemberitahuan bisa menyediakan beberapa tindakan sekaligus. Anda harus selalu mendefinisikan tindakan yang
+    akan diaktifkan bila pengguna mengklik pemberitahuan; biasanya tindakan ini akan membuka
+    {@link android.app.Activity} dalam aplikasi Anda. Anda juga bisa menambahkan tombol pada pemberitahuan
+    yang melakukan tindakan tambahan seperti mendiamkan alarm atau segera merespons
+    pesan teks; fitur ini tersedia mulai Android 4.1. Jika menggunakan tombol tindakan tambahan, Anda
+    juga harus membuat fungsionalitasnya tersedia dalam {@link android.app.Activity} di aplikasi Anda; lihat
+    bagian <a href="#Compatibility">Menangani kompatibilitas</a> untuk detail selengkapnya.
+</p>
+<p>
+    Dalam {@link android.app.Notification}, tindakan itu sendiri didefinisikan oleh
+    {@link android.app.PendingIntent} berisi
+    {@link android.content.Intent} yang memulai
+    {@link android.app.Activity} dalam aplikasi Anda. Untuk mengaitkan
+    {@link android.app.PendingIntent} dengan gestur, panggil metode
+    {@link android.support.v4.app.NotificationCompat.Builder} yang sesuai. Misalnya, jika ingin memulai
+    {@link android.app.Activity} bila pengguna mengklik teks pemberitahuan pada
+    laci pemberitahuan, tambahkan {@link android.app.PendingIntent} dengan memanggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
+</p>
+<p>
+    Memulai {@link android.app.Activity} bila pengguna mengklik pemberitahuan adalah
+    skenario tindakan yang paling umum. Anda juga bisa memulai {@link android.app.Activity} bila pengguna
+    menghilangkan pemberitahuan. Dalam Android 4.1 dan yang lebih baru, Anda bisa memulai
+    {@link android.app.Activity} dari tombol tindakan. Untuk mengetahui selengkapnya, bacalah panduan acuan untuk
+    {@link android.support.v4.app.NotificationCompat.Builder}.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Priority">Prioritas pemberitahuan</h3>
+<p>
+    Jika diinginkan, Anda bisa mengatur prioritas pemberitahuan. Prioritas berfungsi
+    sebagai petunjuk bagi UI perangkat tentang cara menampilkan pemberitahuan.
+    Untuk mengatur prioritas pemberitahuan, panggil {@link
+    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
+    NotificationCompat.Builder.setPriority()} dan teruskan salah satu konstanta prioritas {@link
+    android.support.v4.app.NotificationCompat}. Ada
+    lima level prioritas, mulai dari {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) hingga {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); jika tidak diatur,
+    prioritas default akan ditetapkan {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
+</p>
+<p> Untuk informasi tentang mengatur level prioritas, lihat "Mengatur
+    dan mengelola prioritas pemberitahuan dengan benar" dalam panduan
+Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="SimpleNotification">Membuat pemberitahuan sederhana</h3>
+<p>
+    Cuplikan berikut mengilustrasikan pemberitahuan sederhana yang menetapkan aktivitas untuk dibuka bila
+    pengguna mengklik pemberitahuan. Perhatikan bahwa kode ini membuat
+    objek {@link android.support.v4.app.TaskStackBuilder} dan menggunakannya untuk membuat
+    {@link android.app.PendingIntent} untuk tindakan. Pola ini dijelaskan secara lebih detail
+    di bagian <a href="#NotificationResponse">
+    Mempertahankan Navigasi saat Memulai Aktivitas</a>:
+</p>
+<pre>
+NotificationCompat.Builder mBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.notification_icon)
+        .setContentTitle("My notification")
+        .setContentText("Hello World!");
+// Creates an explicit intent for an Activity in your app
+Intent resultIntent = new Intent(this, ResultActivity.class);
+
+// The stack builder object will contain an artificial back stack for the
+// started Activity.
+// This ensures that navigating backward from the Activity leads out of
+// your application to the Home screen.
+TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
+// Adds the back stack for the Intent (but not the Intent itself)
+stackBuilder.addParentStack(ResultActivity.class);
+// Adds the Intent that starts the Activity to the top of the stack
+stackBuilder.addNextIntent(resultIntent);
+PendingIntent resultPendingIntent =
+        stackBuilder.getPendingIntent(
+            0,
+            PendingIntent.FLAG_UPDATE_CURRENT
+        );
+mBuilder.setContentIntent(resultPendingIntent);
+NotificationManager mNotificationManager =
+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+// mId allows you to update the notification later on.
+mNotificationManager.notify(mId, mBuilder.build());
+</pre>
+<p>Demikian saja. Pengguna Anda kini telah diberi tahu.</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="ApplyStyle">Menerapkan layout yang diperluas pada pemberitahuan</h3>
+<p>
+    Agar pemberitahuan muncul dalam tampilan yang diperluas, buat dahulu
+    objek {@link android.support.v4.app.NotificationCompat.Builder} dengan opsi tampilan normal
+    yang Anda inginkan. Berikutnya, panggil {@link android.support.v4.app.NotificationCompat.Builder#setStyle
+    Builder.setStyle()}  dengan objek layout yang diperluas sebagai argumennya.
+</p>
+<p>
+    Ingatlah bahwa pemberitahuan yang diperluas tidak tersedia pada platform-platform sebelum Android 4.1. Untuk
+    mengetahui cara menangani pemberitahuan untuk Android 4.1 dan untuk platform-platform sebelumnya, bacalah
+    bagian <a href="#Compatibility">Menangani kompatibilitas</a>.
+</p>
+<p>
+    Misalnya, cuplikan kode berikut memperagakan cara mengubah pemberitahuan yang dibuat
+    dalam cuplikan sebelumnya untuk menggunakan layout yang diperluas:
+</p>
+<pre>
+NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
+    .setSmallIcon(R.drawable.notification_icon)
+    .setContentTitle("Event tracker")
+    .setContentText("Events received")
+NotificationCompat.InboxStyle inboxStyle =
+        new NotificationCompat.InboxStyle();
+String[] events = new String[6];
+// Sets a title for the Inbox in expanded layout
+inboxStyle.setBigContentTitle("Event tracker details:");
+...
+// Moves events into the expanded layout
+for (int i=0; i &lt; events.length; i++) {
+
+    inboxStyle.addLine(events[i]);
+}
+// Moves the expanded layout object into the notification object.
+mBuilder.setStyle(inBoxStyle);
+...
+// Issue the notification here.
+</pre>
+
+<h3 id="Compatibility">Menangani kompatibilitas</h3>
+
+<p>
+    Tidak semua fitur pemberitahuan tersedia untuk versi tertentu, walaupun
+    metode untuk mengaturnya ada dalam kelas pustaka dukungan
+    {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}.
+    Misalnya, tombol tindakan, yang bergantung pada pemberitahuan yang diperluas, hanya muncul pada Android
+    4.1 dan lebih tinggi, karena pemberitahuan yang diperluas itu sendiri hanya tersedia pada
+    Android 4.1 dan yang lebih tinggi.
+</p>
+<p>
+    Untuk memastikan kompatibilitas terbaik, buatlah pemberitahuan dengan
+    {@link android.support.v4.app.NotificationCompat NotificationCompat} dan subkelasnya,
+    khususnya {@link android.support.v4.app.NotificationCompat.Builder
+    NotificationCompat.Builder}. Selain itu, ikutilah proses ini bila Anda mengimplementasikan pemberitahuan:
+</p>
+<ol>
+    <li>
+        Sediakan semua fungsionalitas pemberitahuan kepada semua pengguna, terlepas dari versi
+        yang mereka gunakan. Caranya, pastikan semua fungsionalitas tersedia dari
+        {@link android.app.Activity} dalam aplikasi Anda. Anda mungkin perlu menambahkan sebuah
+        {@link android.app.Activity} baru untuk melakukannya.
+        <p>
+            Misalnya, jika Anda ingin menggunakan
+            {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} untuk
+            menyediakan kontrol yang menghentikan dan memulai pemutaran media, implementasikan dahulu
+            kontrol ini pada {@link android.app.Activity} dalam aplikasi Anda.
+        </p>
+    </li>
+    <li>
+        Pastikan semua pengguna bisa memperoleh fungsionalitas dalam {@link android.app.Activity},
+        dengan memulainya bila pengguna mengklik pemberitahuan. Caranya,
+        buatlah {@link android.app.PendingIntent}
+        untuk {@link android.app.Activity}. Panggil
+        {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+        setContentIntent()} untuk menambahkan {@link android.app.PendingIntent} pada pemberitahuan.
+    </li>
+    <li>
+        Kini tambahkan fitur pemberitahuan diperluas yang ingin Anda gunakan pada pemberitahuan. Ingatlah
+        bahwa setiap fungsionalitas yang Anda tambahkan juga harus tersedia dalam {@link android.app.Activity}
+        yang akan dimulai bila pengguna mengklik pemberitahuan.
+    </li>
+</ol>
+
+
+<!-- ------------------------------------------------------------------------------------------ -->
+<!-- ------------------------------------------------------------------------------------------ -->
+<h2 id="Managing">Mengelola Pemberitahuan</h2>
+<p>
+    Bila perlu mengeluarkan pemberitahuan beberapa kali untuk tipe kejadian yang sama,
+hindari membuat pemberitahuan yang sama sekali baru. Sebagai gantinya, Anda harus mempertimbangkan untuk memperbarui
+    pemberitahuan sebelumnya, baik dengan mengubah sebagian nilainya atau dengan menambahkan nilai, atau keduanya.
+</p>
+<p>
+    Misalnya, Gmail akan memberi tahu pengguna bila ada email baru dengan menambah hitungan
+    pesan tidak terbaca dan dengan menambahkan rangkuman tiap email ke pemberitahuan. Ini disebut dengan
+    "stacking" (menumpuk) pemberitahuan; hal ini dijelaskan lebih detail dalam panduan
+    Desain <a href="{@docRoot}design/patterns/notifications.html">Pemberitahuan</a>.
+</p>
+<p class="note">
+    <strong>Catatan:</strong> Fitur Gmail ini mensyaratkan layout "kotak masuk" diperluas, yang merupakan
+    bagian dari fitur pemberitahuan diperluas yang tersedia mulai Android 4.1.
+</p>
+<p>
+    Bagian berikut menjelaskan cara memperbarui pemberitahuan dan cara menghapusnya.
+</p>
+<h3 id="Updating">Memperbarui pemberitahuan</h3>
+<p>
+    Untuk menyiapkan pemberitahuan agar bisa diperbarui, keluarkan pemberitahuan bersama ID pemberitahuan dengan
+    memanggil {@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}.
+    Untuk memperbarui pemberitahuan ini setelah Anda
+    mengeluarkan, memperbarui, atau membuat objek {@link android.support.v4.app.NotificationCompat.Builder},
+    buat objek {@link android.app.Notification} darinya, dan keluarkan
+    {@link android.app.Notification} bersama ID yang sama dengan yang Anda gunakan sebelumnya. Jika
+    pemberitahuan sebelumnya tetap terlihat, sistem akan memperbaruinya dari konten
+    objek {@link android.app.Notification}. Jika pemberitahuan sebelumnya telah dihilangkan, sebuah
+    pemberitahuan baru akan dibuat.
+</p>
+<p>
+    Cuplikan berikut memperagakan pemberitahuan yang diperbarui untuk mencerminkan
+    jumlah kejadian yang telah terjadi. Cuplikan ini menumpuk pemberitahuan, yang menampilkan rangkuman:
+</p>
+<pre>
+mNotificationManager =
+        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+// Sets an ID for the notification, so it can be updated
+int notifyID = 1;
+mNotifyBuilder = new NotificationCompat.Builder(this)
+    .setContentTitle("New Message")
+    .setContentText("You've received new messages.")
+    .setSmallIcon(R.drawable.ic_notify_status)
+numMessages = 0;
+// Start of a loop that processes data and then notifies the user
+...
+    mNotifyBuilder.setContentText(currentText)
+        .setNumber(++numMessages);
+    // Because the ID remains unchanged, the existing notification is
+    // updated.
+    mNotificationManager.notify(
+            notifyID,
+            mNotifyBuilder.build());
+...
+</pre>
+
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Removing">Menghapus pemberitahuan</h3>
+<p>
+    Pemberitahuan tetap terlihat hingga salah satu kejadian berikut terjadi:
+</p>
+<ul>
+    <li>
+        Pengguna menghilangkan pemberitahuan satu per satu atau dengan menggunakan "Clear All" (jika
+        pemberitahuan bisa dihapus).
+    </li>
+    <li>
+        Pengguna mengklik pemberitahuan, dan Anda memanggil
+        {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} bila
+        Anda telah membuat pemberitahuan.
+    </li>
+    <li>
+        Anda memanggil {@link android.app.NotificationManager#cancel(int) cancel()} untuk
+        ID pemberitahuan tertentu. Metode ini juga menghapus pemberitahuan yang berjalan.
+    </li>
+    <li>
+        Anda memanggil {@link android.app.NotificationManager#cancelAll() cancelAll()}, yang menghapus
+        semua pemberitahuan yang dikeluarkan sebelumnya.
+    </li>
+</ul>
+<!-- ------------------------------------------------------------------------------------------ -->
+<!-- ------------------------------------------------------------------------------------------ -->
+<h2 id="NotificationResponse">Mempertahankan Navigasi saat Memulai Aktivitas</h2>
+<p>
+    Bila memulai {@link android.app.Activity} dari pemberitahuan, Anda harus mempertahankan
+    pengalaman navigasi yang diharapkan pengguna. Mengklik <i>Back</i> harus membawa pengguna kembali melalui
+    aliran pekerjaan normal aplikasi ke layar Home, dan mengklik <i>Recents</i> harus menampilkan
+    {@link android.app.Activity} sebagai tugas terpisah. Untuk mempertahankan pengalaman navigasi, Anda
+    harus memulai {@link android.app.Activity} dalam tugas baru. Cara menyiapkan
+    {@link android.app.PendingIntent} untuk memberi Anda tugas baru bergantung pada sifat
+    {@link android.app.Activity} yang Anda mulai. Ada dua situasi umum:
+</p>
+<dl>
+    <dt>
+        Aktivitas rutin
+    </dt>
+    <dd>
+        Anda memulai {@link android.app.Activity} yang merupakan bagian dari aliran pekerjaan normal
+        aplikasi. Dalam situasi ini, siapkan {@link android.app.PendingIntent} untuk
+        memulai tugas baru, dan sediakan {@link android.app.PendingIntent} bersama back-stack
+        yang meniru perilaku <i>Back</i> biasa.
+        <p>
+            Pemberitahuan dari aplikasi Gmail memperagakan hal ini. Bila Anda mengklik pemberitahuan untuk
+            satu pesan email, Anda akan melihat pesan itu sendiri. Menyentuh <b>Back</b> akan membawa Anda
+            kembali melalui Gmail ke layar Home, persis seperti jika memasuki Gmail dari
+            layar Home bukannya memasukinya dari pemberitahuan.
+        </p>
+        <p>
+            Hal ini terjadi terlepas dari aplikasi tempat Anda berada saat menyentuh
+            pemberitahuan. Misalnya, jika Anda dalam Gmail sedang menulis pesan, dan Anda mengklik
+            pemberitahuan untuk satu email, Anda akan segera dibawa ke email itu. Menyentuh <i>Back</i>
+            akan membawa Anda ke kotak masuk kemudian layar Home, bukannya membawa Anda ke
+            pesan yang sedang ditulis.
+        </p>
+    </dd>
+    <dt>
+        Aktivitas khusus
+    </dt>
+    <dd>
+        Pengguna hanya melihat {@link android.app.Activity} ini jika dimulai dari pemberitahuan.
+        Dalam beberapa hal, {@link android.app.Activity} akan memperluas pemberitahuan dengan menyediakan
+        informasi yang akan sulit untuk ditampilkan dalam pemberitahuan itu sendiri. Untuk situasi ini,
+        siapkan {@link android.app.PendingIntent} untuk dimulai dalam tugas baru. Tidak perlu
+        membuat back-stack, karena {@link android.app.Activity} yang dimulai bukan bagian dari
+        aliran aktivitas aplikasi. Mengklik <i>Back</i> tetap akan membawa pengguna ke
+        layar Home.
+    </dd>
+</dl>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="DirectEntry">Menyiapkan PendingIntent aktivitas biasa</h3>
+<p>
+    Untuk menyiapkan {@link android.app.PendingIntent} yang memulai entri langsung
+    {@link android.app.Activity}, ikuti langkah-langkah ini:
+</p>
+<ol>
+    <li>
+        Definisikan hierarki {@link android.app.Activity} aplikasi Anda dalam manifes.
+        <ol style="list-style-type: lower-alpha;">
+            <li>
+                Tambahkan dukungan untuk Android 4.0.3 dan yang terdahulu. Caranya, tetapkan induk
+                {@link android.app.Activity} yang Anda mulai dengan menambahkan elemen
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
+                sebagai anak
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>.
+                <p>
+                    Untuk elemen ini, atur
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code>.
+                    Atur
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#val">android:value</a>="&lt;parent_activity_name&gt;"</code>
+                    dengan <code>&lt;parent_activity_name&gt;</code> sebagai nilai
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
+                    untuk elemen induk
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+. Lihat XML berikut sebagai contoh.
+                </p>
+            </li>
+            <li>
+                Juga tambahkan dukungan untuk Android 4.1 dan yang lebih baru. Caranya, tambahkan atribut
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code>
+                 pada elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+                dari {@link android.app.Activity} yang Anda mulai.
+            </li>
+        </ol>
+        <p>
+            XML akhir akan terlihat seperti ini:
+        </p>
+<pre>
+&lt;activity
+    android:name=".MainActivity"
+    android:label="&#64;string/app_name" &gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.MAIN" /&gt;
+        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+    &lt;/intent-filter&gt;
+&lt;/activity&gt;
+&lt;activity
+    android:name=".ResultActivity"
+    android:parentActivityName=".MainActivity"&gt;
+    &lt;meta-data
+        android:name="android.support.PARENT_ACTIVITY"
+        android:value=".MainActivity"/&gt;
+&lt;/activity&gt;
+</pre>
+    </li>
+    <li>
+        Buat back-stack berdasarkan {@link android.content.Intent} yang memulai
+        {@link android.app.Activity}:
+        <ol style="list-style-type: lower-alpha;">
+            <li>
+                Buat {@link android.content.Intent} untuk memulai {@link android.app.Activity}.
+            </li>
+            <li>
+                Buat stack-builder (pembangun tumpukan) dengan memanggil {@link android.app.TaskStackBuilder#create
+                TaskStackBuilder.create()}.
+            </li>
+            <li>
+                Tambahkan back-stack ke stack-builder dengan memanggil
+                {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}.
+                Untuk setiap {@link android.app.Activity} dalam hierarki yang telah Anda definisikan dalam
+                manifes, back-stack berisi objek {@link android.content.Intent} yang
+                memulai {@link android.app.Activity}. Metode ini juga menambahkan flag yang memulai
+                back-stack dalam tugas baru.
+                <p class="note">
+                    <strong>Catatan:</strong> Walaupun argumen untuk
+                    {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}
+                    adalah acuan ke {@link android.app.Activity} yang dimulai, panggilan metode
+                    tidak akan menambahkan {@link android.content.Intent} yang memulai
+                    {@link android.app.Activity}. Sebagai gantinya, hal itu ditangani dalam langkah berikutnya.
+                </p>
+            </li>
+            <li>
+                Tambahkan {@link android.content.Intent} yang memulai {@link android.app.Activity}
+                dari pemberitahuan, dengan memanggil
+                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
+                Teruskan {@link android.content.Intent} yang Anda buat dalam langkah pertama sebagai
+                argumen ke
+                {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
+            </li>
+            <li>
+                Jika perlu, tambahkan argumen ke objek {@link android.content.Intent} pada
+                back-stack dengan memanggil {@link android.support.v4.app.TaskStackBuilder#editIntentAt
+                TaskStackBuilder.editIntentAt()}. Kadang-kadang perlu memastikan apakah
+                {@link android.app.Activity} target menampilkan data bermakna saat pengguna menelusurinya
+                dengan menggunakan <i>Back</i>.
+            </li>
+            <li>
+                Dapatkan {@link android.app.PendingIntent} untuk back-stack ini dengan memanggil
+                {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.
+                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
+                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+                setContentIntent()}.
+            </li>
+        </ol>
+     </li>
+</ol>
+<p>
+    Cuplikan kode berikut memperagakan prosesnya:
+</p>
+<pre>
+...
+Intent resultIntent = new Intent(this, ResultActivity.class);
+TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
+// Adds the back stack
+stackBuilder.addParentStack(ResultActivity.class);
+// Adds the Intent to the top of the stack
+stackBuilder.addNextIntent(resultIntent);
+// Gets a PendingIntent containing the entire back stack
+PendingIntent resultPendingIntent =
+        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
+...
+NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+builder.setContentIntent(resultPendingIntent);
+NotificationManager mNotificationManager =
+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+mNotificationManager.notify(id, builder.build());
+</pre>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="ExtendedNotification">Menyiapkan PendingIntent aktivitas khusus</h3>
+<p>
+    Bagian berikut menjelaskan cara menyiapkan aktivitas khusus
+    {@link android.app.PendingIntent}.
+</p>
+<p>
+    {@link android.app.Activity} khusus tidak memerlukan back-stack, sehingga Anda tidak perlu
+    mendefinisikan hierarki {@link android.app.Activity}-nya dalam manifes, dan Anda tidak perlu
+    memanggil
+    {@link android.support.v4.app.TaskStackBuilder#addParentStack  addParentStack()} untuk membuat
+    back-stack. Sebagai gantinya, gunakan manifes untuk menyiapkan opsi tugas {@link android.app.Activity},
+    dan buat {@link android.app.PendingIntent} dengan memanggil
+    {@link android.app.PendingIntent#getActivity getActivity()}:
+</p>
+<ol>
+    <li>
+        Dalam manifes, tambahkan atribut berikut pada elemen
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+        untuk {@link android.app.Activity}
+        <dl>
+            <dt>
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code>
+            </dt>
+            <dd>
+                Nama kelas mutlak (fully qualified) aktivitas.
+            </dd>
+            <dt>
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code>
+            </dt>
+            <dd>
+                Dikombinasikan dengan flag
+                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
+                yang Anda atur dalam kode, ini memastikan bahwa {@link android.app.Activity} ini tidak
+                masuk ke dalam tugas default aplikasi. Setiap tugas yang ada yang memiliki
+                afinitas default aplikasi tidak terpengaruh.
+            </dd>
+            <dt>
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code>
+            </dt>
+            <dd>
+                Mengecualikan tugas baru dari <i>Recents</i>, sehingga pengguna tidak bisa tanpa sengaja
+                mengarahkan kembali.
+            </dd>
+        </dl>
+        <p>
+            Cuplikan ini menampilkan elemen:
+        </p>
+<pre>
+&lt;activity
+    android:name=".ResultActivity"
+...
+    android:launchMode="singleTask"
+    android:taskAffinity=""
+    android:excludeFromRecents="true"&gt;
+&lt;/activity&gt;
+...
+</pre>
+    </li>
+    <li>
+        Buat dan keluarkan pemberitahuan:
+        <ol style="list-style-type: lower-alpha;">
+            <li>
+                Buat {@link android.content.Intent} yang memulai
+                {@link android.app.Activity}.
+            </li>
+            <li>
+                Atur {@link android.app.Activity} untuk dimulai dalam tugas kosong yang baru dengan memanggil
+                {@link android.content.Intent#setFlags setFlags()} dengan flag
+                {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
+                dan
+                {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}.
+            </li>
+            <li>
+                Atur setiap opsi lain yang Anda perlukan untuk {@link android.content.Intent}.
+            </li>
+            <li>
+                Buat {@link android.app.PendingIntent} dari {@link android.content.Intent}
+                dengan memanggil {@link android.app.PendingIntent#getActivity getActivity()}.
+                Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk
+                {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+                setContentIntent()}.
+            </li>
+        </ol>
+    <p>
+        Cuplikan kode berikut memperagakan prosesnya:
+    </p>
+<pre>
+// Instantiate a Builder object.
+NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+// Creates an Intent for the Activity
+Intent notifyIntent =
+        new Intent(this, ResultActivity.class);
+// Sets the Activity to start in a new, empty task
+notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+// Creates the PendingIntent
+PendingIntent notifyPendingIntent =
+        PendingIntent.getActivity(
+        this,
+        0,
+        notifyIntent,
+        PendingIntent.FLAG_UPDATE_CURRENT
+);
+
+// Puts the PendingIntent into the notification builder
+builder.setContentIntent(notifyPendingIntent);
+// Notifications are issued by sending them to the
+// NotificationManager system service.
+NotificationManager mNotificationManager =
+    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+// Builds an anonymous Notification object from the builder, and
+// passes it to the NotificationManager
+mNotificationManager.notify(id, builder.build());
+</pre>
+    </li>
+</ol>
+<!-- ------------------------------------------------------------------------------------------ -->
+<!-- ------------------------------------------------------------------------------------------ -->
+<h2 id="Progress">Menampilkan Kemajuan dalam Pemberitahuan</h2>
+<p>
+    Pemberitahuan bisa menyertakan indikator kemajuan beranimasi yang menampilkan status
+operasi yang berjalan kepada pengguna. Jika Anda bisa memperkirakan lamanya operasi berlangsung dan berapa banyak
+    yang sudah selesai pada suatu waktu, gunakan bentuk indikator yang "pasti"
+    (baris kemajuan). Jika Anda tidak bisa memperkirakan lamanya operasi, gunakan
+    bentuk indikator "tidak pasti" (indikator aktivitas).
+</p>
+<p>
+    Indikator kemajuan ditampilkan bersama implementasi platform
+    kelas {@link android.widget.ProgressBar}.
+</p>
+<p>
+    Untuk menggunakan indikator kemajuan pada platform mulai dari Android 4.0, panggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. Untuk
+    versi sebelumnya, Anda harus membuat layout pemberitahuan custom sendiri yang
+menyertakan tampilan {@link android.widget.ProgressBar}.
+</p>
+<p>
+    Bagian berikut ini menjelaskan cara menampilkan kemajuan dalam pemberitahuan dengan menggunakan
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="FixedProgress">Menampilkan indikator kemajuan berdurasi tetap</h3>
+<p>
+    Untuk menampilkan baris kemajuan pasti, tambahkan baris itu ke pemberitahuan dengan memanggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
+    setProgress(max, progress, false)}, kemudian keluarkan pemberitahuan. Selagi operasi berlangsung,
+    tambah <code>progress</code>, dan perbarui pemberitahuan. Di akhir operasi,
+    <code>progress</code> harus sama dengan <code>max</code>. Satu cara umum memanggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
+    adalah mengatur <code>max</code> ke 100, kemudian tambah <code>progress</code> sebagai
+     nilai "persen selesai"untuk operasi itu.
+</p>
+<p>
+    Anda bisa membiarkan baris kemajuan ditampilkan saat operasi selesai, atau menghilangkannya. Dalam
+    hal apa pun, ingatlah memperbarui teks pemberitahuan untuk menampilkan bahwa operasi telah selesai.
+    Untuk menghapus baris kemajuan, panggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress
+    setProgress(0, 0, false)}. Misalnya:
+</p>
+<pre>
+...
+mNotifyManager =
+        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+mBuilder = new NotificationCompat.Builder(this);
+mBuilder.setContentTitle("Picture Download")
+    .setContentText("Download in progress")
+    .setSmallIcon(R.drawable.ic_notification);
+// Start a lengthy operation in a background thread
+new Thread(
+    new Runnable() {
+        &#64;Override
+        public void run() {
+            int incr;
+            // Do the "lengthy" operation 20 times
+            for (incr = 0; incr &lt;= 100; incr+=5) {
+                    // Sets the progress indicator to a max value, the
+                    // current completion percentage, and "determinate"
+                    // state
+                    mBuilder.setProgress(100, incr, false);
+                    // Displays the progress bar for the first time.
+                    mNotifyManager.notify(0, mBuilder.build());
+                        // Sleeps the thread, simulating an operation
+                        // that takes time
+                        try {
+                            // Sleep for 5 seconds
+                            Thread.sleep(5*1000);
+                        } catch (InterruptedException e) {
+                            Log.d(TAG, "sleep failure");
+                        }
+            }
+            // When the loop is finished, updates the notification
+            mBuilder.setContentText("Download complete")
+            // Removes the progress bar
+                    .setProgress(0,0,false);
+            mNotifyManager.notify(ID, mBuilder.build());
+        }
+    }
+// Starts the thread by calling the run() method in its Runnable
+).start();
+</pre>
+
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="ActivityIndicator">Menampilkan indikator aktivitas berlanjut</h3>
+<p>
+    Untuk menampilkan indikator aktivitas tidak pasti, tambahkan aktivitas ke pemberitahuan dengan
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}
+    (dua argumen pertama akan diabaikan), dan keluarkan pemberitahuan. Hasilnya adalah indikator
+    yang memiliki gaya yang sama dengan baris kemajuan, hanya saja animasinya terus berjalan.
+</p>
+<p>
+    Keluarkan pemberitahuan di awal operasi. Animasi akan berjalan hingga Anda
+    memodifikasi pemberitahuan. Bila operasi selesai, panggil
+    {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)}
+    kemudian perbarui pemberitahuan untuk menghapus indikator aktivitas.
+    Selalu lakukan ini; jika makan animasi akan terus berjalan sekalipun operasi telah selesai. Juga
+    ingatlah mengubah teks pemberitahuan untuk menunjukkan bahwa operasi telah selesai.
+</p>
+<p>
+    Untuk melihat cara kerja indikator aktivitas, lihat cuplikan terdahulu. Cari lokasi baris-baris berikut:
+</p>
+<pre>
+// Sets the progress indicator to a max value, the current completion
+// percentage, and "determinate" state
+mBuilder.setProgress(100, incr, false);
+// Issues the notification
+mNotifyManager.notify(0, mBuilder.build());
+</pre>
+<p>
+    Ganti baris yang telah Anda temukan dengan baris berikut:
+</p>
+<pre>
+ // Sets an activity indicator for an operation of indeterminate length
+mBuilder.setProgress(0, 0, true);
+// Issues the notification
+mNotifyManager.notify(0, mBuilder.build());
+</pre>
+
+<h2 id="metadata">Metadata Pemberitahuan</h2>
+
+<p>Pemberitahuan dapat disortir sesuai metadata yang Anda tetapkan dengan
+metode {@link android.support.v4.app.NotificationCompat.Builder} berikut:</p>
+
+<ul>
+    <li>{@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()}
+    memberi tahu sistem cara menangani pemberitahuan aplikasi Anda bila perangkat berada dalam mode Priority
+    (misalnya, jika pemberitahuan menyatakan suatu panggilan masuk, pesan instan, atau alarm).</li>
+    <li>{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} menyebabkan
+    pemberitahuan dengan bidang prioritas diatur ke {@code PRIORITY_MAX} atau {@code PRIORITY_HIGH}
+    muncul dalam jendela kecil mengambang jika pemberitahuan juga memiliki suara atau getaran.</li>
+    <li>{@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()}
+    memungkinkan Anda menambahkan daftar orang ke pemberitahuan. Aplikasi Anda bisa menggunakannya untuk memberi isyarat pada
+    sistem bahwa sistem harus mengelompokkan bersama pemberitahuan dari orang-orang yang ditetapkan, atau memberi peringkat lebih penting pada pemberitahuan
+    untuk orang-orang ini.</li>
+</ul>
+
+<div class="figure" style="width:230px">
+  <img src="{@docRoot}images/ui/notifications/heads-up.png" alt="" width="" height="" id="figure3" />
+  <p class="img-caption">
+    <strong>Gambar 3.</strong> Aktivitas layar penuh yang menampilkan pemberitahuan pendahuluan
+  </p>
+</div>
+
+<h2 id="Heads-up">Pemberitahuan Pendahuluan</h2>
+
+<p>Dengan Android 5.0 (API level 21), pemberitahuan bisa muncul dalam jendela kecil mengambang
+(yang disebut juga dengan <em>pemberitahuan pendahuluan</em>) saat perangkat aktif
+(yakni, perangkat dibuka kuncinya dan layarnya menyala). Pemberitahuan ini
+muncul seperti bentuk ringkas pemberitahuan Anda, hanya saja
+pemberitahuan pendahuluan juga menampilkan tombol tindakan. Pengguna bisa menindaklanjuti atau mengabaikan,
+pemberitahuan pendahuluan tanpa meninggalkan aplikasi saat ini.</p>
+
+<p>Contoh-contoh kondisi yang dapat memicu pemberitahuan pendahuluan antara lain:</p>
+
+<ul>
+  <li>Aktivitas pengguna berada dalam mode layar penuh (aplikasi menggunakan
+{@link android.app.Notification#fullScreenIntent}), atau</li>
+  <li>Pemberitahuan memiliki prioritas tinggi dan menggunakan nada dering atau
+    getaran</li>
+</ul>
+
+<h2 id="lockscreenNotification">Pemberitahuan Layar Kunci</h2>
+
+<p>Dengan rilis Android 5.0 (API level 21), pemberitahuan kini dapat muncul pada
+layar kunci. Aplikasi Anda bisa menggunakan fungsionalitas ini untuk menyediakan kontrol pemutaran media dan
+tindakan umum lainnya. Pengguna bisa memilih lewat Settings apakah akan menampilkan pemberitahuan pada layar kunci, dan
+Anda bisa mendesain apakah pemberitahuan aplikasi akan terlihat pada layar kunci.</p>
+
+<h3 id="visibility">Mengatur Visibilitas</h3>
+
+<p>Aplikasi Anda bisa mengatur level detail terlihat pada pemberitahuan yang ditampilkan di
+layar kunci aman. Anda memanggil {@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()}
+dan menetapkan salah satu nilai berikut:</p>
+
+<ul>
+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} menampilkan isi lengkap
+    pemberitahuan.</li>
+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} tidak menampilkan bagian apa pun dari
+    pemberitahuan ini pada layar kunci.</li>
+    <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} menampilkan informasi dasar,
+    misalnya ikon dan judul isi pemberitahuan, namun menyembunyikan isi lengkap pemberitahuan.</li>
+</ul>
+
+<p>Bila {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} telah diatur, Anda juga bisa
+menyediakan versi alternatif isi pemberitahuan yang menyembunyikan detail tertentu. Misalnya,
+aplikasi SMS dapat menampilkan pemberitahuan yang menampilkan <em>Anda memiliki 3 pesan teks baru</em>, namun menyembunyikan
+isi dan pengirim pesan. Untuk menyediakan pemberitahuan alternatif ini, buat dahulu pemberitahuan
+pengganti menggunakan {@link android.support.v4.app.NotificationCompat.Builder}. Bila Anda membuat
+objek pemberitahuan privat, lampirkan pemberitahuan pengganti melalui metode
+{@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()}
+.</p>
+
+<h3 id="controllingMedia">Mengontrol Pemutaran Media pada Layar Kunci</h3>
+
+<p>Dalam Android 5.0 (API level 21) layar kunci tidak lagi menampilkan kontrol media
+berdasarkan {@link android.media.RemoteControlClient}, yang sekarang telah dihilangkan. Sebagai gantinya, gunakan
+template {@link android.app.Notification.MediaStyle} dengan metode
+{@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
+, yang mengubah tindakan menjadi ikon yang bisa diklik.</p>
+
+<p class="note"><strong>Catatan:</strong> Template dan metode {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()}
+tidak disertakan dalam pustaka dukungan, sehingga fitur-fitur ini berjalan pada Android 5.0 dan yang lebih tinggi
+saja.</p>
+
+<p>Untuk menampilkan kontrol pemutaran media di layar kunci dalam Android 5.0, atur visibilitas
+ke {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC}, seperti dijelaskan di atas. Kemudian tambahkan
+tindakan dan atur template {@link android.app.Notification.MediaStyle}, seperti dijelaskan dalam contoh kode
+berikut:</p>
+
+<pre>
+Notification notification = new Notification.Builder(context)
+    // Show controls on lock screen even when user hides sensitive content.
+    .setVisibility(Notification.VISIBILITY_PUBLIC)
+    .setSmallIcon(R.drawable.ic_stat_player)
+    // Add media control buttons that invoke intents in your media service
+    .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0
+    .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent)  // #1
+    .addAction(R.drawable.ic_next, "Next", nextPendingIntent)     // #2
+    // Apply the media style template
+    .setStyle(new Notification.MediaStyle()
+    .setShowActionsInCompactView(1 /* #1: pause button */)
+    .setMediaSession(mMediaSession.getSessionToken())
+    .setContentTitle("Wonderful music")
+    .setContentText("My Awesome Band")
+    .setLargeIcon(albumArtBitmap)
+    .build();
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Dihilangkannya {@link android.media.RemoteControlClient}
+memiliki implikasi lebih jauh untuk mengontrol media. Lihat
+<a href="{@docRoot}about/versions/android-5.0.html#MediaPlaybackControl">Kontrol Pemutaran Media</a>
+untuk informasi selengkapnya tentang API baru untuk mengelola sesi media dan mengontrol pemutaran.</p>
+
+
+<!-- ------------------------------------------------------------------------------------------ -->
+<h2 id="CustomNotification">Layout Pemberitahuan Custom</h2>
+<p>
+    Kerangka kerja pemberitahuan memungkinkan Anda mendefinisikan layout pemberitahuan custom, yang
+    mendefinisikan penampilan pemberitahuan dalam objek {@link android.widget.RemoteViews}.
+    Pemberitahuan dengan layout custom serupa pemberitahuan normal, namun dibuat berdasarkan
+    {@link android.widget.RemoteViews} yang didefinisikan dalam file layout XML.
+</p>
+<p>
+    Tinggi yang tersedia untuk layout pemberitahuan custom bergantung pada tampilan pemberitahuan. Layout
+    tampilan normal dibatasi hingga 64 dp, dan layout tampilan yang diperluas dibatasi hingga 256 dp.
+</p>
+<p>
+    Untuk mendefinisikan layout pemberitahuan custom, mulailah dengan membuat instance
+    objek {@link android.widget.RemoteViews} yang memekarkan file layout XML. Kemudian,
+    sebagai ganti memanggil metode seperti
+    {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()},
+    panggil {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Untuk mengatur
+    detail isi pemberitahuan custom, gunakan metode dalam
+    {@link android.widget.RemoteViews} untuk mengatur nilai anak tampilan:
+</p>
+<ol>
+    <li>
+        Buat layout XML untuk pemberitahuan di file terpisah. Anda bisa menggunakan nama file
+apa saja yang diinginkan, namun Anda harus menggunakan ekstensi <code>.xml</code>
+    </li>
+    <li>
+        Dalam aplikasi Anda, gunakan metode {@link android.widget.RemoteViews} untuk mendefinisikan
+        ikon dan teks pemberitahuan. Masukkan objek {@link android.widget.RemoteViews} ini ke dalam
+        {@link android.support.v4.app.NotificationCompat.Builder} Anda dengan memanggil
+        {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Hindari
+        mengatur {@link android.graphics.drawable.Drawable} latar belakang pada
+        objek {@link android.widget.RemoteViews} Anda, karena warna teks bisa menjadi tidak terbaca.
+    </li>
+</ol>
+<p>
+    Kelas {@link android.widget.RemoteViews} juga menyertakan metode yang bisa Anda gunakan untuk
+    menambahkan {@link android.widget.Chronometer} atau {@link android.widget.ProgressBar}
+dengan mudah ke layout pemberitahuan Anda. Untuk informasi selengkapnya tentang cara membuat layout custom
+    pemberitahuan Anda, lihat dokumentasi acuan {@link android.widget.RemoteViews}.
+</p>
+<p class="caution">
+    <strong>Perhatian:</strong> Bila Anda menggunakan layout pemberitahuan custom, berhati-hatilah
+    untuk memastikan bahwa layout custom itu bekerja pada berbagai orientasi dan resolusi perangkat. Walaupun
+    berlaku bagi semua layout View, nasihat ini khususnya penting untuk pemberitahuan karena
+    ruang di laci pemberitahuan sangat terbatas. Jangan buat layout custom terlalu
+    kompleks, dan pastikan mengujinya di berbagai konfigurasi.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h4>Menggunakan sumber daya gaya untuk teks pemberitahuan custom</h4>
+<p>
+    Selalu gunakan sumber daya gaya untuk teks pemberitahuan custom. Warna latar belakang
+    pemberitahuan bisa bervariasi di berbagai perangkat dan versi, dan menggunakan sumber daya gaya
+    membantu Anda menangani hal ini. Mulai Android 2.3, sistem mendefinisikan sebuah gaya untuk
+    teks layout pemberitahuan standar. Jika Anda menggunakan gaya yang sama dalam aplikasi yang menargetkan Android
+    2.3 atau yang lebih tinggi, Anda akan memastikan bahwa teks terlihat pada latar belakang tampilan.
+</p>
diff --git a/docs/html-intl/intl/id/guide/topics/ui/overview.jd b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
new file mode 100644
index 0000000..ca8b420
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/overview.jd
@@ -0,0 +1,71 @@
+page.title=Ikhtisar UI
+@jd:body
+
+
+<p>Semua elemen antarmuka pengguna dalam aplikasi Android dibangun menggunakan objek {@link android.view.View} dan
+{@link android.view.ViewGroup}. {@link android.view.View} adalah objek yang menarik
+sesuatu di layar dan dapat berinteraksi dengan pengguna. {@link android.view.ViewGroup} merupakan sebuah
+objek yang menyimpan objek {@link android.view.View} lainnya (dan {@link android.view.ViewGroup}) untuk
+mendefinisikan layout antarmuka.</p>
+
+<p>Android menyediakan sekumpulan subkelas {@link android.view.View} dan {@link
+android.view.ViewGroup} yang menawarkan kontrol input umum (seperti tombol dan bidang
+teks) serta berbagai model layout (seperti layout linear atau relatif).</p>
+
+
+<h2 id="Layout">Layout Antarmuka Pengguna</h2>
+
+<p>Antarmuka pengguna untuk setiap komponen aplikasi Anda didefinisikan menggunakan hierarki objek {link
+android.view.View} dan {@link android.view.ViewGroup}, seperti yang ditampilkan dalam gambar 1. Setiap kelompok tampilan
+merupakan kontainer tak terlihat yang mengelola tampilan anak, sementara tampilan anak ini dapat menjadi kontrol
+input atau widget lain yang
+menarik sebagian dari UI. Pohon hierarki ini bisa sederhana atau bisa juga kompleks bergantung kebutuhan
+(namun yang sederhana paling baik untuk kinerja).</p>
+
+<img src="{@docRoot}images/viewgroup.png" alt="" />
+<p class="img-caption"><strong>Gambar 1.</strong> Ilustrasi dari hierarki tampilan, yang mendefinisikan layout
+UI.</p>
+
+<p>Untuk mendeklarasikan layout, Anda dapat menyediakan objek {@link android.view.View} dalam kode dan mulai
+membangun pohon, namun cara termudah dan terefektif untuk mendefinisikan layout adalah dengan file XML.
+XML menawarkan struktur layout yang dapat dibaca manusia, serupa dengan HTML.</p>
+
+<p>Nama elemen XML untuk tampilan sesuai dengan kelas Android yang diwakilinya. Dengan demikian elemen
+<code>&lt;TextView&gt;</code> membuat widget {@link android.widget.TextView} dalam UI Anda,
+dan elemen <code>&lt;LinearLayout&gt;</code> membuat kelompok tampilan {@link android.widget.LinearLayout}
+. </p>
+
+<p>Misalnya, layout vertikal sederhana dengan tampilan teks dan tombol akan tampak seperti ini:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+              android:orientation="vertical" >
+    &lt;TextView android:id="@+id/text"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:text="I am a TextView" />
+    &lt;Button android:id="@+id/button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="I am a Button" />
+&lt;/LinearLayout>
+</pre>
+
+<p>Saat Anda memuat sumber daya layout di aplikasi, Android akan menginisialisasi setiap simpul layout menjadi
+objek runtime yang bisa Anda gunakan untuk mendefinisikan perilaku tambahan, query status objek, atau memodifikasi
+layout.</p>
+
+<p>Untuk mendapatkan panduan lengkap mengenai pembuatan layout UI, lihat <a href="declaring-layout.html">Layout
+XML</a>.
+
+
+<h2 id="UIComponents">Komponen Antarmuka Pengguna</h2>
+
+<p>Anda tidak harus membuat semua UI menggunakan objek {@link android.view.View} dan {link
+android.view.ViewGroup}. Android menyediakan beberapa komponen aplikasi yang menawarkan
+layout UI standar yang tinggal Anda definisikan kontennya. Komponen UI ini masing-masing
+memiliki set API unik yang dijelaskan dalam masing-masing dokumennya, seperti <a href="{@docRoot}guide/topics/ui/actionbar.html">Action-Bar</a>, <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialog</a>, dan <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Pemberitahuan Status</a>.</p>
+
+
diff --git a/docs/html-intl/intl/id/guide/topics/ui/settings.jd b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
new file mode 100644
index 0000000..89be52f
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/settings.jd
@@ -0,0 +1,1202 @@
+page.title=Pengaturan
+page.tags=preference,preferenceactivity,preferencefragment
+
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#Overview">Ikhtisar</a>
+    <ol>
+      <li><a href="#SettingTypes">Preferensi</a></li>
+    </ol>
+  </li>
+  <li><a href="#DefiningPrefs">Mendefinisikan Preferensi dalam XML</a>
+    <ol>
+      <li><a href="#Groups">Membuat grup pengaturan</a></li>
+      <li><a href="#Intents">Menggunakan intent</a></li>
+    </ol>
+  </li>
+  <li><a href="#Activity">Membuat Aktivitas Preferensi</a></li>
+  <li><a href="#Fragment">Menggunakan Fragmen Preferensi</a></li>
+  <li><a href="#Defaults">Mengatur Nilai Default</a></li>
+  <li><a href="#PreferenceHeaders">Menggunakan Header Preferensi</a>
+    <ol>
+      <li><a href="#CreateHeaders">Membuat file header</a></li>
+      <li><a href="#DisplayHeaders">Menampilkan header</a></li>
+      <li><a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</a></li>
+    </ol>
+  </li>
+  <li><a href="#ReadingPrefs">Preferensi Membaca</a>
+    <ol>
+      <li><a href="#Listening">Mendengarkan perubahan preferensi</a></li>
+    </ol>
+  </li>
+  <li><a href="#NetworkUsage">Mengelola Penggunaan Jaringan</a></li>
+  <li><a href="#Custom">Membangun Preferensi Custom</a>
+    <ol>
+      <li><a href="#CustomSelected">Menetapkan antarmuka pengguna</a></li>
+      <li><a href="#CustomSave">Menyimpan nilai pengaturan</a></li>
+      <li><a href="#CustomInitialize">Menginisialisasi nilai saat ini</a></li>
+      <li><a href="#CustomDefault">Menyediakan nilai default</a></li>
+      <li><a href="#CustomSaveState">Menyimpan dan memulihkan status Preferensi</a></li>
+    </ol>
+  </li>
+</ol>
+
+<h2>Kelas-kelas utama</h2>
+<ol>
+  <li>{@link android.preference.Preference}</li>
+  <li>{@link android.preference.PreferenceActivity}</li>
+  <li>{@link android.preference.PreferenceFragment}</li>
+</ol>
+
+
+<h2>Lihat juga</h2>
+<ol>
+  <li><a href="{@docRoot}design/patterns/settings.html">Panduan desain pengaturan</a></li>
+</ol>
+</div>
+</div>
+
+
+
+
+<p>Aplikasi sering kali menyertakan pengaturan yang memungkinkan pengguna memodifikasi fitur dan perilaku aplikasi. Misalnya,
+beberapa aplikasi memungkinkan pengguna untuk menetapkan apakah pemberitahuan diaktifkan atau menetapkan seberapa sering
+aplikasi menyinkronkan data dengan cloud.</p>
+
+<p>Jika ingin menyediakan pengaturan untuk aplikasi, Anda harus menggunakan
+API Android {@link android.preference.Preference} untuk membangun antarmuka yang konsisten dengan
+pengalaman pengguna di aplikasi Android yang lain (termasuk pengaturan sistem). Dokumen ini menjelaskan
+cara membangun pengaturan aplikasi Anda menggunakan API {@link android.preference.Preference}.</p>
+
+<div class="note design">
+<p><strong>Desain Pengaturan</strong></p>
+  <p>Untuk informasi tentang cara mendesain pengaturan Anda, bacalah panduan desain <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>.</p>
+</div>
+
+
+<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" />
+<p class="img-caption"><strong>Gambar 1.</strong> Cuplikan layar dari pengaturan
+aplikasi Messaging Android. Memilih item yang didefinisikan oleh {@link android.preference.Preference}
+akan membuka antarmuka untuk mengubah pengaturan.</p>
+
+
+
+
+<h2 id="Overview">Ikhtisar</h2>
+
+<p>Sebagai ganti menggunakan objek {@link android.view.View} untuk membangun antarmuka pengguna, pengaturan
+dibangun menggunakan berbagai subkelas dari kelas {@link android.preference.Preference} yang Anda
+deklarasikan dalam file XML.</p>
+
+<p>Objek {@link android.preference.Preference} adalah blok pembangun untuk pengaturan
+tunggal. Setiap {@link android.preference.Preference} muncul sebagai item dalam daftar dan menyediakan UI
+yang sesuai bagi pengguna untuk memodifikasi pengaturan. Misalnya, {@link
+android.preference.CheckBoxPreference} membuat item daftar yang menampilkan kotak cek, dan {@link
+android.preference.ListPreference} membuat item yang membuka dialog berisi daftar pilihan.</p>
+
+<p>Setiap {@link android.preference.Preference} yang Anda tambahkan memiliki pasangan nilai-kunci yang sesuai yang
+digunakan sistem untuk menyimpan pengaturan dalam file {@link android.content.SharedPreferences}
+default untuk pengaturan aplikasi Anda. Bila pengguna mengubah pengaturan, sistem akan memperbarui nilai
+yang bersangkutan dalam file {@link android.content.SharedPreferences} untuk Anda. Satu-satunya saat di mana Anda harus
+berinteraksi langsung dengan file {@link android.content.SharedPreferences} yang terkait adalah bila Anda
+perlu membaca nilai untuk menentukan perilaku aplikasi berdasarkan pengaturan pengguna.</p>
+
+<p>Nilai yang tersimpan di {@link android.content.SharedPreferences} untuk setiap pengaturan bisa berupa
+tipe data berikut:</p>
+
+<ul>
+  <li>Boolean</li>
+  <li>Float</li>
+  <li>Int</li>
+  <li>Long</li>
+  <li>String</li>
+  <li>String {@link java.util.Set}</li>
+</ul>
+
+<p>Oleh karena UI pengaturan aplikasi Anda dibangun menggunakan objek {@link android.preference.Preference}
+sebagai ganti
+objek {@link android.view.View}, Anda perlu menggunakan {@link android.app.Activity} khusus atau
+subkelas {@link android.app.Fragment} untuk menampilkan pengaturan daftar:</p>
+
+<ul>
+  <li>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0 (API level 10 dan yang lebih rendah), Anda harus
+membangun aktivitas sebagai ekstensi dari kelas {@link android.preference.PreferenceActivity}.</li>
+  <li>Pada Android 3.0 dan yang lebih baru, sebaiknya Anda menggunakan {@link android.app.Activity} biasa
+yang menjadi host {@link android.preference.PreferenceFragment} yang menampilkan pengaturan aplikasi Anda.
+Akan tetapi, Anda juga bisa menggunakan {@link android.preference.PreferenceActivity} untuk membuat layout dua panel
+bagi layar besar bila Anda memiliki beberapa grup pengaturan.</li>
+</ul>
+
+<p>Cara mengatur {@link android.preference.PreferenceActivity} Anda dan instance {@link
+android.preference.PreferenceFragment} dibahas di bagian tentang <a href="#Activity">Membuat Aktivitas Preferensi</a> dan <a href="#Fragment">Menggunakan
+Fragmen Preferensi</a>.</p>
+
+
+<h3 id="SettingTypes">Preferensi</h3>
+
+<p>Setiap pengaturan untuk aplikasi Anda diwakili oleh subkelas khusus dari kelas {@link
+android.preference.Preference}. Setiap subkelas menyertakan seperangkat properti utama yang memungkinkan Anda
+untuk menetapkan berbagai hal seperti judul pengaturan dan nilai default. Setiap subkelas juga menyediakan
+antarmuka pengguna dan properti khusus miliknya sendiri. Misalnya, gambar 1 menampilkan cuplikan layar dari
+ pengaturan aplikasi Messaging. Setiap item daftar dalam layar pengaturan didukung oleh objek {@link
+android.preference.Preference} berbeda.</p>
+
+<p>Beberapa preferensi yang paling umum adalah:</p>
+
+<dl>
+  <dt>{@link android.preference.CheckBoxPreference}</dt>
+  <dd>Menampilkan item dengan kotak cek untuk pengaturan yang diaktifkan atau dinonaktifkan. Nilai
+tersimpan adalah boolean (<code>true</code> jika diberi tanda cek).</dd>
+
+  <dt>{@link android.preference.ListPreference}</dt>
+  <dd>Membuka dialog berisi daftar tombol radio. Nilai
+tersimpan bisa berupa tipe nilai apa pun yang didukung (tercantum di atas).</dd>
+
+  <dt>{@link android.preference.EditTextPreference}</dt>
+  <dd>Membuka dialog berisi widget {@link android.widget.EditText}. Nilai tersimpan adalah {@link
+java.lang.String}.</dd>
+</dl>
+
+<p>Lihat kelas {@link android.preference.Preference} untuk mengetahui daftar subkelas lain dan
+propertinya.</p>
+
+<p>Tentu saja, kelas bawaan tidak mengakomodasi setiap kebutuhan dan aplikasi Anda mungkin memerlukan
+sesuatu yang lebih khusus. Misalnya, platform saat ini tidak menyediakan kelas {@link
+android.preference.Preference} untuk mengambil nomor atau tanggal. Anda mungkin perlu mendefinisikan
+subkelas {@link android.preference.Preference} sendiri. Untuk bantuan melakukannya, lihat bagian tentang <a href="#Custom">Membangun Preferensi Custom</a>.</p>
+
+
+
+<h2 id="DefiningPrefs">Mendefinisikan Preferensi dalam XML</h2>
+
+<p>Meskipun bisa membuat instance objek {@link android.preference.Preference} baru saat runtime, Anda
+harus mendefinisikan daftar pengaturan dalam XML dengan hierarki objek
+{@link android.preference.Preference}. Menggunakan file XML untuk mendefinisikan sekumpulan pengaturan lebih disukai karena file
+menyediakan struktur yang mudah dibaca dan diperbarui. Selain itu, pengaturan aplikasi Anda
+umumnya telah ditetapkan sebelumnya, meskipun Anda masih bisa memodifikasi kumpulan tersebut saat runtime.</p>
+
+<p>Setiap subkelas {@link android.preference.Preference} bisa dideklarasikan dengan elemen XML yang
+cocok dengan nama kelas, seperti {@code &lt;CheckBoxPreference&gt;}.</p>
+
+<p>Anda harus menyimpan file XML dalam direktori {@code res/xml/}. Meskipun bisa memberi nama file
+sesuka Anda, biasanya file diberi nama {@code preferences.xml}. Biasanya Anda hanya memerlukan satu file,
+karena cabang di hierarki (yang membuka daftar pengaturanny sendiri) dideklarasikan menggunakan instance
+tersarang {@link android.preference.PreferenceScreen}.</p>
+
+<p class="note"><strong>Catatan:</strong> Jika ingin membuat layout multipanel untuk
+pengaturan, Anda memerlukan file XML terpisah untuk setiap fragmen.</p>
+
+<p>Simpul akar untuk file XML harus merupakan elemen {@link android.preference.PreferenceScreen
+&lt;PreferenceScreen&gt;}. Dalam elemen inilah tempat Anda menambahkan setiap {@link
+android.preference.Preference}. Setiap anak yang Anda tambahkan dalam elemen
+{@link android.preference.PreferenceScreen &lt;PreferenceScreen&gt;} akan tampak sebagai item
+tunggal dalam daftar pengaturan.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;CheckBoxPreference
+        android:key="pref_sync"
+        android:title="@string/pref_sync"
+        android:summary="@string/pref_sync_summ"
+        android:defaultValue="true" />
+    &lt;ListPreference
+        android:dependency="pref_sync"
+        android:key="pref_syncConnectionType"
+        android:title="@string/pref_syncConnectionType"
+        android:dialogTitle="@string/pref_syncConnectionType"
+        android:entries="@array/pref_syncConnectionTypes_entries"
+        android:entryValues="@array/pref_syncConnectionTypes_values"
+        android:defaultValue="@string/pref_syncConnectionTypes_default" />
+&lt;/PreferenceScreen>
+</pre>
+
+<p>Dalam contoh ini, terdapat {@link android.preference.CheckBoxPreference} dan {@link
+android.preference.ListPreference}. Kedua item tersebut menyertakan tiga atribut berikut:</p>
+
+<dl>
+  <dt>{@code android:key}</dt>
+  <dd>Atribut ini diperlukan untuk preferensi yang mempertahankan nilai data. Ini menetapkan kunci
+unik (string) yang digunakan sistem saat menyimpan nilai pengaturan ini dalam {@link
+android.content.SharedPreferences}.
+  <p>Instance satu-satunya di mana atribut ini <em>tidak diperlukan</em> adalah bila preferensi berupa
+{@link android.preference.PreferenceCategory} atau {@link android.preference.PreferenceScreen}, atau
+preferensi menetapkan {@link android.content.Intent} untuk dipanggil (dengan elemen <a href="#Intents">{@code &lt;intent&gt;}</a>) atau {@link android.app.Fragment} untuk ditampilkan (dengan atribut <a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
+android:fragment}</a>).</p>
+  </dd>
+  <dt>{@code android:title}</dt>
+  <dd>Ini menyediakan nama pengaturan yang bisa dilihat oleh pengguna.</dd>
+  <dt>{@code android:defaultValue}</dt>
+  <dd>Ini menetapkan nilai awal yang harus diatur sistem dalam file {@link
+android.content.SharedPreferences}. Anda harus memberikan nilai default untuk semua
+pengaturan.</dd>
+</dl>
+
+<p>Untuk informasi tentang semua atribut lain yang didukung, lihat dokumentasi {@link
+android.preference.Preference} (dan subkelas masing-masing).</p>
+
+
+<div class="figure" style="width:300px">
+  <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" />
+  <p class="img-caption"><strong>Gambar 2.</strong> Mengatur kategori
+    dengan judul. <br/><b>1.</b> Kategori ditetapkan oleh elemen {@link
+android.preference.PreferenceCategory &lt;PreferenceCategory&gt;}. <br/><b>2.</b> Judul
+ditetapkan dengan atribut {@code android:title}.</p>
+</div>
+
+
+<p>Bila daftar pengaturan Anda melebihi sekitar 10 item, Anda mungkin perlu menambahkan judul untuk
+mendefinisikan grup pengaturan atau menampilkan grup tersebut di
+layar terpisah. Opsi ini dijelaskan di bagian berikut.</p>
+
+
+<h3 id="Groups">Membuat grup pengaturan</h3>
+
+<p>Jika Anda menampilkan daftar 10 pengaturan atau lebih, pengguna
+mungkin akan kesulitan dalam memindai, memahami dan memprosesnya. Anda bisa mengatasinya dengan
+membagi sebagian atau semua pengaturan ke dalam beberapa grup, yang secara efektif akan mengubah satu daftar panjang menjadi beberapa daftar
+yang lebih pendek. Suatu grup pengaturan terkait bisa ditampilkan dalam salah satu dari dua cara:</p>
+
+<ul>
+  <li><a href="#Titles">Menggunakan judul</a></li>
+  <li><a href="#Subscreens">Menggunakan sublayar</a></li>
+</ul>
+
+<p>Anda bisa menggunakan salah satu atau keduanya untuk mengelola pengaturan aplikasi Anda. Saat
+memutuskan mana yang akan digunakan dan cara membagi pengaturan, Anda harus mengikuti pedoman dalam
+Panduan <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a> Desain Android.</p>
+
+
+<h4 id="Titles">Menggunakan judul</h4>
+
+<p>Jika ingin menyediakan divider dengan heading di antara grup pengaturan (seperti yang ditampilkan dalam gambar 2),
+tempatkan setiap grup objek {@link android.preference.Preference} di dalam {@link
+android.preference.PreferenceCategory}.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;PreferenceCategory
+        android:title="&#64;string/pref_sms_storage_title"
+        android:key="pref_key_storage_settings">
+        &lt;CheckBoxPreference
+            android:key="pref_key_auto_delete"
+            android:summary="&#64;string/pref_summary_auto_delete"
+            android:title="&#64;string/pref_title_auto_delete"
+            android:defaultValue="false"... />
+        &lt;Preference
+            android:key="pref_key_sms_delete_limit"
+            android:dependency="pref_key_auto_delete"
+            android:summary="&#64;string/pref_summary_delete_limit"
+            android:title="&#64;string/pref_title_sms_delete"... />
+        &lt;Preference
+            android:key="pref_key_mms_delete_limit"
+            android:dependency="pref_key_auto_delete"
+            android:summary="&#64;string/pref_summary_delete_limit"
+            android:title="&#64;string/pref_title_mms_delete" ... />
+    &lt;/PreferenceCategory>
+    ...
+&lt;/PreferenceScreen>
+</pre>
+
+
+<h4 id="Subscreens">Menggunakan sublayar</h4>
+
+<p>Jika ingin menempatkan grup pengaturan ke dalam sublayar (seperti yang ditampilkan dalam gambar 3), tempatkan grup
+objek {@link android.preference.Preference} di dalam {@link
+android.preference.PreferenceScreen}.</p>
+
+<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" />
+<p class="img-caption"><strong>Gambar 3.</strong> Mengatur sublayar. Elemen {@code
+&lt;PreferenceScreen&gt;}
+membuat item yang, bila dipilih, akan membuka daftar terpisah untuk menampilkan pengaturan tersarang.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+&lt;PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;!-- opens a subscreen of settings -->
+    &lt;PreferenceScreen
+        android:key="button_voicemail_category_key"
+        android:title="&#64;string/voicemail"
+        android:persistent="false">
+        &lt;ListPreference
+            android:key="button_voicemail_provider_key"
+            android:title="&#64;string/voicemail_provider" ... />
+        &lt;!-- opens another nested subscreen -->
+        &lt;PreferenceScreen
+            android:key="button_voicemail_setting_key"
+            android:title="&#64;string/voicemail_settings"
+            android:persistent="false">
+            ...
+        &lt;/PreferenceScreen>
+        &lt;RingtonePreference
+            android:key="button_voicemail_ringtone_key"
+            android:title="&#64;string/voicemail_ringtone_title"
+            android:ringtoneType="notification" ... />
+        ...
+    &lt;/PreferenceScreen>
+    ...
+&lt;/PreferenceScreen>
+</pre>
+
+
+<h3 id="Intents">Menggunakan intent</h3>
+
+<p>Dalam beberapa kasus, Anda mungkin ingin item preferensi untuk membuka beberapa aktivitas sebagai ganti
+layar pengaturan, seperti browser web untuk melihat halaman web. Untuk memanggil {@link
+android.content.Intent} saat pengguna memilih item preferensi, tambahkan elemen {@code &lt;intent&gt;}
+sebagai anak dari elemen {@code &lt;Preference&gt;} yang bersangkutan.</p>
+
+<p>Misalnya, berikut ini cara menggunakan item preferensi untuk membuka halaman web:</p>
+
+<pre>
+&lt;Preference android:title="@string/prefs_web_page" >
+    &lt;intent android:action="android.intent.action.VIEW"
+            android:data="http://www.example.com" />
+&lt;/Preference>
+</pre>
+
+<p>Anda bisa membuat intent implisit maupun eksplisit menggunakan atribut berikut:</p>
+
+<dl>
+  <dt>{@code android:action}</dt>
+    <dd>Tindakan yang akan ditetapkan, sesuai metode
+{@link android.content.Intent#setAction setAction()}.</dd>
+  <dt>{@code android:data}</dt>
+    <dd>Data yang akan ditetapkan, sesuai metode {@link android.content.Intent#setData setData()}.</dd>
+  <dt>{@code android:mimeType}</dt>
+    <dd>Tipe MIME yang akan ditetapkan, sesuai metode
+{@link android.content.Intent#setType setType()}.</dd>
+  <dt>{@code android:targetClass}</dt>
+    <dd>Bagian kelas dari nama komponen, sesuai metode {@link android.content.Intent#setComponent
+setComponent()}.</dd>
+  <dt>{@code android:targetPackage}</dt>
+    <dd>Bagian paket dari nama komponen, sesuai metode {@link
+android.content.Intent#setComponent setComponent()}.</dd>
+</dl>
+
+
+
+<h2 id="Activity">Membuat Aktivitas Preferensi</h2>
+
+<p>Untuk menampilkan pengaturan Anda dalam suatu aktivitas, perluas kelas {@link
+android.preference.PreferenceActivity}. Ini adalah ekstensi dari kelas {@link
+android.app.Activity} biasa yang menampilkan daftar pengaturan berdasarkan hierarki objek {@link
+android.preference.Preference}. {@link android.preference.PreferenceActivity}
+secara otomatis mempertahankan pengaturan yang dikaitkan dengan setiap {@link
+android.preference.Preference} bila pengguna membuat perubahan.</p>
+
+<p class="note"><strong>Catatan:</strong> Jika Anda mengembangkan aplikasi untuk Android 3.0 dan
+yang lebih tinggi, sebaiknya gunakan {@link android.preference.PreferenceFragment}. Pindah ke bagian
+berikutnya tentang <a href="#Fragment">Menggunakan Fragmen Preferensi</a>.</p>
+
+<p>Hal paling penting untuk diingat adalah jangan memuat layout tampilan selama callback {@link
+android.preference.PreferenceActivity#onCreate onCreate()}. Sebagai gantinya, panggil {@link
+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
+menambahkan preferensi yang telah Anda deklarasikan dalam file XML ke aktivitas. Misalnya, berikut ini adalah kode minimum
+polos yang diperlukan untuk {@link android.preference.PreferenceActivity} fungsional:</p>
+
+<pre>
+public class SettingsActivity extends PreferenceActivity {
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.preferences);
+    }
+}
+</pre>
+
+<p>Ini sebenarnya kode yang cukup untuk beberapa aplikasi, karena segera setelah pengguna memodifikasi preferensi,
+sistem akan menyimpan perubahan tersebut ke file {@link android.content.SharedPreferences} default yang
+bisa dibaca oleh komponen aplikasi Anda lainnya bila Anda perlu memeriksa pengaturan pengguna. Akan tetapi,
+banyak aplikasi, yang memerlukan kode lebih sedikit untuk mendengarkan perubahan yang terjadi pada preferensi.
+Untuk informasi tentang mendengarkan perubahan di file {@link android.content.SharedPreferences},
+lihat bagian tentang <a href="#ReadingPrefs">Preferensi Membaca</a>.</p>
+
+
+
+
+<h2 id="Fragment">Menggunakan Fragmen Preferensi</h2>
+
+<p>Jika Anda mengembangkan Android 3.0 (API level 11) dan yang lebih tinggi, Anda harus menggunakan {@link
+android.preference.PreferenceFragment} untuk menampilkan daftar objek {@link android.preference.Preference}
+Anda. Anda bisa menambahkan {@link android.preference.PreferenceFragment} ke aktivitas apa pun,&mdash;Anda tidak
+perlu menggunakan {@link android.preference.PreferenceActivity}.</p>
+
+<p><a href="{@docRoot}guide/components/fragments.html">Fragmen</a> menyediakan arsitektur yang lebih
+fleksibel untuk aplikasi Anda, dibandingkan hanya menggunakan aktivitas, apa pun jenis
+aktivitas yang Anda bangun. Dengan sendirinya, kami menyarankan Anda menggunakan {@link
+android.preference.PreferenceFragment} untuk mengontrol tampilan pengaturan Anda sebagai ganti {@link
+android.preference.PreferenceActivity} bila memungkinkan.</p>
+
+<p>Implementasi {@link android.preference.PreferenceFragment} Anda bisa semudah
+mendefinisikan metode {@link android.preference.PreferenceFragment#onCreate onCreate()} untuk memuat
+file preferensi dengan {@link android.preference.PreferenceFragment#addPreferencesFromResource
+addPreferencesFromResource()}. Misalnya:</p>
+
+<pre>
+public static class SettingsFragment extends PreferenceFragment {
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Load the preferences from an XML resource
+        addPreferencesFromResource(R.xml.preferences);
+    }
+    ...
+}
+</pre>
+
+<p>Anda nanti bisa menambahkan fragmen ini ke {@link android.app.Activity} seperti yang Anda lakukan untuk
+{@link android.app.Fragment} lainnya. Misalnya:</p>
+
+<pre>
+public class SettingsActivity extends Activity {
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Display the fragment as the main content.
+        getFragmentManager().beginTransaction()
+                .replace(android.R.id.content, new SettingsFragment())
+                .commit();
+    }
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> {@link android.preference.PreferenceFragment} tidak memiliki
+objek {@link android.content.Context} sendiri. Jika memerlukan objek {@link android.content.Context}
+, Anda bisa memanggil {@link android.app.Fragment#getActivity()}. Akan tetapi, berhati-hatilah untuk memanggil
+{@link android.app.Fragment#getActivity()} hanya bila fragmen telah dikaitkan dengan aktivitas. Bila
+fragmen belum dikaitkan, atau terlepas saat akhir daur hidupnya, {@link
+android.app.Fragment#getActivity()} akan mengembalikan nol.</p>
+
+
+<h2 id="Defaults">Mengatur Nilai Default</h2>
+
+<p>Preferensi yang Anda buat mungkin mendefinisikan beberapa perilaku penting untuk aplikasi, jadi Anda
+perlu menginisialisasi file {@link android.content.SharedPreferences} yang terkait dengan
+nilai default untuk setiap {@link android.preference.Preference} bila pengguna menggunakan aplikasi
+Anda untuk pertama kali.</p>
+
+<p>Hal pertama yang harus Anda lakukan adalah menetapkan nilai default untuk setiap objek {@link
+android.preference.Preference}
+di file XML Anda menggunakan atribut {@code android:defaultValue}. Nilainya bisa berupa tipe data
+apa saja yang sesuai untuk objek {@link android.preference.Preference} bersangkutan. Misalnya:
+</p>
+
+<pre>
+&lt;!-- default value is a boolean -->
+&lt;CheckBoxPreference
+    android:defaultValue="true"
+    ... />
+
+&lt;!-- default value is a string -->
+&lt;ListPreference
+    android:defaultValue="@string/pref_syncConnectionTypes_default"
+    ... />
+</pre>
+
+<p>Kemudian, dari metode {@link android.app.Activity#onCreate onCreate()} dalam aktivitas utama aplikasi
+Anda&mdash;dan dalam aktivitas lainnya yang digunakan pengguna untuk masuk ke aplikasi Anda untuk pertama kali
+&mdash;panggil {@link android.preference.PreferenceManager#setDefaultValues
+setDefaultValues()}:</p>
+
+<pre>
+PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);
+</pre>
+
+<p>Memanggil ini selama {@link android.app.Activity#onCreate onCreate()} akan memastikan aplikasi
+Anda diinisialisasi dengan pengaturan default, yang mungkin perlu
+dibaca oleh aplikasi Anda untuk menentukan beberapa perilaku (seperti apakah akan mengunduh data pada
+jaringan seluler).</p>
+
+<p>Metode ini membutuhkan tiga argumen:</p>
+<ul>
+  <li>{@link android.content.Context} aplikasi Anda.</li>
+  <li>ID sumber daya untuk file XML preferensi yang ingin Anda atur nilai defaultnya.</li>
+  <li>Boolean menunjukkan apakah nilai default harus diatur lebih dari satu kali.
+<p>Bila <code>false</code>, sistem akan mengatur nilai default hanya jika metode ini belum pernah
+dipanggil sebelumnya (atau {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES}
+dalam file preferensi berbagi nilai default salah).</p></li>
+</ul>
+
+<p>Selama Anda mengatur argumen ketiga ke <code>false</code>, Anda bisa dengan aman memanggil metode ini
+setiap kali aktivitas Anda memulai tanpa mengesampingkan preferensi tersimpan pengguna dengan mengatur ulang preferensi tersebut ke
+default. Akan tetapi, jika mengatur ke <code>true</code>, Anda akan mengesampingkan nilai
+sebelumnya dengan default.</p>
+
+
+
+<h2 id="PreferenceHeaders">Menggunakan Header Preferensi</h2>
+
+<p>Dalam kasus yang jarang terjadi, Anda mungkin perlu mendesain pengaturan agar layar pertama
+hanya menampilkan daftar <a href="#Subscreens">sublayar</a> (seperti dalam aplikasi Setting pada sistem,
+seperti yang ditampilkan dalam gambar 4 dan 5). Bila mengembangkan desain seperti itu untuk Android 3.0 dan yang lebih tinggi, Anda
+harus menggunakan fitur "header" yang baru di Android 3.0, sebagai ganti membangun sublayar dengan elemen
+{@link android.preference.PreferenceScreen} tersarang.</p>
+
+<p>Untuk membangun pengaturan dengan header, Anda perlu:</p>
+<ol>
+  <li>Memisahkan setiap grup pengaturan ke dalam instance {@link
+android.preference.PreferenceFragment} terpisah. Ini berarti, setiap grup pengaturan memerlukan file XML
+terpisah.</li>
+  <li>Membuat file header XML yang mencantumkan daftar setiap grup pengaturan dan mendeklarasikan fragmen mana
+yang berisi daftar pengaturan yang sesuai.</li>
+  <li>Memperluas kelas {@link android.preference.PreferenceActivity} untuk menjadi host pengaturan Anda.</li>
+  <li>Mengimplementasikan callback {@link
+android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} untuk menetapkan file
+header.</li>
+</ol>
+
+<p>Manfaat besar dalam menggunakan desain ini adalah karena {@link android.preference.PreferenceActivity}
+secara otomatis akan menampilkan layout dua panel yang ditampilkan dalam gambar 4 bila dijalankan pada layar besar.</p>
+
+<p>Bahkan jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda bisa membangun
+aplikasi untuk menggunakan {@link android.preference.PreferenceFragment} bagi presentasi dua panel pada perangkat
+yang lebih baru sementara tetap mendukung hierarki multilayar biasa pada perangkat
+yang lebih lama (lihat bagian tentang <a href="#BackCompatHeaders">Mendukung versi yang lebih lama dengan
+header preferensi</a>).</p>
+
+<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
+<p class="img-caption"><strong>Gambar 4.</strong> Layout dua panel dengan header. <br/><b>1.</b> Header
+didefinisikan dengan file header XML. <br/><b>2.</b> Setiap grup pengaturan didefinisikan dengan
+{@link android.preference.PreferenceFragment} yang ditetapkan oleh elemen {@code &lt;header&gt;} dalam
+file header.</p>
+
+<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" />
+<p class="img-caption"><strong>Gambar 5.</strong> Perangkat handset dengan header pengaturan. Bila sebuah
+item dipilih, {@link android.preference.PreferenceFragment} terkait akan menggantikan
+header.</p>
+
+
+<h3 id="CreateHeaders" style="clear:left">Membuat file header</h3>
+
+<p>Setiap grup pengaturan dalam daftar header Anda akan ditetapkan oleh elemen {@code &lt;header&gt;}
+tunggal dalam elemen {@code &lt;preference-headers&gt;} akar. Misalnya:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;header
+        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
+        android:title="@string/prefs_category_one"
+        android:summary="@string/prefs_summ_category_one" />
+    &lt;header
+        android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
+        android:title="@string/prefs_category_two"
+        android:summary="@string/prefs_summ_category_two" >
+        &lt;!-- key/value pairs can be included as arguments for the fragment. -->
+        &lt;extra android:name="someKey" android:value="someHeaderValue" />
+    &lt;/header>
+&lt;/preference-headers>
+</pre>
+
+<p>Dengan atribut {@code android:fragment}, setiap header mendeklarasikan instance {@link
+android.preference.PreferenceFragment} yang harus terbuka saat pengguna memilih header.</p>
+
+<p>Elemen {@code &lt;extras&gt;} memungkinkan Anda meneruskan pasangan nilai-kunci ke fragmen di {@link
+android.os.Bundle}. Fragmen bisa mengambil argumen dengan memanggil {@link
+android.app.Fragment#getArguments()}. Anda bisa meneruskan argumen ke fragmen dengan berbagai
+alasan, namun satu alasan yang baik adalah untuk menggunakan kembali subkelas yang sama dari {@link
+android.preference.PreferenceFragment} untuk setiap grup dan menggunakan argumen untuk menetapkan file
+XML preferensi mana yang harus dimuat fragmen.</p>
+
+<p>Misalnya, ada fragmen yang bisa digunakan ulang untuk berbagai grup pengaturan, bila setiap
+header mendefinisikan argumen {@code &lt;extra&gt;} dengan kunci {@code "settings"}:</p>
+
+<pre>
+public static class SettingsFragment extends PreferenceFragment {
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        String settings = getArguments().getString("settings");
+        if ("notifications".equals(settings)) {
+            addPreferencesFromResource(R.xml.settings_wifi);
+        } else if ("sync".equals(settings)) {
+            addPreferencesFromResource(R.xml.settings_sync);
+        }
+    }
+}
+</pre>
+
+
+
+<h3 id="DisplayHeaders">Menampilkan header</h3>
+
+<p>Untuk menampilkan header preferensi, Anda harus mengimplementasikan metode callback {@link
+android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} dan memanggil
+{@link android.preference.PreferenceActivity#loadHeadersFromResource
+loadHeadersFromResource()}. Misalnya:</p>
+
+<pre>
+public class SettingsActivity extends PreferenceActivity {
+    &#64;Override
+    public void onBuildHeaders(List&lt;Header> target) {
+        loadHeadersFromResource(R.xml.preference_headers, target);
+    }
+}
+</pre>
+
+<p>Bila pengguna memilih item dari daftar header, sistem akan membuka {@link
+android.preference.PreferenceFragment} terkait.</p>
+
+<p class="note"><strong>Catatan:</strong> Saat menggunakan header preferensi, subkelas {@link
+android.preference.PreferenceActivity} Anda tidak perlu mengimplementasikan metode {@link
+android.preference.PreferenceActivity#onCreate onCreate()}, karena tugas
+yang diperlukan untuk aktivitas hanyalah memuat header.</p>
+
+
+<h3 id="BackCompatHeaders">Mendukung versi yang lebih lama dengan header preferensi</h3>
+
+<p>Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda tetap bisa menggunakan header untuk
+menyediakan layout dua panel saat berjalan pada Android 3.0 dan yang lebih tinggi. Anda hanya perlu membuat
+file XML preferensi tambahan yang menggunakan elemen {@link android.preference.Preference
+&lt;Preference&gt;} dasar yang berperilaku seperti item header (untuk digunakan oleh Android
+versi yang lebih lama).</p>
+
+<p>Akan tetapi, sebagai ganti membuka {@link android.preference.PreferenceScreen} baru, setiap elemen {@link
+android.preference.Preference &lt;Preference&gt;} mengirimkan {@link android.content.Intent} ke
+{@link android.preference.PreferenceActivity} yang menetapkan file XML preferensi mana yang
+akan dimuat.</p>
+
+<p>Misalnya, ini adalah file XML untuk header preferensi yang menggunakan Android 3.0
+dan yang lebih tinggi ({@code res/xml/preference_headers.xml}):</p>
+
+<pre>
+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;header
+        android:fragment="com.example.prefs.SettingsFragmentOne"
+        android:title="@string/prefs_category_one"
+        android:summary="@string/prefs_summ_category_one" />
+    &lt;header
+        android:fragment="com.example.prefs.SettingsFragmentTwo"
+        android:title="@string/prefs_category_two"
+        android:summary="@string/prefs_summ_category_two" />
+&lt;/preference-headers>
+</pre>
+
+<p>Dan ini adalah file preferensi yang menyediakan header yang sama untuk versi yang lebih lama dari
+Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p>
+
+<pre>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;Preference
+        android:title="@string/prefs_category_one"
+        android:summary="@string/prefs_summ_category_one"  >
+        &lt;intent
+            android:targetPackage="com.example.prefs"
+            android:targetClass="com.example.prefs.SettingsActivity"
+            android:action="com.example.prefs.PREFS_ONE" />
+    &lt;/Preference>
+    &lt;Preference
+        android:title="@string/prefs_category_two"
+        android:summary="@string/prefs_summ_category_two" >
+        &lt;intent
+            android:targetPackage="com.example.prefs"
+            android:targetClass="com.example.prefs.SettingsActivity"
+            android:action="com.example.prefs.PREFS_TWO" />
+    &lt;/Preference>
+&lt;/PreferenceScreen>
+</pre>
+
+<p>Karena dukungan untuk {@code &lt;preference-headers&gt;} telah ditambahkan di Android 3.0, sistem akan memanggil
+{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} di {@link
+android.preference.PreferenceActivity} hanya saat berjalan pada Android 3.0 atau yang lebih tinggi. Untuk memuat
+file header "lama" ({@code preference_headers_legacy.xml}), Anda harus memeriksa versi Android
+dan, jika versi tersebut lebih lama dari Android 3.0 ({@link
+android.os.Build.VERSION_CODES#HONEYCOMB}), panggil {@link
+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk
+memuat file header lama. Misalnya:</p>
+
+<pre>
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    ...
+
+    if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
+        // Load the legacy preferences headers
+        addPreferencesFromResource(R.xml.preference_headers_legacy);
+    }
+}
+
+// Called only on Honeycomb and later
+&#64;Override
+public void onBuildHeaders(List&lt;Header> target) {
+   loadHeadersFromResource(R.xml.preference_headers, target);
+}
+</pre>
+
+<p>Satu-satunya hal yang perlu dilakukan adalah menangani {@link android.content.Intent} yang diteruskan ke
+aktivitas untuk mengidentifikasi file preferensi yang akan dimuat. Jadi ambillah tindakan intent dan bandingkan dengan
+string tindakan yang diketahui yang telah Anda gunakan dalam tag {@code &lt;intent&gt;} XML preferensi:</p>
+
+<pre>
+final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
+...
+
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    String action = getIntent().getAction();
+    if (action != null &amp;&amp; action.equals(ACTION_PREFS_ONE)) {
+        addPreferencesFromResource(R.xml.preferences);
+    }
+    ...
+
+    else if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
+        // Load the legacy preferences headers
+        addPreferencesFromResource(R.xml.preference_headers_legacy);
+    }
+}
+</pre>
+
+<p>Ketahuilah bahwa panggilan berturut-turut ke {@link
+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} akan
+menumpuk semua preferensi ke dalam satu daftar, jadi pastikan bahwa ini hanya dipanggil sekali dengan mengikatkan syarat
+ke pernyataan else-if.</p>
+
+
+
+
+
+<h2 id="ReadingPrefs">Preferensi Membaca</h2>
+
+<p>Secara default, semua preferensi aplikasi Anda disimpan ke file yang bisa diakses dari mana saja
+di dalam aplikasi dengan memanggil metode statis {@link
+android.preference.PreferenceManager#getDefaultSharedPreferences
+PreferenceManager.getDefaultSharedPreferences()}. Ini akan mengembalikan objek {@link
+android.content.SharedPreferences} berisi semua pasangan nilai-kunci yang terkait
+dengan objek {@link android.preference.Preference} yang digunakan di {@link
+android.preference.PreferenceActivity} Anda.</p>
+
+<p>Misalnya, inilah cara membaca salah satu nilai preferensi dari aktivitas lain dalam aplikasi
+Anda:</p>
+
+<pre>
+SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
+String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
+</pre>
+
+
+
+<h3 id="Listening">Mendengarkan perubahan preferensi</h3>
+
+<p>Ada beberapa alasan yang membuat Anda perlu mendapatkan pemberitahuan segera setelah pengguna mengubah salah satu
+preferensi. Untuk menerima callback saat perubahan terjadi pada salah satu preferensi,
+implementasikan antarmuka {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
+SharedPreference.OnSharedPreferenceChangeListener} dan daftarkan listener untuk objek
+{@link android.content.SharedPreferences} dengan memanggil {@link
+android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
+registerOnSharedPreferenceChangeListener()}.</p>
+
+<p>Antarmuka hanya memiliki satu metode callback, {@link
+android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged
+onSharedPreferenceChanged()}, dan mungkin lebih mudah mengimplementasikan antarmuka sebagai bagian dari
+aktivitas Anda. Misalnya:</p>
+
+<pre>
+public class SettingsActivity extends PreferenceActivity
+                              implements OnSharedPreferenceChangeListener {
+    public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType";
+    ...
+
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+        String key) {
+        if (key.equals(KEY_PREF_SYNC_CONN)) {
+            Preference connectionPref = findPreference(key);
+            // Set summary to be the user-description for the selected value
+            connectionPref.setSummary(sharedPreferences.getString(key, ""));
+        }
+    }
+}
+</pre>
+
+<p>Dalam contoh ini, metode akan memeriksa apakah pengaturan yang diubah adalah untuk kunci preferensi yang diketahui. Ini akan
+memanggil {@link android.preference.PreferenceActivity#findPreference findPreference()} untuk mendapatkan objek
+{@link android.preference.Preference} yang diubah agar bisa memodifikasi rangkuman item
+menjadi keterangan pada pilihan pengguna. Ini berarti, bila pengaturan adalah {@link
+android.preference.ListPreference} atau pengaturan multipilihan, Anda harus memanggil {@link
+android.preference.Preference#setSummary setSummary()} bila pengaturan berubah ke tampilkan
+status saat ini (seperti pengaturan Sleep yang ditampilkan dalam gambar 5).</p>
+
+<p class="note"><strong>Catatan:</strong> Seperti dijelaskan dalam dokumen Desain Android tentang <a href="{@docRoot}design/patterns/settings.html">Pengaturan</a>, kami merekomendasikan Anda untuk memperbarui
+rangkuman {@link android.preference.ListPreference} setiap kali pengguna mengubah preferensi untuk
+menjelaskan pengaturan saat ini.</p>
+
+<p>Untuk manajemen daur hidup yang baik di aktivitas, kami merekomendasikan Anda untuk mendaftarkan dan mencabut pendaftaran
+{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} selama callback {@link
+android.app.Activity#onResume} dan {@link android.app.Activity#onPause}:</p>
+
+<pre>
+&#64;Override
+protected void onResume() {
+    super.onResume();
+    getPreferenceScreen().getSharedPreferences()
+            .registerOnSharedPreferenceChangeListener(this);
+}
+
+&#64;Override
+protected void onPause() {
+    super.onPause();
+    getPreferenceScreen().getSharedPreferences()
+            .unregisterOnSharedPreferenceChangeListener(this);
+}
+</pre>
+
+<p class="caution"><strong>Perhatian:</strong> Bila Anda memanggil {@link
+android.content.SharedPreferences#registerOnSharedPreferenceChangeListener
+registerOnSharedPreferenceChangeListener()}, pengelola preferensi saat ini tidak akan
+menyimpan referensi kuat ke listener. Anda harus menyimpan referensi
+kuat bagi listener, atau referensi akan rentan terhadap pengumpulan sampah. Kami
+merekomendasikan Anda untuk mempertahankan referensi bagi listener dalam data instance objek
+yang akan ada selama Anda memerlukan listener tersebut.</p>
+
+<p>Misalnya, dalam kode berikut, caller tidak menyimpan referensi ke
+listener. Akibatnya, listener akan dikenakan pengumpulan sampah,
+dan suatu saat nanti akan gagal:</p>
+
+<pre>
+prefs.registerOnSharedPreferenceChangeListener(
+  // Bad! The listener is subject to garbage collection!
+  new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+});
+</pre>
+
+<p>Sebagai gantinya, simpan referensi ke listener dalam bidang data instance
+objek yang akan ada selama listener dibutuhkan:</p>
+
+<pre>
+SharedPreferences.OnSharedPreferenceChangeListener listener =
+    new SharedPreferences.OnSharedPreferenceChangeListener() {
+  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+    // listener implementation
+  }
+};
+prefs.registerOnSharedPreferenceChangeListener(listener);
+</pre>
+
+<h2 id="NetworkUsage">Mengelola Penggunaan Jaringan</h2>
+
+
+<p>Mulai Android 4.0, aplikasi Settings untuk sistem memungkinkan pengguna melihat seberapa besar
+data jaringan yang digunakan aplikasi mereka saat berada di latar depan dan latar belakang. Kemudian pengguna bisa
+menonaktifkan penggunaan data latar belakang untuk aplikasi individual. Agar pengguna tidak menonaktifkan akses
+aplikasi ke data dari latar belakang, Anda harus menggunakan koneksi data secara efisien dan mengizinkan
+pengguna untuk menyaring penggunaan data aplikasi melalui pengaturan aplikasi Anda.<p>
+
+<p>Misalnya, Anda bisa mengizinkan pengguna untuk mengontrol seberapa sering aplikasi menyinkronkan data, apakah aplikasi
+hanya melakukan pengunggahan/pengunduhan bila ada Wi-Fi, apakah aplikasi menggunakan data saat roaming, dll. Dengan
+tersedianya kontrol ini bagi pengguna, mereka kemungkinan besar tidak akan menonaktifkan akses aplikasi ke data
+saat mendekati batas yang mereka tetapkan dalam Settings pada sistem, karena mereka bisa mengontrol secara tepat
+seberapa besar data yang digunakan aplikasi Anda.</p>
+
+<p>Setelah menambahkan preferensi yang diperlukan dalam {@link android.preference.PreferenceActivity} Anda
+untuk mengontrol kebiasaan data aplikasi, Anda harus menambahkan filter intent untuk {@link
+android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} dalam file manifes Anda. Misalnya:</p>
+
+<pre>
+&lt;activity android:name="SettingsActivity" ... >
+    &lt;intent-filter>
+       &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+       &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p>Filter intent ini menunjukkan pada sistem bahwa ini adalah aktivitas yang mengontrol penggunaan
+data aplikasi Anda. Jadi, saat pengguna memeriksa seberapa banyak data yang digunakan oleh aplikasi dari
+aplikasi Settings pada sistem, tombol <em>View application settings</em> akan tersedia dan menjalankan
+{@link android.preference.PreferenceActivity} sehingga pengguna bisa menyaring seberapa besar data yang digunakan
+aplikasi Anda.</p>
+
+
+
+
+
+
+
+<h2 id="Custom">Membangun Preferensi Custom</h2>
+
+<p>Kerangka kerja Android menyertakan berbagai subkelas {@link android.preference.Preference} yang
+memungkinkan Anda membangun UI untuk beberapa macam tipe pengaturan.
+Akan tetapi, Anda mungkin menemukan pengaturan yang diperlukan bila tidak ada solusi bawaan, seperti
+picker nomor atau picker tanggal. Dalam hal demikian, Anda akan perlu membuat preferensi custom dengan memperluas
+kelas {@link android.preference.Preference} atau salah satu subkelas lainnya.</p>
+
+<p>Bila memperluas kelas {@link android.preference.Preference}, ada beberapa hal
+penting yang perlu Anda lakukan:</p>
+
+<ul>
+  <li>Menetapkan antarmuka pengguna yang akan muncul saat pengguna memilih pengaturan.</li>
+  <li>Menyimpan nilai pengaturan bila perlu.</li>
+  <li>Menginisialisasi {@link android.preference.Preference} dengan nilai saat ini (atau default)
+bila muncul di tampilan.</li>
+  <li>Menyediakan nilai default bila diminta oleh sistem.</li>
+  <li>Jika {@link android.preference.Preference} menyediakan UI sendiri (seperti dialog), simpan
+dan pulihkan status untuk menangani perubahan daur hidup (seperti saat pengguna memutar layar).</li>
+</ul>
+
+<p>Bagian berikut menjelaskan cara melakukan setiap tugas ini.</p>
+
+
+
+<h3 id="CustomSelected">Menetapkan antarmuka pengguna</h3>
+
+  <p>Jika secara langsung memperluas kelas {@link android.preference.Preference}, Anda perlu mengimplementasikan
+{@link android.preference.Preference#onClick()} untuk mendefinisikan tindakan yang terjadi bila pengguna
+memilih item tersebut. Akan tetapi, sebagian besar pengaturan custom memperluas {@link android.preference.DialogPreference} untuk
+menampilkan dialog, sehingga menyederhanakan prosedur. Bila memperluas {@link
+android.preference.DialogPreference}, Anda harus memanggil {@link
+android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} selama di
+konstruktor kelas untuk menetapkan layout dialog.</p>
+
+  <p>Misalnya, beri ini konstruktor untuk {@link
+android.preference.DialogPreference} custom yang mendeklarasikan layout dan menetapkan teks untuk tombol dialog
+negatif dan positif default:</p>
+
+<pre>
+public class NumberPickerPreference extends DialogPreference {
+    public NumberPickerPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setDialogLayoutResource(R.layout.numberpicker_dialog);
+        setPositiveButtonText(android.R.string.ok);
+        setNegativeButtonText(android.R.string.cancel);
+
+        setDialogIcon(null);
+    }
+    ...
+}
+</pre>
+
+
+
+<h3 id="CustomSave">Menyimpan nilai pengaturan</h3>
+
+<p>Anda bisa menyimpan nilai pengaturan kapan saja dengan memanggil salah satu metode {@code persist*()} kelas {@link
+android.preference.Preference}, seperti {@link
+android.preference.Preference#persistInt persistInt()} jika nilai pengaturan adalah integer atau
+{@link android.preference.Preference#persistBoolean persistBoolean()} untuk menyimpan boolean.</p>
+
+<p class="note"><strong>Catatan:</strong> Setiap {@link android.preference.Preference} hanya bisa menyimpan satu
+tipe data, jadi Anda harus menggunakan metode {@code persist*()} yang tepat untuk tipe data yang digunakan
+oleh {@link android.preference.Preference} custom Anda.</p>
+
+<p>Bila Anda memilih untuk mempertahankannya, pengaturan bisa bergantung pada kelas {@link
+android.preference.Preference} yang Anda perluas. Jika Anda memperluas {@link
+android.preference.DialogPreference}, maka Anda harus mempertahankan nilai hanya jika dialog
+tertutup karena hasil positif (pengguna memilih tombol "OK").</p>
+
+<p>Bila {@link android.preference.DialogPreference} tertutup, sistem akan memanggil metode {@link
+android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Metode mencakup argumen
+boolean yang menetapkan apakah hasil pengguna "positif"&mdash;jika nilainya
+<code>true</code>, maka pengguna memilih tombol positif dan Anda harus menyimpan nilai baru. Misalnya:
+</p>
+
+<pre>
+&#64;Override
+protected void onDialogClosed(boolean positiveResult) {
+    // When the user selects "OK", persist the new value
+    if (positiveResult) {
+        persistInt(mNewValue);
+    }
+}
+</pre>
+
+<p>Dalam contoh ini, <code>mNewValue</code> adalah anggota kelas yang menampung nilai
+pengaturan saat ini. Memanggil {@link android.preference.Preference#persistInt persistInt()} akan menyimpan nilai
+ke file {@link android.content.SharedPreferences} (secara otomatis menggunakan kunci yang
+ditetapkan dalam file XML untuk {@link android.preference.Preference} ini).</p>
+
+
+<h3 id="CustomInitialize">Menginisialisasi nilai saat ini</h3>
+
+<p>Bila sistem menambahkan {@link android.preference.Preference} Anda ke layar, ia
+akan memanggil {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} untuk memberi tahu
+Anda apakah pengaturan memiliki nilai yang dipertahankan. Jika tidak ada nilai yang dipertahankan, panggilan ini
+akan menyediakan nilai default bagi Anda.</p>
+
+<p>Metode {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} akan meneruskan
+boolean, <code>restorePersistedValue</code>, untuk menunjukkan apakah nilai dipertahankan
+untuk pengaturan. Jika <code>true</code>, maka Anda harus mengambil nilai yang dipertahankan dengan memanggil
+salah satu metode {@code getPersisted*()} kelas {@link
+android.preference.Preference}, seperti {@link
+android.preference.Preference#getPersistedInt getPersistedInt()} untuk nilai integer. Anda biasanya
+perlu mengambil nilai yang dipertahankan agar bisa memperbarui UI dengan benar untuk merefleksikan
+nilai yang tersimpan sebelumnya.</p>
+
+<p>Jika <code>restorePersistedValue</code> adalah <code>false</code>, maka Anda
+harus menggunakan nilai default yang diteruskan dalam argumen kedua.</p>
+
+<pre>
+&#64;Override
+protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
+    if (restorePersistedValue) {
+        // Restore existing state
+        mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
+    } else {
+        // Set default state from the XML attribute
+        mCurrentValue = (Integer) defaultValue;
+        persistInt(mCurrentValue);
+    }
+}
+</pre>
+
+<p>Setiap metode {@code getPersisted*()} memerlukan argumen yang menetapkan
+nilai default untuk digunakan jika tidak ada nilai yang dipertahankan atau kunci tidak ada. Dalam contoh
+di atas, konstanta lokal yang digunakan untuk menetapkan nilai default dalam kasus {@link
+android.preference.Preference#getPersistedInt getPersistedInt()} tidak bisa mengembalikan nilai yang dipertahankan.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Anda <strong>tidak bisa</strong> menggunakan
+<code>defaultValue</code> sebagai nilai default dalam metode {@code getPersisted*()}, karena
+nilainya selalu nol bila <code>restorePersistedValue</code> adalah <code>true</code>.</p>
+
+
+<h3 id="CustomDefault">Menyediakan nilai default</h3>
+
+<p>Jika instance kelas {@link android.preference.Preference} Anda menetapkan nilai default
+(dengan atribut {@code android:defaultValue}), maka
+sistem akan memanggil {@link android.preference.Preference#onGetDefaultValue
+onGetDefaultValue()} bila membuat instance objek untuk mengambil nilai. Anda harus mengimplementasikan
+metode ini agar sistem bisa menyimpan nilai default dalam {@link
+android.content.SharedPreferences}. Misalnya:</p>
+
+<pre>
+&#64;Override
+protected Object onGetDefaultValue(TypedArray a, int index) {
+    return a.getInteger(index, DEFAULT_VALUE);
+}
+</pre>
+
+<p>Argumen metode menyediakan semua hal yang Anda perlukan: larik atribut dan posisi
+indeks dari {@code android:defaultValue}, yang harus Anda ambil. Alasan Anda harus
+mengimplementasikan metode ini untuk mengekstrak nilai default dari atribut adalah karena Anda harus menetapkan
+nilai default lokal untuk atribut jika nilai tidak didefinisikan.</p>
+
+
+
+<h3 id="CustomSaveState">Menyimpan dan memulihkan status Preferensi</h3>
+
+<p>Seperti halnya {@link android.view.View} di layout, subkelas {@link android.preference.Preference}
+Anda bertanggung jawab menyimpan dan memulihkan statusnya jika aktivitas atau fragmen
+di-restart (seperti saat pengguna memutar layar). Untuk menyimpan
+dan memulihkan status kelas {@link android.preference.Preference} dengan benar, Anda harus mengimplementasikan
+metode callback daur hidup {@link android.preference.Preference#onSaveInstanceState
+onSaveInstanceState()} dan {@link
+android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p>
+
+<p>Status {@link android.preference.Preference} Anda didefinisikan oleh objek yang mengimplementasikan
+antarmuka {@link android.os.Parcelable}. Kerangka kerja Android menyediakan objek seperti itu untuk Anda gunakan
+sebagai titik mulai untuk mendefinisikan objek status Anda: kelas {@link
+android.preference.Preference.BaseSavedState}.</p>
+
+<p>Untuk mendefinisikan cara kelas {@link android.preference.Preference} menyimpan statusnya, Anda harus
+memperluas kelas {@link android.preference.Preference.BaseSavedState}. Anda hanya perlu mengesampingkan
+ beberapa metode dan mendefinisikan objek {@link android.preference.Preference.BaseSavedState#CREATOR}
+.</p>
+
+<p>Untuk sebagian besar aplikasi, Anda bisa menyalin implementasi berikut dan cukup mengubah baris yang
+menangani {@code value} jika subkelas {@link android.preference.Preference} Anda menyimpan tipe
+data selain integer.</p>
+
+<pre>
+private static class SavedState extends BaseSavedState {
+    // Member that holds the setting's value
+    // Change this data type to match the type saved by your Preference
+    int value;
+
+    public SavedState(Parcelable superState) {
+        super(superState);
+    }
+
+    public SavedState(Parcel source) {
+        super(source);
+        // Get the current preference's value
+        value = source.readInt();  // Change this to read the appropriate data type
+    }
+
+    &#64;Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        // Write the preference's value
+        dest.writeInt(value);  // Change this to write the appropriate data type
+    }
+
+    // Standard creator object using an instance of this class
+    public static final Parcelable.Creator&lt;SavedState> CREATOR =
+            new Parcelable.Creator&lt;SavedState>() {
+
+        public SavedState createFromParcel(Parcel in) {
+            return new SavedState(in);
+        }
+
+        public SavedState[] newArray(int size) {
+            return new SavedState[size];
+        }
+    };
+}
+</pre>
+
+<p>Dengan implementasi {@link android.preference.Preference.BaseSavedState} di atas yang ditambahkan
+ke aplikasi Anda (biasanya sebagai subkelas dari subkelas {@link android.preference.Preference}), Anda
+nanti perlu mengimplementasikan metode {@link android.preference.Preference#onSaveInstanceState
+onSaveInstanceState()} dan {@link
+android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} untuk subkelas
+{@link android.preference.Preference} Anda.</p>
+
+<p>Misalnya:</p>
+
+<pre>
+&#64;Override
+protected Parcelable onSaveInstanceState() {
+    final Parcelable superState = super.onSaveInstanceState();
+    // Check whether this Preference is persistent (continually saved)
+    if (isPersistent()) {
+        // No need to save instance state since it's persistent,
+        // use superclass state
+        return superState;
+    }
+
+    // Create instance of custom BaseSavedState
+    final SavedState myState = new SavedState(superState);
+    // Set the state's value with the class member that holds current
+    // setting value
+    myState.value = mNewValue;
+    return myState;
+}
+
+&#64;Override
+protected void onRestoreInstanceState(Parcelable state) {
+    // Check whether we saved the state in onSaveInstanceState
+    if (state == null || !state.getClass().equals(SavedState.class)) {
+        // Didn't save the state, so call superclass
+        super.onRestoreInstanceState(state);
+        return;
+    }
+
+    // Cast state to custom BaseSavedState and pass to superclass
+    SavedState myState = (SavedState) state;
+    super.onRestoreInstanceState(myState.getSuperState());
+
+    // Set this Preference's widget to reflect the restored state
+    mNumberPicker.setValue(myState.value);
+}
+</pre>
+
diff --git a/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
new file mode 100644
index 0000000..0307b34
--- /dev/null
+++ b/docs/html-intl/intl/id/guide/topics/ui/ui-events.jd
@@ -0,0 +1,291 @@
+page.title=Kejadian Input
+parent.title=Antarmuka Pengguna
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#EventListeners">Event Listener</a></li>
+    <li><a href="#EventHandlers">Event Handler</a></li>
+    <li><a href="#TouchMode">Mode Sentuh</a></li>
+    <li><a href="#HandlingFocus">Menangani Fokus</a></li>
+  </ol>
+
+</div>
+</div>
+
+<p>Di Android, ada lebih dari satu cara untuk mencegat kejadian dari interaksi pengguna dengan aplikasi Anda.
+Saat mempertimbangkan kejadian dalam antarmuka pengguna Anda, pendekatannya adalah menangkap kejadian
+dari objek View tertentu yang digunakan pengguna untuk berinteraksi. Kelas View menyediakan sarana untuk melakukannya.</p>
+
+<p>Dalam berbagai kelas View yang akan digunakan untuk menyusun layout, Anda mungkin melihat beberapa metode callback
+publik yang tampak berguna untuk kejadian UI. Metode ini dipanggil oleh kerangka kerja Android ketika masing-masing
+tindakan terjadi pada objek itu. Misalnya, bila View (seperti Button/Tombol) disentuh,
+metode <code>onTouchEvent()</code> akan dipanggil pada objek itu. Akan tetapi, untuk mencegatnya, Anda harus memperluas
+kelas dan mengesampingkan metode itu. Akan tetapi, memperluas setiap objek View
+untuk menangani kejadian seperti itu tidaklah praktis. Karena itulah kelas View juga berisi
+sekumpulan antarmuka tersarang dengan callback yang jauh lebih mudah didefinisikan. Antarmuka ini,
+yang disebut <a href="#EventListeners">event listener</a>, merupakan tiket Anda untuk menangkap interaksi pengguna dengan UI.</p>
+
+<p>Walaupun Anda akan lebih sering menggunakan event listener ini untuk interaksi pengguna,
+mungkin ada saatnya Anda ingin memperluas kelas View, untuk membuat komponen custom.
+Mungkin Anda ingin memperluas kelas {@link android.widget.Button}
+untuk membuat sesuatu yang lebih menarik. Dalam hal ini, Anda akan dapat mendefinisikan perilaku kejadian default untuk kelas Anda dengan menggunakan
+kelas <a href="#EventHandlers">event handler</a>.</p>
+
+
+<h2 id="EventListeners">Event Listener</h2>
+
+<p>Event listener merupakan antarmuka di kelas {@link android.view.View} yang berisi metode
+callback tunggal. Metode ini akan dipanggil oleh kerangka kerja Android bila View yang
+telah didaftarkan dengan listener dipicu oleh interaksi pengguna dengan item dalam UI.</p>
+
+<p>Yang juga disertakan dalam antarmuka event listener adalah metode callback berikut ini:</p>
+
+<dl>
+  <dt><code>onClick()</code></dt>
+    <dd>Dari {@link android.view.View.OnClickListener}.
+    Ini dipanggil baik saat pengguna menyentuh item
+ (bila dalam mode sentuh), maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
+menekan tombol "enter" yang sesuai atau menekan trackball.</dd>
+  <dt><code>onLongClick()</code></dt>
+    <dd>Dari {@link android.view.View.OnLongClickListener}.
+    Ini dipanggil baik saat pengguna menyentuh dan menahan item (bila dalam mode sentuh),
+maupun memfokuskan pada item dengan tombol navigasi atau trackball dan
+menekan serta menahan tombol "enter" yang sesuai atau menekan dan menahan trackball (selama satu detik).</dd>
+  <dt><code>onFocusChange()</code></dt>
+    <dd>Dari {@link android.view.View.OnFocusChangeListener}.
+    Ini dipanggil saat pengguna menyusuri ke atau dari item, dengan menggunakan tombol navigasi atau trackball.</dd>
+  <dt><code>onKey()</code></dt>
+    <dd>Dari {@link android.view.View.OnKeyListener}.
+    Ini dipanggil saat pengguna memfokuskan pada item dan menekan atau melepas tombol fisik pada perangkat.</dd>
+  <dt><code>onTouch()</code></dt>
+    <dd>Dari {@link android.view.View.OnTouchListener}.
+    Ini dipanggil saat pengguna melakukan tindakan yang digolongkan sebagai kejadian sentuh, termasuk penekanan, pelepasan,
+atau gerak perpindahan pada layar (dalam batasan item itu).</dd>
+  <dt><code>onCreateContextMenu()</code></dt>
+    <dd>Dari {@link android.view.View.OnCreateContextMenuListener}.
+    Ini dipanggil saat Menu Konteks sedang dibuat (akibat "klik lama" terus-menerus). Lihat diskusi
+tentang menu konteks di panduan pengembang <a href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a>.
+</dd>
+</dl>
+
+<p>Metode ini satu-satunya yang menempati antarmukanya masing-masing. Untuk mendefinisikan salah satu metode ini
+dan menangani kejadian Anda, implementasikan antarmuka tersarang dalam Aktivitas Anda atau definisikan sebagai kelas anonim.
+Kemudian, teruskan satu
+instance implementasi Anda pada masing-masing metode <code>View.set...Listener()</code>. (Misalnya, panggil
+<code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>
+dan teruskan implementasi {@link android.view.View.OnClickListener OnClickListener} Anda.)</p>
+
+<p>Contoh di bawah menunjukkan cara mendaftarkan on-click listener untuk Button. </p>
+
+<pre>
+// Create an anonymous implementation of OnClickListener
+private OnClickListener mCorkyListener = new OnClickListener() {
+    public void onClick(View v) {
+      // do something when the button is clicked
+    }
+};
+
+protected void onCreate(Bundle savedValues) {
+    ...
+    // Capture our button from layout
+    Button button = (Button)findViewById(R.id.corky);
+    // Register the onClick listener with the implementation above
+    button.setOnClickListener(mCorkyListener);
+    ...
+}
+</pre>
+
+<p>Anda juga akan merasa lebih praktis mengimplementasikan OnClickListener sebagai bagian dari Aktivitas.
+Ini akan menghindari beban kelas ekstra dan alokasi objek. Misalnya:</p>
+<pre>
+public class ExampleActivity extends Activity implements OnClickListener {
+    protected void onCreate(Bundle savedValues) {
+        ...
+        Button button = (Button)findViewById(R.id.corky);
+        button.setOnClickListener(this);
+    }
+
+    // Implement the OnClickListener callback
+    public void onClick(View v) {
+      // do something when the button is clicked
+    }
+    ...
+}
+</pre>
+
+<p>Perhatikan bahwa callback <code>onClick()</code> dalam contoh di atas tidak memiliki
+nilai hasil, namun beberapa metode event listener lainnya harus mengembalikan boolean. Sebabnya
+bergantung pada kejadian. Untuk sebagian yang mengembalikan boolean, ini sebabnya:</p>
+<ul>
+  <li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> -
+    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
+    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
+    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
+    on-click listener lainnya.</li>
+  <li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> -
+    Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh.
+    Yaitu, mengembalikan <em>benar</em> untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini;
+    mengembalikan <em>salah</em> jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke
+    on-key listener lainnya.</li>
+  <li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> -
+    Ini mengembalikan boolean untuk menunjukkan apakah listener Anda telah menggunakan kejadian ini. Yang penting adalah
+kejadian ini bisa memiliki beberapa tindakan yang saling mengikuti. Jadi, jika Anda mengembalikan <em>salah</em>saat
+kejadian tindakan turun diterima, itu menunjukkan bahwa Anda belum menggunakan kejadian itu dan juga
+tidak tertarik dengan tindakan berikutnya dari kejadian ini. Karena itu, Anda tidak akan diminta untuk melakukan tindakan
+ lainnya dalam kejadian, seperti gerakan jari, atau kejadian tindakan naik yang akan terjadi.</li>
+</ul>
+
+<p>Ingatlah bahwa kejadian tombol fisik selalu disampaikan ke View yang sedang difokus. Kejadian ini dikirim mulai dari atas
+hierarki View, kemudian turun hingga tujuan yang sesuai. Jika View Anda (atau anak View Anda)
+saat ini sedang fokus, maka Anda dapat melihat kejadian berpindah melalui metode.<code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
+dispatchKeyEvent()}</code> Sebagai pengganti untuk menangkap kejadian penting melalui View, Anda juga dapat menerima
+semua kejadian dalam Aktivitas Anda dengan <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
+dan <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
+
+<p>Selain itu, saat memikirkan tentang input teks aplikasi Anda, ingatlah bahwa banyak perangkat yang hanya memiliki
+metode input perangkat lunak. Metode seperti itu tidak harus berbasis tombol; sebagian mungkin menggunakan input suara, tulisan tangan, dan seterusnya. Meskipun
+metode input menyajikan antarmuka seperti keyboard, itu umumnya <strong>tidak</strong> memicu keluarga kejadian
+<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>. Anda sama sekali tidak boleh
+membangun UI yang mengharuskan penekanan tombol tertentu dikontrol kecuali jika Anda ingin membatasi aplikasi Anda pada perangkat yang memiliki
+keyboard fisik. Khususnya, jangan mengandalkan metode ini untuk memvalidasi input saat pengguna menekan tombol
+enter; melainkan, gunakan tindakan seperti {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} untuk menandai
+metode input mengenai reaksi yang diharapkan aplikasi Anda, sehingga bisa mengubah UI-nya secara signifikan. Hindari anggapan
+tentang bagaimana metode input perangkat lunak seharusnya bekerja dan percayalah bahwa metode akan menyediakan teks yang sudah diformat bagi aplikasi Anda.</p>
+
+<p class="note"><strong>Catatan:</strong> Android akan memanggil event handler terlebih dahulu kemudian handler
+default yang sesuai dari definisi kelas. Karena itu, mengembalikan <em>benar</em> dari event listener ini akan menghentikan
+penyebaran kejadian ke event listener lain dan juga akan memblokir callback ke
+event handler default di View. Pastikan bahwa Anda ingin mengakhiri kejadian saat mengembalikan <em>true</em>.</p>
+
+
+<h2 id="EventHandlers">Event Handler</h2>
+
+<p>Jika Anda membuat komponen custom dari View, maka Anda dapat mendefinisikan penggunaan beberapa
+metode callback sebagai event handler default.
+Dalam dokumen tentang <a href="{@docRoot}guide/topics/ui/custom-components.html">Komponen
+Custom</a>, Anda akan melihat penggunaan beberapa callback umum untuk penanganan kejadian,
+termasuk:</p>
+<ul>
+  <li><code>{@link  android.view.View#onKeyDown}</code> - Dipanggil bila terjadi kejadian tombol baru.</li>
+  <li><code>{@link  android.view.View#onKeyUp}</code> - Dipanggil bila terjadi kejadian tombol naik.</li>
+  <li><code>{@link  android.view.View#onTrackballEvent}</code> - Dipanggil bila terjadi kejadian gerakan trackball.</li>
+  <li><code>{@link  android.view.View#onTouchEvent}</code> - Dipanggil bila terjadi kejadian gerakan layar sentuh.</li>
+  <li><code>{@link  android.view.View#onFocusChanged}</code> - Dipanggil bila View memperoleh atau kehilangan fokus.</li>
+</ul>
+<p>Ada beberapa metode lain yang harus Anda ketahui, yang bukan bagian dari kelas View,
+namun bisa berdampak langsung pada kemampuan Anda menangani kejadian. Jadi, saat mengelola kejadian yang lebih kompleks dalam
+layout, pertimbangkanlah metode-metode lain ini:</p>
+<ul>
+  <li><code>{@link  android.app.Activity#dispatchTouchEvent(MotionEvent)
+    Activity.dispatchTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
+    android.app.Activity} Anda mencegat semua kejadian sentuh sebelum dikirim ke jendela.</li>
+  <li><code>{@link  android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)
+    ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> - Ini memungkinkan {@link
+    android.view.ViewGroup} memantau kejadian saat dikirim ke View anak.</li>
+  <li><code>{@link  android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean)
+    ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> - Panggil ini
+    pada View induk untuk menunjukan larangan mencegat kejadian sentuh dengan <code>{@link
+    android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code>.</li>
+</ul>
+
+<h2 id="TouchMode">Mode Sentuh</h2>
+<p>
+Saat pengguna menyusuri antarmuka pengguna dengan tombol pengarah atau trackball, Anda
+perlu memberikan fokus pada item tindakan (seperti tombol) agar pengguna bisa mengetahui apa
+yang akan menerima input.  Akan tetapi jika perangkat memiliki kemampuan sentuh, dan pengguna
+mulai berinteraksi dengan antarmuka dengan menyentuhnya, maka Anda tidak perlu lagi
+menyorot item, atau memfokuskan pada View tertentu.  Karena itu, ada mode
+untuk interaksi yang bernama "mode sentuh".
+</p>
+<p>
+Untuk perangkat berkemampuan sentuh, setelah pengguna menyentuh layar, perangkat
+akan masuk ke mode sentuh.  Dari sini dan selanjutnya, hanya View dengan
+{@link android.view.View#isFocusableInTouchMode} benar yang akan dapat difokus, seperti widget pengedit teks.
+View lain yang dapat disentuh, seperti tombol, tidak akan difokus bila disentuh; View ini akan
+langsung memicu on-click listener bila ditekan.
+</p>
+<p>
+Kapan saja pengguna menekan tombol pengarah atau menggulir dengan trackball, perangkat akan
+keluar dari mode sentuh, dan mencari tampilan untuk difokuskan. Kini pengguna bisa melanjutkan interaksi
+dengan antarmuka pengguna tanpa menyentuh layar.
+</p>
+<p>
+Status mode sentuh dipertahankan di seluruh sistem (semua jendela dan aktivitas).
+Untuk query status saat ini, Anda bisa memanggil
+{@link android.view.View#isInTouchMode} untuk mengetahui apakah perangkat saat ini sedang dalam mode sentuh.
+</p>
+
+
+<h2 id="HandlingFocus">Menangani Fokus</h2>
+
+<p>Kerangka kerja ini akan menangani gerakan fokus rutin sebagai respons input pengguna.
+Ini termasuk mengubah fokus saat View dihapus atau disembunyikan, atau saat tersedia View
+baru. View menunjukkan kesediaannya untuk mengambil fokus
+melalui metode <code>{@link android.view.View#isFocusable()}</code>. Untuk mengubah apakah View bisa mengambil
+fokus, panggil <code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code>.  Saat dalam mode sentuh,
+Anda dapat me-query apakah View memungkinkan fokus dengan <code>{@link android.view.View#isFocusableInTouchMode()}</code>.
+Anda bisa mengubahnya dengan <code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code>.
+</p>
+
+<p>Gerakan fokus berdasarkan pada algoritma yang mencari tetangga terdekat dalam
+arah yang diberikan. Dalam kasus yang jarang terjadi, algoritma default mungkin
+tidak cocok dengan perilaku yang diinginkan pengembang. Dalam situasi ini, Anda bisa memberikan
+pengesampingan eksplisit dengan mengikuti atribut XML berikut dalam file layout:
+<var>nextFocusDown</var>, <var>nextFocusLeft</var>, <var>nextFocusRight</var>, dan
+<var>nextFocusUp</var>. Tambahkan salah satu atribut ini ke View <em>dari</em> mana fokus
+meninggalkan. Definisikan nilai atribut untuk menjadi ID View
+<em>ke</em> mana fokus harus diberikan. Misalnya:</p>
+<pre>
+&lt;LinearLayout
+    android:orientation="vertical"
+    ... >
+  &lt;Button android:id="@+id/top"
+          android:nextFocusUp="@+id/bottom"
+          ... />
+  &lt;Button android:id="@+id/bottom"
+          android:nextFocusDown="@+id/top"
+          ... />
+&lt;/LinearLayout>
+</pre>
+
+<p>Biasanya, dalam layout vertikal ini, navigasi ke atas dari Button pertama tidak akan membawa ke
+mana pun, tidak pula akan menyusuri ke bawah dari Button kedua. Karena sekarang Button atas telah
+mendefinisikan Button bawah sebagai <var>nextFocusUp</var> (dan sebaliknya), fokus navigasi akan
+silih berganti dari atas ke bawah dan bawah ke atas.</p>
+
+<p>Jika Anda ingin mendeklarasikan View sebagai dapat difokus dalam UI (bila biasanya tidak dapat difokus),
+tambahkan atribut XML <code>android:focusable</code> ke View, dalam deklarasi layout Anda.
+Atur nilai <var>true</var>. Anda juga bisa mendeklarasikan View
+sebagai dapat difokus saat dalam Mode Sentuh dengan <code>android:focusableInTouchMode</code>.</p>
+<p>Untuk meminta View tertentu difokus, panggil <code>{@link android.view.View#requestFocus()}</code>.</p>
+<p>Untuk mendengarkan kejadian fokus (diberi tahu bila View menerima atau kehilangan fokus), gunakan
+<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code>
+, seperti yang dibahas di bagian <a href="#EventListeners">Event Listener</a>, di atas.</p>
+
+
+
+<!--
+<h2 is="EventCycle">Event Cycle</h2>
+   <p>The basic cycle of a View is as follows:</p>
+   <ol>
+    <li>An event comes in and is dispatched to the appropriate View. The View
+    handles the event and notifies any listeners.</li>
+    <li>If, in the course of processing the event, the View's bounds may need
+    to be changed, the View will call {@link android.view.View#requestLayout()}.</li>
+    <li>Similarly, if in the course of processing the event the View's appearance
+    may need to be changed, the View will call {@link android.view.View#invalidate()}.</li>
+    <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
+    the framework will take care of measuring, laying out, and drawing the tree
+    as appropriate.</li>
+   </ol>
+
+   <p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on
+   the UI thread when calling any method on any View.
+   If you are doing work on other threads and want to update the state of a View
+   from that thread, you should use a {@link android.os.Handler}.
+   </p>
+-->
diff --git a/docs/html-intl/intl/id/training/articles/direct-boot.jd b/docs/html-intl/intl/id/training/articles/direct-boot.jd
new file mode 100644
index 0000000..a7e3cf3
--- /dev/null
+++ b/docs/html-intl/intl/id/training/articles/direct-boot.jd
@@ -0,0 +1,181 @@
+page.title=Direct Boot
+page.keywords=pratinjau,sdk,direct boot
+page.tags=androidn
+page.image=images/cards/card-nyc_2x.jpg
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#run">Meminta Akses untuk Berjalan Selama Direct Boot</a></li>
+    <li><a href="#access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</a></li>
+    <li><a href="#notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</a></li>
+    <li><a href="#migrating">Migrasi Data yang Ada</a></li>
+    <li><a href="#testing">Menguji Aplikasi Peka Enkripsi Anda</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Android N berjalan dalam mode <i>Direct Boot</i> yang aman
+bila perangkat telah dihidupkan namun pengguna tidak membuka
+kunci perangkat. Untuk mendukung hal ini, sistem menyediakan dua lokasi penyimpanan untuk data:</p>
+
+<ul>
+<li><i>Penyimpanan yang dienkripsi dengan kredensial</i>, yang merupakan lokasi penyimpanan default
+dan hanya tersedia setelah pengguna membuka kunci perangkat.</li>
+<li><i>Penyimpanan yang dienkripsi dengan perangkat</i>, yang merupakan lokasi penyimpanan yang tersedia
+selama mode Direct Boot dan setelah pengguna membuka kunci perangkat.</li>
+</ul>
+
+<p>Secara default, aplikasi tidak berjalan selama mode Direct Boot.
+Jika aplikasi Anda perlu melakukan tindakan selama mode Direct Boot, Anda bisa mendaftarkan
+komponen aplikasi yang harus dijalankan selama mode ini. Beberapa kasus penggunaan umum
+untuk aplikasi yang perlu dijalankan selama mode Direct Boot antara lain:</p>
+
+<ul>
+<li>Aplikasi yang telah menjadwalkan pemberitahuan, seperti aplikasi
+beker.</li>
+<li>Aplikasi yang menyediakan pemberitahuan pengguna yang penting, seperti aplikasi SMS.</li>
+<li>Aplikasi yang menyediakan layanan aksesibilitas, seperti TalkBack.</li>
+</ul>
+
+<p>Jika aplikasi Anda perlu mengakses data saat dijalankan dalam mode Direct Boot, gunakan
+penyimpanan yang dienkripsi dengan perangkat. Penyimpanan yang dienkripsi dengan perangkat berisi data
+yang dienkripsi dengan kunci yang hanya tersedia setelah perangkat melakukan
+booting yang berhasil diverifikasi.</p>
+
+<p>Untuk data yang harus dienkripsi dengan kunci yang dikaitkan dengan kredensial
+pengguna, seperti PIN atau kata sandi, gunakan penyimpanan yang dienkripsi dengan kredensial.
+Penyimpanan yang dienkripsi dengan kredensial hanya tersedia setelah pengguna berhasil
+membuka kunci perangkat, hingga saat pengguna menghidupkan ulang perangkat lagi. Jika
+pengguna mengaktifkan layar kunci setelah membuka kunci perangkat, hal ini tidak akan mengunci
+penyimpanan yang dienkripsi dengan kredensial.</p>
+
+<h2 id="run">Meminta Akses untuk Berjalan Selama Direct Boot</h2>
+
+<p>Aplikasi harus mendaftarkan komponennya pada sistem agar
+bisa berjalan selama mode Direct Boot atau mengakses
+penyimpanan yang dienkripsi dengan perangkat. Aplikasi mendaftar pada sistem dengan menandai komponen sebagai
+<i>peka enkripsi</i>. Untuk menandai komponen Anda sebagai peka enkripsi, setel atribut
+<code>android:directBootAware</code> ke true dalam manifes Anda.<p>
+
+<p>Komponen yang peka enkripsi bisa mendaftar untuk menerima pesan siaran
+<code>LOCKED_BOOT_COMPLETED</code> dari
+sistem bila perangkat telah dihidupkan ulang. Pada tahap ini
+penyimpanan yang dienkripsi dengan perangkat akan tersedia, dan komponen Anda bisa mengeksekusi tugas-tugas yang perlu
+dijalankan selama mode Direct Boot, seperti memicu alarm yang terjadwal.</p>
+
+<p>Cuplikan kode berikut adalah contoh cara mendaftarkan
+{@link android.content.BroadcastReceiver} sebagai peka enkripsi, dan menambahkan sebuah
+filter intent untuk <code>LOCKED_BOOT_COMPLETED</code>, dalam manifes aplikasi:</p>
+
+<pre>
+&lt;receiver
+  android:directBootAware="true" &gt;
+  ...
+  &lt;intent-filter&gt;
+    &lt;action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /&gt;
+  &lt;/intent-filter&gt;
+&lt;/receiver&gt;
+</pre>
+
+<p>Setelah pengguna membuka kunci perangkat, semua komponen bisa mengakses
+penyimpanan yang dienkripsi dengan perangkat serta penyimpanan yang dienkripsi dengan kredensial.</p>
+
+<h2 id="access">Mengakses Penyimpanan yang Dienkripsi dengan Perangkat</h2>
+
+<p>Untuk mengakses penyimpanan yang dienkripsi dengan perangkat, buat instance
+{@link android.content.Context} kedua dengan memanggil
+<code>Context.createDeviceProtectedStorageContext()</code>. Semua panggilan
+API penyimpanan yang dibuat menggunakan konteks ini mengakses penyimpanan yang dienkripsi dengan perangkat. Contoh
+berikut mengakses penyimpanan yang dienkripsi dengan perangkat dan membuka file data aplikasi
+yang ada:</p>
+
+<pre>
+Context directBootContext = appContext.createDeviceProtectedStorageContext();
+// Access appDataFilename that lives in device encrypted storage
+FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
+// Use inStream to read content...
+</pre>
+
+<p>Gunakan penyimpanan yang dienkripsi dengan perangkat hanya untuk
+informasi yang harus bisa diakses selama mode Direct Boot.
+Jangan gunakan penyimpanan yang dienkripsi dengan perangkat sebagai penyimpanan terenkripsi serba guna.
+Untuk informasi pengguna yang bersifat pribadi, atau data terenkripsi yang tidak diperlukan selama
+mode Direct Boot, gunakan penyimpanan yang dienkripsi dengan kredensial.</p>
+
+<h2 id="notification">Mendapatkan Pemberitahuan saat Pengguna Membuka Kunci</h2>
+
+<p>Setelah pengguna membuka kunci perangkat setelah restart, aplikasi Anda bisa beralih untuk
+mengakses penyimpanan yang dienkripsi dengan kredensial dan menggunakan layanan sistem biasa yang
+bergantung pada kredensial pengguna.</p>
+
+<p>Agar diberi tahu bila pengguna membuka kunci perangkat setelah boot ulang,
+daftarkan {@link android.content.BroadcastReceiver} dari komponen yang berjalan
+untuk mendengarkan pesan <code>ACTION_USER_UNLOCKED</code>. Atau, Anda bisa
+menerima pesan {@link android.content.Intent#ACTION_BOOT_COMPLETED
+ACTION_BOOT_COMPLETED} yang ada, yang sekarang menunjukkan bahwa perangkat telah dihidupkan dan
+pengguna telah membuka kunci perangkat.</p>
+
+<p>Anda bisa langsung kueri apakah pengguna telah membuka kunci perangkat dengan memanggil
+<code>UserManager.isUserUnlocked()</code>.</p>
+
+<h2 id="migrating">Migrasi Data yang Ada</h2>
+
+<p>Jika pengguna memperbarui perangkat mereka untuk menggunakan mode Direct Boot,
+data Anda yang ada mungkin perlu dipindahkan ke penyimpanan yang dienkripsi dengan perangkat. Gunakan
+<code>Context.moveSharedPreferencesFrom()</code> dan
+<code>Context.moveDatabaseFrom()</code> untuk memindahkan data preferensi dan
+basis data antara penyimpanan yang dienkripsi dengan kredensial dan penyimpanan yang dienkripsi dengan perangkat.</p>
+
+<p>Pertimbangkan dengan baik saat memutuskan data apa yang akan dipindahkan dari
+penyimpanan yang dienkripsi dengan kredensial ke penyimpanan yang dienkripsi dengan perangkat. Anda sebaiknya tidak memindahkan
+informasi pengguna yang bersifat rahasia, seperti kata sandi atau token otorisasi, ke
+penyimpanan yang dienkripsi dengan perangkat. Dalam beberapa skenario, Anda mungkin perlu mengelola
+set data terpisah pada dua tempat penyimpanan yang dienkripsi.</p>
+
+<h2 id="testing">Menguji Aplikasi Peka Enkripsi Anda</h2>
+
+<p>Uji aplikasi peka enkripsi Anda menggunakan mode Direct Boot baru. Ada
+dua cara untuk mengaktifkan Direct Boot.</p>
+
+<p class="caution"><strong>Perhatian:</strong> Mengaktifkan Direct Boot
+akan menghapus semua data pengguna pada perangkat.</p>
+
+<p>Pada perangkat yang didukung dengan Android N terpasang, aktifkan
+Direct Boot dengan melakukan salah satu hal berikut:</p>
+
+<ul>
+<li>Pada perangkat, aktifkan <b>Developer options</b> jika Anda belum melakukannya dengan
+masuk ke <b>Settings &gt; About phone</b>, dan menyentuh <b>Build number</b>
+tujuh kali. Setelah layar Developer options terbuka, masuk ke
+<b>Settings &gt; Developer options</b> dan pilih
+<b>Convert to file encryption</b>.</li>
+<li>Gunakan perintah shell adb berikut untuk mengaktifkan mode Direct Boot:
+<pre class="no-pretty-print">
+$ adb reboot-bootloader
+$ fastboot --wipe-and-use-fbe
+</pre>
+</li>
+</ul>
+
+<p>Mode emulasi Direct Boot juga tersedia, jika Anda perlu mengganti
+mode pada perangkat pengujian. Mode emulasi sebaiknya hanya digunakan selama
+pengembangan dan bisa menyebabkan kehilangan data. Untuk mengaktifkan mode emulasi Direct Boot,
+setel pola kunci pada perangkat, pilih "No thanks" jika ditanya mengenai
+layar start-up aman saat menetapkan pola kunci, kemudian gunakan
+perintah shell adb berikut:</p>
+
+<pre class="no-pretty-print">
+$ adb shell sm set-emulate-fbe true
+</pre>
+
+<p>Untuk menonaktifkan mode emulasi Direct Boot, gunakan perintah berikut:</p>
+
+<pre class="no-pretty-print">
+$ adb shell sm set-emulate-fbe false
+</pre>
+
+<p>Menggunakan perintah ini akan menyebabkan perangkat melakukan boot ulang.</p>
diff --git a/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
new file mode 100644
index 0000000..30aed6f
--- /dev/null
+++ b/docs/html-intl/intl/id/training/articles/scoped-directory-access.jd
@@ -0,0 +1,148 @@
+page.title=Scoped Directory Access
+page.keywords=pratinjau,sdk,scoped directory access
+page.tags=androidn
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#accessing">Mengakses Direktori Penyimpanan Eksternal</a></li>
+    <li><a href="#removable">Mengakses Direktori pada Media Lepas-Pasang</a></li>
+    <li><a href="#best">Praktik Terbaik</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Aplikasi seperti aplikasi foto biasanya hanya memerlukan akses ke direktori tertentu dalam
+penyimpanan eksternal, seperti direktori <code>Pictures</code>. Pendekatan
+yang ada dalam mengakses penyimpanan eksternal tidak didesain untuk memberi kemudahan
+akses direktori tertarget untuk tipe aplikasi ini. Misalnya:</p>
+
+<ul>
+<li>Meminta {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
+atau {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} dalam manifes Anda
+akan memungkinkan akses ke semua direktori publik pada penyimpanan eksternal, yang mungkin
+lebih banyak akses dari yang dibutuhkan aplikasi Anda.</li>
+<li>Menggunakan
+<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
+Access Framework</a> biasanya membuat pengguna Anda memilih direktori
+melalui UI sistem, yang tidak diperlukan jika aplikasi Anda selalu mengakses
+direktori eksternal yang sama.</li>
+</ul>
+
+<p>Android N menyediakan API baru yang disederhanakan untuk mengakses
+direktori penyimpanan eksternal umum. </p>
+
+<h2 id="accessing">Mengakses Direktori Penyimpanan Eksternal</h2>
+
+<p>Gunakan kelas <code>StorageManager</code> untuk mendapatkan instance
+<code>StorageVolume</code> yang tepat. Kemudian, buat intent dengan memanggil metode
+<code>StorageVolume.createAccessIntent()</code> dari instance itu.
+Gunakan intent ini untuk mengakses direktori penyimpanan eksternal. Untuk mendapatkan daftar
+semua volume yang tersedia, termasuk volume media lepas-pasang, gunakan
+<code>StorageManager.getVolumesList()</code>.</p>
+
+<p>Jika Anda memiliki informasi tentang file spesifik, gunakan
+<code>StorageManager.getStorageVolume(File)</code> untuk mendapatkan
+<code>StorageVolume</code> yang berisi file tersebut. Panggil
+<code>createAccessIntent()</code> pada <code>StorageVolume</code> ini untuk mengakses
+direktori penyimpanan eksternal untuk file tersebut.</p>
+
+<p>
+Di volume kedua, seperti kartu SD eksternal, teruskan null saat memanggil
+<code>StorageVolume.createAccessIntent()</code> untuk meminta akses ke seluruh
+volume, sebagai ganti direktori spesifik.
+<code>StorageVolume.createAccessIntent()</code> akan mengembalikan null jika Anda meneruskan
+null ke volume utama, atau jika Anda meneruskan nama direktori yang tidak valid.
+</p>
+
+<p>Cuplikan kode berikut adalah contoh cara membuka direktori
+<code>Pictures</code> dalam penyimpanan bersama utama:</p>
+
+<pre>
+StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
+StorageVolume volume = sm.getPrimaryVolume();
+Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
+startActivityForResult(intent, request_code);
+</pre>
+
+<p>Sistem ini mencoba untuk memberikan akses ke direktori eksternal, dan jika
+diperlukan mengonfirmasi akses dengan pengguna menggunakan UI yang disederhanakan:</p>
+
+<img src="{@docRoot}images/android-7.0/scoped-directory-access-framed.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-framed.png 1x,
+{@docRoot}images/android-7.0/scoped-directory-access-framed_2x.png 2x" />
+<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi yang meminta
+akses ke direktori Pictures.</p>
+
+<p>Jika pengguna memberi akses, sistem akan memanggil penggantian
+<code>onActivityResult()</code> Anda dengan kode hasil
+<code>Activity.RESULT_OK</code>, dan data intent yang berisi URI. Gunakan
+URI yang disediakan untuk mengakses informasi direktori, serupa dengan menggunakan URI
+yang dikembalikan oleh
+<a href="{@docRoot}guide/topics/providers/document-provider.html">Storage
+Access Framework</a>.</p>
+
+<p>Jika pengguna tidak memberi akses, sistem akan memanggil penggantian
+<code>onActivityResult()</code> Anda dengan kode hasil
+<code>Activity.RESULT_CANCELED</code>, dan data intent nol.</p>
+
+<p class="note"><b>Catatan</b>: Mendapatkan akses ke direktori eksternal tertentu
+juga akan memperoleh akses ke subdirektori dalam direktori tersebut.</p>
+
+<h2 id="removable">Mengakses Direktori pada Media Lepas-Pasang</h2>
+
+<p>Untuk menggunakan Scoped Directory Access guna mengakses direktori pada media lepas-pasang,
+pertama tambahkan {@link android.content.BroadcastReceiver} yang akan mendengarkan pemberitahuan
+{@link android.os.Environment#MEDIA_MOUNTED}, misalnya:</p>
+
+<pre>
+&lt;receiver
+    android:name=".MediaMountedReceiver"
+    android:enabled="true"
+    android:exported="true" &gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.intent.action.MEDIA_MOUNTED" /&gt;
+        &lt;data android:scheme="file" /&gt;
+    &lt;/intent-filter&gt;
+&lt;/receiver&gt;
+</pre>
+
+<p>Bila pengguna memasang media lepas-pasang, seperti kartu SD, sistem akan mengirimkan pemberitahuan
+{@link android.os.Environment#MEDIA_MOUNTED}. Pemberitahuan ini
+memberikan sebuah objek <code>StorageVolume</code> dalam data intent yang bisa
+Anda gunakan untuk mengakses direktori pada media lepas-pasang. Contoh berikut
+mengakses direktori <code>Pictures</code> pada media lepas-pasang:</p>
+
+<pre>
+// BroadcastReceiver has already cached the MEDIA_MOUNTED
+// notification Intent in mediaMountedIntent
+StorageVolume volume = (StorageVolume)
+    mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
+volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
+startActivityForResult(intent, request_code);
+</pre>
+
+<h2 id="best">Praktik Terbaik</h2>
+
+<p>Bila memungkinkan, pertahankan URI akses direktori eksternal sehingga Anda tidak perlu
+berulang kali meminta akses ke pengguna. Setelah pengguna memberikan akses, panggil
+<code>getContentResolver().takePersistableUriPermssion()</code> bersama
+URI akses direktori. Sistem akan mempertahankan URI dan permintaan
+akses berikutnya akan mengembalikan <code>RESULT_OK</code> dan tidak menampilkan UI konfirmasi kepada
+pengguna.</p>
+
+<p>Jika pengguna menolak akses ke direktori eksternal, jangan langsung
+meminta akses lagi. Berulang kali meminta akses akan menghasilkan pengalaman
+pengguna yang buruk. Jika permintaan ditolak oleh pengguna, dan aplikasi meminta akses
+lagi, UI akan menampilkan kotak centang <b>Don't ask again</b>:</p>
+
+<img src="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png" srcset="{@docRoot}images/android-7.0/scoped-directory-access-dont-ask.png 1x,
+{@docRoot}images/android-7.0/scoped-directory-access-dont-ask_2x.png 2x" />
+<p class="img-caption"><strong>Gambar 1.</strong> Sebuah aplikasi membuat
+permintaan kedua untuk mengakses media lepas-pasang.</p>
+
+<p>Jika pengguna memilih <b>Don't ask again</b> dan menolak permintaan,
+semua permintaan berikutnya untuk direktori yang diberikan dari aplikasi
+Anda secara otomatis akan ditolak, dan tidak ada UI permintaan yang akan ditampilkan ke pengguna.</p>
\ No newline at end of file
diff --git a/docs/html-intl/intl/id/training/articles/security-config.jd b/docs/html-intl/intl/id/training/articles/security-config.jd
new file mode 100644
index 0000000..e13429d
--- /dev/null
+++ b/docs/html-intl/intl/id/training/articles/security-config.jd
@@ -0,0 +1,747 @@
+page.title=Konfigurasi Keamanan Jaringan
+page.keywords=androidn,keamanan,jaringan
+page.image=images/cards/card-nyc_2x.jpg
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#manifest">Menambahkan File Konfigurasi Keamanan</a></li>
+  <li><a href="#CustomTrust">Menyesuaikan CA Tepercaya</a>
+      <ol>
+      <li><a href="#ConfigCustom">Mengonfigurasi CA Tepercaya Khusus</a></li>
+      <li><a href="#LimitingCas">Membatasi Set CA Tepercaya</a></li>
+      <li><a href="#TrustingAdditionalCas">Mempercayai CA Tambahan</a></li>
+      </ol>
+  </li>
+  <li><a href="#TrustingDebugCa">CA Debug Saja</a></li>
+  <li><a href="#UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</a></li>
+  <li><a href="#CertificatePinning">Menyematkan Sertifikat</a></li>
+  <li><a href="#ConfigInheritance">Perilaku Pewarisan Konfigurasi</a></li>
+  <li><a href="#FileFormat">Format File Konfigurasi</a></li>
+</ol>
+</div>
+</div>
+
+
+<p>
+  Android N menyertakan fitur
+  Network Security Configuration yang memungkinkan aplikasi menyesuaikan setelan keamanan jaringan mereka dalam
+  file konfigurasi deklaratif yang aman tanpa memodifikasi kode aplikasi. Setelan ini bisa
+  dikonfigurasi untuk domain dan aplikasi tertentu. Kemampuan
+  utama fitur ini adalah sebagai berikut:
+</p>
+
+<ul>
+  <li>
+    <b>Trust-anchor khusus:</b> Menyesuaikan Certificate Authorities (CA) mana
+    yang dipercaya untuk koneksi aman aplikasi. Misalnya,
+    mempercayai sertifikat tertentu yang ditandatangani sendiri atau membatasi
+    set CA umum yang dipercaya aplikasi.
+  </li>
+
+  <li>
+    <b>Penggantian hanya-debug:</b> Men-debug secara aman koneksi aman dalam aplikasi
+    tanpa menambahkan risiko pada basis yang telah dipasang.
+  </li>
+
+  <li>
+    <b>Berhenti dari lalu lintas cleartext:</b> Melindungi aplikasi dari
+    penggunaan lalu lintas cleartext secara tidak sengaja.
+  </li>
+
+  <li>
+    <b>Penyematan sertifikat:</b> Membatasi koneksi aman aplikasi ke
+    sertifikat tertentu.
+  </li>
+</ul>
+
+
+<h2 id="manifest">Menambahkan File Konfigurasi Keamanan</h2>
+
+<p>
+  Fitur Network Security Configuration menggunakan file XML tempat Anda menetapkan
+  setelan untuk aplikasi. Anda harus menyertakan sebuah entri dalam manifes aplikasi
+  untuk menunjuk ke file ini. Kutipan kode berikut dari sebuah manifes
+  yang memperagakan cara membuat entri ini:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;manifest ... &gt;
+  &lt;application ... &gt;
+    &lt;meta-data android:name="android.security.net.config"
+               android:resource="@xml/network_security_config" /&gt;
+    ...
+  &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<h2 id="CustomTrust">Menyesuaikan CA Tepercaya</h2>
+
+<p>
+  Aplikasi mungkin perlu mempercayai set CA khusus sebagai ganti default
+  platform. Alasannya yang paling umum adalah:
+</p>
+
+<ul>
+  <li>Menghubungkan ke host dengan otoritas sertifikat khusus (ditandatangani sendiri,
+  dikeluarkan oleh CA internal, dll).
+  </li>
+
+  <li>Membatasi set CA hanya untuk CA yang Anda percaya sebagai ganti setiap CA
+  yang sudah terpasang.
+  </li>
+
+  <li>Mempercayai CA tambahan yang tidak disertakan dalam sistem.
+  </li>
+</ul>
+
+<p>
+  Secara default koneksi (mis. TLS, HTTPS) aman dari semua aplikasi mempercayai
+  CA yang telah dipasang oleh sistem, dan aplikasi yang menargetkan API level 23
+  (Android M) ke bawah, juga mempercayai penyimpanan CA yang ditambahkan pengguna secara default. Aplikasi
+  bisa menyesuaikan koneksinya menggunakan {@code base-config} (untuk
+  penyesuaian lebar-aplikasi) atau {@code domain-config} (untuk penyesuaian
+  per-domain).
+</p>
+
+
+<h3 id="ConfigCustom">Mengonfigurasi CA Khusus</h3>
+
+<p>
+  Anggaplah Anda ingin menghubungkan ke host Anda yang menggunakan sertifikat
+  SSL yang ditandatangani sendiri atau ke host yang sertifikat SSL-nya dikeluarkan oleh CA non-publik
+  yang Anda percaya, seperti CA internal perusahaan Anda.
+</p>
+
+<p>
+  <code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/my_ca"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+<p>
+  Menambahkan sertifikat CA yang ditandatangani sendiri atau sertifikat CA non-publik, dalam format PEM atau DER, ke
+  {@code res/raw/my_ca}.
+</p>
+
+
+<h3 id="LimitingCas">Membatasi Set CA Tepercaya</h3>
+
+<p>
+  Aplikasi yang tidak ingin mempercayai semua CA yang dipercaya oleh sistem
+  sebagai gantinya bisa menetapkan set CA sendiri yang telah dikurangi untuk dipercaya. Ini akan melindungi
+  aplikasi dari sertifikat palsu yang dikeluarkan oleh selain CA.
+</p>
+
+<p>
+  Konfigurasi untuk membatasi set CA tepercaya mirip dengan <a href="#TrustingACustomCa">mempercayai CA khusus</a> untuk domain tertentu selain
+  beberapa CA disediakan dalam sumber daya.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+        &lt;domain includeSubdomains="true"&gt;cdn.example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/trusted_roots"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+<p>
+  Menambahkan CA tepercaya, dalam format PEM atau DER, ke {@code res/raw/trusted_roots}.
+  Perhatikan, jika menggunakan format PEM, file <em>hanya</em> boleh berisi data PEM
+  dan tidak ada teks tambahan. Anda juga bisa menyediakan beberapa elemen
+  <a href="#certificates"><code>&lt;certificates&gt;</code></a>
+sebagai ganti satu elemen.
+</p>
+
+
+<h3 id="TrustingAdditionalCas">
+  Mempercayai CA Tambahan
+</h3>
+
+<p>
+  Sebuah aplikasi mungkin perlu mempercayai CA tambahan yang tidak dipercaya oleh sistem,
+  hal ini bisa disebabkan karena sistem belum menyertakan CA atau CA tidak
+  memenuhi persyaratan untuk memasukkan ke dalam sistem Android. Aplikasi
+  bisa melakukannya dengan menetapkan beberapa sumber sertifikat untuk
+  konfigurasi.
+</p>
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;base-config&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/extracas"/&gt;
+            &lt;certificates src="system"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/base-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+
+<h2 id="TrustingDebugCa">Mengonfigurasi CA untuk Debug</h2>
+
+<p>
+  Saat men-debug aplikasi yang terhubung melalui HTTPS, Anda mungkin perlu
+  menghubungkan ke server pengembangan lokal, yang tidak memiliki sertifikat
+  SSL untuk server produksi Anda. Untuk mendukungnya tanpa
+  memodifikasi kode aplikasi, Anda bisa menetapkan CA hanya-debug
+  yang <i>hanya</i> dipercaya bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">
+android:debuggable</a>
+  adalah {@code true} dengan menggunakan {@code debug-overrides}. Biasanya IDE dan alat
+  build menyetel flag ini secara otomatis untuk build non-rilis.
+</p>
+
+<p>
+  Ini lebih aman daripada kode kondisional biasa karena, sebagai tindakan
+  pencegahan keamanan, toko aplikasi tidak menerima aplikasi yang ditandai
+  bisa-di-debug.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;debug-overrides&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/debug_cas"/&gt;
+        &lt;/trust-anchors&gt;
+    &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+
+<h2 id="UsesCleartextTraffic">Berhenti dari Lalu Lintas Cleartext</h2>
+
+<p>
+  Aplikasi bermaksud menyambung ke tujuan hanya menggunakan koneksi
+ aman dapat memilih keluar dari dukungan cleartext (menggunakan protokol
+ HTTP yang tidak terenkripsi sebagai ganti HTTPS) ke tujuan tersebut. Opsi ini akan membantu mencegah
+  regresi tidak disengaja dalam aplikasi karena perubahan dalam URL yang disediakan oleh sumber-sumber
+  eksternal seperti server backend.
+  Lihat {@link android.security.NetworkSecurityPolicy#isCleartextTrafficPermitted
+  NetworkSecurityPolicy.isCleartextTrafficPermitted()} untuk detail selengkapnya.
+</p>
+
+<p>
+  Misalnya, aplikasi mungkin ingin memastikan semua koneksi ke {@code
+  secure.example.com} selalu dilakukan melalui HTTPS untuk melindungi lalu lintas sensitif
+  dari jaringan yang berbahaya.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config usesCleartextTraffic="false"&gt;
+        &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+
+<h2 id="CertificatePinning">Menyematkan Sertifikat</h2>
+
+<p>
+  Biasanya aplikasi mempercayai semua CA yang telah terpasang. Jika salah satu dari CA ini
+  mengeluarkan sertifikat palsu, aplikasi akan berisiko terkena serangan
+  MiTM. Beberapa aplikasi memilih untuk membatasi set sertifikat yang mereka terima
+  baik dengan membatasi set CA yang mereka percaya atau dengan menyematkan sertifikat.
+</p>
+
+<p>
+  Penyematan sertifikat dilakukan dengan memberikan seperangkat sertifikat dengan hash
+  kunci publik (SubjectPublicKeyInfo pada sertifikat X.509). Rantai
+  sertifikat nanti hanya berlaku jika rantai sertifikat berisi setidaknya salah satu
+  dari kunci publik yang disematkan.
+</p>
+
+<p>
+  Perhatikan, saat menggunakan penyematan sertifikat, Anda harus selalu menyertakan kunci
+  cadangan sehingga jika Anda terpaksa beralih ke kunci baru, atau mengubah CA (saat
+  menyematkan ke sertifikat CA atau perantara CA tersebut), konektivitas
+  aplikasi Anda tidak terpengaruh. Jika tidak, Anda harus mendorong
+  pembaruan ke aplikasi tersebut untuk memulihkan konektivitas.
+</p>
+
+<p>
+  Selain itu dimungkinkan juga menyetel waktu habis masa berlaku untuk pin setelah
+  penyematan tidak dilakukan. Hal ini membantu mencegah masalah konektivitas dalam
+  aplikasi yang belum diperbarui. Akan tetapi, menyetel waktu kedaluwarsa
+  pada pin mungkin akan membuat penyematan bisa diabaikan.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;pin-set expiration="2018-01-01"&gt;
+            &lt;pin digest="SHA-256"&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
+            &lt;!-- backup pin --&gt
+            &lt;pin digest="SHA-256"&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
+        &lt;/pin-set&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+
+<h2 id="ConfigInheritance">Perilaku Pewarisan Konfigurasi</h2>
+
+<p>
+  Nilai yang tidak disetel dalam konfigurasi tertentu akan diwariskan. Perilaku ini memungkinkan konfigurasi
+  yang lebih kompleks sambil menjaga file konfigurasi tetap terbaca.
+</p>
+
+<p>
+  Jika nilai tidak disetel dalam entri tertentu maka nilai dari entri berikutnya yang lebih
+  umum akan digunakan. Nilai yang tidak disetel dalam {@code domain-config} akan
+  diambil dari {@code domain-config} induk, jika tersarang, atau dari {@code
+  base-config} jika tidak. Nilai yang tidak disetel dalam {@code base-config} akan menggunakan
+  nilai default platform.
+</p>
+
+<p>
+  Misalnya pertimbangkan, bila semua koneksi ke subdomain {@code
+  example.com} harus menggunakan set CA khusus. Selain itu, lalu lintas cleartext ke
+  domain ini diizinkan <em>kecuali</em> saat menghubungkan ke {@code
+  secure.example.com}. Dengan menyarangkan konfigurasi untuk {@code
+  secure.example.com} dalam konfigurasi untuk {@code example.com},
+  {@code trust-anchors} tidak perlu digandakan.
+</p>
+
+<p>
+<code>res/xml/network_security_config.xml</code>:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;domain-config&gt;
+        &lt;domain includeSubdomains="true"&gt;example.com&lt;/domain&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="@raw/my_ca"/&gt;
+        &lt;/trust-anchors&gt;
+        &lt;domain-config cleartextTrafficPermitted="false"&gt;
+            &lt;domain includeSubdomains="true"&gt;secure.example.com&lt;/domain&gt;
+        &lt;/domain-config&gt;
+    &lt;/domain-config&gt;
+&lt;/network-security-config&gt;
+</pre>
+</p>
+
+
+<h2 id="FileFormat">Format File Konfigurasi</h2>
+
+<p>
+  Fitur Network Security Configuration menggunakan format file XML.
+  Struktur keseluruhan file ditampilkan dalam contoh kode berikut:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;network-security-config&gt;
+    &lt;base-config&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+    &lt;/base-config&gt;
+
+    &lt;domain-config&gt;
+        &lt;domain&gt;android.com&lt;/domain&gt;
+        ...
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+        &lt;pin-set&gt;
+            &lt;pin digest="..."&gt;...&lt;/pin&gt;
+            ...
+        &lt;/pin-set&gt;
+    &lt;/domain-config&gt;
+    ...
+    &lt;debug-overrides&gt;
+        &lt;trust-anchors&gt;
+            &lt;certificates src="..."/&gt;
+            ...
+        &lt;/trust-anchors&gt;
+    &lt;/debug-overrides&gt;
+&lt;/network-security-config&gt;
+</pre>
+
+<p>
+  Bagian berikut menjelaskan sintaks dan detail lainnya dari format
+  file.
+</p>
+
+<h3 id="network-security-config">
+  &lt;network-security-config&gt;
+</h3>
+
+<dl class="xml">
+  <dt>
+    bisa berisi:
+  </dt>
+
+  <dd>
+    0 atau 1 <code><a href="#base-config">&lt;base-config&gt;</a></code><br>
+    Sejumlah <code><a href=
+    "#domain-config">&lt;domain-config&gt;</a></code><br>
+    0 atau 1 <code><a href="#debug-overrides">&lt;debug-overrides&gt;</a></code>
+  </dd>
+</dl>
+
+<h3 id="base-config">
+  &lt;base-config&gt;
+</h3>
+
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+</dl>
+
+<pre class="stx">
+&lt;base-config <a href=
+"#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+    ...
+&lt;/base-config&gt;
+</pre>
+<dl class="xml">
+  <dt>
+    bisa berisi:
+  </dt>
+
+  <dd>
+    <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
+  </dd>
+
+  <dt>
+    keterangan:
+  </dt>
+
+  <dd>
+    Konfigurasi default yang digunakan oleh semua koneksi yang tujuannya tidak
+    tercakup oleh <a href="#domain-config"><code>domain-config</code></a>.
+
+<p>
+  Nilai yang tidak disetel akan menggunakan nilai default platform. Konfigurasi
+  default untuk aplikasi yang menargetkan API level 24 ke atas:
+</p>
+
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+    &lt;trust-anchors&gt;
+        &lt;certificates src="system" /&gt;
+    &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+Konfigurasi default untuk aplikasi yang menargetkan API level 23 ke bawah:
+<pre>
+&lt;base-config usesCleartextTraffic="true"&gt;
+    &lt;trust-anchors&gt;
+        &lt;certificates src="system" /&gt;
+        &lt;certificates src="user" /&gt;
+    &lt;/trust-anchors&gt;
+&lt;/base-config&gt;
+</pre>
+
+  </dd>
+</dl>
+
+<h3 id="domain-config">&lt;domain-config&gt;</h3>
+<dl class="xml">
+<dt>sintaks:</dt>
+<dd>
+<pre class="stx">&lt;domain-config <a href="#usesCleartextTraffic">usesCleartextTraffic</a>=["true" | "false"]&gt;
+    ...
+&lt;/domain-config&gt;</pre>
+</dd>
+
+<dt>Bisa Berisi:</dt>
+
+<dd>
+1 atau beberapa <code><a href="#domain">&lt;domain&gt;</a></code>
+<br/>0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
+<br/>0 atau 1 <code><a href="#pin-set">&lt;pin-set&gt;</code></a>
+<br/>Sejumlah <code>&lt;domain-config&gt;</code> tersarang</dd>
+
+<dt>Keterangan</dt>
+<dd>Konfigurasi yang digunakan untuk koneksi ke tujuan tertentu seperti didefinisikan oleh elemen {@code domain}.
+
+<p>Perhatikan, jika beberapa elemen {@code domain-config} mencakup suatu tujuan, konfigurasi dengan aturan domain paling spesifik (terpanjang) yang cocok
+akan digunakan.</p></dd>
+</dl>
+
+
+<h3 id="domain">&lt;domain&gt;</h3>
+
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+
+  <dd>
+    <pre class="stx">
+&lt;domain includeSubdomains=["true" | "false"]&gt;example.com&lt;/domain&gt;
+</pre>
+  </dd>
+
+  <dt>
+    Atribut:
+  </dt>
+
+  <dd>
+    <dl class="attr">
+      <dt>
+        {@code includeSubdomains}
+      </dt>
+
+      <dd>
+        Jika {@code "true"} maka aturan domain ini akan dicocokkan dengan domain dan semua
+        subdomain, termasuk subdomain dari subdomain, jika tidak peraturan hanya
+        diterapkan pada kecocokan yang persis tepat.
+      </dd>
+    </dl>
+  </dd>
+
+  <dt>
+    Keterangan:
+  </dt>
+</dl>
+
+<h3 id="debug-overrides">&lt;debug-overrides&gt;</h3>
+
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+
+  <dd>
+    <pre class="stx">
+&lt;debug-overrides&gt;
+    ...
+&lt;/debug-overrides&gt;
+</pre>
+  </dd>
+
+  <dt>
+    Bisa Berisi:
+  </dt>
+
+  <dd>
+    0 atau 1 <code><a href="#trust-anchors">&lt;trust-anchors&gt;</a></code>
+  </dd>
+
+  <dt>
+    Keterangan:
+  </dt>
+
+  <dd>
+    Pengesampingan yang akan diterapkan bila <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
+    adalah {@code "true"} yang biasanya terjadi untuk build non-rilis
+    yang dihasilkan oleh alat IDE dan build. Trust-anchor yang ditetapkan dalam {@code
+    debug-overrides} akan ditambahkan ke semua konfigurasi lainnya dan penyematan
+    sertifikat tidak dilakukan bila rantai sertifikat server menggunakan satu dari
+    trust-anchor hanya-debug ini. Jika <a href="{@docRoot}guide/topics/manifest/application-element.html#debug">android:debuggable</a>
+    adalah {@code "false"} maka bagian ini akan diabaikan sepenuhnya.
+  </dd>
+</dl>
+
+<h3 id="trust-anchors">&lt;trust-anchors&gt;</h3>
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+
+  <dd>
+    <pre class="stx">
+&lt;trust-anchors&gt;
+...
+&lt;/trust-anchors&gt;
+</pre>
+  </dd>
+
+  <dt>
+    Bisa Berisi:
+  </dt>
+
+  <dd>
+    Sejumlah <code><a href="#certificates">&lt;certificates&gt;</a></code>
+  </dd>
+
+  <dt>
+    Keterangan:
+  </dt>
+
+  <dd>
+    Set trust-anchor untuk koneksi aman.
+  </dd>
+</dl>
+
+
+<h3 id="certificates">&lt;certificates&gt;</h3>
+<dl class="xml">
+<dt>sintaks:</dt>
+<dd><pre class="stx">&lt;certificates src=["system" | "user" | "<i>raw resource</i>"]
+              overridePins=["true" | "false"] /&gt;
+</pre></dd>
+<dt>keterangan:</dt>
+<dd>Set sertifikat X.509 untuk elemen {@code trust-anchors}.</dd>
+
+<dt>atribut:</dt>
+<dd><dl class="attr">
+<dt>{@code src}</dt>
+<dd>
+Sumber sertifikat CA, bisa salah satu dari
+<ul>
+  <li>ID sumber daya mentah yang menunjuk ke file berisi sertifikat X.509.
+  Sertifikat harus dikodekan dalam format DER atau PEM. Dalam hal sertifikat
+  PEM, file <em>tidak boleh</em> berisi data tambahan non-PEM seperti
+  komentar.
+  </li>
+
+  <li>{@code "system"} untuk sertifikat CA sistem yang telah terpasang.
+  </li>
+
+  <li>{@code "user"} untuk sertifikat CA yang ditambahkan pengguna.
+  </li>
+</ul>
+</dd>
+
+<dt>{@code overridePins}</dt>
+<dd>
+  <p>
+    Menetapkan apakah CA dari sumber akan mengabaikan penyematan sertifikat. Jika {@code
+    "true"} kemudian rangkaian sertifikat melalui salah satu CA dari
+    sumber ini maka tidak dilakukan penyematan. Hal ini bisa berguna untuk debug CA
+    atau untuk mendukung dengan memungkinkan pengguna melakukan MiTM atas lalu lintas aman aplikasi Anda.
+  </p>
+
+  <p>
+    Default-nya adalah {@code "false"} kecuali jika ditetapkan dalam elemen {@code debug-overrides},
+    dalam hal demikian default-nya adalah {@code "true"}.
+  </p>
+</dd>
+</dl>
+</dd>
+
+
+<h3 id="pin-set">&lt;pin-set&gt;</h3>
+
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+
+  <dd>
+<pre class="stx">
+&lt;pin-set expiration="date"&gt;
+...
+&lt;/pin-set&gt;
+</pre>
+  </dd>
+
+  <dt>
+    Bisa Berisi:
+  </dt>
+
+  <dd>
+    Sejumlah <code><a href="#pin">&lt;pin&gt;</a></code>
+  </dd>
+
+  <dt>
+    Keterangan:
+  </dt>
+
+  <dd>
+    Satu set pin kunci publik. Agar koneksi aman bisa dipercaya, salah satu
+    kunci publik dalam rantai kepercayaan harus berada dalam set pin. Lihat
+    <code><a href="#pin">&lt;pin&gt;</a></code> untuk mengetahui format pin.
+  </dd>
+
+  <dt>
+    Atribut:
+  </dt>
+
+  <dd>
+    <dl class="attr">
+      <dt>
+        {@code expiration}
+      </dt>
+
+      <dd>
+        Tanggal, dalam format {@code yyyy-MM-dd}, pada saat dan setelah pin
+        kedaluwarsa, sehingga menonaktifkan penyematan. Jika atribut tidak disetel maka
+        pin tidak kedaluwarsa.
+        <p>
+          Tanggal kedaluwarsa membantu mencegah masalah konektivitas di aplikasi yang
+          tidak mengambil pembaruan untuk set pin mereka, misalnya karena pengguna
+          menonaktifkan pembaruan aplikasi.
+        </p>
+      </dd>
+    </dl>
+  </dd>
+</dl>
+
+<h3 id="pin">&lt;pin&gt;</h3>
+<dl class="xml">
+  <dt>
+    sintaks:
+  </dt>
+
+  <dd>
+<pre class="stx">
+&lt;pin digest=["SHA-256"]&gt;base64 encoded digest of X.509
+    SubjectPublicKeyInfo (SPKI)&lt;/pin&gt;
+</pre>
+  </dd>
+
+  <dt>
+    Atribut:
+  </dt>
+
+  <dd>
+    <dl class="attr">
+      <dt>
+        {@code digest}
+      </dt>
+
+      <dd>
+        Algoritme intisari yang digunakan untuk menghasilkan pin. Saat ini, hanya
+        {@code "SHA-256"} yang didukung.
+      </dd>
+    </dl>
+  </dd>
+</dl>
diff --git a/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
new file mode 100644
index 0000000..abd4e43
--- /dev/null
+++ b/docs/html-intl/intl/id/training/basics/network-ops/data-saver.jd
@@ -0,0 +1,234 @@
+page.title=Data Saver
+metaDescription=Optimalisasi penggunaan data yang diaktifkan pengguna.
+page.keywords="android N", "data usage", "metered network"
+page.image=images/cards/card-nyc_2x.jpg
+@jd:body
+
+<div id="tb-wrapper">
+  <div id="tb">
+    <h2>
+      Dalam dokumen ini
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#status">Memeriksa Preferensi Data Saver</a>
+        <ol>
+          <li>
+            <a href="#request-whitelist">Meminta izin daftar putih</a>
+          </li>
+        </ol>
+      </li>
+
+      <li>
+        <a href="#monitor-changes">Memantau Perubahan pada Preferensi
+        Data Saver</a>
+      </li>
+
+      <li>
+        <a href="#testing">Menguji dengan Perintah Android Debug Bridge</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  Selama penggunaan ponsel cerdas, biaya paket data seluler bisa saja
+  melebihi harga perangkat itu sendiri. Di N Developer Preview, pengguna bisa
+  mengaktifkan Data Saver berdasarkan lingkup perangkat untuk menghemat data, baik saat
+  roaming, mendekati akhir siklus penagihan, atau pada paket data prabayar kecil.
+</p>
+
+<p>
+  Bila pengguna mengaktifkan Data Saver di <strong>Settings</strong> dan perangkat
+  berada dalam jaringan berkuota, sistem akan memblokir penggunaan data latar belakang dan memberi tahu
+  aplikasi untuk menghemat penggunaan data latar depan bila memungkinkan. Pengguna bisa
+  memasukkan aplikasi tertentu ke daftar putih untuk memungkinkan penggunaan data berkuota bila Data
+  Saver diaktifkan.
+</p>
+
+<p>
+  N Developer Preview memperluas {@link android.net.ConnectivityManager}
+  API untuk menyediakan cara pada aplikasi untuk <a href="#status">menerima preferensi Data Saver
+  pengguna</a> dan <a href="#monitor-changes">memantau perubahan
+  preferensi</a>. Hal ini dianggap praktik terbaik bagi aplikasi untuk memeriksa apakah
+  pengguna telah mengaktifkan DataSaver dan berusaha membatasi penggunaan data latar depan dan
+  data latar belakang.
+</p>
+
+<h2 id="status">
+  Memeriksa Preferensi Data Saver
+</h2>
+
+<p>
+  Di N Developer Preview, aplikasi bisa menggunakan {@link
+  android.net.ConnectivityManager} API untuk menentukan pembatasan penggunaan data
+  apa yang sedang diterapkan. Metode {@code getRestrictBackgroundStatus()}
+  akan mengembalikan salah satu dari nilai berikut:
+</p>
+
+<dl>
+  <dt>
+    {@code RESTRICT_BACKGROUND_STATUS_DISABLED}
+  </dt>
+
+  <dd>
+    Data Saver dinonaktifkan.
+  </dd>
+
+  <dt>
+    {@code RESTRICT_BACKGROUND_STATUS_ENABLED}
+  </dt>
+
+  <dd>
+    Pengguna telah mengaktifkan Data Saver untuk aplikasi ini. Aplikasi harus berusaha membatasi
+    penggunaan data di latar depan dan dengan halus menangani pembatasan penggunaan
+    data latar belakang.
+  </dd>
+
+  <dt>
+    {@code RESTRICT_BACKGROUND_STATUS_WHITELISTED}
+  </dt>
+
+  <dd>
+    Pengguna telah mengaktifkan Data Saver namun aplikasi telah dimasukkan dalam daftar putih. Aplikasi harus
+    tetap berusaha membatasi penggunaan data latar belakang dan latar depan.
+  </dd>
+</dl>
+
+<p>
+  Hal ini dianggap praktik terbaik untuk membatasi penggunaan data bila perangkat
+  terhubung ke jaringan berkuota, meskipun Data Saver telah dinonaktifkan atau aplikasi
+  telah dimasukkan dalam daftar putih. Kode contoh berikut menggunakan {@link
+  android.net.ConnectivityManager#isActiveNetworkMetered
+  ConnectivityManager.isActiveNetworkMetered()} dan {@code
+  ConnectivityManager.getRestrictBackgroundStatus()} untuk menentukan berapa banyak data
+  yang harus digunakan aplikasi:
+</p>
+
+<pre>
+ConnectivityManager connMgr = (ConnectivityManager)
+        getSystemService(Context.CONNECTIVITY_SERVICE);
+// Checks if the device is on a metered network
+if (connMgr.isActiveNetworkMetered()) {
+  // Checks user’s Data Saver settings.
+  switch (connMgr.getRestrictBackgroundStatus()) {
+    case RESTRICT_BACKGROUND_STATUS_ENABLED:
+    // Background data usage is blocked for this app. Wherever possible,
+    // the app should also use less data in the foreground.
+
+    case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+    // The app is whitelisted. Wherever possible,
+    // the app should use less data in the foreground and background.
+
+    case RESTRICT_BACKGROUND_STATUS_DISABLED:
+    // Data Saver is disabled. Since the device is connected to a
+    // metered network, the app should use less data wherever possible.
+  }
+} else {
+  // The device is not on a metered network.
+  // Use data as required to perform syncs, downloads, and updates.
+}
+</pre>
+
+<h3 id="request-whitelist">
+  Meminta izin daftar putih
+</h3>
+
+<p>
+  Jika aplikasi Anda perlu menggunakan data di latar belakang, aplikasi bisa meminta izin
+  daftar putih dengan mengirim
+  <code>Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS</code>
+  yang mengandung URI dari nama paket aplikasi Anda: misalnya,
+  <code>package:MY_APP_ID</code>.
+</p>
+
+<p>
+  Mengirim intent dan URI akan membuka aplikasi <strong>Settings</strong> dan
+  menampilkan setelan penggunaan data untuk aplikasi Anda. Pengguna nanti bisa memutuskan apakah akan
+  mengaktifkan data latar belakang untuk aplikasi Anda. Sebelum Anda mengirim intent ini, sebaiknya
+  tanyakan kepada pengguna terlebih dahulu apakah mereka ingin membuka aplikasi
+  <strong>Settings</strong> untuk keperluan mengaktifkan penggunaan
+  data latar belakang.
+</p>
+
+<h2 id="monitor-changes">
+  Memantau Perubahan pada Preferensi Data Saver
+</h2>
+
+<p>
+  Aplikasi bisa memantau perubahan pada preferensi Data Saver dengan membuat {@link
+  android.content.BroadcastReceiver} untuk memantau {@code
+  ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED} dan secara dinamis
+  mendaftarkan penerima pada {@link android.content.Context#registerReceiver
+  Context.registerReceiver()}. Bila menerima siaran ini, aplikasi harus
+  <a href="#status">memeriksa apakah preferensi Data Saver baru memengaruhi
+  izinnya</a> dengan memanggil {@code
+  ConnectivityManager.getRestrictBackgroundStatus()}.
+</p>
+
+<p class="note">
+  <strong>Catatan:</strong> Sistem hanya mengirim siaran ini ke aplikasi yang
+  secara dinamis mendaftar padanya dengan {@link
+  android.content.Context#registerReceiver Context.registerReceiver()}. Aplikasi
+  yang mendaftar untuk menerima siaran ini dalam manifes mereka
+  tidak akan menerimanya.
+</p>
+
+<h2 id="testing">
+  Menguji dengan Perintah Android Debug Bridge
+</h2>
+
+<a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a>
+menyediakan beberapa perintah yang bisa Anda gunakan untuk memeriksa dan
+mengonfigurasi izin jaringan:
+
+<dl>
+  <dt>
+    <code>$ adb shell dumpsys netpolicy</code>
+  </dt>
+
+  <dd>
+    Menghasilkan laporan berisi setelan pembatasan jaringan latar belakang
+    global saat ini, UID paket saat ini di daftar putih, dan izin jaringan
+    untuk paket yang diketahui lainnya.
+  </dd>
+
+  <dt>
+    <code>$ adb shell cmd netpolicy</code>
+  </dt>
+
+  <dd>
+    Menampilkan daftar lengkap dari perintah Network Policy Manager (netpolicy).
+  </dd>
+
+  <dt>
+    <code>$ adb shell cmd netpolicy set restrict-background
+    &lt;boolean&gt;</code>
+  </dt>
+
+  <dd>
+    Mengaktifkan atau menonaktifkan mode Data Saver saat meneruskan <code>true</code> atau
+ <code>false</code>, masing-masing.
+  </dd>
+
+  <dt>
+    <code>$ adb shell cmd netpolicy add restrict-background-whitelist
+    &lt;UID&gt;</code>
+  </dt>
+
+  <dd>
+    Menambahkan UID paket tertentu ke daftar putih untuk mengizinkan penggunaan data berkuota
+  di latar belakang.
+  </dd>
+
+  <dt>
+    <code>$ adb shell cmd netpolicy remove restrict-background-whitelist
+    &lt;UID&gt;</code>
+  </dt>
+
+  <dd>
+    Membuang UID paket tertentu dari daftar putih untuk memblokir
+    penggunaan data berkuota di latar belakang saat Data Saver diaktifkan.
+  </dd>
+</dl>
diff --git a/docs/html-intl/intl/id/training/material/animations.jd b/docs/html-intl/intl/id/training/material/animations.jd
new file mode 100644
index 0000000..e57a03f
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/animations.jd
@@ -0,0 +1,550 @@
+page.title=Mendefinisikan Animasi Custom
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#Touch">Menyesuaikan Umpan Balik Sentuh</a></li>
+  <li><a href="#Reveal">Menggunakan Reveal Effect</a></li>
+  <li><a href="#Transitions">Menyesuaikan Transisi Aktivitas</a></li>
+  <li><a href="#ViewState">Menganimasikan Perubahan Status Tampilan</a></li>
+  <li><a href="#AnimVector">Menganimasikan Drawable Vektor</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+
+<p>Animasi dalam desain bahan memberi pengguna umpan balik tentang tindakannya dan menyediakan
+kesinambungan visual saat pengguna berinteraksi dengan aplikasi Anda. Tema bahan menyediakan beberapa animasi default
+untuk tombol dan transisi aktivitas, dan Android 5.0 (API level 21) ke atas memungkinkan Anda menyesuaikan
+animasi ini dan membuat yang baru:</p>
+
+<ul>
+<li>Umpan balik sentuh</li>
+<li>Singkap Melingkar</li>
+<li>Transisi aktivitas</li>
+<li>Gerakan melengkung</li>
+<li>Perubahan status tampilan</li>
+</ul>
+
+
+<h2 id="Touch">Menyesuaikan Umpan Balik Sentuh</h2>
+
+<p>Umpan balik sentuh dalam desain bahan menyediakan konfirmasi visual seketika pada
+titik kontak bila pengguna berinteraksi dengan elemen UI. Animasi umpan balik sentuh default
+untuk tombol menggunakan kelas {@link android.graphics.drawable.RippleDrawable} baru, yang bertransisi
+di antara berbagai status dengan efek riak.</p>
+
+<p>Di sebagian besar kasus, Anda harus menerapkan fungsionalitas ini dalam XML tampilan dengan menetapkan
+latar belakang tampilan sebagai:</p>
+
+<ul>
+<li><code>?android:attr/selectableItemBackground</code> untuk riak berbatas.</li>
+<li><code>?android:attr/selectableItemBackgroundBorderless</code> untuk riak yang meluas ke luar
+tampilan. Latar belakang ini akan digambar di atas, dan dibatasi oleh, induk tampilan terdekat dengan
+latar belakang non-null.</li>
+</ul>
+
+<p class="note"><strong>Catatan:</strong> <code>selectableItemBackgroundBorderless</code> adalah
+atribut baru yang diperkenalkan di API level 21.</p>
+
+
+<p>Atau, Anda bisa mendefinisikan {@link android.graphics.drawable.RippleDrawable}
+sebagai sumber daya XML dengan menggunakan elemen <code>ripple</code>.</p>
+
+<p>Anda bisa menetapkan warna ke objek-objek {@link android.graphics.drawable.RippleDrawable}. Untuk mengubah
+warna default umpan balik sentuh, gunakan atribut <code>android:colorControlHighlight</code>
+tema.</p>
+
+<p>Untuk informasi selengkapnya, lihat referensi API bagi kelas {@link
+android.graphics.drawable.RippleDrawable}.</p>
+
+
+<h2 id="Reveal">Menggunakan Reveal Effect</h2>
+
+<p>Animasi singkap memberi pengguna kesinambungan visual saat menampilkan atau menyembunyikan sekelompok
+elemen UI. Metode {@link android.view.ViewAnimationUtils#createCircularReveal
+ViewAnimationUtils.createCircularReveal()} memungkinkan Anda menganimasikan lingkaran terpangkas
+untuk memperlihatkan atau menyembunyikan tampilan.</p>
+
+<p>Untuk memperlihatkan tampilan yang sebelumnya tidak terlihat dengan menggunakan efek ini:</p>
+
+<pre>
+// previously invisible view
+View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the final radius for the clipping circle
+int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
+
+// create the animator for this view (the start radius is zero)
+Animator anim =
+    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
+
+// make the view visible and start the animation
+myView.setVisibility(View.VISIBLE);
+anim.start();
+</pre>
+
+<p>Untuk menyembunyikan sebuah tampilan yang sebelumnya terlihat dengan menggunakan efek ini:</p>
+
+<pre>
+// previously visible view
+final View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the initial radius for the clipping circle
+int initialRadius = myView.getWidth();
+
+// create the animation (the final radius is zero)
+Animator anim =
+    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
+
+// make the view invisible when the animation is done
+anim.addListener(new AnimatorListenerAdapter() {
+    &#64;Override
+    public void onAnimationEnd(Animator animation) {
+        super.onAnimationEnd(animation);
+        myView.setVisibility(View.INVISIBLE);
+    }
+});
+
+// start the animation
+anim.start();
+</pre>
+
+
+<h2 id="Transitions">Menyesuaikan Transisi Aktivitas</h2>
+
+<!-- shared transition video -->
+<div style="width:290px;margin-left:35px;float:right">
+  <div class="framed-nexus5-port-span-5">
+  <video class="play-on-hover" autoplay="">
+    <source src="{@docRoot}design/material/videos/ContactsAnim.mp4">
+    <source src="{@docRoot}design/material/videos/ContactsAnim.webm">
+    <source src="{@docRoot}design/material/videos/ContactsAnim.ogv">
+  </video>
+  </div>
+  <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+    <p class="img-caption" style="margin-top:3px;margin-bottom:10px"><strong>Gambar 1</strong> - Transisi
+    dengan elemen bersama.</p>
+    <em>Untuk memutar ulang film, klik layar perangkat</em>
+  </div>
+</div>
+
+<p>Transisi aktivitas dalam aplikasi desain bahan memberikan koneksi visual antar berbagai status
+melalui gerakan dan transformasi di antara elemen umum. Anda bisa menetapkan animasi custom untuk
+masuk ke dan keluar dari transisi dan untuk transisi elemen bersama di antara aktivitas.</p>
+
+<ul>
+<li>Transisi <strong>masuk</strong> menentukan cara tampilan di aktivitas memasuki suatu babak.
+misalnya, dalam transisi masuk <em>explode</em>, tampilan memasuki babak dari sisi luar
+dan melayang masuk ke arah tengah layar.</li>
+
+<li>Transisi <strong>keluar</strong> menentukan cara tampilan di aktivitas keluar dari suatu babak. Misalnya
+, dalam transisi keluar <em>explode</em>, tampilan akan keluar dari babak dari bagian
+tengahnya.</li>
+
+<li>Transisi <strong>elemen bersama</strong> menentukan cara menggunakan bersama suatu tampilan
+oleh dua transisi aktivitas di antara aktivitas-aktivitas ini. Misalnya, jika dua aktivitas memiliki
+gambar yang sama dengan posisi dan ukuran berbeda, transisi elemen bersama <em>changeImageTransform</em>
+mentransformasikan dan menskalakan gambar secara mulus di antara aktivitas-aktivitas ini.</li>
+</ul>
+
+<p>Android 5.0 (API level 21) mendukung transisi masuk dan transisi keluar ini:</p>
+
+<ul>
+<li><em>explode</em> - Memindahkan tampilan masuk ke atau keluar dari tengah babak.</li>
+<li><em>slide</em> - Memindahkan tampilan masuk ke atau keluar dari salah satu tepi babak.</li>
+<li><em>fade</em> - Menambahkan atau menghapus tampilan dari babak dengan mengubah opasitasnya.</li>
+</ul>
+
+<p>Transisi apa pun yang memperluas kelas {@link android.transition.Visibility} didukung
+sebagai transisi masuk atau transisi keluar. Untuk informasi selengkapnya, lihat referensi API untuk kelas
+{@link android.transition.Transition}.</p>
+
+<p>Android 5.0 (API level 21) juga mendukung transisi elemen bersama ini:</p>
+
+<ul>
+<li><em>changeBounds</em> - Menganimasikan perubahan pada batas-batas layout tampilan target.</li>
+<li><em>changeClipBounds</em> - Menganimasikan perubahan pada batas-batas pemangkasan tampilan target.</li>
+<li><em>changeTransform</em> - Menganimasikan perubahan pada skala dan rotasi tampilan target.</li>
+<li><em>changeImageTransform</em> - Menganimasikan perubahan pada ukuran dan skala gambar target.</li>
+</ul>
+
+<p>Bila Anda mengaktifkan transisi aktivitas dalam aplikasi, transisi memudar-silang default akan
+diaktifkan di antara aktivitas masuk dan aktivitas keluar.</p>
+
+<img src="{@docRoot}training/material/images/SceneTransition.png" alt="" width="600" height="405" style="margin-top:20px" />
+<p class="img-caption">
+  <strong>Gambar 2</strong> - Transisi babak dengan satu elemen bersama.
+</p>
+
+<h3>Menetapkan transisi custom</h3>
+
+<p>Pertama, aktifkan transisi konten jendela dengan atribut <code>android:windowContentTransitions</code>
+bila Anda mendefinisikan gaya yang mewarisi tema bahan. Anda juga bisa menetapkan
+transisi-transisi masuk, keluar, dan elemen bersama dalam definisi gaya:</p>
+
+<pre>
+&lt;style name="BaseAppTheme" parent="android:Theme.Material">
+  &lt;!-- enable window content transitions -->
+  &lt;item name="android:windowContentTransitions">true&lt;/item>
+
+  &lt;!-- specify enter and exit transitions -->
+  &lt;item name="android:windowEnterTransition">@transition/explode&lt;/item>
+  &lt;item name="android:windowExitTransition">@transition/explode&lt;/item>
+
+  &lt;!-- specify shared element transitions -->
+  &lt;item name="android:windowSharedElementEnterTransition">
+    &#64;transition/change_image_transform&lt;/item>
+  &lt;item name="android:windowSharedElementExitTransition">
+    &#64;transition/change_image_transform&lt;/item>
+&lt;/style>
+</pre>
+
+<p>Transisi <code>change_image_transform</code> dalam contoh ini didefinisikan sebagai berikut:</p>
+
+<pre>
+&lt;!-- res/transition/change_image_transform.xml -->
+&lt;!-- (see also Shared Transitions below) -->
+&lt;transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+  &lt;changeImageTransform/>
+&lt;/transitionSet>
+</pre>
+
+<p>Elemen <code>changeImageTransform</code> menunjukkan
+kelas {@link android.transition.ChangeImageTransform}. Untuk informasi selengkapnya, lihat referensi
+API untuk {@link android.transition.Transition}.</p>
+
+<p>Sebaliknya, untuk mengaktifkan transisi konten jendela dalam kode Anda, panggil
+metode {@link android.view.Window#requestFeature Window.requestFeature()}:</p>
+
+<pre>
+// inside your activity (if you did not enable transitions in your theme)
+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+
+// set an exit transition
+getWindow().setExitTransition(new Explode());
+</pre>
+
+<p>Untuk menetapkan transisi dalam kode Anda, panggil metode-metode ini dengan objek {@link
+android.transition.Transition}:</p>
+
+<ul>
+  <li>{@link android.view.Window#setEnterTransition Window.setEnterTransition()}</li>
+  <li>{@link android.view.Window#setExitTransition Window.setExitTransition()}</li>
+  <li>{@link android.view.Window#setSharedElementEnterTransition
+      Window.setSharedElementEnterTransition()}</li>
+  <li>{@link android.view.Window#setSharedElementExitTransition
+      Window.setSharedElementExitTransition()}</li>
+</ul>
+
+<p>Metode {@link android.view.Window#setExitTransition setExitTransition()} dan {@link
+android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} mendefinisikan
+transisi keluar untuk aktivitas yang memanggil. Metode {@link android.view.Window#setEnterTransition
+setEnterTransition()} dan {@link android.view.Window#setSharedElementEnterTransition
+setSharedElementEnterTransition()} mendefinisikan transisi masuk untuk aktivitas yang dipanggil.</p>
+
+<p>Untuk mendapatkan efek penuh sebuah transisi, Anda harus mengaktifkan transisi konten jendela pada
+aktivitas yang memanggil maupun aktivitas yang dipanggil. Jika tidak, aktivitas yang memanggil akan memulai transisi keluar,
+namun kemudian Anda akan melihat transisi jendela (seperti mengelupas atau memudar).</p>
+
+<p>Untuk memulai transisi masuk sesegera mungkin, gunakan metode
+{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()}
+pada aktivitas yang dipanggil. Ini memungkinkan Anda mendapatkan transisi masuk yang lebih dramatis.</p>
+
+<h3>Memulai aktivitas dengan menggunakan transisi</h3>
+
+<p>Jika Anda mengaktifkan transisi dan mengatur transisi keluar untuk aktivitas, transisi itu akan diaktifkan
+bila Anda menjalankan aktivitas lain sebagai berikut:</p>
+
+<pre>
+startActivity(intent,
+              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
+</pre>
+
+<p>Jika Anda telah mengatur transisi masuk untuk aktivitas kedua, transisi juga akan diaktifkan
+bila aktivitas dimulai. Untuk menonaktifkan transisi bila Anda memulai aktivitas lain, sediakan
+bundel opsi <code>null</code>.</p>
+
+<h3>Memulai aktivitas dengan satu elemen bersama</h3>
+
+<p>Untuk membuat animasi transisi layar di antara dua aktivitas yang memiliki satu elemen bersama:</p>
+
+<ol>
+<li>Aktifkan transisi konten jendela dalam tema Anda.</li>
+<li>Tetapkan transisi elemen bersama dalam gaya Anda.</li>
+<li>Definisikan transisi Anda sebagai sumber daya XML.</li>
+<li>Tetapkan nama umum pada elemen bersama dalam kedua layout dengan
+    atribut <code>android:transitionName</code>.</li>
+<li>Gunakan metode {@link android.app.ActivityOptions#makeSceneTransitionAnimation
+ActivityOptions.makeSceneTransitionAnimation()}.</li>
+</ol>
+
+<pre>
+// get the element that receives the click event
+final View imgContainerView = findViewById(R.id.img_container);
+
+// get the common element for the transition in this activity
+final View androidRobotView = findViewById(R.id.image_small);
+
+// define a click listener
+imgContainerView.setOnClickListener(new View.OnClickListener() {
+    &#64;Override
+    public void onClick(View view) {
+        Intent intent = new Intent(this, Activity2.class);
+        // create the transition animation - the images in the layouts
+        // of both activities are defined with android:transitionName="robot"
+        ActivityOptions options = ActivityOptions
+            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
+        // start the new activity
+        startActivity(intent, options.toBundle());
+    }
+});
+</pre>
+
+<p>Untuk tampilan dinamis bersama yang Anda hasilkan dalam kode, gunakan
+metode {@link android.view.View#setTransitionName View.setTransitionName()} untuk menetapkan
+nama elemen umum di kedua aktivitas.</p>
+
+<p>Untuk membalik animasi transisi babak bila Anda menyelesaikan aktivitas kedua, panggil metode
+{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()}
+sebagai ganti {@link android.app.Activity#finish Activity.finish()}.</p>
+
+<h3>Memulai aktivitas dengan beberapa elemen bersama</h3>
+
+<p>Untuk membuat animasi transisi babak antara dua aktivitas yang memiliki lebih dari satu
+elemen bersama, definisikan elemen bersama di kedua layout dengan atribut <code>android:transitionName</code>
+ (atau gunakan metode {@link android.view.View#setTransitionName View.setTransitionName()}
+di kedua aktivitas), dan buat sebuah objek {@link android.app.ActivityOptions} sebagai berikut:</p>
+
+<pre>
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
+        Pair.create(view1, "agreedName1"),
+        Pair.create(view2, "agreedName2"));
+</pre>
+
+
+<h2 id="CurvedMotion">Menggunakan Gerakan Melengkung</h2>
+
+<p>Animasi dalam desain bahan mengandalkan kurva untuk pola interpolasi waktu dan
+gerakan spasial. Dengan Android 5.0 (API level 21) ke atas, Anda bisa mendefinisikan kurva pewaktuan custom dan
+pola gerakan melengkung untuk animasi.</p>
+
+<p>Kelas {@link android.view.animation.PathInterpolator} adalah interpolator baru berdasarkan sebuah
+kurva Bézier atau objek {@link android.graphics.Path}. Interpolator ini menetapkan kurva gerakan
+dalam bujur sangkar 1x1, dengan titik-titik jangkar di (0,0) dan (1,1) dan titik-titik kontrol sebagaimana ditetapkan menggunakan
+argumen konstruktor. Anda juga bisa mendefinisikan interpolator path sebagai sumber daya XML:</p>
+
+<pre>
+&lt;pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="0.4"
+    android:controlY1="0"
+    android:controlX2="1"
+    android:controlY2="1"/>
+</pre>
+
+<p>Sistem menyediakan sumber daya XML untuk tiga kurva dasar dalam
+spesifikasi desain bahan:</p>
+
+<ul>
+  <li><code>&#64;interpolator/fast_out_linear_in.xml</code></li>
+  <li><code>&#64;interpolator/fast_out_slow_in.xml</code></li>
+  <li><code>&#64;interpolator/linear_out_slow_in.xml</code></li>
+</ul>
+
+<p>Anda bisa meneruskan objek {@link android.view.animation.PathInterpolator} ke metode {@link
+android.animation.Animator#setInterpolator Animator.setInterpolator()}.</p>
+
+<p>Kelas {@link android.animation.ObjectAnimator} memiliki konstruktor-konstruktor baru yang memungkinkan Anda menganimasikan
+koordinat bersama sebuah path dengan menggunakan dua atau beberapa properti sekaligus. Misalnya, animator berikut
+menggunakan objek {@link android.graphics.Path} untuk menganimasikan properti X dan Y sebuah tampilan:</p>
+
+<pre>
+ObjectAnimator mAnimator;
+mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
+...
+mAnimator.start();
+</pre>
+
+
+<h2 id="ViewState">Menganimasikan Perubahan Status Tampilan</h2>
+
+<p>Kelas {@link android.animation.StateListAnimator} memungkinkan Anda mendefinisikan animator yang berjalan bila
+status tampilan berubah. Contoh berikut menampilkan cara mendefinisikan {@link
+android.animation.StateListAnimator} sebagai sumber daya XML:</p>
+
+<pre>
+&lt;!-- animate the translationZ property of a view when pressed -->
+&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
+  &lt;item android:state_pressed="true">
+    &lt;set>
+      &lt;objectAnimator android:propertyName="translationZ"
+        android:duration="@android:integer/config_shortAnimTime"
+        android:valueTo="2dp"
+        android:valueType="floatType"/>
+        &lt;!-- you could have other objectAnimator elements
+             here for "x" and "y", or other properties -->
+    &lt;/set>
+  &lt;/item>
+  &lt;item android:state_enabled="true"
+    android:state_pressed="false"
+    android:state_focused="true">
+    &lt;set>
+      &lt;objectAnimator android:propertyName="translationZ"
+        android:duration="100"
+        android:valueTo="0"
+        android:valueType="floatType"/>
+    &lt;/set>
+  &lt;/item>
+&lt;/selector>
+</pre>
+
+<p>Untuk menyertakan animasi status tampilan custom ke tampilan, definisikan animator menggunakan
+elemen <code>selector</code> dalam sumber daya file XML sebagaimana dalam contoh ini, dan tetapkan ke
+tampilan Anda dengan atribut <code>android:stateListAnimator</code>. Untuk menetapkan animator daftar status
+ke sebuah tampilan dalam kode Anda, gunakan metode {@link android.animation.AnimatorInflater#loadStateListAnimator
+AnimationInflater.loadStateListAnimator()}, dan tetapkan animator ke tampilan dengan
+metode {@link android.view.View#setStateListAnimator View.setStateListAnimator()}.</p>
+
+<p>Bila tema Anda memperluas tema bahan, tombol-tombol akan memiliki animasi Z secara default. Untuk menghindari
+perilaku ini di tombol Anda, aturlah atribut <code>android:stateListAnimator</code> ke
+<code>@null</code>.</p>
+
+<p>Kelas {@link android.graphics.drawable.AnimatedStateListDrawable} memungkinkan Anda membuat drawable
+yang menampilkan animasi di antara perubahan status tampilan terkait. Sebagian widget sistem di
+Android 5.0 menggunakan animasi ini secara default. Contoh berikut menampilkan cara
+mendefinisikan {@link android.graphics.drawable.AnimatedStateListDrawable} sebagai sumber daya XML:</p>
+
+<pre>
+&lt;!-- res/drawable/myanimstatedrawable.xml -->
+&lt;animated-selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    &lt;!-- provide a different drawable for each state-->
+    &lt;item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
+        android:state_pressed="true"/>
+    &lt;item android:id="@+id/focused" android:drawable="@drawable/drawableF"
+        android:state_focused="true"/>
+    &lt;item android:id="@id/default"
+        android:drawable="@drawable/drawableD"/>
+
+    &lt;!-- specify a transition -->
+    &lt;transition android:fromId="@+id/default" android:toId="@+id/pressed">
+        &lt;animation-list>
+            &lt;item android:duration="15" android:drawable="@drawable/dt1"/>
+            &lt;item android:duration="15" android:drawable="@drawable/dt2"/>
+            ...
+        &lt;/animation-list>
+    &lt;/transition>
+    ...
+&lt;/animated-selector>
+</pre>
+
+
+<h2 id="AnimVector">Menganimasikan Drawable Vektor</h2>
+
+<p><a href="{@docRoot}training/material/drawables.html#VectorDrawables">Drawable Vektor </a>
+bisa diubah skalanya tanpa kehilangan definisi. Kelas {@link android.graphics.drawable.AnimatedVectorDrawable}
+memungkinkan Anda menganimasikan properti drawable vektor.</p>
+
+<p>Anda biasanya mendefinisikan drawable vektor yang dianimasikan dalam tiga file XML:</p>
+
+<ul>
+<li>Drawable vektor dengan elemen <code>&lt;vector&gt;</code> dalam
+<code>res/drawable/</code></li>
+<li>Drawable vektor animasi dengan elemen <code>&lt;animated-vector&gt;</code> dalam
+<code>res/drawable/</code></li>
+<li>Satu atau beberapa animator objek dengan elemen <code>&lt;objectAnimator&gt;</code> dalam
+<code>res/anim/</code></li>
+</ul>
+
+<p>Drawable vektor yang dianimasikan bisa menganimasikan atribut elemen <code>&lt;group&gt;</code> dan
+<code>&lt;path&gt;</code>. Elemen <code>&lt;group&gt;</code> mendefinisikan satu set
+path atau subgrup, dan elemen <code>&lt;path&gt;</code> mendefinisikan path yang harus digambar.</p>
+
+<p>Bila Anda mendefinisikan drawable vektor yang ingin dianimasikan, gunakan atribut <code>android:name</code>
+untuk menetapkan nama unik ke grup dan path, sehingga Anda bisa merujuknya dari
+definisi animator Anda. Misalnya:</p>
+
+<pre>
+&lt;!-- res/drawable/vectordrawable.xml -->
+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:width="64dp"
+    android:viewportHeight="600"
+    android:viewportWidth="600">
+    &lt;group
+        <strong>android:name="rotationGroup"</strong>
+        android:pivotX="300.0"
+        android:pivotY="300.0"
+        android:rotation="45.0" >
+        &lt;path
+            <strong>android:name="v"</strong>
+            android:fillColor="#000000"
+            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+    &lt;/group>
+&lt;/vector>
+</pre>
+
+<p>Definisi drawable vektor yang dianimasikan merujuk pada grup dan path dalam drawable vektor
+berdasarkan namanya:</p>
+
+<pre>
+&lt;!-- res/drawable/animvectordrawable.xml -->
+&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+  android:drawable="@drawable/vectordrawable" >
+    &lt;target
+        android:name="rotationGroup"
+        android:animation="@anim/rotation" />
+    &lt;target
+        android:name="v"
+        android:animation="@anim/path_morph" />
+&lt;/animated-vector>
+</pre>
+
+<p>Definisi animasi menyatakan objek {@link android.animation.ObjectAnimator} atau {@link
+android.animation.AnimatorSet}. Animator pertama dalam contoh ini memutar
+grup target sebanyak 360 derajat:</p>
+
+<pre>
+&lt;!-- res/anim/rotation.xml -->
+&lt;objectAnimator
+    android:duration="6000"
+    android:propertyName="rotation"
+    android:valueFrom="0"
+    android:valueTo="360" />
+</pre>
+
+<p>Animator kedua dalam contoh ini perlahan-lahan mengubah bentuk path drawable vektor dari satu bentuk ke
+bentuk yang lain. Kedua path harus kompatibel untuk morphing: keduanya harus memiliki jumlah perintah yang sama
+dan jumlah parameter yang sama untuk setiap perintah.</p>
+
+<pre>
+&lt;!-- res/anim/path_morph.xml -->
+&lt;set xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;objectAnimator
+        android:duration="3000"
+        android:propertyName="pathData"
+        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
+        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
+        android:valueType="pathType" />
+&lt;/set>
+</pre>
+
+<p>Untuk informasi selengkapnya, lihat referensi API bagi {@link
+android.graphics.drawable.AnimatedVectorDrawable}.</p>
diff --git a/docs/html-intl/intl/id/training/material/compatibility.jd b/docs/html-intl/intl/id/training/material/compatibility.jd
new file mode 100644
index 0000000..ef444c3
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/compatibility.jd
@@ -0,0 +1,168 @@
+page.title=Mempertahankan Kompatibilitas
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#Theme">Mendefinisikan Gaya Alternatif</a></li>
+  <li><a href="#Layouts">Menyediakan Layout Alternatif</a></li>
+  <li><a href="#SupportLib">Menggunakan Support Library</a></li>
+  <li><a href="#CheckVersion">Memeriksa Versi Sistem</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+
+<p>Sebagian fitur desain bahan seperti tema bahan dan transisi aktivitas custom
+hanya tersedia pada Android 5.0 (API level 21) ke atas. Akan tetapi, Anda bisa mendesain aplikasi untuk menggunakan
+fitur-fitur ini saat dijalankan pada perangkat yang mendukung desain bahan dan tetap kompatibel
+dengan perangkat yang menjalankan rilis Android sebelumnya.</p>
+
+
+<h2 id="Theme">Mendefinisikan Gaya Alternatif</h2>
+
+<p>Anda bisa mengonfigurasi aplikasi untuk menggunakan tema bahan pada perangkat yang mendukungnya dan mengembalikan
+ke tema lama pada perangkat yang menjalankan versi Android terdahulu:</p>
+
+<ol>
+<li>Definisikan tema yang mewarisi tema lama (seperti Holo) di
+    <code>res/values/styles.xml</code>.</li>
+<li>Definisikan tema bernama sama yang mewarisi tema bahan di
+    <code>res/values-v21/styles.xml</code>.</li>
+<li>Atur tema ini sebagai tema aplikasi Anda dalam file manifes.</li>
+</ol>
+
+<p class="note"><strong>Catatan:</strong>
+Jika aplikasi Anda menggunakan tema bahan namun tidak menyediakan tema alternatif dengan cara ini,
+aplikasi itu tidak akan berjalan pada versi Android sebelum 5.0.
+</p>
+
+
+<h2 id="Layouts">Menyediakan Layout Alternatif</h2>
+
+<p>Jika layout yang Anda desain sesuai dengan panduan desain bahan tidak menggunakan salah satu
+atribut XML baru yang diperkenalkan di Android 5.0 (API level 21), layout itu akan berfungsi pada
+versi Android sebelumnya. Jika tidak, Anda bisa menyediakan layout alternatif. Anda juga bisa menyediakan
+layout alternatif untuk menyesuaikan cara aplikasi ditampilkan pada versi Android terdahulu.</p>
+
+<p>Buatlah file layout untuk Android 5.0 (API level 21) dalam <code>res/layout-v21/</code> dan
+file layout alternatif untuk versi Android terdahulu dalam <code>res/layout/</code>.
+Misalnya, <code>res/layout/my_activity.xml</code> adalah layout alternatif untuk
+<code>res/layout-v21/my_activity.xml</code>.</p>
+
+<p>Untuk menghindari duplikasi kode, definisikan gaya dalam <code>res/values/</code>, modifikasi
+gaya di <code>res/values-v21/</code> untuk API baru, dan gunakan pewarisan gaya, dengan mendefinisikan
+gaya dasar di <code>res/values/</code> dan mewarisi gaya di <code>res/values-v21/</code>.</p>
+
+
+<h2 id="SupportLib">Menggunakan Support Library</h2>
+
+<p><a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
+r21 ke atas menyertakan fitur desain bahan berikut:</p>
+
+<ul>
+<li><a href="{@docRoot}training/material/theme.html">Gaya desain bahan</a> untuk beberapa widget sistem
+    bila Anda menerapkan salah satu tema <code>Theme.AppCompat</code>.</li>
+<li><a href="{@docRoot}training/material/theme.html#ColorPalette">Atribut tema palet warna</a>
+    dalam tema <code>Theme.AppCompat</code>.</li>
+<li>Widget {@link android.support.v7.widget.RecyclerView} untuk <a href="{@docRoot}training/material/lists-cards.html#RecyclerView">
+menampilkan kumpulan data.</a></li>
+<li>Widget {@link android.support.v7.widget.CardView} untuk <a href="{@docRoot}training/material/lists-cards.html#CardView">membuat kartu</a>.</li>
+<li>Kelas {@link android.support.v7.graphics.Palette} untuk <a href="{@docRoot}training/material/drawables.html#ColorExtract">mengekstrak warna mencolok dari
+    gambar</a>.</li>
+</ul>
+
+<h3>Widget sistem</h3>
+
+<p>Tema-tema <code>Theme.AppCompat</code> menyediakan gaya desain bahan untuk widget ini:</p>
+
+<ul>
+  <li>{@link android.widget.EditText}</li>
+  <li>{@link android.widget.Spinner}</li>
+  <li>{@link android.widget.CheckBox}</li>
+  <li>{@link android.widget.RadioButton}</li>
+  <li>{@link android.support.v7.widget.SwitchCompat}</li>
+  <li>{@link android.widget.CheckedTextView}</li>
+</ul>
+
+<h3>Palet Warna</h3>
+
+<p>Untuk memperoleh gaya desain bahan dan menyesuaikan palet warna dengan Android v7 Support
+Library, terapkan salah satu tema <code>Theme.AppCompat</code>:</p>
+
+<pre>
+&lt;!-- extend one of the Theme.AppCompat themes -->
+&lt;style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
+    &lt;!-- customize the color palette -->
+    &lt;item name="colorPrimary">@color/material_blue_500&lt;/item>
+    &lt;item name="colorPrimaryDark">@color/material_blue_700&lt;/item>
+    &lt;item name="colorAccent">@color/material_green_A200&lt;/item>
+&lt;/style>
+</pre>
+
+<h3>Daftar dan Kartu</h3>
+
+<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link
+android.support.v7.widget.CardView} tersedia di versi Android terdahulu melalui
+Android v7 Support Library dengan pembatasan ini:</p>
+<ul>
+<li>{@link android.support.v7.widget.CardView} memundurkan ke implementasi bayangan terprogram
+    dengan menggunakan pengisi tambahan.</li>
+<li>{@link android.support.v7.widget.CardView} tidak memangkas tampilan anaknya yang berpotongan
+    dengan sudut melengkung.</li>
+</ul>
+
+
+<h3>Dependensi</h3>
+
+<p>Untuk menggunakan fitur-fitur ini di versi Android sebelum 5.0 (API level 21), sertakan
+Android v7 Support Library dalam proyek Anda sebagai <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a>:</p>
+
+<pre>
+dependencies {
+    compile 'com.android.support:appcompat-v7:21.0.+'
+    compile 'com.android.support:cardview-v7:21.0.+'
+    compile 'com.android.support:recyclerview-v7:21.0.+'
+}
+</pre>
+
+
+<h2 id="CheckVersion">Memeriksa Versi Sistem</h2>
+
+<p>Fitur berikut hanya tersedia di Android 5.0 (API level 21) ke atas:</p>
+
+<ul>
+<li>Transisi aktivitas</li>
+<li>Umpan balik sentuh</li>
+<li>Animasi membuka</li>
+<li>Animasi berbasis path</li>
+<li>Drawable vektor</li>
+<li>Pewarnaan drawable</li>
+</ul>
+
+<p>Untuk menjaga kompatibilitas dengan versi Android terdahulu, periksa {@link
+android.os.Build.VERSION#SDK_INT version} sistem saat runtime sebelum Anda memanggil API untuk salah satu
+fitur ini:</p>
+
+<pre>
+// Check if we're running on Android 5.0 or higher
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+    // Call some material design APIs here
+} else {
+    // Implement this feature without material design
+}
+</pre>
+
+<p class="note"><strong>Catatan:</strong> Untuk menetapkan versi Android yang didukung aplikasi Anda,
+gunakan atribut <code>android:minSdkVersion</code> dan <code>android:targetSdkVersion</code>
+dalam file manifes. Untuk menggunakan fitur desain bahan di Android 5.0, atur
+atribut <code>android:targetSdkVersion</code> ke <code>21</code>. Untuk informasi selengkapnya, lihat
+panduan <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">API
+&lt;uses-sdk&gt;</a>.</p>
diff --git a/docs/html-intl/intl/id/training/material/drawables.jd b/docs/html-intl/intl/id/training/material/drawables.jd
new file mode 100644
index 0000000..493abd4
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/drawables.jd
@@ -0,0 +1,126 @@
+page.title=Bekerja dengan Drawable
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#DrawableTint">Mewarnai Sumber Daya Drawable</a></li>
+  <li><a href="#ColorExtract">Mengekstrak Warna Mencolok dari Gambar</a></li>
+  <li><a href="#VectorDrawables">Membuat Drawable Vektor</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+<p>Kemampuan berikut untuk drawable membantu Anda mengimplementasikan desain bahan dalam aplikasi Anda:</p>
+
+<ul>
+<li>Pewarnaan drawable</li>
+<li>Ekstraksi warna mencolok</li>
+<li>Drawable vektor</li>
+</ul>
+
+<p>Pelajaran ini menampilkan cara menggunakan fitur-fitur ini dalam aplikasi Anda.</p>
+
+
+<h2 id="DrawableTint">Mewarnai Sumber Daya Drawable</h2>
+
+<p>Dengan Android 5.0 (API level 21) ke atas, Anda bisa mewarnai bitmap dan sembilan-tambalan yang didefinisikan sebagai
+alpha-mask. Anda bisa mewarnainya dengan sumber daya warna atau atribut tema yang mencocokkan ke
+sumber daya warna (misalnya, <code>?android:attr/colorPrimary</code>). Biasanya, Anda membuat aset ini
+hanya sekali dan mewarnainya secara otomatis agar cocok dengan tema Anda.</p>
+
+<p>Anda bisa menerapkan warna ke objek {@link android.graphics.drawable.BitmapDrawable} atau {@link
+android.graphics.drawable.NinePatchDrawable} dengan metode {@code setTint()}. Anda juga bisa
+mengatur warna dan mode dalam layout dengan atribut <code>android:tint</code> dan
+<code>android:tintMode</code>.</p>
+
+
+<h2 id="ColorExtract">Mengekstrak Warna Mencolok dari Gambar</h2>
+
+<p>Android Support Library r21 ke atas menyertakan kelas {@link
+android.support.v7.graphics.Palette}, yang memungkinkan Anda mengekstrak warna mencolok dari gambar.
+Kelas ini mengekstrak warna mencolok berikut:</p>
+
+<ul>
+<li>Menyala</li>
+<li>Menyala pekat</li>
+<li>Menyala pucat</li>
+<li>Pudar</li>
+<li>Pudar pekat</li>
+<li>Pudar pucat</li>
+</ul>
+
+<p>Untuk mengekstrak warna-warna ini, teruskan objek {@link android.graphics.Bitmap} ke
+metode statis {@link android.support.v7.graphics.Palette#generate Palette.generate()} dalam
+thread latar belakang tempat Anda memuat gambar. Jika Anda tidak bisa menggunakan thread itu, panggil metode
+{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} dan
+sediakan listener sebagai gantinya.</p>
+
+<p>Anda bisa mengambil warna mencolok dari gambar dengan metode getter di kelas
+<code>Palette</code>, misalnya <code>Palette.getVibrantColor</code>.</p>
+
+<p>Untuk menggunakan kelas {@link android.support.v7.graphics.Palette} dalam proyek Anda, tambahkan
+<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> berikut ke
+modul aplikasi Anda:</p>
+
+<pre>
+dependencies {
+    ...
+    compile 'com.android.support:palette-v7:21.0.0'
+}
+</pre>
+
+<p>Untuk informasi selengkapnya, lihat referensi API untuk kelas {@link android.support.v7.graphics.Palette}.
+</p>
+
+
+<h2 id="VectorDrawables">Membuat Drawable Vektor</h2>
+
+<!-- video box -->
+<a class="notice-developers-video" href="https://www.youtube.com/watch?v=wlFVIIstKmA" style="margin-top:18px">
+<div>
+    <h3>Video</h3>
+    <p>Grafis Vektor Android</p>
+</div>
+</a>
+
+<p>Di Android 5.0 (API Level 21) ke atas, Anda bisa mendefinisikan drawable vektor, yang berubah skala tanpa
+kehilangan definisi. Anda hanya memerlukan satu file aset per gambar vektor, bukan file aset untuk
+setiap densitas layar seperti pada gambar bitmap. Untuk membuat gambar vektor, Anda mendefinisikan detail
+bentuknya dalam sebuah elemen XML <code>&lt;vector&gt;</code>.</p>
+
+<p>Contoh berikut mendefinisikan gambar vektor berbentuk hati:</p>
+
+<pre>
+&lt;!-- res/drawable/heart.xml -->
+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
+    &lt;!-- intrinsic size of the drawable -->
+    android:height="256dp"
+    android:width="256dp"
+    &lt;!-- size of the virtual canvas -->
+    android:viewportWidth="32"
+    android:viewportHeight="32">
+
+  &lt;!-- draw a path -->
+  &lt;path android:fillColor="#8fff"
+      android:pathData="M20.5,9.5
+                        c-1.955,0,-3.83,1.268,-4.5,3
+                        c-0.67,-1.732,-2.547,-3,-4.5,-3
+                        C8.957,9.5,7,11.432,7,14
+                        c0,3.53,3.793,6.257,9,11.5
+                        c5.207,-5.242,9,-7.97,9,-11.5
+                        C25,11.432,23.043,9.5,20.5,9.5z" />
+&lt;/vector>
+</pre>
+
+<p>Gambar vektor direpresentasikan di Android sebagai objek {@link android.graphics.drawable.VectorDrawable}.
+ Untuk informasi selengkapnya tentang sintaks <code>pathData</code>, lihat <a href="http://www.w3.org/TR/SVG11/paths.html#PathData">Referensi Path SVG</a>. Untuk informasi selengkapnya
+tentang menganimasikan properti drawable vektor, lihat
+<a href="{@docRoot}training/material/animations.html#AnimVector">Menganimasikan Drawable Vektor</a>.</p>
diff --git a/docs/html-intl/intl/id/training/material/get-started.jd b/docs/html-intl/intl/id/training/material/get-started.jd
new file mode 100644
index 0000000..1a551a9
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/get-started.jd
@@ -0,0 +1,171 @@
+page.title=Memulai
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#ApplyTheme">Menerapkan Tema Bahan</a></li>
+  <li><a href="#Layouts">Mendesain Layout Anda</a></li>
+  <li><a href="#Depth">Menetapkan Ketinggian di Tampilan Anda</a></li>
+  <li><a href="#ListsCards">Membuat Daftar dan Kartu</a></li>
+  <li><a href="#Animations">Menyesuaikan Animasi Anda</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+
+<p>Untuk membuat aplikasi dengan desain bahan:</p>
+
+<ol>
+  <li style="margin-bottom:10px">
+    Tinjaulah <a href="http://www.google.com/design/spec">spesifikasi desain bahan</a>.</li>
+  <li style="margin-bottom:10px">
+    Terapkan <strong>tema</strong> bahan ke aplikasi Anda.</li>
+  <li style="margin-bottom:10px">
+    Buat <strong>layout</strong> agar mengikuti panduan desain bahan.</li>
+  <li style="margin-bottom:10px">
+    Tetapkan <strong>ketinggian</strong> tampilan Anda untuk menghasilkan bayangan.</li>
+  <li style="margin-bottom:10px">
+    Gunakan <strong>widget</strong> sistem untuk daftar dan kartu.</li>
+  <li style="margin-bottom:10px">
+    Sesuaikan <strong>animasi</strong> di aplikasi Anda.</li>
+</ol>
+
+<h3>Mempertahankan kompatibilitas mundur</h3>
+
+<p>Anda bisa menambahkan banyak fitur desain bahan ke aplikasi sekaligus mempertahankan kompatibilitas dengan
+versi Android sebelum 5.0. Untuk informasi selengkapnya, lihat
+<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.</p>
+
+<h3>Memperbarui aplikasi dengan desain bahan</h3>
+
+<p>Untuk memperbarui aplikasi yang ada guna memasukkan desain bahan, perbarui layout Anda dengan mengikuti
+panduan desain bahan. Juga pastikan memasukkan kedalaman, umpan balik sentuh, dan
+animasi.</p>
+
+<h3>Membuat aplikasi baru dengan desain bahan</h3>
+
+<p>Jika Anda sedang membuat aplikasi baru dengan fitur desain bahan, <a href="http://www.google.com/design/spec">panduan desain bahan</a> akan memberi Anda
+kerangka kerja desain yang kohesif. Ikuti panduan itu dan gunakan fungsionalitas baru di
+kerangka kerja Android untuk mendesain dan mengembangkan aplikasi Anda.</p>
+
+
+<h2 id="ApplyTheme">Menerapkan Tema Bahan</h2>
+
+<p>Untuk menerapkan tema bahan dalam aplikasi Anda, tetapkan gaya yang mewarisi
+<code>android:Theme.Material</code>:</p>
+
+<pre>
+&lt;!-- res/values/styles.xml -->
+&lt;resources>
+  &lt;!-- your theme inherits from the material theme -->
+  &lt;style name="AppTheme" parent="android:Theme.Material">
+    &lt;!-- theme customizations -->
+  &lt;/style>
+&lt;/resources>
+</pre>
+
+<p>Tema bahan menyediakan widget sistem terbaru yang memungkinkan Anda mengatur palet warnanya dan
+animasi default untuk umpan balik sentuh dan transisi aktivitas. Untuk detail selengkapnya, lihat
+<a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a>.</p>
+
+
+<h2 id="Layouts">Mendesain Layout Anda</h2>
+
+<p>Selain menerapkan dan menyesuaikan tema bahan, layout Anda harus mematuhi
+<a href="http://www.google.com/design/spec">panduan desain bahan</a>. Bila Anda mendesain
+layout, berikan perhatian khusus pada hal-hal berikut:</p>
+
+<ul>
+<li>Petak patokan</li>
+<li>Garis utama</li>
+<li>Pengaturan Jarak</li>
+<li>Ukuran target sentuh</li>
+<li>Struktur layout</li>
+</ul>
+
+
+<h2 id="Depth">Menetapkan Ketinggian di Tampilan Anda</h2>
+
+<p>Tampilan bisa menghasilkan bayangan, dan nilai ketinggian tampilan
+menentukan ukuran bayangan dan urutan penggambarannya. Untuk mengatur ketinggian tampilan, gunakan
+atribut <code>android:elevation</code> dalam layout:</p>
+
+<pre>
+&lt;TextView
+    android:id="&#64;+id/my_textview"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="&#64;string/next"
+    android:background="&#64;color/white"
+    android:elevation="5dp" />
+</pre>
+
+<p>Properti <code>translationZ</code> baru memungkinkan Anda membuat animasi yang mencerminkan
+perubahan sementara pada ketinggian tampilan. Perubahan ketinggian bisa berguna saat
+<a href="{@docRoot}training/material/animations.html#ViewState">merespons
+gerakan sentuh</a>.</p>
+
+<p>Untuk detail selengkapnya, lihat <a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan
+Bayangan dan Memangkas Tampilan</a>.</p>
+
+
+<h2 id="ListsCards">Membuat Daftar dan Kartu</h2>
+
+<p>{@link android.support.v7.widget.RecyclerView} adalah versi {@link
+android.widget.ListView} yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.
+{@link android.support.v7.widget.CardView} memungkinkan Anda menampilkan potongan informasi dalam kartu dengan
+tampilan konsisten di seluruh aplikasi. Contoh kode berikut memperagakan cara menyertakan
+{@link android.support.v7.widget.CardView} dalam layout Anda:</p>
+
+<pre>
+&lt;android.support.v7.widget.CardView
+    android:id="&#64;+id/card_view"
+    android:layout_width="200dp"
+    android:layout_height="200dp"
+    card_view:cardCornerRadius="3dp">
+    ...
+&lt;/android.support.v7.widget.CardView>
+</pre>
+
+<p>Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar
+dan Kartu</a>.</p>
+
+
+<h2 id="Animations">Menyesuaikan Animasi Anda</h2>
+
+<p>Android 5.0 (API level 21) menyertakan API baru untuk membuat animasi custom di aplikasi Anda.
+Misalnya, Anda bisa mengaktifkan transisi aktivitas dan mendefinisikan transisi keluar di
+aktivitas:</p>
+
+<pre>
+public class MyActivity extends Activity {
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // enable transitions
+        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+        setContentView(R.layout.activity_my);
+    }
+
+    public void onSomeButtonClicked(View view) {
+        getWindow().setExitTransition(new Explode());
+        Intent intent = new Intent(this, MyOtherActivity.class);
+        startActivity(intent,
+                      ActivityOptions
+                          .makeSceneTransitionAnimation(this).toBundle());
+    }
+}
+</pre>
+
+<p>Bila Anda memulai aktivitas lain dari aktivitas ini, transisi keluar akan diaktifkan.</p>
+
+<p>Untuk mengetahui selengkapnya tentang API animasi yang baru, lihat <a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a>.</p>
diff --git a/docs/html-intl/intl/id/training/material/index.jd b/docs/html-intl/intl/id/training/material/index.jd
new file mode 100644
index 0000000..53697d2
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/index.jd
@@ -0,0 +1,60 @@
+page.title=Desain Bahan untuk Pengembang
+page.image=images/cards/material_2x.png
+page.metaDescription=Pelajari cara menerapkan desain bahan pada aplikasi Anda.
+
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dependensi dan Prasyarat</h2>
+  <ul>
+    <li>Android 5.0 (API Level 21)</li>
+  </ul>
+</div>
+</div>
+
+<p>Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan interaksi di
+berbagai platform dan perangkat. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan
+yang dijelaskan dalam
+<a href="http://www.google.com/design/spec/material-design/introduction.html">spesifikasi desain bahan
+</a> dan gunakan komponen serta fungsionalitas baru yang tersedia di Android 5.0
+(API level 21).</p>
+
+<p>Kelas ini menampilkan kepada Anda cara membuat aplikasi desain bahan dengan elemen-elemen berikut:</p>
+
+<ul>
+<li>Tema bahan</li>
+<li>Widget untuk kartu dan daftar</li>
+<li>Bayangan custom dan pemangkasan tampilan</li>
+<li>Drawable vektor</li>
+<li>Animasi custom</li>
+</ul>
+
+<p>Kelas ini juga mengajarkan cara mempertahankan kompatibilitas dengan versi Android sebelum
+5.0 (API level 21) bila Anda menggunakan fitur desain bahan dalam aplikasi.</p>
+
+<h2>Pelajaran</h2>
+
+<dl>
+  <dt><a href="{@docRoot}training/material/get-started.html">Memulai</a></dt>
+  <dd>Pelajari cara memperbarui aplikasi Anda dengan fitur desain bahan.</dd>
+
+  <dt><a href="{@docRoot}training/material/theme.html">Menggunakan Tema Bahan</a></dt>
+  <dd>Pelajari cara menerapkan gaya desain bahan pada aplikasi Anda.</dd>
+
+  <dt><a href="{@docRoot}training/material/lists-cards.html">Membuat Daftar dan Kartu</a></dt>
+  <dd>Pelajari cara membuat daftar dan kartu dengan tampilan dan cara kerja yang konsisten menggunakan widget sistem.</dd>
+
+  <dt><a href="{@docRoot}training/material/shadows-clipping.html">Mendefinisikan Bayangan dan Memangkas Tampilan</a></dt>
+  <dd>Pelajari cara mengatur elevasi tampilan Anda untuk membuat bayangan custom dan cara memangkas tampilan.</dd>
+
+  <dt><a href="{@docRoot}training/material/drawables.html">Bekerja dengan Drawable</a></dt>
+  <dd>Pelajari cara membuat drawable vektor dan cara mewarnai sumber daya drawable.</dd>
+
+  <dt><a href="{@docRoot}training/material/animations.html">Mendefinisikan Animasi Custom</a></dt>
+  <dd>Pelajari cara membuat animasi custom untuk tampilan dan transisi aktivitas dengan elemen bersama.</dd>
+
+  <dt><a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a></dt>
+  <dd>Pelajari cara mempertahankan kompatibilitas dengan versi platform sebelum Android 5.0.</dd>
+</dl>
diff --git a/docs/html-intl/intl/id/training/material/lists-cards.jd b/docs/html-intl/intl/id/training/material/lists-cards.jd
new file mode 100644
index 0000000..46dd19af
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/lists-cards.jd
@@ -0,0 +1,266 @@
+page.title=Membuat Daftar dan Kartu
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#RecyclerView">Membuat Daftar</a></li>
+  <li><a href="#CardView">Membuat Kartu</a></li>
+  <li><a href="#Dependencies">Menambahkan Dependensi</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+
+<p>Untuk membuat daftar dan kartu yang kompleks dengan gaya desain bahan di aplikasi, Anda bisa menggunakan widget
+{@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}.
+</p>
+
+
+<h2 id="RecyclerView">Membuat Daftar</h2>
+
+<p>Widget {@link android.support.v7.widget.RecyclerView} adalah
+versi {@link android.widget.ListView} yang lebih maju dan fleksibel. Widget ini adalah kontainer untuk menampilkan set data
+besar yang bisa digulir secara sangat efisien dengan mempertahankan tampilan dalam jumlah terbatas. Gunakan
+widget {@link android.support.v7.widget.RecyclerView} bila Anda memiliki kumpulan data dengan elemen
+yang berubah saat runtime berdasarkan tindakan pengguna atau kejadian jaringan.</p>
+
+<p>Kelas {@link android.support.v7.widget.RecyclerView} menyederhanakan penampilan dan penanganan
+set data yang besar dengan menyediakan:</p>
+
+<ul>
+  <li>Pengelola layout untuk memosisikan item</li>
+  <li>Animasi default untuk operasi item umum, misalnya penghapusan atau penambahan item</li>
+</ul>
+
+<p>Anda juga memiliki keluwesan untuk mendefinisikan pengelola layout custom dan animasi untuk widget {@link
+android.support.v7.widget.RecyclerView}.</p>
+
+<img src="{@docRoot}training/material/images/RecyclerView.png" alt="" width="550" height="106" />
+<p class="img-caption">
+<strong>Gambar 1</strong>. Widget <code>RecyclerView</code>.
+</p>
+
+<p>Untuk menggunakan widget {@link android.support.v7.widget.RecyclerView}, Anda harus menetapkan
+adaptor dan pengelola layout. Untuk membuat adaptor, perluas kelas {@link
+android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}. Detail
+implementasi bergantung pada detail set data Anda dan tipe tampilan. Untuk informasi selengkapnya,
+ lihat <a href="#RVExamples">contoh-contoh</a> di bawah.</p>
+
+<div style="float:right">
+<img src="{@docRoot}design/material/images/list_mail.png" alt="" width="250" height="426" />
+<p class="img-caption" style="margin-left:8px">
+<strong>Gambar 2</strong> - Daftar berisi <code>RecyclerView</code>.
+</p>
+</div>
+
+<p><strong>Pengelola layout</strong> memosisikan tampilan item dalam {@link
+android.support.v7.widget.RecyclerView} dan menentukan waktu untuk menggunakan ulang tampilan item yang tidak
+lagi terlihat oleh pengguna. Untuk menggunakan ulang (atau <em>mendaur ulang</em>) tampilan, pengelola layout bisa meminta
+adaptor untuk mengganti konten tampilan dengan elemen lain dalam dataset. Mendaur ulang
+tampilan dengan cara ini akan meningkatkan kinerja karena menghindari pembuatan tampilan yang tidak diperlukan atau
+melakukan pencarian {@link android.app.Activity#findViewById findViewById()} yang mahal.</p>
+
+<p>{@link android.support.v7.widget.RecyclerView} menyediakan semua pengelola layout bawaan ini:</p>
+
+<ul>
+<li>{@link android.support.v7.widget.LinearLayoutManager} menampilkan item dalam
+daftar gulir vertikal atau horizontal.</li>
+<li>{@link android.support.v7.widget.GridLayoutManager} menampilkan item dalam petak.</li>
+<li>{@link android.support.v7.widget.StaggeredGridLayoutManager} menampilkan item dalam petak zigzag.</li>
+</ul>
+
+<p>Untuk membuat pengelola layout custom, perluas kelas {@link
+android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager}.</p>
+
+<h3>Animasi</h3>
+
+<p>Animasi untuk menambahkan dan menghapus item diaktifkan secara default di {@link
+android.support.v7.widget.RecyclerView}. Untuk menyesuaikan animasi ini, perluas kelas
+{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator}dan gunakan
+metode {@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()}.
+</p>
+
+<h3 id="RVExamples">Contoh</h3>
+
+<p>Contoh kode berikut memperagakan cara menambahkan
+{@link android.support.v7.widget.RecyclerView} ke layout:</p>
+
+<pre>
+&lt;!-- A RecyclerView with some commonly used attributes -->
+&lt;android.support.v7.widget.RecyclerView
+    android:id="@+id/my_recycler_view"
+    android:scrollbars="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
+</pre>
+
+<p>Begitu Anda menambahkan widget {@link android.support.v7.widget.RecyclerView} ke layout,
+dapatkan pengatur atau handle objek itu, hubungkan dengan pengelola layout, dan sertakan adaptor untuk data
+yang akan ditampilkan:</p>
+
+<pre>
+public class MyActivity extends Activity {
+    private RecyclerView mRecyclerView;
+    private RecyclerView.Adapter mAdapter;
+    private RecyclerView.LayoutManager mLayoutManager;
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.my_activity);
+        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
+
+        // use this setting to improve performance if you know that changes
+        // in content do not change the layout size of the RecyclerView
+        mRecyclerView.setHasFixedSize(true);
+
+        // use a linear layout manager
+        mLayoutManager = new LinearLayoutManager(this);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+
+        // specify an adapter (see also next example)
+        mAdapter = new MyAdapter(myDataset);
+        mRecyclerView.setAdapter(mAdapter);
+    }
+    ...
+}
+</pre>
+
+<p>Adaptor menyediakan akses ke item dataset Anda, membuat tampilan untuk item, dan
+mengganti konten sebagian tampilan dengan item data baru bila item semula tidak lagi
+terlihat. Contoh kode berikut menampilkan implementasi sederhana untuk sebuah dataset yang terdiri dari
+larik string yang ditampilkan dengan menggunakan widget {@link android.widget.TextView}:</p>
+
+<pre>
+public class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.ViewHolder> {
+    private String[] mDataset;
+
+    // Provide a reference to the views for each data item
+    // Complex data items may need more than one view per item, and
+    // you provide access to all the views for a data item in a view holder
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        // each data item is just a string in this case
+        public TextView mTextView;
+        public ViewHolder(TextView v) {
+            super(v);
+            mTextView = v;
+        }
+    }
+
+    // Provide a suitable constructor (depends on the kind of dataset)
+    public MyAdapter(String[] myDataset) {
+        mDataset = myDataset;
+    }
+
+    // Create new views (invoked by the layout manager)
+    &#64;Override
+    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+                                                   int viewType) {
+        // create a new view
+        View v = LayoutInflater.from(parent.getContext())
+                               .inflate(R.layout.my_text_view, parent, false);
+        // set the view's size, margins, paddings and layout parameters
+        ...
+        ViewHolder vh = new ViewHolder(v);
+        return vh;
+    }
+
+    // Replace the contents of a view (invoked by the layout manager)
+    &#64;Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        // - get element from your dataset at this position
+        // - replace the contents of the view with that element
+        holder.mTextView.setText(mDataset[position]);
+
+    }
+
+    // Return the size of your dataset (invoked by the layout manager)
+    &#64;Override
+    public int getItemCount() {
+        return mDataset.length;
+    }
+}
+</pre>
+
+
+<div style="float:right;margin-top:15px;margin-left:30px">
+<img src="{@docRoot}design/material/images/card_travel.png" alt="" width="225" height="383">
+<p class="img-caption" style="margin-left:12px">
+<strong>Gambar 3</strong>. Contoh kartu.
+</p>
+</div>
+
+<h2 id="CardView">Membuat Kartu</h2>
+
+<p>{@link android.support.v7.widget.CardView} memperluas kelas {@link android.widget.FrameLayout}
+dan memungkinkan Anda menampilkan informasi dalam kartu yang memiliki tampilan konsisten lintas platform. Widget {@link
+android.support.v7.widget.CardView} bisa memiliki bayangan dan sudut membulat.</p>
+
+<p>Untuk membuat kartu dengan bayangan, gunakan atribut <code>card_view:cardElevation</code>.
+{@link android.support.v7.widget.CardView} menggunakan elevasi nyata dan bayangan dinamis pada Android 5.0
+(API level 21) ke atas dan memundurkan ke implementasi bayangan terprogram pada versi terdahulu.
+Untuk informasi selengkapnya, lihat <a href="{@docRoot}training/material/compatibility.html">Mempertahankan
+Kompatibilitas</a>.</p>
+
+<p>Gunakan properti-properti ini untuk menyesuaikan penampilan
+widget {@link android.support.v7.widget.CardView}:</p>
+
+<ul>
+  <li>Untuk mengatur radius sudut pada layout Anda, gunakan atribut <code>card_view:cardCornerRadius</code>.
+</li>
+  <li>Untuk mengatur radius sudut dalam kode Anda, gunakan metode <code>CardView.setRadius</code>.</li>
+  <li>Untuk mengatur warna latar belakang kartu, gunakan atribut <code>card_view:cardBackgroundColor</code>.
+</li>
+</ul>
+
+<p>Contoh kode berikut menampilkan cara menyertakan widget {@link android.support.v7.widget.CardView}
+dalam layout:</p>
+
+<pre>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    ... >
+    &lt;!-- A CardView that contains a TextView -->
+    &lt;android.support.v7.widget.CardView
+        xmlns:card_view="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/card_view"
+        android:layout_gravity="center"
+        android:layout_width="200dp"
+        android:layout_height="200dp"
+        card_view:cardCornerRadius="4dp">
+
+        &lt;TextView
+            android:id="@+id/info_text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+    &lt;/android.support.v7.widget.CardView>
+&lt;/LinearLayout>
+</pre>
+
+<p>Untuk informasi selengkapnya, lihat referensi API untuk {@link android.support.v7.widget.CardView}.</p>
+
+
+<h2 id="Dependencies">Menambahkan Dependensi</h2>
+
+<p>Widget {@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}
+adalah bagian dari <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support
+Library</a>. Untuk menggunakan widget dalam proyek Anda, tambahkan
+<a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a> ini ke
+modul aplikasi Anda:</p>
+
+<pre>
+dependencies {
+    ...
+    compile 'com.android.support:cardview-v7:21.0.+'
+    compile 'com.android.support:recyclerview-v7:21.0.+'
+}
+</pre>
diff --git a/docs/html-intl/intl/id/training/material/shadows-clipping.jd b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
new file mode 100644
index 0000000..5431926
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/shadows-clipping.jd
@@ -0,0 +1,133 @@
+page.title=Mendefinisikan Bayangan dan Memangkas Tampilan
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#Elevation">Menetapkan Elevasi pada Tampilan Anda</a></li>
+  <li><a href="#Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</a></li>
+  <li><a href="#Clip">Memangkas Tampilan</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+<p>Desain bahan memperkenalkan elevasi untuk elemen-elemen UI. Elevasi membantu pengguna memahami
+arti penting relatif masing-masing elemen dan memfokuskan perhatian pada tugas yang ada.</p>
+
+<p>Elevasi tampilan, yang dinyatakan dengan properti Z, menentukan tampilan visual
+bayangannya: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar dan lebih halus. Tampilan dengan nilai Z lebih tinggi menutupi
+tampilan dengan nilai Z lebih rendah; akan tetapi, nilai Z tampilan tidak memengaruhi ukuran tampilan.</p>
+
+<p>Bayangan digambar oleh induk tampilan yang dinaikkan, sehingga terkena pemangkasan standar tampilan,
+yang dipangkas oleh induk secara default.</p>
+
+<p>Elevasi juga berguna untuk membuat animasi tempat memunculkan widget untuk sementara di atas
+bidang tampilan saat melakukan beberapa tindakan.</p>
+
+<p>Untuk informasi selengkapnya tentang elevasi dalam desain bahan, lihat
+<a href="http://www.google.com/design/spec/what-is-material/objects-in-3d-space.html">Objek
+di ruang 3D</a>.</p>
+
+
+<h2 id="Elevation">Menetapkan Elevasi pada Tampilan Anda</h2>
+
+<p>Nilai Z untuk tampilan memiliki dua komponen:
+
+<ul>
+<li>Elevasi: Komponen statis.</li>
+<li>Transformasi: Komponen dinamis yang digunakan untuk animasi.</li>
+</ul>
+
+<p><code>Z = elevation + translationZ</code></p>
+
+<img src="{@docRoot}training/material/images/shadows-depth.png" width="580" height="261" alt="" />
+<p class="img-caption"><strong>Gambar 1</strong> - Bayangan untuk berbagai elevasi tampilan.</p>
+
+<p>Untuk mengatur elevasi tampilan dalam definisi layout, gunakan atribut <code>android:elevation</code>.
+ Untuk mengatur elevasi tampilan dalam kode aktivitas, gunakan
+metode {@link android.view.View#setElevation View.setElevation()}.</p>
+
+<p>Untuk mengatur transformasi tampilan, gunakan metode {@link android.view.View#setTranslationZ
+View.setTranslationZ()}.</p>
+
+<p>Metode {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} dan {@link
+android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} yang baru memudahkan
+Anda menganimasikan elevasi tampilan. Untuk informasi selengkapnya, lihat referensi API untuk
+{@link android.view.ViewPropertyAnimator} dan panduan pengembang <a href="{@docRoot}guide/topics/graphics/prop-animation.html">Animasi Properti</a>.
+</p>
+
+<p>Anda juga bisa menggunakan {@link android.animation.StateListAnimator}
+untuk menetapkan animasi ini secara deklaratif. Ini khususnya berguna bila
+perubahan status memicu animasi, seperti saat seorang pengguna menekan tombol. Untuk informasi selengkapnya, lihat
+<a href="{@docRoot}training/material/animations.html#ViewState">Menganimasikan Perubahan Status Tampilan</a>.</p>
+
+<p>Nilai Z diukur dengan satuan dp (density-independent pixel).</p>
+
+
+<h2 id="Shadows">Menyesuaikan Bayangan dan Garis Luar Tampilan</h2>
+
+<p>Batas-batas drawable latar belakang tampilan menentukan bentuk default bayangannya.
+<strong>Garis luar</strong> menyatakan bentuk luar objek grafis dan mendefinisikan
+bidang riak untuk umpan balik sentuh.</p>
+
+<p>Perhatikan tampilan ini, yang didefinisikan dengan drawable latar belakang:</p>
+
+<pre>
+&lt;TextView
+    android:id="@+id/myview"
+    ...
+    android:elevation="2dp"
+    android:background="@drawable/myrect" />
+</pre>
+
+<p>Drawable latar belakang didefinisikan sebagai persegi panjang dengan sudut membulat:</p>
+
+<pre>
+&lt;!-- res/drawable/myrect.xml -->
+&lt;shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    &lt;solid android:color="#42000000" />
+    &lt;corners android:radius="5dp" />
+&lt;/shape>
+</pre>
+
+<p>Tampilan ini menghasilkan bayangan dengan sudut membulat, karena drawable latar belakang mendefinisikan
+garis luar tampilan. Memberikan garis luar custom akan mengesampingkan bentuk default bayangan tampilan.</p>
+
+<p>Untuk mendefinisikan garis luar custom suatu tampilan dalam kode Anda:<p>
+
+<ol>
+<li>Perluas kelas {@link android.view.ViewOutlineProvider}.</li>
+<li>Kesampingkan metode {@link android.view.ViewOutlineProvider#getOutline getOutline()}.</li>
+<li>Tetapkan penyedia garis luar baru untuk tampilan Anda dengan metode {@link
+android.view.View#setOutlineProvider View.setOutlineProvider()}.</li>
+</ol>
+
+<p>Anda bisa membuat garis luar lonjong dan persegi panjang yang bersudut membulat dengan menggunakan metode dalam
+kelas {@link android.graphics.Outline}. Penyedia garis luar default untuk tampilan memperoleh garis luar
+dari latar belakang tampilan. Untuk mencegah tampilan menghasilkan bayangan, atur penyedia garis luarnya
+ke <code>null</code>.</p>
+
+
+<h2 id="Clip">Memangkas Tampilan</h2>
+
+<p>Memangkas tampilan memudahkan Anda mengubah bentuk tampilan. Anda bisa memangkas tampilan agar
+konsistensi dengan elemen desain lainnya atau mengubah bentuk tampilan untuk merespons input pengguna.
+Anda bisa memangkas tampilan hingga area garis luarnya dengan menggunakan metode {@link android.view.View#setClipToOutline
+View.setClipToOutline()} atau atribut <code>android:clipToOutline</code>. Hanya
+garis-garis luar persegi panjang, lingkaran, dan persegi panjang bersudut bulat yang mendukung pemangkasan, seperti yang ditentukan oleh
+metode {@link android.graphics.Outline#canClip Outline.canClip()}.</p>
+
+<p>Untuk memangkas tampilan ke bentuk drawable, atur drawable sebagai latar belakang tampilan
+(seperti yang ditampilkan di atas) dan panggil metode {@link android.view.View#setClipToOutline View.setClipToOutline()}.
+</p>
+
+<p>Memangkas tampilan adalah operasi yang mahal; jadi, jangan animasikan bentuk yang Anda gunakan
+untuk memangkas tampilan. Untuk memperoleh efek ini, gunakan animasi <a href="{@docRoot}training/material/animations.html#Reveal">Reveal Effect</a>.</p>
diff --git a/docs/html-intl/intl/id/training/material/theme.jd b/docs/html-intl/intl/id/training/material/theme.jd
new file mode 100644
index 0000000..5acdcd2
--- /dev/null
+++ b/docs/html-intl/intl/id/training/material/theme.jd
@@ -0,0 +1,131 @@
+page.title=Menggunakan Tema Bahan
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>Pelajaran ini mengajarkan Anda cara</h2>
+<ol>
+  <li><a href="#ColorPalette">Menyesuaikan Palet Warna</a></li>
+  <li><a href="#StatusBar">Menyesuaikan Baris Status</a></li>
+  <li><a href="#Inheritance">Tampilan Setiap Tema</a></li>
+</ol>
+<h2>Anda juga harus membaca</h2>
+<ul>
+  <li><a href="http://www.google.com/design/spec">Spesifikasi desain bahan</a></li>
+  <li><a href="{@docRoot}design/material/index.html">Desain bahan di Android</a></li>
+</ul>
+</div>
+</div>
+
+
+<p>Tema bahan yang baru menyediakan:</p>
+
+<ul>
+  <li>Widget sistem yang memungkinkan Anda mengatur palet warnanya</li>
+  <li>Animasi umpan balik sentuh untuk widget sistem</li>
+  <li>Animasi transisi aktivitas</li>
+</ul>
+
+<p>Anda bisa menyesuaikan tampilan tema bahan
+sesuai dengan identitas merek Anda dengan palet warna yang Anda kontrol. Anda bisa mewarnai action-bar dan
+baris status dengan menggunakan atribut tema, seperti yang ditampilkan dalam <a href="#fig3">Gambar 3</a>.</p>
+
+<p>Widget sistem memiliki desain baru dan animasi umpan balik sentuh. Anda bisa menyesuaikan
+palet warna, animasi umpan balik sentuh, dan transisi aktivitas untuk aplikasi.</p>
+
+<p>Tema bahan didefinisikan sebagai:</p>
+
+<ul>
+  <li><code>@android:style/Theme.Material</code> (versi gelap)</li>
+  <li><code>@android:style/Theme.Material.Light</code> (versi terang)</li>
+  <li><code>@android:style/Theme.Material.Light.DarkActionBar</code></li>
+</ul>
+
+<p>Untuk daftar gaya bahan yang bisa Anda gunakan, lihat referensi API untuk
+{@link android.R.style R.style}.</p>
+
+<!-- two columns, dark/light material theme example -->
+<div style="width:700px;margin-top:25px;margin-bottom:10px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+  <img src="{@docRoot}design/material/images/MaterialDark.png" width="500" height="238">
+  <div style="width:170px;margin:0 auto">
+  <p style="margin-top:8px;font-size:12px"><strong>Gambar 1</strong>. Tema bahan gelap</p>
+  </div>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+  <img src="{@docRoot}design/material/images/MaterialLight.png" width="500" height="238">
+  <div style="width:170px;margin:0 auto">
+  <p style="margin-top:8px;font-size:12px"><strong>Gambar 2</strong>. Tema bahan terang</p>
+  </div>
+</div>
+<br style="clear:left">
+</div>
+
+<p class="note">
+<strong>Catatan:</strong> Tema bahan hanya tersedia di Android 5.0 (API level 21)
+ke atas. <a href="{@docRoot}tools/support-library/features.html#v7">v7 Support Library</a>
+menyediakan tema dengan gaya desain bahan untuk beberapa widget dan dukungan untuk menyesuaikan
+palet warna. Untuk informasi selengkapnya, lihat
+<a href="{@docRoot}training/material/compatibility.html">Mempertahankan Kompatibilitas</a>.
+</p>
+
+
+<h2 id="ColorPalette">Menyesuaikan Palet Warna</h2>
+
+<p style="margin-bottom:30px">Untuk menyesuaikan warna dasar tema agar cocok dengan merek Anda, definisikan
+warna custom menggunakan atribut tema saat Anda mewariskan dari tema bahan:</p>
+
+<pre>
+&lt;resources>
+  &lt;!-- inherit from the material theme -->
+  &lt;style name="AppTheme" parent="android:Theme.Material">
+    &lt;!-- Main theme colors -->
+    &lt;!--   your app branding color for the app bar -->
+    &lt;item name="android:colorPrimary">@color/primary&lt;/item>
+    &lt;!--   darker variant for the status bar and contextual app bars -->
+    &lt;item name="android:colorPrimaryDark">@color/primary_dark&lt;/item>
+    &lt;!--   theme UI controls like checkboxes and text fields -->
+    &lt;item name="android:colorAccent">@color/accent&lt;/item>
+  &lt;/style>
+&lt;/resources>
+</pre>
+
+<div style="float:right;margin-left:25px;margin-top:20px;margin-bottom:10px" id="fig3">
+<img src="{@docRoot}training/material/images/ThemeColors.png" width="250" height="445" />
+<p class="img-caption" style="margin-bottom:0px">
+<strong>Gambar 3.</strong> Menyesuaikan tema bahan.</p>
+</div>
+
+
+<h2 id="StatusBar">Menyesuaikan Baris Status</h2>
+
+<p>Tema bahan memungkinkan Anda menyesuaikan baris status dengan mudah; jadi Anda bisa menetapkan
+warna yang cocok dengan merek Anda dan memberikan kontras yang cukup untuk menampilkan ikon status putih. Untuk
+mengatur warna custom bagi baris status, gunakan atribut <code>android:statusBarColor</code> bila
+Anda memperluas tema bahan. Secara default, <code>android:statusBarColor</code> mewarisi
+nilai <code>android:colorPrimaryDark</code>.</p>
+
+<p>Anda juga bisa menggambar sendiri di belakang baris status. Misalnya, jika Anda ingin menampilkan
+baris status secara transparan di atas foto, dengan gradasi gelap yang halus untuk memastikan
+ikon status putih tetap terlihat. Caranya, atur atribut <code>android:statusBarColor</code> ke
+<code>&#64;android:color/transparent</code> dan sesuaikan flag jendela seperti yang diperlukan. Anda juga bisa
+menggunakan metode {@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} untuk
+animasi atau pemudaran.</p>
+
+<p class="note">
+<strong>Catatan:</strong> Baris status harus selalu memiliki delineasi yang jelas dari
+toolbar utama, kecuali bila Anda menampilkan gambar detail atau konten media tepi-ke-tepi di belakang
+baris ini dan bila Anda menggunakan gradasi untuk memastikan ikon tetap terlihat.
+</p>
+
+<p>Bila Anda menyesuaikan baris navigasi dan baris status, jadikan keduanya transparan atau modifikasi
+baris status saja. Baris navigasi harus tetap hitam di semua kasus lainnya.</p>
+
+
+<h2 id="Inheritance">Tampilan Setiap Tema</h3>
+
+<p>Elemen dalam definisi layout XML bisa menetapkan atribut <code>android:theme</code>,
+yang merujuk sumber daya tema. Atribut ini memodifikasi tema untuk elemen itu dan setiap
+elemen anak, yang berguna untuk mengubah palet warna tema dalam porsi tertentu
+pada antarmuka.</p>
diff --git a/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
new file mode 100644
index 0000000..41af6de
--- /dev/null
+++ b/docs/html-intl/intl/id/training/tv/playback/picture-in-picture.jd
@@ -0,0 +1,213 @@
+page.title=Gambar-dalam-gambar
+page.keywords=pratinjau,sdk,PIP,Gambar-dalam-gambar
+page.tags=androidn
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dalam dokumen ini</h2>
+<ol>
+  <li><a href="#declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung
+Gambar-dalam-gambar</a></li>
+  <li><a href="#pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</a>
+</li>
+  <li><a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>
+</li>
+  <li><a href="#continuing_playback">Melanjutkan Pemutaran Video Saat dalam
+Gambar-dalam-gambar</a></li>
+  <li><a href="#single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
+ Gambar-dalam-gambar</a></li>
+  <li><a href="#best">Praktik Terbaik</a></li>
+</ol>
+
+<h2>Lihat Juga</h2>
+<ol>
+  <li><a href="{@docRoot}preview/features/multi-window.html">Dukungan
+Multi-Jendela</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>Di Android N, pengguna Android TV sekarang bisa menonton video
+dalam jendela yang disematkan di sudut layar saat menyusuri
+aplikasi. Mode gambar-dalam-gambar (PIP) memungkinkan aplikasi menjalankan aktivitas
+video dalam jendela yang disematkan selagi aktivitas lain tetap berjalan di
+latar belakang. Jendela PIP memungkinkan pengguna melakukan multitasking saat menggunakan aplikasi Anda, yang
+membantu pengguna menjadi lebih produktif.</p>
+
+<p>Aplikasi Anda bisa memutuskan kapan memicu mode PIP. Inilah beberapa contoh
+kapan memasuki mode PIP:</p>
+
+<ul>
+<li>Aplikasi Anda bisa memindahkan video ke dalam mode PIP bila pengguna mengarah
+mundur dari video untuk menjelajah materi lainnya.</li>
+<li>Aplikasi Anda bisa mengalihkan video ke dalam mode PIP selagi pengguna menonton akhir episode
+dari materi. Layar utama menampilkan informasi
+promosi atau rangkuman tentang episode berikutnya dalam seri tersebut.</li>
+<li>Aplikasi Anda bisa menyediakan suatu cara bagi pengguna untuk mengantre materi tambahan selagi
+mereka menonton video. Video terus dimainkan dalam mode PIP selagi layar
+utama menampilkan aktivitas pemilihan materi.</li>
+</ul>
+
+<p>Jendela PIP memiliki luas 240x135 dp dan ditampilkan di layer paling atas pada salah satu
+dari empat sudut layar, yang dipilih oleh sistem. Pengguna bisa memunculkan
+menu PIP yang memungkinkan mereka untuk beralih mode dari jendela PIP ke layar penuh, atau menutup jendela
+PIP, dengan menekan dan menahan tombol <b>Beranda</b> pada remote. Jika video
+lain mulai diputar pada layar utama, jendela PIP secara otomatis
+ditutup. Pengguna juga bisa menutup jendela PIP melalui Recents.</p>
+
+<img src="{@docRoot}images/android-7.0/pip-active.png" />
+<p class="img-caption"><strong>Gambar 1.</strong> Video
+Gambar-dalam-gambar terlihat di sudut layar selagi pengguna menjelajahi materi pada layar
+utama.</p>
+
+<p>PIP memanfaatkan API multi-jendela yang tersedia di Android N untuk
+menyediakan jendela hamparan video yang disematkan. Untuk menambahkan PIP ke aplikasi, Anda harus
+mendaftarkan aktivitas yang mendukung PIP, mengalihkan aktivitas Anda ke mode PIP bila
+diperlukan, serta memastikan elemen UI disembunyikan dan pemutaran video berlanjut bila
+aktivitas dalam mode PIP.</p>
+
+<h2 id="declaring">Mendeklarasikan Bahwa Aktivitas Anda Mendukung Gambar-dalam-gambar</h2>
+
+<p>Secara default, sistem tidak secara otomatis mendukung PIP untuk aplikasi.
+Jika Anda ingin mendukung PIP dalam aplikasi, daftarkan aktivitas
+video Anda dalam manifes dengan menyetel
+<code>android:supportsPictureInPicture</code> dan
+<code>android:resizeableActivity</code> ke <code>true</code>. Juga, tetapkan
+bahwa aktivitas Anda menangani perubahan konfigurasi layout sehingga aktivitas
+Anda tidak diluncurkan ulang saat terjadi perubahan layout selama transisi mode PIP.</p>
+
+<pre>
+&lt;activity android:name="VideoActivity"
+    android:resizeableActivity="true"
+    android:supportsPictureInPicture="true"
+    android:configChanges=
+        "screenSize|smallestScreenSize|screenLayout|orientation"
+    ...
+</pre>
+
+<p>Saat mendaftarkan aktivitas Anda, ingatlah bahwa dalam mode PIP aktivitas
+Anda akan ditampilkan pada jendela hamparan kecil pada layar TV. Aktivitas
+pemutaran video dengan UI minimal akan memberikan pengalaman pengguna terbaik. Aktivitas yang
+mengandung elemen UI kecil mungkin tidak memberikan pengalaman pengguna yang baik
+ketika beralih ke mode PIP, karena pengguna tidak dapat melihat elemen UI secara jelas
+di jendela PIP.</p>
+
+<h2 id="pip_button">Mengalihkan Aktivitas Anda ke Gambar-dalam-gambar</h2>
+
+Bila Anda perlu untuk mengalihkan aktivitas ke mode PIP, panggil
+<code>Activity.enterPictureInPictureMode()</code>. Contoh berikut mengalihkan
+ke mode PIP bila pengguna memilih tombol PIP khusus pada baris
+kontrol media:</p>
+
+<pre>
+&#64;Override
+public void onActionClicked(Action action) {
+    if (action.getId() == R.id.lb_control_picture_in_picture) {
+        getActivity().enterPictureInPictureMode();
+        return;
+    }
+    ...
+</pre>
+
+<p>Menambahkan tombol PIP ke baris kontrol media Anda akan memungkinkan pengguna dengan mudah beralih
+ke mode PIP selagi mengontrol pemutaran video.</p>
+
+<img src="{@docRoot}images/android-7.0/pip-button.png" />
+<p class="img-caption"><strong>Gambar 1.</strong> Tombol
+gambar-dalam-gambar pada baris kontrol media.</p>
+
+<p>Android N menyertakan kelas
+<code>PlaybackControlsRow.PictureInPictureAction</code> baru yang mendefinisikan
+tindakan PIP baris kontrol dan menggunakan ikon PIP.</p>
+
+<h2 id="handling_ui">Menangani UI Selama Gambar-dalam-gambar</h2>
+
+<p>Bila aktivitas memasuki mode PIP, aktivitas Anda seharusnya hanya menampilkan pemutaran
+video. Buang elemen UI sebelum aktivitas Anda memasuki PIP,
+dan pulihkan elemen ini bila aktivitas Anda beralih ke layar penuh lagi.
+Ganti <code>Activity.onPictureInPictureModeChanged()</code> atau
+<code>Fragment.onPictureInPictureModeChanged()</code> dan aktifkan atau
+nonaktifkan elemen UI saat diperlukan, misalnya:</p>
+
+<pre>
+&#64;Override
+public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+    if (isInPictureInPictureMode) {
+        // Hide the controls in picture-in-picture mode.
+        ...
+    } else {
+        // Restore the playback UI based on the playback status.
+        ...
+    }
+}
+</pre>
+
+<h2 id="continuing_playback">Melanjutkan Pemutaran Video Saat dalam
+Gambar-dalam-gambar</h2>
+
+<p>Bila aktivitas Anda beralih ke PIP, sistem akan menganggap aktivitas tersebut berada dalam
+keadaan berhenti sementara, dan akan memanggil metode <code>onPause()</code> aktivitas Anda. Pemutaran
+video tidak boleh berhenti sementara dan harus terus diputar jika aktivitas tersebut
+berhenti sementara karena mode PIP. Periksa PIP dalam metode
+<code>onPause()</code> aktivitas Anda dan tangani pemutaran dengan tepat,
+misalnya:</p>
+
+<pre>
+&#64;Override
+public void onPause() {
+    // If called while in PIP mode, do not pause playback
+    if (isInPictureInPictureMode()) {
+        // Continue playback
+        ...
+    }
+    // If paused but not in PIP, pause playback if necessary
+    ...
+}
+</pre>
+
+<p>Bila aktivitas meninggalkan mode PIP dan kembali ke mode layar penuh, sistem
+akan melanjutkan aktivitas Anda dan memanggil metode <code>onResume()</code>.</p>
+
+<h2 id="single_playback">Menggunakan Aktivitas Pemutaran Tunggal untuk
+ Gambar-dalam-gambar</h2>
+
+<p>Di aplikasi Anda, seorang pengguna bisa memilih video baru saat menyusuri materi di
+layar utama, selagi aktivitas pemutaran video dalam mode PIP. Putar
+video baru di aktivitas pemutaran yang ada dalam mode layar penuh, sebagai ganti
+meluncurkan aktivitas baru yang dapat membingungkan pengguna.</p>
+
+<p>Guna memastikan aktivitas tunggal digunakan untuk permintaan pemutaran video dan
+beralih ke atau dari mode PIP bila dibutuhkan, setel
+<code>android:launchMode</code> aktivitas ke <code>singleTask</code> dalam manifes Anda:
+</p>
+
+<pre>
+&lt;activity android:name="VideoActivity"
+    ...
+    android:supportsPictureInPicture="true"
+    android:launchMode="singleTask"
+    ...
+</pre>
+
+<p>Di aktivitas Anda, ganti {@link android.app.Activity#onNewIntent
+Activity.onNewIntent()} dan tangani video baru, yang akan menghentikan pemutaran video
+jika diperlukan.</p>
+
+<h2 id="best">Praktik Terbaik</h2>
+
+<p>PIP ditujukan untuk aktivitas yang memutar video layar penuh. Saat mengalihkan
+aktivitas Anda ke mode PIP, hindari menampilkan apa pun selain materi video.
+Pantau saat aktivitas Anda memasuki mode PIP dan sembunyikan elemen UI, seperti dijelaskan
+dalam <a href="#handling_ui">Menangani UI Selama Gambar-dalam-gambar</a>.</p>
+
+<p>Karena jendela PIP ditampilkan sebagai jendela mengambang di sudut
+layar, Anda harus menghindari menampilkan informasi penting di layar utama
+di area mana saja yang bisa terhalang oleh jendela PIP.</p>
+
+<p>Bila aktivitas ada berada dalam mode PIP, secara default aktivitas itu tidak mendapatkan fokus masukan. Untuk
+menerima kejadian masukan saat dalam mode PIP, gunakan
+<code>MediaSession.setMediaButtonReceiver()</code>.</p>
diff --git a/docs/html-intl/intl/id/training/tv/tif/content-recording.jd b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
new file mode 100644
index 0000000..3389dbf
--- /dev/null
+++ b/docs/html-intl/intl/id/training/tv/tif/content-recording.jd
@@ -0,0 +1,142 @@
+page.title=Perekaman TV
+page.keywords=pratinjau,sdk,tv,perekaman
+page.tags=androidn
+page.image=images/cards/card-nyc_2x.jpg
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dalam dokumen ini</h2>
+  <ol>
+    <li><a href="#supporting">Menunjukkan Dukungan untuk Perekaman</a></li>
+    <li><a href="#recording">Merekam Sesi</a></li>
+    <li><a href="#errors">Menangani Kesalahan Perekaman</a></li>
+    <li><a href="#sessions">Mengelola Sesi yang Direkam</a></li>
+    <li><a href="#best">Praktik Terbaik</a></li>
+  </ol>
+</div>
+</div>
+
+<p>Layanan masukan TV memungkinkan pengguna menghentikan sementara dan melanjutkan pemutaran saluran melalui
+API perekaman. Android N telah berkembang hingga ke perekaman
+dengan memungkinkan pengguna menyimpan beberapa sesi rekaman.</p>
+
+<p>Pengguna bisa menjadwalkan rekaman terlebih dahulu, atau memulai rekaman sambil menonton
+suatu acara. Setelah sistem menyimpan rekaman, pengguna bisa menjelajah, menata,
+dan memutar kembali rekaman tersebut menggunakan aplikasi TV di sistem.</p>
+
+<p>Jika Anda ingin menyediakan fungsi perekaman untuk layanan masukan TV,
+Anda harus menunjukkan pada sistem bahwa aplikasi Anda mendukung perekaman, mengimplementasikan
+kemampuan merekam program, menangani dan mengomunikasikan kesalahan yang muncul
+selama perekaman, dan mengelola sesi perekaman Anda.</p>
+
+<p class="note"><strong>Catatan:</strong> Aplikasi Live Channels belum
+menyediakan cara bagi pengguna untuk membuat atau mengakses perekaman. Hingga dibuat perubahan
+di aplikasi Live Channels, mungkin sulit menguji sepenuhnya pengalaman
+perekaman untuk layanan masukan TV Anda.</p>
+
+<h2 id="supporting">Menunjukkan Dukungan untuk Perekaman</h2>
+
+<p>Untuk memberi tahu sistem bahwa layanan masukan TV Anda mendukung perekaman, setel
+atribut <code>android:canRecord</code> di file XML metadata layanan Anda
+ke <code>true</code>:
+</p>
+
+<pre>
+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+  <b>android:canRecord="true"</b>
+  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" /&gt;
+</pre>
+
+<p>Untuk informasi selengkapnya mengenai layanan file metadata, lihat
+<a href="{@docRoot}training/tv/tif/tvinput.html#manifest">Mendeklarasikan Layanan Masukan TV Anda
+di Manifes</a>.
+</p>
+
+<p>Atau, Anda bisa menunjukkan dukungan perekaman dalam kode Anda menggunakan
+langkah-langkah ini:</p>
+
+<ol>
+<li>Dalam metode <code>TvInputService.onCreate()</code> Anda, buat objek
+<code>TvInputInfo</code> baru menggunakan kelas <code>TvInputInfo.Builder</code>.
+</li>
+<li>Saat membuat objek <code>TvInputInfo</code> baru, panggil
+<code>setCanRecord(true)</code> sebelum memanggil <code>build()</code> untuk
+ menunjukkan layanan Anda mendukung perekaman.</li>
+<li>Daftarkan objek <code>TvInputInfo</code> Anda pada sistem dengan memanggil
+<code>TvInputManager.updateTvInputInfo()</code>.</li>
+</ol>
+
+<h2 id="recording">Merekam Sesi</h2>
+
+<p>Setelah layanan masukan TV Anda mendaftar bahwa mendukung fungsionalitas
+perekaman, sistem akan memanggil
+<code>TvInputService.onCreateRecordingSession()</code> bila perlu untuk mengakses
+implementasi perekaman aplikasi Anda. Implementasikan subkelas
+<code>TvInputService.RecordingSession</code> Anda sendiri dan kembalikan
+bila callback <code>onCreateRecordingSession()</code> dipicu.
+ Subkelas ini bertanggung jawab mengalihkan ke saluran data yang benar,
+merekam data yang diminta, dan memberitahukan status perekaman serta kesalahan ke
+sistem.</p>
+
+<p>Bila sistem memanggil <code>RecordingSession.onTune()</code>, dengan meneruskan
+URI saluran, setel ke saluran yang ditetapkan URI. Beri tahu sistem bahwa
+aplikasi Anda telah disetel ke saluran yang diinginkan dengan memanggil <code>notifyTuned()</code>,
+atau, jika aplikasi Anda tidak bisa disetel ke saluran yang tepat, panggil
+<code>notifyError()</code>.</p>
+
+<p>Sistem berikutnya akan memanggil callback <code>RecordingSession.onStartRecording()</code>.
+ Aplikasi Anda harus segera mulai merekam. Bila sistem memanggil
+callback ini, sistem mungkin akan memberikan URI yang berisi informasi tentang program
+yang akan direkam. Bila perekaman selesai, Anda perlu menyalin data
+ini ke tabel data <code>RecordedPrograms</code>.</p>
+
+<p>Terakhir, sistem akan memanggil <code>RecordingSession.onStopRecording()</code>.
+Pada tahap ini, aplikasi Anda harus segera berhenti merekam. Anda juga perlu
+membuat entri dalam tabel <code>RecordedPrograms</code>. Entri ini harus
+menyertakan URI data sesi yang direkam dalam kolom
+<code>RecordedPrograms.COLUMN_RECORDING_DATA_URI</code>, dan informasi
+program yang diberikan sistem dalam panggilan awal ke
+<code>onStartRecording()</code>.</p>
+
+<p>Untuk detail selengkapnya tentang cara mengakses tabel <code>RecordedPrograms</code>
+lihat <a href="#sessions">Mengelola Sesi yang Direkam</a>.</p>
+
+<h2 id="errors">Menangani Kesalahan Perekaman</h2>
+
+<p>Jika terjadi kesalahan selama perekaman, yang menghasilkan data terekam yang tidak bisa digunakan,
+beri tahu sistem dengan memanggil <code>RecordingSession.notifyError()</code>.
+Begitu juga, Anda bisa memanggil <code>notifyError()</code> setelah sesi rekaman dibuat
+agar sistem mengetahui bahwa aplikasi Anda tidak bisa lagi merekam sesi.</p>
+
+<p>Jika terjadi kesalahan selama perekaman, namun Anda ingin menyediakan rekaman parsial
+yang bisa digunakan pengguna untuk pemutaran, panggil
+<code>RecordingSession.notifyRecordingStopped()</code> untuk memungkinkan sistem
+menggunakan sesi parsial.</p>
+
+<h2 id="sessions">Mengelola Sesi yang Direkam</h2>
+
+<p>Sistem menyimpan informasi untuk semua sesi yang direkam dari semua
+aplikasi saluran yang mampu merekam dalam tabel penyedia materi <code>TvContract.RecordedPrograms</code>.
+ Informasi ini bisa diakses lewat URI materi
+<code>RecordedPrograms.Uri</code>. Gunakan API penyedia materi untuk
+membaca, menambahkan, dan menghapus entri dari tabel ini.</p>
+
+<p>Untuk informasi selengkapnya tentang menangani data penyedia materi, lihat
+<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+Dasar-Dasar Penyedia Materi</a>.</p>
+
+<h2 id="best">Praktik Terbaik</h2>
+
+<p>Perangkat TV mungkin memiliki penyimpanan terbatas, jadi pertimbangkan sebaik mungkin saat
+mengalokasikan penyimpanan untuk menyimpan sesi rekaman. Gunakan
+<code>RecordingCallback.onError(RECORDING_ERROR_INSUFFICIENT_SPACE)</code> bila
+tidak cukup ruang untuk menyimpan sesi rekaman.</p>
+
+<p>Bila pengguna memulai perekaman, Anda harus memulai perekaman data
+secepatnya. Untuk memfasilitasinya, selesaikan setiap tugas yang memakan waktu di awal,
+seperti mengakses dan mengalokasikan ruang penyimpanan, saat sistem memanggil callback
+<code>onCreateRecordingSession()</code>. Hal ini akan memungkinkan Anda memulai
+perekaman dengan segera bila callback <code>onStartRecording()</code>
+dipicu.</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..212870a 100644
--- a/docs/html-intl/intl/in/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/in/about/versions/nougat/index.jd
@@ -1,107 +1,72 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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 -->
 </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>
-        Laporkan masalah
-          </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Lihat catatan rilis
-          </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Bergabunglah dengan komunitas pengembang
-          </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">Terbaru</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +78,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/in/preview/features/background-optimization.jd b/docs/html-intl/intl/in/preview/features/background-optimization.jd
deleted file mode 100644
index c6bf175..0000000
--- a/docs/html-intl/intl/in/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=Optimalisasi Latar Belakang
-page.metaDescription=Pembatasan baru pada siaran implisit.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      Dalam dokumen ini
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">Pembatasan pada CONNECTIVITY_ACTION</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">Menjadwalkan Pekerjaan Jaringan pada Koneksi
-        Berbiaya Tetap</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Memantau Konektivitas Jaringan Saat Aplikasi
-        Dijalankan</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">Pembatasan pada NEW_PICTURE dan
-        NEW_VIDEO</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">Metode JobInfo Baru</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">Metode JobParameter Baru</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">Mengoptimalkan Aplikasi Anda Lebih Jauh</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  Proses latar belakang bisa menguras memori dan baterai. Misalnya, sebuah
-  siaran implisit dapat memulai banyak proses latar belakang yang telah didaftarkan
-  untuk mendengarkannya, sekalipun proses-proses itu mungkin tidak melakukan banyak pekerjaan. Hal ini bisa
-  berdampak besar pada kinerja perangkat dan pengalaman pengguna.
-</p>
-
-<p>
-  Untuk meringankan masalah ini, Android N menerapkan pembatasan
-  berikut:
-</p>
-
-<ul>
-  <li>Aplikasi yang menargetkan Pratinjau tidak menerima siaran {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} jika mereka
-  mendaftar untuk menerimanya dalam manifes mereka. Aplikasi yang berjalan tetap
-  bisa mendengarkan {@code CONNECTIVITY_CHANGE} pada thread utama mereka dengan mendaftarkan
-  {@link android.content.BroadcastReceiver} pada {@link
-  android.content.Context#registerReceiver Context.registerReceiver()}.
-  </li>
-
-  <li>Aplikasi tidak bisa mengirim atau menerima siaran {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} atau {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Optimalisasi ini
-  memengaruhi semua aplikasi, tidak hanya aplikasi yang menargetkan Pratinjau.
-  </li>
-</ul>
-
-<p>
-  Jika aplikasi Anda menggunakan intent ini, Anda harus membuang dependensi padanya
-  secepat mungkin agar Anda bisa menargetkan perangkat Android N dengan benar.
-  Kerangka kerja Android menyediakan beberapa solusi untuk mengurangi kebutuhan akan
-  siaran implisit ini. Misalnya, {@link android.app.job.JobScheduler}
-  dan<a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> menyediakan mekanisme yang tangguh untuk menjadwalkan operasi
-  jaringan bila kondisi yang ditetapkan, seperti koneksi ke jaringan
-  berbiaya tetap, terpenuhi. Anda sekarang juga bisa menggunakan {@link android.app.job.JobScheduler}
-  untuk bereaksi terhadap perubahan penyedia materi. Objek {@link android.app.job.JobInfo}
-  membungkus parameter yang digunakan {@link android.app.job.JobScheduler}
-  untuk menjadwalkan pekerjaan Anda. Bila syarat-syarat pekerjaan sudah terpenuhi, sistem
-  akan mengeksekusi pekerjaan ini pada {@link android.app.job.JobService} aplikasi Anda.
-</p>
-
-<p>
-  Dalam dokumen ini, kita akan mempelajari cara menggunakan metode alternatif, seperti
-  {@link android.app.job.JobScheduler}, untuk menyesuaikan aplikasi Anda dengan pembatasan
-  yang baru.
-</p>
-
-<h2 id="connectivity-action">
-  Pembatasan pada CONNECTIVITY_ACTION
-</h2>
-
-<p>
-  Aplikasi yang menargetkan Android N tidak menerima siaran {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} jika mereka
-  mendaftar untuk menerimanya dalam manifes mereka, dan proses yang bergantung pada siaran
-  ini tidak akan dimulai. Hal ini bisa menimbulkan masalah bagi aplikasi yang ingin
-  memantau perubahan jaringan atau melakukan aktivitas jaringan dalam jumlah besar bila perangkat
-  menghubungkan ke jaringan berbiaya tetap. Beberapa solusi untuk menyiasati pembatasan
-  ini sudah ada dalam kerangka kerja Android, namun pemilihan solusi
-  yang tepat bergantung pada apa yang ingin dicapai oleh aplikasi Anda.
-</p>
-
-<p class="note">
-  <strong>Catatan:</strong> Sebuah {@link android.content.BroadcastReceiver} yang mendaftar pada
-  {@link android.content.Context#registerReceiver Context.registerReceiver()}
-  akan terus menerima siaran ini saat aplikasi berjalan.
-</p>
-
-<h3 id="sched-jobs">
-  Menjadwalkan Pekerjaan Jaringan pada Koneksi Berbiaya Tetap
-</h3>
-
-<p>
-  Saat menggunakan kelas {@link android.app.job.JobInfo.Builder JobInfo.Builder}
-  untuk membangun objek {@link android.app.job.JobInfo} Anda, terapkan metode {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} dan teruskan {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} sebagai parameter pekerjaan. Contoh kode berikut
-  menjadwalkan layanan yang akan dijalankan ketika perangkat terhubung ke jaringan
-  berbiaya tetap dan dikenai biaya:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  Bila syarat untuk pekerjaan Anda terpenuhi, aplikasi Anda akan menerima callback untuk menjalankan
-  metode {@link android.app.job.JobService#onStartJob onStartJob()} dalam
-  {@code JobService.class} yang ditetapkan. Untuk melihat contoh selengkapnya mengenai implementasi {@link
-  android.app.job.JobScheduler}, lihat <a href="{@docRoot}samples/JobScheduler/index.html">aplikasi contoh JobScheduler</a>.
-</p>
-
-<p>
-  Aplikasi yang menggunakan layanan GMSCore, dan menargetkan Android 5.0 (API level 21)
-  atau yang lebih rendah, bisa menggunakan <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> dan menetapkan {@code Task.NETWORK_STATE_UNMETERED}.
-</p>
-
-<h3 id="monitor-conn">
-  Memantau Konektivitas Jaringan Saat Aplikasi Dijalankan
-</h3>
-
-<p>
-  Aplikasi yang berjalan tetap bisa memantau {@code CONNECTIVITY_CHANGE} dengan
-  {@link android.content.BroadcastReceiver} yang telah didaftarkan. Akan tetapi, {@link
-  android.net.ConnectivityManager} API menyediakan metode yang lebih tangguh untuk meminta
-  callback hanya bila persyaratan jaringan yang ditetapkan terpenuhi.
-</p>
-
-<p>
-  Objek {@link android.net.NetworkRequest} mendefinisikan parameter
-  callback jaringan dari segi {@link android.net.NetworkCapabilities}. Anda
-  membuat objek {@link android.net.NetworkRequest} dengan kelas {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder}. {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
-  kemudian meneruskan objek {@link android.net.NetworkRequest} ke sistem. Bila
-  syarat jaringan terpenuhi, aplikasi akan menerima callback untuk mengeksekusi
-  metode {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} yang didefinisikan dalam kelas {@link
-  android.net.ConnectivityManager.NetworkCallback}.
-</p>
-
-<p>
-  Aplikasi akan terus menerima callback hingga aplikasi keluar atau memanggil
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}.
-</p>
-
-<h2 id="media-broadcasts">
-  Pembatasan pada NEW_PICTURE dan NEW_VIDEO
-</h2>
-
-<p>
-  Di Android N, aplikasi tidak bisa mengirim atau menerima siaran {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} atau {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Pembatasan ini membantu
-  meringankan dampak terhadap kinerja dan pengalaman pengguna bila beberapa aplikasi harus
-  aktif untuk memproses gambar atau video baru. Android N
-  memperluas {@link android.app.job.JobInfo} dan {@link
-  android.app.job.JobParameters} untuk menyediakan solusi alternatif.
-</p>
-
-<h3 id="new-jobinfo">
-  Metode JobInfo baru
-</h3>
-
-<p>
-  Untuk memicu pekerjaan saat perubahan URI materi, Android N memperluas
-  {@link android.app.job.JobInfo} API dengan metode berikut:
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    Membungkus parameter yang diperlukan untuk memicu pekerjaan saat perubahan URI materi.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    Meneruskan objek {@code TriggerContentUri} ke {@link
-    android.app.job.JobInfo}. Sebuah {@link android.database.ContentObserver}
-    akan memantau URI materi yang dibungkus. Jika terdapat beberapa objek {@code
-    TriggerContentUri} yang berhubungan dengan pekerjaan, sistem memberikan sebuah
-    callback bahkan jika itu hanya melaporkan perubahan pada salah satu URI materi.
-  </dd>
-
-  <dd>
-    Tambahkan flag {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} untuk
-    memicu pekerjaan jika ada turunan dari perubahan URI yang diberikan. Flag ini
-    berkaitan dengan parameter {@code notifyForDescendants} yang diteruskan ke {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>Catatan:</strong> {@code TriggerContentUri()} tidak bisa digunakan
-  bersama-sama dengan {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} atau {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}. Untuk terus memantau perubahan materi, jadwalkan
-  {@link android.app.job.JobInfo} baru sebelum {@link
-  android.app.job.JobService} aplikasi selesai menangani callback terbaru.
-</p>
-
-<p>
-  Kode contoh berikut menjadwalkan pekerjaan yang akan dipicu bila sistem melaporkan
-  perubahan ke URI materi, {@code MEDIA_URI}:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  Bila sistem melaporkan perubahan dalam URI materi yang ditetapkan, aplikasi Anda
-  akan menerima callback dan objek {@link android.app.job.JobParameters}
-  akan diteruskan ke metode {@link android.app.job.JobService#onStartJob onStartJob()}
-  dalam {@code MediaContentJob.class}.
-</p>
-
-<h3 id="new-jobparam">
-  Metode JobParameter Baru
-</h3>
-
-<p>
-  Android N juga memperluas {@link android.app.job.JobParameters} untuk
-  memungkinkan aplikasi Anda menerima informasi yang berguna tentang otoritas materi
-  dan URI yang memicu pekerjaan:
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    Mengembalikan larik URL yang telah memicu pekerjaan. Ini akan berupa {@code
-    null} jika tidak ada URI yang memicu pekerjaan (misalnya, pekerjaan
-    dipicu karena batas waktu atau alasan lainnya), atau jumlah
-    URI yang berubah lebih dari 50.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    Mengembalikan larik string otoritas materi yang telah memicu pekerjaan.
-    Jika larik yang dikembalikan bukan {@code null}, gunakan {@code getTriggeredContentUris()}
-    untuk mengambil detail URI yang telah berubah.
-  </dd>
-</dl>
-
-<p>
-  Kode contoh berikut mengganti metode {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} dan
-  mencatat otoritas materi serta URI yang telah memicu pekerjaan:
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  Mengoptimalkan Aplikasi Anda Lebih Jauh
-</h2>
-
-<p>
-  Mengoptimalkan aplikasi Anda untuk berjalan pada perangkat yang mempunyai memori rendah, atau dalam kondisi
-  memori rendah, dapat meningkatkan kinerja dan pengalaman pengguna. Membuang
-  dependensi pada layanan latar belakang dan penerima siaran
-  implisit yang terdaftar secara statis bisa membantu aplikasi Anda berjalan lebih baik pada perangkat demikian. Meskipun
-  Android N telah mengambil langkah-langkah untuk mengurangi sebagian masalah ini, Anda disarankan
-  agar mengoptimalkan aplikasi untuk berjalan tanpa menggunakan
-  proses latar belakang ini sama sekali.
-</p>
-
-<p>
-  Android N memperkenalkan beberapa tambahan perintah <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> yang
-  bisa Anda gunakan untuk menguji perilaku aplikasi dengan proses latar belakang dinonaktifkan:
-</p>
-
-<ul>
-  <li>Untuk mensimulasikan kondisi saat siaran implisit dan layanan latar belakang
-  tidak tersedia, masukkan perintah berikut:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>Untuk mengaktifkan kembali siaran implisit dan layanan latar belakang, masukkan
-  perintah berikut:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/in/preview/features/icu4j-framework.jd b/docs/html-intl/intl/in/preview/features/icu4j-framework.jd
deleted file mode 100644
index 1d97623..0000000
--- a/docs/html-intl/intl/in/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=ICU4J Android Framework API
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Dalam dokumen ini:</h2>
-<ol>
-    <li><a href="#relation">Hubungan dengan ICU4J</a></li>
-    <li><a href="#migration">Migrasi ke android.icu API dari ICU4J </a></li>
-    <li><a href="#licence">Lisensi</a></li>
-</ol>
-
-<h2>Lihat Juga</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">Dokumentasi untuk ICU4J</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">Standar terbaru yang didukung
-    oleh ICU4J</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J merupakan serangkaian pustaka Java sumber terbuka yang banyak digunakan dan menyediakan Unicode
-  serta dukungan globalisasi untuk aplikasi perangkat lunak. Android N
-  mengekspos subset ICU4J API dalam kerangka kerja Android bagi pengembang aplikasi
-  untuk digunakan pada paket {@code android.icu}. API ini menggunakan
-  data pelokalan yang ada pada perangkat. Hasilnya, Anda bisa mengurangi footprint
-  APK dengan tidak mengompilasi pustaka ICU4J ke APK Anda; sebagai gantinya,
-  cukup memanggilnya dalam kerangka kerja. (Dalam hal ini, Anda mungkin perlu menyediakan
-  <a href="{@docRoot}google/play/publishing/multiple-apks.html">beberapa versi
-  APK Anda</a>, sehingga pengguna yang menjalankan versi Android lebih rendah dari Android N
-  bisa mengunduh versi aplikasi yang berisi pustaka ICU4J.)
-</p>
-
-<p>
-  Dokumen ini diawali dengan menyediakan beberapa informasi dasar tentang level Android API
-  minimum yang diperlukan untuk mendukung pustaka-pustaka ini. Kemudian dijelaskan tentang apa
-  yang perlu Anda ketahui tentang implementasi ICU4J spesifik Android. Terakhir,
-  Anda akan diberi tahu cara menggunakan ICU4J API dalam kerangka kerja Android.
-</p>
-
-<h2 id="relation">Hubungan dengan ICU4J</h2>
-
-<p>
-  Android N mengekspos subset ICU4J API lewat
-  paket <code>android.icu</code>, bukannya <code>com.ibm.icu</code>. Kerangka kerja
-  Android dapat memilih untuk tidak
-  mengekspos ICU4J API karena berbagai alasan; misalnya, Android N tidak mengekspos
-  beberapa API yang tidak digunakan lagi atau yang dinyatakan belum
-  stabil oleh tim ICU. Karena tim ICU tidak lagi menggunakan API di masa mendatang, Android juga akan menandainya
-  sebagai tidak digunakan lagi namun akan terus menyertakannya.
-</p>
-
-<p class="table-caption"><strong>Tabel 1.</strong> Versi ICU dan CLDR yang digunakan
-  di Android N.</p>
-<table>
-<tr>
-<th>Level Android API</th>
-<th>Versi ICU</th>
-<th>Versi CLDR</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>Inilah beberapa hal penting yang harus diperhatikan:</p>
-
-<ul>
-<li>ICU4J Android Framework API tidak menyertakan semua ICU4J API.</li>
-<li>Pengembang NDK harus mengetahui bahwa Android ICU4C tidak didukung.</li>
-<li>API dalam kerangka kerja Android tidak menggantikan dukungan Android untuk
-<a href="{@docRoot}guide/topics/resources/localization.html">melokalkan dengan
-sumber daya</a>.</li>
-</ul>
-
-<h2 id="migration">Migrasi ke paket android.icu dari com.ibm.icu</h2>
-
-<p>
-  Jika Anda sudah menggunakan ICU4J API dalam aplikasi, dan
-  <code>android.icu</code> API memenuhi persyaratan Anda, maka migrasi ke
-  API kerangka kerja mengharuskan Anda untuk mengubah impor Java
-  dari <code>com.ibm.icu</code> ke <code>android.icu</code>. Kemudian Anda bisa
-  membuang salinan file ICU4J dari APK.
-</p>
-
-<p class="note">
-  <b>Catatan</b>: API kerangka kerja ICU4J menggunakan ruang nama {@code android.icu}
-  sebagai ganti {@code com.ibm.icu}. Hal ini untuk menghindari konflik
-  ruang nama di APK yang berisi pustaka {@code com.ibm.icu} sendiri.
-</p>
-
-<h3 id="migrate-from-android">
-  Migrasi ke API android.icu dari Android SDK API lainnya
-</h3>
-
-<p>
-  Beberapa kelas dalam paket <code>java</code> dan <code>android</code> memiliki
-  padanannya dengan yang ditemukan di ICU4J. Akan tetapi, ICU4J seringkali menyediakan dukungan
-  yang lebih luas untuk standar dan bahasa.
-</p>
-<p>Inilah beberapa contoh untuk membantu Anda memulai:</p>
-<table>
-<tr>
-<th>Kelas</th>
-<th>Alternatif</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">Lisensi</h2>
-
-<p>
-  ICU4J dirilis dengan lisensi ICU. Untuk detailnya, lihat <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">Panduan Pengguna
-  ICU.</a>
-</p>
diff --git a/docs/html-intl/intl/in/preview/features/multilingual-support.jd b/docs/html-intl/intl/in/preview/features/multilingual-support.jd
deleted file mode 100644
index 29104cb..0000000
--- a/docs/html-intl/intl/in/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=Bahasa dan Lokal
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Dalam dokumen ini:</h2>
-<ol>
-	  <li><a href="#preN">Tantangan dalam Mengatasi Masalah Sumber Daya Bahasa</a></li>
-    <li><a href="#postN">Peningkatan pada Strategi Resolusi Sumber Daya</a></li>
-    <li><a href="#design">Mendesain Aplikasi Anda untuk Mendukung Lokal
-      Tambahan</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N memberikan dukungan yang disempurnakan untuk pengguna multibahasa,
-yang memungkinkan mereka memilih beberapa lokal dalam setelan. Android N
-menyediakan kemampuan ini dengan memperbanyak jumlah lokal yang didukung
-dan mengubah cara sistem mengatasi masalah sumber daya. Metode baru mengatasi
-masalah sumber daya ini lebih tangguh dan didesain agar kompatibel dengan APK yang ada, namun
-Anda harus ekstra hati-hati terhadap perilaku tak terduga. Misalnya, Anda
-harus menguji untuk memastikan aplikasi Anda secara default diatur ke bahasa yang diinginkan. Juga,
-jika aplikasi Anda mendukung beberapa bahasa, Anda harus memastikan dukungan ini berfungsi
-sebagaimana diinginkan. Terakhir, Anda harus mencoba memastikan aplikasi Anda dengan lancar menangani
-bahasa yang tidak secara eksplisit Anda dukung dalam desain.</p>
-
-<p>Dokumen ini diawali dengan menjelaskan strategi resolusi sumber daya sebelum
-Android N. Berikutnya, akan dijelaskan strategi
-resolusi sumber daya Android N yang telah ditingkatkan. Terakhir, akan djelaskan cara memanfaatkan
-jumlah lokal yang telah diperbanyak untuk mendukung lebih banyak pengguna multibahasa.</p>
-
-<h2 id="preN">Tantangan dalam Mengatasi Masalah Sumber Daya Bahasa</h2>
-
-<p>Sebelum Android N, Android tidak selalu
- berhasil mencocokkan lokal aplikasi dan lokal sistem.</p>
-
- <p>Misalnya, anggaplah Anda menghadapi situasi berikut:</p>
- <ul>
- <li>Bahasa default aplikasi Anda adalah {@code en_US} (US English), dan aplikasi juga
-  berisi string bahasa Spanyol yang telah dilokalkan di file sumber daya {@code es_ES}.
-</li>
- <li> Perangkat telah disetel ke {@code es_MX} </li>
-
-<p>Bila kode Java Anda merujuk ke string, sistem akan memuat
-string dari file sumber daya default ({@code en_US}), sekalipun aplikasi memiliki
-sumber daya bahasa Spanyol yang dilokalkan pada {@code es_ES}. Hal ini karena bila sistem
-  tidak bisa menemukan hasil yang persis, sistem akan terus mencari sumber daya dengan menghilangkan
-  kode negara dari lokal tersebut. Akhirnya, jika tidak ada hasil yang ditemukan, sistem akan mengembalikan
- ke default, yakni {@code en_US}. </p>
-
-
-<p>Sistem juga akan default ke {@code en_US} jika pengguna memilih
-bahasa yang sama sekali tidak didukung oleh aplikasi, seperti bahasa Prancis. Misalnya:</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>Tabel 1.</strong> Resolusi sumber daya tanpa lokal yang persis sama.
-</p>
-<table>
-<tbody>
-<tr>
-<th>Setelan Pengguna</th>
-<th>Sumber Daya Aplikasi</th>
-<th>Resolusi Sumber Daya</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-default (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-Coba fr_CH =&gt; Gagal<br>
-Coba fr =&gt; Gagal<br>
-Gunakan default (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>Dalam contoh ini, sistem menampilkan string bahasa Inggris
-tanpa mengetahui apakah pengguna memahami bahasa Inggris. Perilaku ini sudah sangat umum
-sekarang. Android N harus mengurangi frekuensi
-hasil seperti ini secara substansial.</p>
-
-<h2 id="postN">Peningkatan pada Strategi Resolusi Sumber Daya</h2>
-<p>Android N menghadirkan resolusi sumber daya yang lebih handal, dan
-secara otomatis menemukan solusi yang lebih baik. Akan tetapi, untuk mempercepat resolusi dan meningkatkan
-kemudahan pemeliharaan, Anda harus menyimpan sumber daya dalam dialek induk yang paling umum.
- Misalnya, jika sebelumnya Anda telah menyimpan sumber daya bahasa Spanyol di direktori {@code es-US}
-, pindahkan ke direktori {@code es-419}, yang berisi bahasa Spanyol Amerika Latin.
- Demikian pula, jika Anda memiliki string sumber daya dalam folder bernama {@code en-GB}, ganti nama
- folder itu menjadi {@code en-001} (bahasa Inggris internasional), karena induk yang paling umum
- untuk string <code>en-GB</code> adalah {@code en-001}.
- Contoh berikut menjelaskan mengapa praktik-praktik ini meningkatkan kinerja dan
-reliabilitas resolusi sumber daya.</p>
-
-<h3>Contoh resolusi sumber daya</h3>
-
-<p>Dengan Android N, kasus yang dijelaskan dalam <strong>Tabel 1</strong> diatasi
-secara berbeda:</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>Tabel 2.</strong> Strategi resolusi yang ditingkatkan bila tidak ada
-lokal yang sama persis.</p>
-<table>
-<tr>
-<th>Setelan Pengguna</th>
-<th>Sumber Daya Aplikasi</th>
-<th>Resolusi Sumber Daya</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-default (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-Coba fr_CH =&gt; Gagal<br>
-Coba fr =&gt; Gagal<br>
-Coba anak dari fr =&gt; fr_FR<br>
-Gunakan fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>Sekarang pengguna mendapatkan sumber daya bahasa Prancis sebagai ganti bahasa Inggris. Contoh ini juga menunjukkan
- mengapa Anda harus menyimpan string bahasa Prancis di {@code fr} bukan pada {@code fr_FR}
- untuk Android N. Arah aksi di sini adalah untuk mencocokkan dengan induk dialek terdekat,
- membuat resolusi lebih cepat dan lebih dapat diprediksi.</p>
-
-<p>Selain logika resolusi yang diperbaiki ini, Android sekarang menawarkan lebih banyak
-pilihan bahasa untuk pengguna. Mari kita coba lagi contoh di atas dengan menetapkan bahasa Italia
- sebagai bahasa pengguna tambahan, tetapi tanpa dukungan aplikasi untuk bahasa Prancis.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>Tabel 3.</strong> Resolusi sumber daya bila aplikasi hanya mencocokkan
-setelan lokal yang disukai kedua oleh pengguna.</p>
-<table>
-<tr>
-<th>Setelan Pengguna</th>
-<th>Sumber Daya Aplikasi</th>
-<th>Resolusi Sumber Daya</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-default (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-Coba fr_CH =&gt; Gagal<br>
-Coba fr =&gt; Gagal<br>
-Coba anak dari fr =&gt; Gagal<br>
-Coba it_CH =&gt; Gagal<br>
-Coba it =&gt; Gagal<br>
-Coba anak dari it =&gt; it_IT<br>
-Gunakan it_IT
-</td>
-
-</tr>
-
-</table>
-<p>Pengguna tetap mendapatkan bahasa yang mereka pahami, meskipun aplikasi tidak
-mendukung bahasa Prancis.</p>
-
-
-<h2 id="design">Mendesain Aplikasi Anda untuk Mendukung Lokal Tambahan</h2>
-<h3>LocaleList API</h3>
-
-<p>Android N menambahkan API baru {@code LocaleList.getDefault()}
-yang memungkinkan aplikasi langsung kueri daftar bahasa yang telah ditetapkan pengguna. API ini
-memungkinkan Anda membuat
- perilaku aplikasi yang lebih canggih dan tampilan materi yang lebih optimal. Misalnya, Telusur
-  bisa menampilkan hasil dalam beberapa bahasa berdasarkan setelan pengguna.  Aplikasi browser
-  bisa menghindari penawaran menerjemahkan halaman dalam bahasa yang sudah diketahui pengguna,
-  dan aplikasi keyboard bisa mengaktifkan otomatis semua layout yang sesuai. </p>
-
-<h3>Formatter</h3>
-
-<p>Hingga Android 6.0 (API level 23), Android hanya mendukung satu atau dua lokal
- untuk banyak bahasa umum
-(en, es, ar, fr, ru). Karena hanya ada beberapa varian dari setiap bahasa,
-aplikasi bisa menghindar dengan menyimpan beberapa nomor dan tanggal sebagai string hard-code
-dalam file sumber daya.  Akan tetapi, dengan perluasan set lokal yang didukung Android,
-maka akan ada
-perbedaan format yang signifikan untuk tanggal, waktu, mata uang, dan informasi
-serupa bahkan dalam lokal tunggal. Menjadikan format Anda sebagai hard-code bisa menghasilkan
-pengalaman yang membingungkan bagi pengguna akhir.  Karena itu, saat mengembangkan untuk Android N
-pastikan menggunakan formatter sebagai ganti menjadikan string angka dan tanggal sebagai hard-code.</p>
-
-<p>Contoh terbaik adalah bahasa Arab, yang mendukung Android N berkembang dari
-satu {@code ar_EG} menjadi 27 lokal bahasa Arab. Bahasa lokal ini bisa berbagi hampir semua sumber daya,
-namun sebagian lebih memilih digit ASCII, sementara yang lain memilih digit asli. Misalnya,
-bila Anda ingin membuat kalimat dengan variabel digit, seperti
-"Pilih PIN 4 digit", gunakan formatter seperti yang ditampilkan di bawah ini:</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/in/preview/features/notification-updates.jd b/docs/html-intl/intl/in/preview/features/notification-updates.jd
deleted file mode 100644
index 0ad2770..0000000
--- a/docs/html-intl/intl/in/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,393 +0,0 @@
-page.title=Pemberitahuan
-page.tags=pemberitahuan
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>Dokumen ini berisi</h2>
-<ol>
-  <li><a href="#direct">Balasan Langsung</a></li>
-  <li><a href="#bundle">Bundel Pemberitahuan</a></li>
-  <li><a href="#custom">Tampilan Khusus</a></li>
-  <li><a href="#style">Gaya Pesan</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N memperkenalkan beberapa API baru yang memungkinkan aplikasi untuk mengeposkan
-pemberitahuan yang sangat mudah terlihat dan interaktif.</p>
-
-<p>Android N menambahkan API pemberitahuan{@link android.support.v4.app.RemoteInput}
-yang ada untuk mendukung balasan inline pada handset. Fitur ini memungkinkan pengguna
- merespons dengan cepat dari bayangan pemberitahuan tanpa mengunjungi aplikasi Anda.</p>
-
-<p>
-  Android N juga memungkinkan Anda menggabungkan pemberitahuan yang serupa agar
-  muncul sebagai satu pemberitahuan. Untuk memungkinkan hal ini, Android N menggunakan metode {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} yang sudah ada. Pengguna bisa memperluas setiap
-  pemberitahuan, dan melakukan tindakan seperti membalas dan menutup setiap
-  pemberitahuan, satu per satu dari bayangan pemberitahuan.
-</p>
-
-<p>Terakhir, Android N juga menambahkan API baru yang memungkinkan Anda untuk memanfaatkan dekorasi
-sistem dalam tampilan pemberitahuan yang disesuaikan untuk aplikasi Anda. API ini membantu
-memastikan semua tampilan pemberitahuan sama-sama menggunakan penyajian yang konsisten dengan
-template standar.</p>
-
-<p>Dokumen ini menyoroti beberapa perubahan penting yang harus Anda
- perhitungkan saat menggunakan fitur pemberitahuan baru dalam aplikasi Anda.</p>
-
-<h2 id="direct">Balasan Langsung</h2>
-
-<p>Dengan fitur Balasan Langsung di Android N, pengguna bisa dengan cepat
-merespons pesan teks atau memperbarui daftar tugas secara langsung dalam antarmuka
-pemberitahuan. Pada perangkat genggam, tindakan balasan inline muncul sebagai tombol tambahan
- yang dilampirkan pada pemberitahuan. Bila pengguna membalas lewat keyboard, sistem akan melampirkan
- respons teks ke intent
-    yang telah Anda tetapkan untuk tindakan pemberitahuan dan mengirimkan intent ke
-     aplikasi perangkat genggam Anda.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>Gambar 1.</strong> Android N menambahkan tombol tindakan <strong>Reply</strong>.
-
-</p>
-
-<h3>Menambahkan tindakan balasan inline</h3>
-
-<p>Untuk membuat tindakan pemberitahuan yang mendukung balasan langsung:
-</p>
-
-<ol>
-<li>Buat instance {@link android.support.v4.app.RemoteInput.Builder}
- yang bisa Anda tambahkan ke tindakan
-pemberitahuan. Konstruktor kelas ini akan menerima string bahwa sistem menggunakannya sebagai kunci
- untuk masukan teks. Kemudian, aplikasi perangkat genggam Anda akan menggunakan kunci itu untuk mengambil teks
-  masukan tersebut.
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>Lampirkan objek {@link android.support.v4.app.RemoteInput}
- pada tindakan dengan menggunakan <code>addRemoteInput()</code>.
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>Terapkan tindakan pada pemberitahuan dan keluarkan pemberitahuan.
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> Sistem akan meminta pengguna memasukkan respons bila mereka memicu
-tindakan pemberitahuan. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Gambar 2.</strong> Pengguna memasukkan teks dari bayangan pemberitahuan.
-</p>
-
-<h3>
-  Mengambil masukan pengguna dari balasan inline
-</h3>
-
-<p>
-  Untuk menerima masukan pengguna dari antarmuka pemberitahuan ke aktivitas yang Anda
-deklarasikan dalam intent tindakan balasan:
-</p>
-
-<ol>
-  <li>Panggil {@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()} dengan meneruskan intent tindakan pemberitahuan sebagai
-  parameter masukan. Metode ini mengembalikan {@link android.os.Bundle} yang
-  berisi respons teks.
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>Lakukan kueri pada bundel menggunakan kunci hasil (diberikan ke konstruktor {@link
-  android.support.v4.app.RemoteInput.Builder}). Anda bisa menyelesaikan
-  proses ini dan mengambil teks masukan dengan membuat sebuah metode, seperti dalam
-  cuplikan kode berikut:
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>Kompilasilah dan keluarkan pemberitahuan lain, menggunakan ID pemberitahuan yang sama dengan
-  yang Anda berikan untuk pemberitahuan sebelumnya. Indikator kemajuan
-    menghilang dari antarmuka pemberitahuan untuk memberi tahu pengguna mengenai balasan
-    yang berhasil. Saat menangani pemberitahuan baru ini, gunakan konteks yang
-    diteruskan ke metode {@code onReceive()} penerima.
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  Untuk aplikasi interaktif, seperti chat, akan berguna bila menyertakan
-  konteks tambahan saat menangani teks yang diambil. Misalnya, aplikasi ini bisa menampilkan
-  beberapa baris riwayat chat sekaligus. Bila pengguna merespons melalui {@link
-  android.support.v4.app.RemoteInput}, Anda bisa memperbarui riwayat balasan
-  menggunakan metode {@code setRemoteInputHistory()}.
-</p>
-
-<p>
-  Pemberitahuan harus diperbarui atau dibatalkan setelah aplikasi
- menerima masukan jarak jauh. Bila pengguna membalas ke pembaruan jarak jauh
-  menggunakan Balasan Langsung,
-  jangan batalkan pemberitahuan. Melainkan, perbarui pemberitahuan untuk menampilkan balasan pengguna.
-Untuk pemberitahuan yang menggunakan {@code MessagingStyle}, Anda harus menambahkan
-balasannya sebagai pesan terbaru. Saat menggunakan template lain, Anda bisa
-menambahkan balasan pengguna ke riwayat masukan jarak jauh.
-</p>
-
-<h2 id="bundle">Bundel Pemberitahuan</h2>
-
-<p>Android N membekali pengembang dengan sebuah cara baru untuk menyatakan
- antrean pemberitahuan: <i>bundel pemberitahuan</i>. Ini mirip dengan fitur
-  <a href="{@docRoot}training/wearables/notifications/stacks.html">Tumpukan
-  Pemberitahuan</a> dalam Android Wear. Misalnya, jika aplikasi Anda membuat pemberitahuan
-  untuk pesan yang diterima, bila lebih dari satu pesan diterima, pemberitahuan tersebut akan
- dibundel sebagai satu grup. Anda bisa
- menggunakan metode {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} yang ada untuk membundel pemberitahuan yang sama.</p>
-
-<p>
-  Grup pemberitahuan menerapkan hierarki pada pemberitahuan yang ada di dalamnya.
-  Di bagian teratas hierarki adalah pemberitahuan induk yang menampilkan informasi
-  rangkuman untuk grup tersebut. Pengguna secara bertahap bisa
-  memperbesar grup pemberitahuan, dan sistem akan menampilkan informasi lebih banyak saat
-  pengguna menggali lebih dalam. Bila pengguna memperbesar bundel, sistem akan memperlihatkan informasi lebih
-  banyak untuk semua pemberitahuan anak; bila pengguna
-  memperbesar salah satu pemberitahuan tersebut, sistem akan memperlihatkan seluruh isinya.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Gambar 3.</strong> Pengguna secara bertahap bisa memperluas grup
-  pemberitahuan.
-</p>
-
-<p class="note">
-  <strong>Catatan:</strong> Jika aplikasi yang sama mengirim empat atau beberapa pemberitahuan
-  dan tidak menetapkan pengelompokan,
-  sistem secara otomatis akan mengelompokannya.
-</p>
-
-<p>Untuk mengetahui cara menambahkan pemberitahuan ke grup, lihat
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">Menambahkan
-Setiap Pemberitahuan ke Grup</a>.</p>
-
-
-<h3 id="best-practices">Praktik terbaik untuk bundel pemberitahuan</h3>
-<p>Bagian ini memberikan panduan tentang kapan menggunakan grup pemberitahuan sebagai ganti
-pemberitahuan {@link android.app.Notification.InboxStyle InboxStyle}
-yang telah tersedia di
-platform Android versi sebelumnya.</p>
-
-<h3>Kapan menggunakan bundel pemberitahuan</h3>
-
-<p>Anda harus menggunakan grup pemberitahuan hanya jika semua kondisi berikut ini
-bernilai benar untuk kasus penggunaan Anda:</p>
-
-<ul>
-  <li>Pemberitahuan anak adalah pemberitahuan lengkap dan bisa ditampilkan
-   masing-masing tanpa perlu rangkuman grup.</li>
-  <li>Ada untungnya memunculkan pemberitahuan anak satu per satu. Misalnya:
-
-  </li>
-  <ul>
-    <li>Mereka dapat diaplikasikan, dengan tindakan khusus untuk masing-masing anak.</li>
-    <li>Ada lebih banyak informasi pada anak yang ingin dibaca oleh pengguna.</li>
-  </ul>
-</ul>
-
-<p>Contoh kasus penggunaan yang baik untuk grup pemberitahuan antara lain: aplikasi perpesanan
-yang menampilkan daftar pesan yang masuk, atau aplikasi email yang menampilkan daftar email
-yang diterima.</p>
-
-<p>
-Contoh kasus penggunaan saat pemberitahuan tunggal lebih disukai
- meliputi pesan pribadi dari satu orang, atau representasi daftar dari
- item teks baris tunggal. Anda bisa menggunakan
-({@link android.app.Notification.InboxStyle InboxStyle} atau
-{@link android.app.Notification.BigTextStyle BigTextStyle}) untuk mencapai
-hal ini.
-</p>
-
-<h3 id ="post">Menampilkan bundel pemberitahuan</h3>
-
-<p>
-  Aplikasi ini harus selalu mengeposkan rangkuman grup, sekalipun grup hanya berisi
-  satu anak. Sistem akan menyembunyikan rangkuman dan langsung menampilkan
-  pemberitahuan anak jika hanya berisi pemberitahuan tunggal. Hal ini akan memastikan
-  sistem bisa memberikan pengalaman yang konsisten saat pengguna menggeser
-  anak grup.
-</p>
-
-<p class="note">
-  <strong>Catatan:</strong> Versi Android N ini tidak menyembunyikan
-  rangkuman untuk grup pemberitahuan yang berisi satu anak. Fungsionalitas
-  ini akan ditambahkan dalam Android N versi berikutnya.
-</p>
-
-<h3>Mengintip pemberitahuan</h3>
-
-<p>Walaupun sistem biasanya menampilkan pemberitahuan anak sebagai sebuah grup, Anda bisa menyetelnya
- agar muncul untuk sementara muncul sebagai
- <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">
- pemberitahuan pendahuluan</a>. Fitur ini khususnya berguna karena memungkinkan
-  akses langsung ke pemberitahuan anak terbaru dan tindakan yang dikaitkan dengannya.
-</p>
-
-
-<h3>Kompatibilitas mundur</h3>
-
-<p>
-  Baik grup pemberitahuan maupun masukan jauh telah menjadi bagian dari {@link
-  android.app.Notification} API sejak Android 5.0 (API level 21) untuk mendukung
-  perangkat Android Wear. Jika Anda sudah membuat pemberitahuan dengan API ini,
-  satu-satunya tindakan yang harus Anda ambil adalah memverifikasi apakah perilaku aplikasi sesuai dengan panduan yang
-  dijelaskan di atas, dan mempertimbangkan implementasi {@code
-  setRemoteInputHistory()}.
-</p>
-
-<p>
-  Untuk mendukung kompatibilitas mundur, tersedia API yang sama bersama
-  kelas {@link android.support.v4.app.NotificationCompat}
-  pustaka dukungan, yang memungkinkan Anda untuk membuat pemberitahuan yang bekerja pada versi Android
-  sebelumnya. Pada perangkat genggam dan tablet, pengguna hanya melihat pemberitahuan rangkuman,
-  sehingga aplikasi masih memiliki model inbox atau pemberitahuan sama yang
-  mewakili seluruh materi informasi grup. Karena perangkat Android
-  Wear memungkinkan pengguna melihat semua pemberitahuan anak bahkan pada level platform
-  yang lebih lama, maka Anda harus membangun pemberitahuan anak dengan mengabaikan level
-  API.
-</p>
-
-<h2 id="custom"> Tampilan Khusus</h2>
-<p>Mulai dari Android N, Anda bisa menyesuaikan tampilan pemberitahuan dan
-tetap mendapatkan dekorasi sistem seperti header pemberitahuan, tindakan, dan
-layout yang bisa diperluas.</p>
-
-<p>Untuk mengaktifkan kemampuan ini, Android N menambahkan API berikut untuk menata gaya
-  tampilan khusus Anda:</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> Menata gaya pemberitahuan selain pemberitahuan
-media.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> Menata gaya pemberitahuan media.</dd>
-</dl>
-
-<p>Untuk menggunakan API baru ini, panggil metode {@code setStyle()}, dengan meneruskan
-gaya tampilan khusus yang diinginkan padanya.</p>
-
-<p>Cuplikan ini menampilkan cara membuat objek pemberitahuan khusus dengan metode
-{@code DecoratedCustomViewStyle()}.</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">Gaya Perpesanan</h2>
-<p>
-  Android N memperkenalkan API baru untuk menyesuaikan gaya pemberitahuan.
-  Dengan menggunakan kelas <code>MessageStyle</code>, Anda bisa mengubah beberapa
-  label yang ditampilkan pada pemberitahuan, termasuk judul percakapan,
-  pesan tambahan, dan tampilan materi untuk pemberitahuannya.
-</p>
-
-<p>
-  Cuplikan kode berikut memperagakan cara menyesuaikan sebuah
-  gaya pemberitahuan menggunakan kelas <code>MessageStyle</code>.
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
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..7c5fe5d 100644
--- a/docs/html-intl/intl/ja/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
@@ -1,107 +1,72 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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 -->
 </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>
-        問題の報告</a>
-</div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        リリースノートの確認</a>
-</div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        開発者コミュニティに参加</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">新着</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +78,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..3220f19 100644
--- a/docs/html-intl/intl/ja/index.jd
+++ b/docs/html-intl/intl/ja/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/ja/preview/download_mp2.jd b/docs/html-intl/intl/ja/preview/download_mp2.jd
deleted file mode 100644
index 67b1bc4..0000000
--- a/docs/html-intl/intl/ja/preview/download_mp2.jd
+++ /dev/null
@@ -1,359 +0,0 @@
-page.title=ダウンロード
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">Android Preview SDK のコンポーネントをダウンロード、インストールする前に、次の利用規約に同意する必要があります。
-</p>
-
-    <h2 class="norule">利用規約</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-以下は、Android SDK Preview の使用許諾契約です(以下「本契約」)。
-
-1.はじめに
-
-1.1 Android SDK Preview(以下、本契約で「Preview」という。具体的には利用可能な場合には Android システム ファイル、パッケージ型 API、Preview ライブラリ ファイルを含む)は、本契約の規定に従ってライセンス許可されます。本契約では、デベロッパーの Preview の使用に関して、デベロッパーと Google の間で法的拘束力のある契約を結びます。
-
-1.2 「Android」とは、Android オープン ソース プロジェクト(http://source.android.com/ にて随時更新)にて利用可能な、端末向けの Android ソフトウェア スタックを意味します。
-
-1.3 「Google」とは、1600 Amphitheatre Parkway, Mountain View, CA 94043, United States に主たる事業所を有するデラウェア州法人である Google Inc. を意味します。
-
-2.本契約の同意
-
-2.1 Preview を使用するには、まず本契約に同意する必要があります。本契約に同意しない場合は Preview を使用できません。
-
-2.2 同意するかまたは Preview を使用するためにクリックすると、本契約に同意したことになります。
-
-2.3 米国またはその他の国(デベロッパーが居住している国かまたはデベロッパーが Preview を使用する国を含む)の法律により Preview の使用を禁止されている人である場合、Preview を使用することも、使用許諾契約に同意することもできません。
-
-2.4 雇用主またはその他の事業体を代表または代理して本契約に拘束されることに同意し Preview を企業または組織の内部で使用する場合、担当者の雇用主またはその他の事業体を本契約に法的に拘束する完全な法的権限を有していることを表明および保証するものとします。担当者が必要な権限を有していない場合は、担当者の雇用主またはその他の事業体を代表または代理して、本契約に同意することも、Preview を使用することもできません。
-
-3.Google Preview ライセンス
-
-3.1 本契約の規定に従い、Google は Android プラットフォーム上で実行するアプリケーションの開発に Preview を個人的にもしくは企業または組織の内部で使用するための、ロイヤリティ フリーな、譲渡不可で、非排他的な、サブライセンス不可の、限定された、取り消し可能なライセンスを付与するものとします。
-
-3.2 Preview に関するすべての法的権利、所有権、利益(Preview に含まれる知的財産権を含む)は Google またはサードパーティが所有するものとします。「知的財産権」とは、特許法、著作権法、営業秘密法、商標法、不当競争防止法に基づいて発生するすべての権利、およびその他のすべての所有権を意味します。デベロッパーに明示的に付与されていない権利は、すべて Google が所有します。
-
-3.3 本契約で明示的に許可されている目的以外においては、Preview を使用できません。当該のサードパーティのライセンスで必要とされる場合を除き、デベロッパーは、(a) Preview または Preview の一部をコピー(バックアップ目的を除く)、修正、改造、再配布、逆コンパイル、リバース エンジニアリング、逆アセンブルまたは派生物の作成、または(b)モバイル ハンドセットまたは個人用 PC 以外のハードウェア端末への Preview の読み込み、Preview と他のソフトウェアとの結合、または Preview の一部を組み込んだソフトウェアや端末の配布はできません。
-
-3.4 デベロッパーは、Android の断片化につながるような行為をしないことに同意します。これには、Preview から派生したソフトウェア開発キットの配布、作成への参加、宣伝を含みます(ただし必ずしもこれらには限定されません)。
-
-3.5 オープンソース ソフトウェア ライセンス下でライセンス付与された Preview のコンポーネントの使用、複製、配布は、本契約ではなく、そのオープンソース ソフトウェアのライセンスに準拠するものとします。デベロッパーは、許諾されるすべての権利下で、そのようなオープンソース ソフトウェア ライセンスに対して、優良ライセンシーのままでいることに同意し、そのような権利を終了、停止、または違反する可能性のあるいかなる行為も差し控えることに同意するものとします。
-
-3.6 デベロッパーは、Google が提供する Preview の形式および性質は事前の通知なしに変更される場合があり、今後リリースされる Preview のバージョンでは、以前のバージョンの Preview で開発されたアプリケーションとの互換性がない可能性があることに同意します。デベロッパーは、Google が事前の通知なく、Google の単独の裁量でデベロッパーまたはユーザーへの Preview(または Preview 内の一部の機能)の提供を(恒久的または一時的に)停止する場合があることに同意します。
-
-3.7 本契約のいかなる部分も、Google のいかなる商標名、商標、サービスマーク、ロゴ、ドメイン名、またはその他のブランド識別表示を使用する権利もデベロッパーに付与するものではありません。
-
-3.8 デベロッパーは、Preview に添付または収録されているすべての知的財産権に関する通知(著作権および商標の通知を含む)の削除、隠ぺい、改ざんを行わないことに同意します。
-
-4.デベロッパーによる Preview の使用
-
-4.1 Google は、本契約に基づき Preview を使用してデベロッパーが開発したソフトウェア アプリケーションに関して、デベロッパー(またはデベロッパーのライセンサー)からいかなる権利、所有権、または利益(当該アプリケーションに含まれる知的財産権を含む)も取得するものではないことに同意します。
-
-4.2 デベロッパーは、Preview を(a)本契約、および(b)該当する司法管轄区における適用される法律、規則、または一般に認められた慣行またはガイドライン(米国またはその他の該当国におけるデータまたはソフトウェアの輸出入に関する法律を含む)で認められている目的にのみ使用することに同意します。
-
-4.3 Preview を使用してアプリケーションを開発する場合、デベロッパーはユーザーのプライバシーおよび法的権利を保護することに同意します。ユーザーからデベロッパーにユーザー名、パスワード、またはその他のログイン情報または個人情報が提供される場合、デベロッパーは、情報がデベロッパーのアプリケーションに提供されることをユーザーに認識させ、当該ユーザーについてプライバシーに関する法的に十分な通知および保護を行わなければなりません。デベロッパーのアプリケーションに個人情報または秘密情報が保存される場合、この保存は保護された方法で行われなければなりません。ユーザーからデベロッパーのアプリケーションに Google アカウントの情報が提供された場合、デベロッパーのアプリケーションでは、ユーザーが許可したタイミングで、かつユーザーが許可した限定された目的にのみ、当該情報を使用してユーザーの Google アカウントにアクセスすることが認められるものとします。
-
-4.4 デベロッパーは、Preview に関して、第三者(Google、およびあらゆる携帯電話会社を含むが、これらに限定されない)のサーバー、ネットワーク、またはその他の財産またはサービスへの妨害、中断、損害、または許可されていない態様でのアクセスとなる行為(そのような行為に該当する対象製品の開発または販売 / 配布を含む)に関与しないことに同意します。
-
-4.5 デベロッパーは、デベロッパーが Android および Android のアプリケーションを介して作成、送信、表示するデータ、コンテンツ、リソース、および自身の行為の結果(Google に発生する可能性のあるあらゆる損失および損害を含む)について、自身が単独で責任を負うこと(および Google がこれについてデベロッパーまたはいかなる第三者に対しても一切責任を負わないこと)に同意します。
-
-4.6 デベロッパーは、本契約、適用される第三者の契約もしくは利用規約、または適用される法律もしくは規則に基づく自身の義務に違反したこと、および当該違反の結果(Google または第三者に発生したあらゆる損失および損害を含む)について、自身が単独で責任を負うこと(および Google がこれについてデベロッパーまたはいかなる第三者に対しても一切責任を負わないこと)に同意します。
-
-4.7 Preview は開発中であり、デベロッパーによるテスティングやフィードバックは開発プロセスの重要な一部となります。デベロッパーは、Preview の使用により、一部の機能の実装が開発中であると認識し、Preview が安定したリリースの完全な機能性を持つことに依存すべきでないことを認識するものとします。本 Preview は、公式の Android SDK のリリース後はサポート対象でなくなるため、デベロッパーは、Preview を使用するいかなるアプリケーションも公然と配布または引き渡さないことに同意するものとします。
-
-5.デベロッパーの資格情報
-
-5.1 デベロッパーは、Google が発行した、またはデベロッパー自身で選択した、自身のデベロッパー用資格情報の秘密を保持する責任を負うこと、および自身のデベロッパー用資格情報のもとで開発されたすべてのアプリケーションについて単独で責任を負うことに同意します。
-
-6.プライバシーおよび情報
-
-6.1 Google は、Preview の継続的な技術革新と改良のために、ソフトウェアから特定の使用状況統計情報(一意識別子、関連する IP アドレス、ソフトウェアのバージョン番号、Preview のどのツール/サービスがどのように使用されているかに関する情報を含むが、これらに限定されない)を収集できます。この情報が収集される前に、Preview に通知が表示され、デベロッパーの同意が求められます。デベロッパーが同意しない場合は、情報は収集されません。
-
-6.2 収集されるデータは、Preview の改良のために集約された形で精査され、Google のプライバシー ポリシー(http://www.google.com/policies/privacy/)に従って管理されます。
-
-7.第三者のアプリケーション
-
-7.1 デベロッパーが、Preview を使用して第三者が開発したアプリケーションを実行する、あるいは第三者から提供されたデータ、コンテンツ、リソースにアクセスする場合、デベロッパーは、Google がそれらのアプリケーション、データ、コンテンツ、リソースについて責任を負わないことに同意します。デベロッパーは、そのような第三者のアプリケーションを介してアクセスするすべてのデータ、コンテンツ、リソースについては、それらを生成した者が単独で責任を負うものであり、Google はそれらの第三者のアプリケーション、データ、コンテンツ、またはリソースの使用もしくはアクセスによって生じたあらゆる損失および損害について一切責任を負わないことを理解します。
-
-7.2 デベロッパーは、そのような第三者のアプリケーションを介して表示されるデータ、コンテンツ、リソースは、提供者(あるいは代理の第三者または事業体)が所有する知的財産権で保護されている場合があることを認識するものとします。デベロッパーは、当該所有者からの明確な許可がない限り、それらのデータ、コンテンツ、リソース(全体または一部)の変更、貸与、賃貸、担保、配布または派生物の作成を行うことはできません。
-
-7.3 デベロッパーは、そのような第三者のアプリケーション、データ、コンテンツまたはリソースの使用が、デベロッパーと当該第三者間の別の規約に従うものであることを認識するものとします。
-
-8.Google API の使用
-
-8.1 Google API
-
-8.1.1 API を使用して Google からデータを取得する場合、デベロッパーは、そのデータは、Google またはデータを提供する事業体(あるいは代理の第三者または事業体)が所有する知的財産権で保護されている場合があることを認識するものとします。そのような API の使用は追加の利用規約に従うものとします。デベロッパーは、当該の利用規約による許可がない限り、そのデータ(全体または一部)の変更、貸与、賃貸、担保、配布または派生物の作成を行うことはできません。
-
-8.1.2 デベロッパーは、API を使用して Google からユーザーのデータを取得する場合、ユーザーが明示的に同意した場合のみ、およびユーザーが許可したタイミングとその目的にのみ、データを取得できることを理解し、同意します。
-
-9.本契約の終了
-
-9.1 本契約は、下記の規定に従ってデベロッパーまたは Google のいずれかによって解約されるまで、継続して適用されるものとします。
-
-9.2 デベロッパーが本契約の解約を希望する場合は、Preview および関連するデベロッパー資格情報の使用を停止することで、契約を終了するものとします。
-
-9.3 Google は、理由の有無にかかわらず、書面で通知することでいつでもデベロッパーとの本契約を解約することができます。
-
-9.4 本契約は事前の通知またはその他の措置なく、次のうち早い方に自動的に終了します。
-(A)Google が、デベロッパーが居住している国またはデベロッパーがサービスを使用する国での Preview または Preview の一部の配布を停止したとき。
-(B)Google が Android SDK の最終バージョンをリリースしたとき。
-
-9.5 本契約が終了すると、本契約で付与されていたライセンスは終了し、デベロッパーは速やかに Preview のすべての使用を停止するものとし、第 10 条、第 11 条、第 12 条、第 14 条の規定は無期限に効力を有するものとします。
-
-10.免責事項
-
-10.1 デベロッパーは、デベロッパーによる Preview の使用はデベロッパー自身の責任において行うものであること、および Preview は「現状有姿」かつ「提供可能な限りにおいて」、Google からのいかなる種類の保証もなく提供されるものであることを明示的に理解し、これに同意します。
-
-10.2 デベロッパーによる Preview および Preview の使用を通じてダウンロードまたはその他の方法で取得されたマテリアルの使用は、デベロッパー自身の裁量および責任において行うものであり、当該使用の結果として生じるデベロッパーのコンピュータ システムもしくはその他の端末への損害またはデータの喪失についての責任はデベロッパーが単独で負います。前述を制限することなく、Preview は安定したリリースではなく、コンピュータやその他の端末の利用の完全な回復不可能な損失を含む、重大な損害を引き起こす可能性のあるエラー、欠陥、およびセキュリティ上の脆弱性が含まれている可能性があることを理解します。
-
-10.3 Google はまた、商品性、特定目的への適合性、および権利侵害がないことの黙示的な保証および条件を含む(ただしこれらに限定されない)、明示的か黙示的かを問わずあらゆる種類のすべての保証および条件を明示的に否定します。
-
-11.責任の制限
-
-11.1 デベロッパーは、Google、その子会社および関連会社、ならびにそのライセンサーが、デベロッパーに発生した直接損害、間接損害、偶発的損害、特別損害、結果的損害、または懲罰的損害(データの喪失を含む)について、Google またはその代表者が当該損失が発生する可能性について告知されていたかどうか、または知っていたはずであるかどうかにかかわらず、いかなる責任法理のもとでもデベロッパーに対して責任を負わないことを明示的に理解し、これに同意します。
-
-12.補償
-
-12.1 法律で認められる最大限の範囲内において、デベロッパーは、(a)デベロッパーが Preview を使用したこと、および(b)デベロッパーが Preview で開発したアプリケーションが他者のいかなる知的財産権を侵害していること、または他者の名誉を毀損している、もしくは他者のパブリシティ権もしくはプライバシー権を侵害していること、および(c)デベロッパーが本契約に違反したことから発生したあらゆる申し立て、普通法上の訴訟、衡平法上の訴訟、または法的手続き、ならびにあらゆる損失、責任、損害、費用、および経費(合理的な弁護士報酬を含む)について、Google、その関連会社、ならびに当該各社の取締役、役員、従業員、代理人を防御し、補償し、免責することに同意します。
-
-13.契約の変更
-
-13.1 Google は、Preview の新しいバージョンを配布することにより、いつでも本契約を変更することができます。変更が生じた場合、Google は、Preview の提供ウェブサイト上に使用許諾契約の改訂版を公開します。
-
-14.法的一般条項
-
-14.1 本契約は、デベロッパーと Google の間の法的な合意のすべてを表し、デベロッパーによる Preview の使用(別の契約下で Google が提供するサービスを除く)に適用され、Preview に関するデベロッパーと Google の間のあらゆる事前の合意に完全に取って代わるものです。
-
-14.2 デベロッパーは、Google が本契約に定める(または適用される法律のもとで Google が享受できる)法的な権利または救済措置を行使または執行しなかった場合でも、Google の権利が正式に放棄されたとはみなされないこと、および Google が以後も引き続き当該権利および救済措置を行使または執行できることに同意します。
-
-14.3 本件について判断を下す管轄権を有する司法裁判所によって、本契約のいずれかの条項が無効と判断された場合、当該条項は、本契約の残りの部分に影響を与えることなく本契約から削除されるものとします。本契約の残りの条項は、以後も引き続き有効かつ執行可能であるものとします。
-
-14.4 デベロッパーは、Google が親会社となっている各グループ企業が、本契約の第三受益者となること、および当該企業が、当該企業に利益(または受益権)を付与する本契約の条項を直接執行する、また当該条項に依拠する権利を有することを了承し、これに同意します。上記以外のいかなる人または法人も、本契約の第三受益者とはならないものとします。
-
-14.5 輸出規制。Preview は、米国輸出管理法令の対象です。デベロッパーは、Preview に適用されるすべての国内および国際の輸出管理法令に従わなければなりません。これらの法律には、仕向け地、ユーザー、および最終用途に関する制限が含まれます。
-
-14.6 デベロッパーは、Google から事前に書面で承認を得ずに、本契約を譲渡または移転することはできません。また、そのような承認を得ずに計画された譲渡はすべて無効になります。デベロッパーは、Google から事前に書面で承認を得ずに、本契約に基づく自身の責任または義務を他者に委任してはなりません。
-
-14.7 本契約あるいは本契約に基づくデベロッパーと Google の関係から発生または関連するすべての申し立ては、米国カリフォルニア州の抵触法を除いて、カリフォルニア州法に準拠するものとします。デベロッパーおよび Google は、本契約あるいは本契約に基づくデベロッパーと Google の関係から発生または関連する法的事項の解決について、米国カリフォルニア州サンタクララ郡に所在の連邦裁判所または州立裁判所が専属管轄権を有することに合意します。上記にかかわらず、デベロッパーは、Google が任意の司法管轄区において差し止め命令による救済(または同等の緊急法的救済)を求める申し立てを行うことが認められることに同意します。
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">上記の利用規約を読み、同意します。</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>本書の内容</h2>
-      <ol>
-        <li><a href="#sdk">Preview SDK</a></li>
-        <li><a href="#docs">デベロッパー ドキュメント</a></li>
-        <li><a href="#images">ハードウェアのシステム イメージ</a></li>
-      </ol>
-
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  Android M Preview SDK には、アプリとプラットフォームの次期リリースで提供される新しい API とのテストに役立つ開発ツール、Android システム ファイル、ライブラリ ファイルが含まれています。
-このドキュメントでは、アプリのテスト用にダウンロードできる Preview のコンポーネントを入手する方法について説明します。
-
-</p>
-
-
-<h2 id="sdk">Preview SDK</h2>
-
-<p>
-  Preview SDK <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK マネージャー</a>経由でダウンロードできます。Preview SDK のダウンロードと設定の詳細については、<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Set Up the Preview SDK</a> をご覧ください。
-
-</p>
-
-
-<h2 id="docs">デベロッパー ドキュメント</h2>
-
-<p>
-  デベロッパー ドキュメントのダウンロード パッケージでは、詳細な Preview の API リファレンス情報や API の比較レポートが提供されます。
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-<h2 id="images">ハードウェアのシステム イメージ</h2>
-
-<p>
-  これらのシステム イメージでは、テスト用に物理端末にプラットフォームのプレビュー バージョンをインストールできます。
-端末にこれらのイメージを 1 つ以上設定すると、アプリをインストールして、プラットフォームの次期バージョンでアプリがどのように動作するかをテストできます。
-端末にシステム イメージをインストールするプロセスでは、<em>端末からすべてのデータが削除</em>されるため、システム イメージのインストール前にデータをバックアップする必要があります。
-
-
-</p>
-
-<p class="warning">
-  <b>警告:</b> 次の Android システム イメージはプレビュー版であり、今後変更される可能性があります。デベロッパーによるシステム イメージの使用は、Android SDK Preview 使用許諾契約に準拠するものとします。
-Android Preview システム イメージは安定したリリースではなく、お使いのコンピュータ システム、端末、データに影響を与える可能性のあるエラーや欠陥が含まれている場合があります。
-
-プレビュー版の Android システム イメージは工場出荷版の OS と同等のテストを受けておらず、お使いの電話やインストールされているサービス、アンインストールの動作停止を引き起こす場合があります。
-
-
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">端末にイメージをインストールする</h3>
-
-<p>
-  テスト用に端末イメージを使用するには、互換性のある端末にインストールする必要があります。次の手順に従って、システム イメージをインストールします。
-
-</p>
-
-<ol>
-  <li>この一覧の中からいずれかのシステム イメージ パッケージをダウンロードして、解凍します。</li>
-  <li>保持するデータを端末からバックアップします。</li>
-  <li>
-<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
- の手順に従って端末にイメージをフラッシュします。</li>
-</ol>
-
-<p class="note">
-  <strong>注:</strong> 開発用端末に Preview のシステム イメージをフラッシュすると、OTA アップデートを通じて次のプレビュー リリースに自動的にアップグレードされます。
-
-</p>
-
-<h3 id="revertDevice">端末を工場出荷時の仕様に戻す</h3>
-
-<p>
-  Preview をアンインストールして、工場出荷時の仕様に戻すには、
-<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> にアクセス
-して、端末にフラッシュするイメージをダウンロードします。同じページの手順に従って端末にイメージをフラッシュします。
-
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/ja/preview/features/background-optimization.jd b/docs/html-intl/intl/ja/preview/features/background-optimization.jd
deleted file mode 100644
index 04921c7..0000000
--- a/docs/html-intl/intl/ja/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=バックグラウンド処理の最適化
-page.metaDescription=暗黙的なブロードキャストに対する新しい制限。
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      このドキュメントの内容
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">CONNECTIVITY_ACTION に対する制限</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">従量制ではない接続でネットワーク ジョブをスケジュールする</a>
-
-      </li>
-
-      <li>
-        <a href="#monitor-conn">アプリを実行しているときにネットワーク接続を監視する</a>
-
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">NEW_PICTURE と NEW_VIDEO に対する制限</a>
-
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">新しい JobInfo メソッド</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">新しい JobParameter メソッド</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">アプリをさらに最適化する</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  バックグラウンド処理が多くのメモリと電池を消費する場合があります。たとえば、多くのバックグラウンド処理が暗黙的なブロードキャストをリッスンするように登録されていますが、バックグラウンド処理が有用でない場合でも、暗黙的なブロードキャストによりこれらの処理が開始されることがあります。
-
-バックグラウンド処理が端末のパフォーマンスとユーザー エクスペリエンスの両方に多大な影響を及ぼす可能性があります。
-
-</p>
-
-<p>
-  Android N では、こういった問題を緩和するために、以下の制限が適用されます。
-
-</p>
-
-<ul>
-  <li>プレビュー向けのアプリは、マニフェストで {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} ブロードキャストの受信登録をしていても、このブロードキャストを受信しません。
-実行中のアプリは、{@link
-  android.content.Context#registerReceiver Context.registerReceiver()} で {@link android.content.BroadcastReceiver} を登録することにより、メインスレッドで {@code CONNECTIVITY_CHANGE} を引き続きリッスンできます。
-
-
-  </li>
-
-  <li>アプリは、{@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} ブロードキャストまたは {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO} ブロードキャストを送受信できません。この最適化は、プレビューをターゲットにしたアプリだけでなく、すべてのアプリに影響を及ぼします。
-
-  </li>
-</ul>
-
-<p>
-  アプリでこれらのインテントのいずれかを使用する場合は、Android N 端末を適切にターゲットにできるように、可能な限りインテントとの依存性を削除する必要があります。
-
-  Android フレームワークは、これらの暗黙的なブロードキャストの必要性を軽減するいくつかのソリューションを提供します。
-たとえば、{@link android.app.job.JobScheduler} と <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> は、従量制ではないネットワークへの接続など、指定条件が満たされたときに、ネットワーク操作をスケジュールするための堅牢なメカニズムを提供します。
-
-
-また、コンテンツ プロバイダの変更に対応するために、{@link android.app.job.JobScheduler} を使用することもできます。{@link android.app.job.JobInfo} オブジェクトは、{@link android.app.job.JobScheduler} がジョブをスケジュールするために使用するパラメータをカプセル化します。
-
-
-ジョブの条件が満たされると、システムはこのジョブをアプリの {@link android.app.job.JobService} で実行します。
-
-</p>
-
-<p>
-  このドキュメントでは、アプリをこれらの新しい制限に対応させるために、
-{@link android.app.job.JobScheduler} などの代替メソッドの使用法について説明します。
-
-</p>
-
-<h2 id="connectivity-action">
-  CONNECTIVITY_ACTION に対する制限
-</h2>
-
-<p>
-  Android N 向けのアプリは、マニフェストで {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} ブロードキャストの受信登録をしていても、このブロードキャストを受信しません。また、このブロードキャストに依存している処理は開始されません。
-
-これにより、ネットワークの変更をリッスンするアプリ、または端末が従量制ではないネットワークに接続したときにネットワーク アクティビティをまとめて実行するアプリに問題が発生する可能性があります。
-
-Android フレームワークは、この制限を回避するためのいくつかのソリューションを備えていますが、アプリで実行するタスクに応じて、適切なソリューションを選択してください。
-
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>
-{@link android.content.Context#registerReceiver Context.registerReceiver()} で登録された {@link android.content.BroadcastReceiver} は、アプリが実行中のときにこれらのブロードキャストを継続して受信します。
-
-</p>
-
-<h3 id="sched-jobs">
-  従量制ではない接続でネットワーク ジョブをスケジュールする
-</h3>
-
-<p>
-  {@link android.app.job.JobInfo} オブジェクトをビルドするために {@link android.app.job.JobInfo.Builder JobInfo.Builder} を使用するときは、{@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} メソッドを適用し、{@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} をジョブ パラメータとして渡します。
-次のコードサンプルは、端末が従量制ではないネットワークに接続し、充電しているときに実行するサービスをスケジュールします。
-
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  ジョブの条件が満たされたとき、アプリはコールバックを受け取り、指定された {@code JobService.class} で {@link android.app.job.JobService#onStartJob onStartJob()} メソッドを実行します。
-
-{@link
-  android.app.job.JobScheduler} 実装の例については、<a href="{@docRoot}samples/JobScheduler/index.html">JobScheduler サンプルアプリ</a>をご覧ください。
-</p>
-
-<p>
-  GMSCore サービスを使用し、Android 5.0(API レベル 21)以前をターゲットにしているアプリは、<a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> を使用して {@code Task.NETWORK_STATE_UNMETERED} を指定できます。
-
-</p>
-
-<h3 id="monitor-conn">
-  アプリを実行しているときにネットワーク接続を監視する
-</h3>
-
-<p>
-  実行されているアプリは、登録された {@link android.content.BroadcastReceiver} を使用して {@code CONNECTIVITY_CHANGE} を引き続きリッスンできます。
-ただし、{@link
-  android.net.ConnectivityManager} API は、特定のネットワーク条件が満たされたときだけコールバックをリクエストするより堅牢なメソッドを提供します。
-
-</p>
-
-<p>
-  {@link android.net.NetworkRequest} オブジェクトは、{@link android.net.NetworkCapabilities} に応じてネットワーク コールバックのパラメータを定義します。
-{@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder} クラスを使って {@link android.net.NetworkRequest} オブジェクトを作成します。次に、{@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()} は、{@link android.net.NetworkRequest} オブジェクトをシステムに渡します。
-
-ネットワーク条件が満たされると、アプリはコールバックを受け取り、{@link
-  android.net.ConnectivityManager.NetworkCallback} クラスで定義された {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} メソッドを実行します。
-
-
-</p>
-
-<p>
-  アプリは終了するか、{@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()} を呼び出すまで、コールバックを受信し続けます。
-
-</p>
-
-<h2 id="media-broadcasts">
-  NEW_PICTURE と NEW_VIDEO に対する制限
-</h2>
-
-<p>
-  Android N では、アプリは、{@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} ブロードキャストまたは {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO} ブロードキャストを送受信できません。この制限は、新しいイメージや動画を処理するためにいくつかのアプリを起動する必要があるときに、パフォーマンスとユーザー エクスペリエンスへの影響を軽減するのに役立ちます。
-
-Android N では、{@link android.app.job.JobInfo} と {@link
-  android.app.job.JobParameters} を拡張することにより、代わりのソリューションを提供しています。
-
-</p>
-
-<h3 id="new-jobinfo">
-  新しい JobInfo メソッド
-</h3>
-
-<p>
-  Android N では、コンテンツ URI の変更でジョブをトリガーするために、{@link android.app.job.JobInfo} API に次のメソッドが追加されています。
-
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    コンテンツ URI の変更でジョブをトリガーするために必要なパラメータをカプセル化します。
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    {@code TriggerContentUri} オブジェクトを {@link
-    android.app.job.JobInfo} に渡します。{@link android.database.ContentObserver} は、カプセル化されたコンテンツ URI を監視します。
-ジョブに関連する複数の {@code
-    TriggerContentUri} オブジェクトがある場合、システムは、1 つのコンテンツ URI のみの変更を通知する場合でも、コールバックを提供します。
-
-  </dd>
-
-  <dd>
-    指定した URI の子孫のいずれかが変更された場合、ジョブをトリガーするために、{@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} フラグを追加します。
-このフラグは、{@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()} に渡される {@code notifyForDescendants} パラメータに相当します。
-
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>注:</strong> {@code TriggerContentUri()} は、{@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} または {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()} と組み合わせて使うことはできません。
-コンテンツの変更を継続的に監視するには、アプリの {@link
-  android.app.job.JobService} が最新のコールバックの処理を完了する前に、新しい
-{@link android.app.job.JobInfo} をスケジュールします。
-</p>
-
-<p>
-  次のサンプルコードは、システムが変更をコンテンツ URI {@code MEDIA_URI} に通知するときにトリガーされるジョブをスケジュールします。
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  システムが特定のコンテンツ URI の変更を通知すると、アプリはコールバックを受け取り、{@link android.app.job.JobParameters} オブジェクトが {@code MediaContentJob.class} の {@link android.app.job.JobService#onStartJob onStartJob()} メソッドに渡されます。
-
-
-
-</p>
-
-<h3 id="new-jobparam">
-  新しい JobParameter メソッド
-</h3>
-
-<p>
-  また、Android N では、{@link android.app.job.JobParameters} が拡張され、ジョブをトリガーしたコンテンツ権限や URI についての有用な情報をアプリが受け取れるようになっています。
-
-
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    ジョブをトリガーした URI の配列を返します。この配列は、ジョブをトリガーした URI がない場合(たとえば、期限切れ、またはその他の理由でジョブがトリガーされた場合)、または変更された URI の数が 50 を超える場合は、{@code
-    null} になります。
-
-
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    ジョブをトリガーしたコンテンツ権限の文字列配列を返します。
-    返された配列が {@code null} ではない場合、どの URI が変更されたかについて、詳細を取得するために {@code getTriggeredContentUris()} を使用します。
-
-  </dd>
-</dl>
-
-<p>
-  次のサンプルコードは、{@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} メソッドをオーバーライドし、ジョブを起動したコンテンツ権限と URI を記録します。
-
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  アプリをさらに最適化する
-</h2>
-
-<p>
-  アプリをメモリ不足の端末またはメモリ不足の状況で実行するために最適化すると、パフォーマンスとユーザー エクスペリエンスが向上します。
-バックグラウンド サービスと静的に登録された暗黙的なブロードキャスト レシーバーへの依存関係を削除すると、そのような端末上のアプリの動作が向上します。
-
-Android N では、これらの問題を削減するための措置が講じられていますが、これらのバックグラウンド処理をまったく使用せずに、アプリが実行されるように最適化することをお勧めします。
-
-
-
-</p>
-
-<p>
-  Android N には、それらのバックグラウンド処理を無効にした状態でアプリの動作をテストするために使用できるいくつかの <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge(ADB)</a>コマンドが追加されています。
-
-</p>
-
-<ul>
-  <li>暗黙的なブロードキャストとバックグラウンド サービスが利用できない状態をシミュレートするには、次のコマンドを入力します。
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>暗黙的なブロードキャストとバックグラウンド サービスを再度有効にするには、次のコマンドを入力します。
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/ja/preview/features/icu4j-framework.jd b/docs/html-intl/intl/ja/preview/features/icu4j-framework.jd
deleted file mode 100644
index 6a25cec..0000000
--- a/docs/html-intl/intl/ja/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=ICU4J Android フレームワーク API
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>このドキュメントの内容:</h2>
-<ol>
-    <li><a href="#relation">ICU4J との関係</a></li>
-    <li><a href="#migration">ICU4J から android.icu API に移行する</a></li>
-    <li><a href="#licence">ライセンス</a></li>
-</ol>
-
-<h2>関連ドキュメント</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">ICU4J のドキュメント</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">ICU4J でサポートされている最新の標準</a>
-
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J は幅広く使用されている、オープンソースの Java ライブラリのセットで、Unicode のほか、ソフトウェア アプリのグローバル化のサポートを提供しています。
-Android N では、アプリのデベロッパー向けの Android フレームワーク内で ICU4J API のサブセットを公開しており、{@code android.icu} パッケージ内で使用できます。
-
-これらの API は、端末上のローカライズ データを使用します。
-そのため、ICU4J ライブラリを APK にコンパイルせず、フレームワーク内にあるライブラリを呼び出せばよいので、APK のフットプリントを削減できます
-
-(この場合、Android N より前のバージョンの Android を実行しているユーザーも、ICU4J ライブラリを含むバージョンのアプリをダウンロードできるようにするには、<a href="{@docRoot}google/play/publishing/multiple-apks.html">APK を複数のバージョン</a>用意する必要があります)。
-
-
-
-</p>
-
-<p>
-  ここではまず、これらのライブラリをサポートするために必要な最低限の Android API レベルについて基本的な情報を説明します。
-次に、Android 固有の ICU4J の実装に必要な情報を説明します。
-最後に、Android フレームワーク内で ICU4J API を使用する方法について説明します。
-
-</p>
-
-<h2 id="relation">ICU4J との関係</h2>
-
-<p>
-  Android N では、<code>com.ibm.icu</code> ではなく
-<code>android.icu</code> パッケージを介して ICU4J API のサブセットを公開しています。Android フレームワークでは、さまざまな理由により ICU4J API を公開しないという選択も考えられます。たとえば、Android N で廃止された API を公開しないため、または ICU チームからまだ安定版の発表がないため、などの理由があります。
-
-
-
-ICU チームが今後 API を廃止した場合、Android でも廃止と見なすことになりますが、引き続きそれらの API を含める予定です。
-
-</p>
-
-<p class="table-caption"><strong>表 1.</strong> Android N で使用される ICU および CLDR のバージョン
-</p>
-<table>
-<tr>
-<th>Android API レベル</th>
-<th>ICU バージョン</th>
-<th>CLDR バージョン</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>いくつか注意事項があります。</p>
-
-<ul>
-<li>ICU4J Android フレームワーク API には、すべての ICU4J API が含まれているわけではありません。</li>
-<li>NDK デベロッパーは、Android ICU4C がサポートされていない点にご注意ください。</li>
-<li>Android フレームワーク内の API は、Android の<a href="{@docRoot}guide/topics/resources/localization.html">リソースを使用したローカライズ</a>に対するサポートに代わるものではありません。
-
-</li>
-</ul>
-
-<h2 id="migration">com.ibm.icu から android.icu パッケージに移行する</h2>
-
-<p>
-  アプリ内で既に ICU4J API を使用しており、
-<code>android.icu</code> API がその要件を満たしている場合、このフレームワーク API に移行するには、Java のインポートを <code>com.ibm.icu</code> から <code>android.icu</code> に変更します。
-
-次に、APK から ICU4J ファイルのコピーを削除します。
-
-</p>
-
-<p class="note">
-  <b>注</b>:ICU4J フレームワーク API では、名前空間に {@code com.ibm.icu} ではなく{@code android.icu} を使用します。
-これは、独自の {@code com.ibm.icu} ライブラリを含む APK で名前空間が競合しないようにするためです。
-
-</p>
-
-<h3 id="migrate-from-android">
-  その他の Android SDK API から android.icu API に移行する
-</h3>
-
-<p>
-  <code>java</code> および <code>android</code> パッケージには、ICU4J にあるクラスと同等のクラスが一部含まれています。
-しかし多くの場合、ICU4J では、より幅広い標準と言語のサポートを提供しています。
-
-</p>
-<p>次に、すぐに利用できる例をいくつか示します。</p>
-<table>
-<tr>
-<th>クラス</th>
-<th>代替クラス</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">ライセンス</h2>
-
-<p>
-  ICU4J は ICU ライセンスでリリースされています。詳細については、<a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">ICU ユーザーガイド</a>をご覧ください。
-
-</p>
diff --git a/docs/html-intl/intl/ja/preview/features/multilingual-support.jd b/docs/html-intl/intl/ja/preview/features/multilingual-support.jd
deleted file mode 100644
index 44686d2..0000000
--- a/docs/html-intl/intl/ja/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=言語とロケール
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>このドキュメントの内容:</h2>
-<ol>
-	  <li><a href="#preN">言語リソースの解決における課題</a></li>
-    <li><a href="#postN">リソース解決方針の改善</a></li>
-    <li><a href="#design">追加のロケールをサポートするためのアプリ設計
-</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N では、複数言語のユーザーのサポートが強化されており、設定で複数のロケールを選択できます。
-Android N ではこの機能を提供するために、サポート対象のロケール数を大幅に拡大し、システムがリソースを解決する方法を変更しました。
-
-この新しいリソース解決方法は、より堅牢で、既存の APK との互換性を保つよう設計されていますが、予想外の動作には十分に注意してください。
-
-たとえば、アプリで目的の言語がデフォルトに設定されているかをテストする必要があります。
-また、アプリで複数の言語をサポートする場合、そのサポートが意図したとおりに機能するかを確かめてください。
-
-最後に、明示的にサポートを設計していない言語については、アプリで適切に処理する必要があります。
-</p>
-
-<p>このドキュメントでは最初に、Android N より前のバージョンのリソース解決方針について説明します。次に、Android N の改善されたリソース解決方針について説明します。
-
-最後に、増大したロケールを活用し、より多くの複数言語ユーザーをサポートする方法について説明します。
-</p>
-
-<h2 id="preN">言語リソースの解決における課題</h2>
-
-<p>Android N より前のバージョンの Android では、アプリとシステムのロケールを一致させることができない場合がありました。
-</p>
-
- <p>たとえば、以下の状況を想定します。</p>
- <ul>
- <li>アプリのデフォルトの言語が {@code en_US}(米国英語)で、{@code es_ES} リソース ファイルでスペイン語の文字列もローカライズされています。
-
-</li>
- <li> 端末は {@code es_MX} に設定されています。 </li>
-
-<p>Java コードが文字列を参照するときに、アプリでスペイン語のリソースが {@code es_ES} でローカライズされている場合でも、システムではデフォルト({@code en_US})リソース ファイルから文字列が読み込まれます。
-
-これは、システムで完全一致が見つからない場合に、ロケールから国コードを削除して引き続きリソースを探すためです。
-
-最後に、一致が見つからない場合は、デフォルトである {@code en_US} にフォールバックされます。
- </p>
-
-
-<p>ユーザーがアプリでまったくサポートされていないフランス語などを選択した場合にも、システムはデフォルトの {@code en_US} を読み込みます。
-次に例を示します。</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>表 1.</strong> ロケールの完全一致がない場合のリソース解決
-</p>
-<table>
-<tbody>
-<tr>
-<th>ユーザー設定</th>
-<th>アプリのリソース</th>
-<th>リソース解決</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-デフォルト(en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-fr_CH を試行 =&gt; 失敗<br>
-fr を試行 =&gt; 失敗<br>
-デフォルト(en)を使用
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>この例では、システムはユーザーが英語を理解できるかどうかを認識せず、英語の文字列を表示します。
-この動作は現在、ごく一般的です。
-Android N では、このような状況が大幅に削減されるはずです。
-</p>
-
-<h2 id="postN">リソース解決方針の改善</h2>
-<p>Android N は、より堅牢なリソース解決を導入しており、自動的に適切な代替言語を見つけます。
-ただし、解決を迅速化し保守性を向上させるには、最も一般的な親言語でリソースを保存する必要があります。
-
- たとえば、これまで {@code es-US} ディレクトリにスペイン語のリソースを保存していた場合、{@code es-419} ディレクトリに移動します。ここには、ラテンアメリカのスペイン語が格納されます。
-
- 同様に {@code en-GB} という名前のフォルダにリソースを保存している場合、そのフォルダの名前を {@code en-001}(国際英語)に変更します。<code>en-GB</code> 文字列の最も一般的な親言語は {@code en-001} であるためです。
-
-
- 次の例では、このような対応がリソース解決のパフォーマンスと信頼性を向上する根拠について説明します。
-</p>
-
-<h3>リソース解決の例</h3>
-
-<p>Android N では、<strong>表 1</strong> で説明した例の解決方法が異なります。
-</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>表 2.</strong> ロケールの完全一致が存在しない場合の改善された解決方針
-</p>
-<table>
-<tr>
-<th>ユーザー設定</th>
-<th>アプリのリソース</th>
-<th>リソース解決</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-デフォルト(en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-fr_CH を試行 =&gt; 失敗<br>
-fr を試行 =&gt; 失敗<br>
-fr の子言語を試行 =&gt; fr_FR<br>
-fr_FR を使用
-</td>
-</tr>
-
-</table>
-
-
-<p>これで、ユーザーは英語ではなくフランス語のリソースを利用できます。この例は、フランス語の文字列を Android N の {@code fr_FR} ではなく {@code fr} に保存すべき理由も示しています。これが、最も近い親言語と一致させ、迅速に解決し、予測しやすくするための対策になります。
-
-
-</p>
-
-<p>この改善された解決ロジックに加えて、Android では、選択できるユーザー言語を増やしました。
-もう一度上記の例で説明します。今回は、追加のユーザー言語としてイタリア語が指定され、アプリはフランス語をサポートしていません。
-  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>表 3.</strong> アプリがユーザーの 2 番目に優先されるロケール設定のみと一致する場合のリソース解決
-</p>
-<table>
-<tr>
-<th>ユーザー設定</th>
-<th>アプリのリソース</th>
-<th>リソース解決</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-デフォルト(en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-fr_CH を試行 =&gt; 失敗<br>
-fr を試行 =&gt; 失敗<br>
-fr の子を試行 =&gt; 失敗<br>
-it_CH を試行 =&gt; 失敗<br>
-it を試行 =&gt; 失敗<br>
-it の子言語を試行 =&gt; it_IT<br>
-it_IT を使用
-</td>
-
-</tr>
-
-</table>
-<p>アプリでフランス語をサポートしていなくても、ユーザーが理解できる言語が使用されます。
-</p>
-
-
-<h2 id="design">追加のロケールをサポートするためのアプリ設計</h2>
-<h3>LocaleList API</h3>
-
-<p>Android N では、新しい API {@code LocaleList.getDefault()} が加わりました。これにより、アプリは直接、ユーザーが指定した言語のリストを問い合わせることができます。
-この API を使用すると、アプリの動作がさらに洗練され、コンテンツの表示がより最適化されます。
-
-たとえば検索で、ユーザーの設定に基づいて複数の言語で結果を表示できます。
-ブラウザ アプリは、ユーザーが理解できる言語の翻訳ページを表示することがなくなり、キーボード アプリは、自動的に最適なレイアウトを有効にすることができます。
-
- </p>
-
-<h3>フォーマッタ</h3>
-
-<p>Android 6.0(API レベル 23)までは、Android は多くの一般的な言語(en、es、ar、fr、ru)に対して 1 つか 2 つのロケールのみをサポートしていました。
-
-各言語にはわずかなバリエーションしかなかったため、アプリはリソース ファイルでハードコーディングされた文字列として数字や日付を保存し、処理することができました。
-
-しかし Android で幅広いロケールのセットがサポートされるようになったため、日付、時刻、通貨などの情報は、1 つのロケール内でも形式が大幅に異なる場合があります。
-
-
-形式をハードコーディングすると、エンドユーザーが混乱するおそれがあります。
-したがって、Android N で開発するときは、数字や日付の文字列をハードコーディングせず、必ずフォーマッタを使用してください。
-</p>
-
-<p>その良い例がアラビア語です。アラビア語のロケールのサポートは {@code ar_EG} の 1 つだけでしたが、Android N では 27 に増えました。
-これらのロケールは、ほとんどのリソースを共有できますが、数字は ASCII 表記とネイティブ表記で好みが分かれています。
-たとえば、「4 桁の PIN を選択してください」など、数字の変数を含む文を作成する場合、以下のようにフォーマッタを使用します。
-
-</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/ja/preview/features/notification-updates.jd b/docs/html-intl/intl/ja/preview/features/notification-updates.jd
deleted file mode 100644
index d7cdc36..0000000
--- a/docs/html-intl/intl/ja/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,393 +0,0 @@
-page.title=通知
-page.tags=notifications
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>このドキュメントの内容</h2>
-<ol>
-  <li><a href="#direct">ダイレクト リプライ</a></li>
-  <li><a href="#bundle">バンドル通知</a></li>
-  <li><a href="#custom">カスタムビュー</a></li>
-  <li><a href="#style">メッセージ スタイル</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N には、アプリが視認性の高いインタラクティブな通知を投稿できるようにする新しい API がいくつか導入されています。
-</p>
-
-<p>Android N では、ハンドセットでインライン リプライをサポートするために、既存の {@link android.support.v4.app.RemoteInput} 通知 API が拡張されています。
-これらの機能を使用すると、ユーザーは、アプリにアクセスすることなく、通知シェードからすばやく応答できます。
-</p>
-
-<p>
-  Android N では、類似した通知をバンドルして、単一の通知として表示することもできます。
-このバンドルを可能にするために、Android N では、既存の {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} メソッドが使用されます。ユーザーは、各通知を展開して、通知シェードから個別に返信や消去などのアクションを各通知に対して行うことができます。
-
-
-</p>
-
-<p>最後に、Android N には、アプリのカスタマイズした通知ビューでシステム デコレーションを活用できるようにする新しい API が追加されています。
-これらの API は、通知ビューで、標準のテンプレートを使った一貫した表示を共有できるようにします。
-
-</p>
-
-<p>このドキュメントでは、アプリでこれらの新しい通知機能を使用するときに考慮する必要のある主な変更点について説明します。
-</p>
-
-<h2 id="direct">ダイレクト リプライ</h2>
-
-<p>Android N のダイレクト リプライ機能を使用すると、ユーザーは、テキスト メッセージにすばやく応答したり、通知インターフェース内でタスクリストを直接アップデートしたりできます。
-
-ハンドヘルド デバイスでは、インライン リプライ アクションが、通知にアタッチされた追加ボタンとして表示されます。
-ユーザーがキーボード経由で返信する場合、通知アクション向けに指定したインテントにテキストによる応答がアタッチされ、そのインテントがハンドヘルド デバイス用アプリに送信されます。
-
-
-
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>図 1.</strong> Android N に追加された [<strong>Reply</strong>] アクション ボタン。
-
-</p>
-
-<h3>インライン リプライ アクションを追加する</h3>
-
-<p>ダイレクト リプライをサポートする通知アクションを作成する方法は次のとおりです。
-</p>
-
-<ol>
-<li>通知アクションに追加できる {@link android.support.v4.app.RemoteInput.Builder} のインスタンスを作成します。
-
-このクラスのコンストラクタは、システムがテキスト入力のキーとして使用する文字列を受け取ります。
-その後、ハンドヘルド デバイス用アプリはそのキーを使用して、入力テキストを取得します。
-
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li> <code>addRemoteInput()</code> を使用して、{@link android.support.v4.app.RemoteInput} オブジェクトをアクションにアタッチします。
-
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>アクションを通知に適用し、通知を発行します。
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> ユーザーが通知アクションをトリガーすると、ユーザーは応答を入力するよう求められます。
- </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>図 2.</strong> ユーザーは通知シェードでテキスト メッセージを入力できます。
-</p>
-
-<h3>
-  インライン リプライからユーザー入力を取得する
-</h3>
-
-<p>
-  リプライ アクションのインテントで宣言したアクティビティで、通知インターフェースからのユーザー入力を取得する方法は次のとおりです。
-
-</p>
-
-<ol>
-  <li>通知アクションのインテントを入力パラメータとして渡すことにより、{@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()} を呼び出します。
-このメソッドは、テキストによる応答が含まれた {@link android.os.Bundle} を返します。
-
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>result キー({@link
-  android.support.v4.app.RemoteInput.Builder} コンストラクタに提供されている)を使用して、バンドルへのクエリを実行します。次のコード スニペットに示すようにメソッドを作成することにより、このプロセスを完了して入力テキストを取得できます。
-
-
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>以前の通知に指定したのと同じ通知 ID を使用して、別の通知をビルドして発行します。
-進捗インジケーターが通知インターフェースに表示されなくなり、リプライが正常に行われたことがわかります。
-
-この新しい通知で作業するときは、レシーバーの {@code onReceive()} メソッドに渡されるコンテキストを使用します。
-
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  チャットなどのインタラクティブなアプリでは、取得されたテキストを処理するときに、追加のコンテキストを含めると役立つ場合があります。
-たとえば、このようなアプリでは複数行のチャット履歴が表示されることがあります。
-{@link
-  android.support.v4.app.RemoteInput} を介してユーザーが応答した場合、{@code setRemoteInputHistory()} メソッドを使用してリプライ履歴を更新できます。
-
-</p>
-
-<p>
-  アプリがリモート入力を受け取った後、通知は更新またはキャンセルされる必要があります。
-ユーザーがダイレクト リプライを使用してリモート更新にリプライする場合は、通知をキャンセルしないでください。
-
-代わりに、通知を更新してユーザーのリプライを表示します。{@code MessagingStyle} を使用した通知の場合は、リプライを最新のメッセージとして追加する必要があります。
-
-他のテンプレートを使用する場合は、ユーザーのリプライをリモート入力履歴に追加できます。
-
-</p>
-
-<h2 id="bundle">バンドル通知</h2>
-
-<p>Android N は、通知のキューを表す新しい方法である
- <i>バンドル通知</i>をデベロッパーに提供します。この機能は、Android Wear の<a href="{@docRoot}training/wearables/notifications/stacks.html">通知スタック</a>機能に似ています。
-
-たとえば、受信したメッセージの通知をアプリで作成する場合、複数のメッセージが受信されると、通知が単一のグループにバンドルされます。
-
-既存の {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} メソッドを使用して、同様の通知をバンドルできます。
-</p>
-
-<p>
-  通知グループでは、通知グループを構成する通知が階層化されます。
-  この階層の最上位には、そのグループの概要情報を表示する親通知があります。
-ユーザーは通知グループを順次展開できます。ユーザーが階層を深くたどると、より多くの情報が表示されます。
-
-ユーザーがバンドルを展開すると、すべての子通知の詳細情報が表示されます。ユーザーがいずれかの通知を展開すると、そのコンテンツがすべて表示されます。
-
-
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>図 3.</strong> ユーザーは通知グループを順次展開できます。
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>同じアプリが 4 つ以上の通知を送信するときにグループ化が指定されていない場合、システムにより自動的に通知がグループ化されます。
-
-
-</p>
-
-<p>通知をグループに追加する方法については、<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">各通知をグループに追加する</a>をご覧ください。
-
-</p>
-
-
-<h3 id="best-practices">バンドル通知のベストプラクティス</h3>
-<p>このセクションでは、前のバージョンの Android プラットフォームで利用可能な {@link android.app.Notification.InboxStyle InboxStyle} 通知の代わりに、通知グループを使用する必要がある状況についてのガイドラインを提供します。
-
-
-</p>
-
-<h3>バンドル通知を使用するとき</h3>
-
-<p>ユースケースで次のすべての条件が満たされた場合にのみ通知グループを使用する必要があります。
-</p>
-
-<ul>
-  <li>子通知が完全な通知であり、グループの概要なしに、子通知を個別に表示できる。
-</li>
-  <li>子通知を個別に表示するメリットがある。次に例を示します。
-
-  </li>
-  <ul>
-    <li>子通知がアクション可能であり、各子通知に固有のアクションがある。</li>
-    <li>ユーザーが読みたい多くの情報が子通知にある。</li>
-  </ul>
-</ul>
-
-<p>通知グループの適切なユースケースの例には、着信メッセージのリストを表示するメッセージング アプリや受信したメールのリストを表示するメールアプリなどが含まれます。
-
-</p>
-
-<p>
-単一の通知が望ましいユースケースの例には、1 人のユーザーからの個別メッセージや、1 行のテキスト メッセージ アイテムのリスト表示が含まれます。
-
-このリスト表示を行うには、
-{@link android.app.Notification.InboxStyle InboxStyle} または {@link android.app.Notification.BigTextStyle BigTextStyle} を使用します。
-
-
-</p>
-
-<h3 id ="post">バンドル通知を表示する</h3>
-
-<p>
-  アプリは、グループに単一の子通知が含まれている場合でも、グループの概要を常に送信する必要があります。
-グループに単一の通知のみが含まれている場合、システムによって、概要の表示が非表示になり、子通知が直接表示されます。
-これにより、ユーザーがグループの子通知をスワイプして消すときに一貫した使用感が出ます。
-
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>このバージョンの Android N では、単一の子通知が含まれる通知グループの概要を非表示にできません。
-この機能は、将来のバージョンの Android N に追加されます。
-
-</p>
-
-<h3>通知をピークする</h3>
-
-<p>通常、子通知はグループとして表示されますが、子通知を<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">ヘッドアップ通知</a>として一時的に表示するように設定できます。
-
-
-この機能は、特に最新の子通知とその関連するアクションへの即時アクセスを可能にするので便利です。
-
-</p>
-
-
-<h3>下位互換性</h3>
-
-<p>
-  Android 5.0(API レベル 21)以降では、Android Wear 端末をサポートするために、通知グループとリモート入力が {@link
-  android.app.Notification} API の一部になっています。
-これらの API を使用して通知を既に作成している場合は、アプリの動作が上記のガイドラインに適合していることの確認と、{@code
-  setRemoteInputHistory()} の実装検討のみを行ってください。
-
-
-</p>
-
-<p>
-  下位互換性をサポートするために、サポート ライブラリの {@link android.support.v4.app.NotificationCompat} クラスで同じ API が利用できるようになっているため、前の Android バージョンで機能する通知を作成できます。
-
-
-携帯端末とタブレットでは、概要通知のみがユーザーに表示されるため、アプリは、受信トレイスタイルやグループの全情報を表す同等の通知を引き続きサポートする必要があります。
-
-Android Wear 端末では、古いプラットフォーム レベル上にもすべての子通知が表示されるため、API レベルに関係なく、子通知を作成する必要があります。
-
-
-
-</p>
-
-<h2 id="custom"> カスタムビュー</h2>
-<p>Android N 以降では通知ビューをカスタマイズでき、通知ヘッダー、アクション、展開レイアウトなどのシステム デコレーションを引き続き取得できます。
-
-</p>
-
-<p>この機能を有効にするために、Android N には、カスタムビューにスタイルを適用する次の API が追加されています。
-</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> メディア通知以外の通知にスタイルを適用します。
-</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> メディア通知にスタイルを適用します。</dd>
-</dl>
-
-<p>この新しい API を使用するには、{@code setStyle()} メソッドを呼び出し、目的のカスタムビュー スタイルに渡します。
-</p>
-
-<p>次のコード スニペットは、
-{@code DecoratedCustomViewStyle()} メソッドでカスタム通知オブジェクトを作成する方法を示しています。</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">メッセージング スタイル</h2>
-<p>
-  Android N では、通知スタイルをカスタマイズするための新しい API が提供されます。
-  <code>MessageStyle</code> クラスを使用して、会話タイトル、追加メッセージ、通知のコンテンツ ビューなど、通知に表示される複数のラベルを変更できます。
-
-
-</p>
-
-<p>
-  次のコード スニペットは、<code>MessageStyle</code> クラスを使用して通知のスタイルをカスタマイズする方法を示しています。
-
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
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..20561a4 100644
--- a/docs/html-intl/intl/ko/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
@@ -1,78 +1,62 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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>
           개발자 커뮤니티 가입
@@ -82,26 +66,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>
-        문제 보고
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        릴리스 노트 보기
-        </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        개발자 커뮤니티 가입
-      </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">최신</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +77,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/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
index 68ed568..0f58b79 100644
--- a/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
+++ b/docs/html-intl/intl/ko/guide/topics/providers/content-provider-basics.jd
@@ -891,7 +891,7 @@
     사용자 사전 제공자의 데이터 유형은 제공자의 계약 클래스
 {@link android.provider.UserDictionary.Words}의 참조 문서에 나열되어 있습니다(계약 클래스는
 <a href="#ContractClasses">계약 클래스</a> 섹션에 설명되어 있습니다).
-    @link android.database.Cursor#getType
+    {@link android.database.Cursor#getType
     Cursor.getType()}을 호출해서도 데이터 유형을 결정할 수 있습니다.
 </p>
 <p>
diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
index 01c8587..b459df7 100644
--- a/docs/html-intl/intl/ko/index.jd
+++ b/docs/html-intl/intl/ko/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/ko/preview/download_mp2.jd b/docs/html-intl/intl/ko/preview/download_mp2.jd
deleted file mode 100644
index ff9dd7e..0000000
--- a/docs/html-intl/intl/ko/preview/download_mp2.jd
+++ /dev/null
@@ -1,360 +0,0 @@
-page.title=다운로드
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">Android 미리 보기 SDK의 구성 요소를 다운로드하고 설치하기 전에 우선 다음과 같은 사용 약관에 동의해야 합니다.
-</p>
-
-    <h2 class="norule">사용 약관</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-이것은 Android SDK 미리 보기 라이선스 계약서입니다(이하 "라이선스 계약").
-
-1. 개요
-
-1.1 Android SDK 미리 보기(본 라이선스 계약에서는 "미리 보기"라고 칭하며, 구체적으로 Android 시스템 파일, 패키지 API 및 미리 보기 라이브러리 파일이 이용 가능한 경우 및 이용 가능하게 전환된 경우 이를 포함한 것을 가리킴)는 본 라이선스 계약 조건에 따라 계약자에게 사용을 허여합니다. 본 라이선스 계약은 미리 보기 사용과 관련하여 계약자와 Google 간에 법적 구속력이 있는 계약을 체결합니다.
-
-1.2 "Android"는 기기를 위한 Android 소프트웨어 스택을 의미합니다. 이는 http://source.android.com/ URL에 위치하며 수시로 업데이트되는 Android 오픈 소스 프로젝트에서 제공됩니다.
-
-1.3 "Google"은 미국 1600 Amphitheatre Parkway, Mountain View, CA 94043에 본사를 두고 있는 델라웨어주 법인인 Google Inc.를 의미합니다.
-
-2. 라이선스 계약에 동의
-
-2.1 이 미리 보기를 사용하려면, 먼저 라이선스 계약에 동의해야 합니다. 이 라이선스 계약에 동의하지 않고 미리 보기를 사용해서는 안 됩니다.
-
-2.2 수락을 클릭하고/거나 미리 보기를 사용하면 본 라이선스 계약 조건에 동의하는 것으로 간주됩니다.
-
-2.3 미국법 또는 현재 거주 중이거나 미리 보기를 사용하는 국가를 포함하여 다른 국가의 법에 따라 미리 보기를 받는 것이 금지된 경우, 미리 보기를 사용할 수 없으며 본 라이선스 계약을 수락할 수 없습니다.
-
-2.4 회사 또는 단체 내에서 내부적으로 미리 보기를 사용하며 고용주 또는 기타 단체를 대신하여 본 라이선스 계약 준수에 동의하는 경우, 계약자의 고용주나 그 단체에 본 라이선스 계약에 대한 구속력을 부여할 수 있는 모든 법적 권한을 계약자가 갖고 있음을 진술하고 보증합니다. 구속력을 부여할 수 있는 법적 권한이 없을 경우, 고용주 또는 기타 단체를 대신하여 본 라이선스 계약에 동의하거나 미리 보기를 사용할 수 없습니다.
-
-3. Google이 허하는 미리 보기 라이선스
-
-3.1 본 라이선스 계약의 조건에 따라 Google은 계약자에게 로열티 없고 양도 불가능하며 비독점적이고 2차 인가를 불허하며, 한정되고 무효화할 수 있는 미리 보기 사용 권한을 허용하여 회사 또는 조직 내에서 개인적 또는 내부적으로 사용할 수 있도록 합니다. 이는 Android 플랫폼에서 실행되는 애플리케이션을 개발할 목적으로만 사용해야 합니다.
-
-3.2 계약자는 SDK에 존재하는 지적 재산권을 포함한 SDK에 대한 모든 법적인 권리, 소유권 및 이익이 Google 또는 제3자에게 있음에 동의합니다 "지적 재산권"은 모든 특허법, 저작권법, 영업비밀법, 상표법상 존재하는 모든 권리 및 기타 모든 재산권을 의미합니다. Google은 계약자에게 명시적으로 부여하지 않은 모든 권리를 보유합니다.
-
-3.3 본 라이선스 계약에 명시적으로 허용된 용도 외에는 미리 보기를 사용할 수 없습니다. 해당 제3자 라이선스 요건이 허용하는 범위를 제외하고 계약자는 미리 보기의 일부분을 (a) 복사(백업 목적 제외), 수정, 개작, 재배포, 역컴파일, 리버스 엔지니어링, 분해하거나 이를 통해 파생물을 생성하거나 (b) 개인 컴퓨터를 제외한 모바일 단말기 또는 기타 모든 하드웨어 기기에 미리 보기의 일부를 로드하거나, 미리 보기의 일부를 다른 소프트웨어와 결합하거나 미리 보기의 일부가 통합된 일체의 소프트웨어나 기기를 배포해서는 안 됩니다.
-
-3.4 계약자는 미리 보기에서 파생된 소프트웨어 개발 키트의 배포, 이러한 키트 생성에 참여 또는 홍보를 포함하되 이에 국한되지 않고, Android의 단편화를 야기하는 어떠한 행동도 취하지 않을 것임에 동의합니다.
-
-3.5 오픈 소스 소프트웨어 라이선스에 의거한 미리 보기 구성요소의 사용, 재생산, 배포에는 본 라이선스 계약이 아닌, 해당 오픈 소스 소프트웨어 라이선스의 조건이 적용됩니다. 계약자는 허용된 모든 권한 하에서 그러한 오픈 소스 소프트웨어 라이선스에 관해 충실한 피허가자로서의 자세를 견지할 것이며 그러한 권한을 종료, 일시 중단 또는 침해하는 행위를 삼갈 것을 동의합니다.
-
-3.6 계약자는 Google이 제공하는 SDK의 형태 및 특성이 사전 통지 없이 변경될 수 있음에 동의하며, 이전 버전의 미리 보기에서 개발된 애플리케이션이 이후 버전의 SDK와 호환되지 않을 수 있음에 동의합니다. 계약자는 계약자 또는 사용자에게 사전 통지 없이 SDK(또는 SDK에 포함된 기능) 제공을(영구적 또는 일시적으로) 중단할 수 있는 권한이 Google에게 있음에 동의합니다.
-
-3.7 본 라이선스 계약은 계약자에게 Google의 상표명, 상표, 서비스 표시, 로고, 도메인 이름, 기타 독특한 브랜드 특징에 대한 사용 권한을 부여하지 않습니다.
-
-3.8 계약자는 SDK에 부착되어 있거나 포함되어 있는 모든 소유권 고지 사항(저작권 및 상표 고지 사항 포함)을 제거, 변경 또는 불분명하게 만들지 않을 것에 동의합니다.
-
-4. 계약자의 미리 보기 사용
-
-4.1 Google은 본 라이선스 계약의 어떤 조항도 계약자(또는 계약자의 사용 허가자)가 미리 보기를 사용하여 개발한 소프트웨어 애플리케이션에 대한 권리, 소유권 또는 이익, 그리고 해당 애플리케이션에 존재하는 모든 지적 재산권을 부여하지 않는다는 점에 동의합니다.
-
-4.2 계약자는 (a) 본 라이선스 계약 그리고 (b) 모든 준거법, 규정 또는 관련 관할권 내에서 일반적으로 수용되는 관행 또는 지침(미국 또는 기타 관련 국가로/에서의 데이터 또는 소프트웨어 수출과 관련된 모든 법률 포함)에서 허용하는 용도에 한하여 미리 보기를 사용하고 애플리케이션을 작성하는 것에 동의합니다.
-
-4.3 계약자는 일반 대중 사용자를 대상으로 미리 보기를 사용하여 애플리케이션을 개발하는 경우, 해당 사용자의 프라이버시 및 법적 권리를 보호하는 것에 동의합니다. 사용자가 계약자에게 사용자 이름, 비밀번호 또는 기타 로그인 정보나 개인 정보를 제공하는 경우, 계약자는 제공된 정보가 자신의 애플리케이션에 제공된다는 사실을 사용자에게 알려야 하며, 반드시 법적으로 적절한 개인정보 보호정책 고지 및 보호를 해당 사용자에게 제공해야 합니다. 애플리케이션에서 사용자가 제공한 개인정보나 민감한 정보를 저장하는 경우, 이를 안전하게 처리해야 합니다. 사용자들이 애플리케이션에 Google 계정 정보를 제공하는 경우, 애플리케이션은 해당 사용자의 Google 계정에 액세스하는 목적으로만, 그리고 각 사용자가 허용한 범위 내의 한정된 목적으로만 이러한 정보를 사용해야 합니다.
-
-4.4 계약자는 Google 또는 기타 모든 타사의 서버, 네트워크 또는 기타 모든 재산 또는 서비스를 허가 없이 방해, 교란, 손상 또는 액세스하는 애플리케이션의 개발 또는 배포를 포함한 하등의 행위에 미리 보기를 이용하지 않을 것임을 동의합니다.
-
-4.5 계약자는 자신이 Android 및/또는 Android용 애플리케이션을 통해 생성, 전송 또는 표시하는 모든 데이터, 콘텐츠 또는 리소스 그리고 그로 인한 결과(Google이 입을 수 있는 모든 피해나 손실 포함)에 대해 전적으로 책임이 있다는 것(그리고 Google은 계약자 또는 모든 제3자에 대한 책임이 없다는 것)에 동의합니다.
-
-4.6 계약자는 본 라이선스 계약, 모든 해당 제3자 계약 또는 서비스 약관, 또는 모든 준거법 또는 규정에 의거한 계약자 의무 위반, 그리고 그로 인한 결과(Google 또는 제3자가 입을 수 있는 모든 피해나 손실 포함)에 전적으로 책임이 있다는 것(그리고 Google은 계약자 또는 모든 제3자에 대한 책임이 없다는 것)에 동의합니다.
-
-4.7 이 미리 보기는 현재 개발 단계에 있으며, 계약자의 테스트와 피드백은 그러한 개발 과정에 중요한 부분을 차지합니다. 미리 보기를 사용함으로써 계약자는 일부 기능의 구현은 아직 개발 중인 상태이며 미리 보기가 안정된 릴리스처럼 완벽하게 기능할 것이라 믿고 사용해서는 안 된다는 점을 인지하는 것으로 간주합니다. 계약자는 이 미리 보기를 사용한 애플리케이션을 공개적으로 배포 또는 배송하지 않기로 동의합니다. 이 미리 보기는 공식 Android SDK가 출시된 이후에는 더 이상 지원되지 않기 때문입니다.
-
-5. 계약자의 개발자 자격 증명
-
-5.1 계약자는 Google이 발급했거나 자신이 선택한 모든 개발자 자격 증명에 대한 기밀성을 유지할 책임이 있으며 계약자의 개발자 자격 증명 하에 개발된 모든 애플리케이션에 대한 전적인 책임이 있음에 동의합니다.
-
-6. 개인정보 보호정책 및 정보
-
-6.1 미리 보기를 지속적으로 혁신하고 개선하기 위해, Google은 고유 식별자, 관련 IP 주소, 소프트웨어 버전 번호, 미리 보기에서 사용 중인 도구 및/또는 서비스와 도구의 사용법에 대한 정보를 포함하되 이에 국한되지 않고 소프트웨어에서 특정 사용량 통계 정보를 수집할 수 있습니다. 그러한 정보를 수집하기 전에 미리 보기는 계약자에게 이를 통지하고 동의를 구할 것입니다. 계약자가 동의하지 않을 경우 정보를 수집하지 않습니다.
-
-6.2 수집된 데이터는 모두 취합된 형태로 미리 보기 개선을 위해 검토되며, Google의 개인정보 보호정책에 따라 유지 관리됩니다. 이 정보는 http://www.google.com/policies/privacy/를 참조하십시오.
-
-7. 제3자 애플리케이션
-
-7.1 제3자가 개발한 애플리케이션을 실행하거나 제3자가 제공한 데이터, 콘텐츠 또는 리소스에 액세스하기 위해 미리 보기를 사용하는 경우, 계약자는 Google이 그러한 애플리케이션, 데이터, 콘텐츠 또는 리소스에 대한 책임이 없음에 동의합니다. 계약자는 그러한 제3자 애플리케이션을 통해 자신이 액세스한 모든 데이터, 콘텐츠 또는 리소스에 대한 책임은 그것을 만든 사람에게 있음에 동의합니다. 또한 계약자가 그러한 모든 제3자 애플리케이션, 데이터, 콘텐츠 또는 리소스를 사용하거나 액세스함으로써 비롯된 모든 피해나 손실에 대한 책임이 Google에게 없음에 동의합니다.
-
-7.2 그러한 제3자 애플리케이션을 통해 계약자에게 제공된 데이터, 콘텐츠 그리고 리소스는 그것을 제공한 제공자(또는 제공자를 대신하는 기타 개인 또는 기업)가 소유한 지적 재산권에 의해 보호될 수 있음을 유의해야 합니다. 그러한 데이터, 콘텐츠 또는 리소스(전부 또는 일부)를 수정, 임대, 리스, 대여, 판매, 배포하거나 이를 기반으로 파생물을 생성해서는 안 됩니다. 단, 관련 소유자로부터 그러한 작업을 수행해도 좋다는 허락을 받은 경우에는 예외입니다.
-
-7.3 계약자는 그러한 제3자 애플리케이션, 데이터, 콘텐츠 또는 리소스의 사용은 계약자와 관련 제3자 간에 체결하는 별도의 계약 조건의 적용을 받는다는 것을 인정합니다.
-
-8. Google API 사용
-
-8.1 Google Data API
-
-8.1.1 Google에서 데이터를 검색하기 위해 API를 사용하는 경우, 그러한 데이터가 Google 또는 데이터를 제공하는 당사자(또는 당사자를 대신하는 기타 개인 또는 기업)가 소유한 지적 재산권에 의해 보호될 수 있음을 인정합니다. 그러한 API를 사용하는 경우, 추가적인 서비스 약관의 적용을 받을 수 있습니다. 관련 서비스 약관에 허용되지 않은 한, 그러한 데이터(전부 또는 일부)를 변경, 임대, 리스, 대여, 판매, 배포하거나 이를 기반으로 파생물을 생성해서는 안 됩니다.
-
-8.1.2 Google에서 사용자 데이터를 검색하기 위해 API를 사용하는 경우, 계약자는 사용자로부터 명시적인 동의를 얻은 경우에 한하여, 그리고 해당 사용자가 허용한 범위 내의 한정된 목적으로만 데이터를 검색해야 합니다.
-
-9. 라이선스 계약 종료
-
-9.1 본 라이선스 계약은 계약자 또는 Google에 의해 아래와 같은 조건 하에 종료될 때까지 계속 적용됩니다.
-
-9.2 계약자가 라이선스 계약을 종료하고자 하는 경우, 미리 보기 및 관련 개발자 자격 증명 일체의 사용을 중단하는 것으로 그러한 의사를 피력할 수 있습니다.
-
-9.3 Google은 언제든 이유 여하를 불문하고 계약자에게 통고하여 라이선스 계약을 종료할 수 있습니다.
-
-9.4 본 라이선스 계약은 통보 또는 여타의 행위 없이도 자동으로 종료됩니다. 이에 해당되려면 다음과 같은 조건이 수반되어야 합니다.
-(A) Google이 계약자가 거주하는 국가 또는 계약자가 서비스를 사용하는 지역에서 미리 보기 또는 미리 보기의 특정 부분 제공을 중지하는 경우 및
-(B) Google이 Android SDK의 최종 릴리스 버전을 발행하는 경우.
-
-9.5 본 라이선스 계약이 종료되면 라이선스 계약으로 계약자에게 허용한 라이선스가 취소되며, 이에 따라 계약자는 미리 보기 사용을 즉시 모두 중단해야 하고 제 10, 11, 12 및 14절의 조항이 기한 없이 유지됩니다.
-
-10. 면책 조항
-
-10.1 계약자는 미리 보기 이용에 대한 위험 부담이 전적으로 본인에게 있으며, Google이 일체의 보증 없이 미리 보기를 "있는 그대로" 그리고 "이용 가능한" 상태로 제공한다는 것을 분명히 이해하고 동의합니다.
-
-10.2 미리 보기 이용 및 이용 과정에서 다운로드하거나 얻게 되는 모든 자료를 사용하는 것은 본인의 재량에 따르며 이에 대한 위험 부담이 전적으로 본인에게 있으며, 그러한 사용으로 인해 발생하는 컴퓨터 시스템 또는 다른 기기의 손상 또는 데이터 손실에 대한 책임은 전적으로 본인에게 있습니다. 전술한 조항을 제한하지 않는 범위 내에서 계약자는 미리 보기가 안정된 릴리스가 아니며 오류, 결함 및 보안 취약성이 포함되어 있을 수 있어 그 결과로 중대한 손상을 유발할 수 있다는 점을 이해하는 것으로 간주합니다. 여기에는 계약자의 컴퓨터 시스템 또는 기타 기기의 완전하고 돌이킬 수 없는 손실도 포함됩니다.
-
-10.3 더 나아가, Google은 상품성, 특정 목적에 대한 적합성 및 비침해의 묵시적 보증 등을 포함하되 이에 국한되지 않고 명시적이든 묵시적이든 모든 종류의 보증 및 조건을 명시적으로 부인합니다.
-
-11. 책임 한계
-
-11.1 계약자는 계약자에게 발생할 수 있는 직접, 간접, 부수적, 특별, 결과적 또는 징벌적 손해에 대해 그 어떤 책임 이론에 근거해서도 Google, 해당 자회사, 계열사 및 사용 허가자가 어떠한 책임도 지지 아니함을 분명히 이해하고 동의합니다. 이러한 손해에는 Google 또는 해당 대리자가 이러한 손실 발생 가능성에 대해 통지를 받았거나 이러한 사항을 인식했는지에 상관없이 모든 데이터 손실이 포함됩니다.
-
-12. 면책
-
-12.1 법률에 의해 허용되는 최대한의 범위 안에서 계약자는 (a) 미리 보기 사용, (b) 계약자가 미리 보기에서 개발한 일체의 애플리케이션에서 초래된 모든 사람의 저작권, 상표, 영업비밀, 트레이드 드레스, 특허 또는 기타 지적 재산권의 침해, 또는 어떤 사람의 명예를 훼손하거나 초상권 또는 개인정보 보호정책을 침해함 또는 (C)계약자 본인이 본 라이선스 계약을 위반함으로써 발생하거나 생기는 모든 청구, 조치, 소송 또는 절차, 그리고 모든 손실, 책임, 손해, 경비(합리적인 변호사 비용 포함)로부터 Google을 옹호하고, 면책시키고, Google이 손해를 입지 않도록 하는 데 동의합니다.
-
-13. 라이선스 계약 변경
-
-13.1 미리 보기의 새로운 버전을 배포할 때, Google은 본 라이선스 계약의 내용을 변경할 수 있습니다. 그러한 변경이 이뤄진 경우, Google은 미리 보기가 제공되는 웹사이트에 새로운 라이선스 계약 버전을 게재할 것입니다.
-
-14. 일반 법적 조건
-
-14.1 본 라이선스 계약은 계약자와 Google 간의 모든 법적 계약을 구성하며, 계약자의 미리 보기 사용을 규제하고(별도의 서면 계약을 통해 Google이 계약자에게 제공하는 모든 서비스는 제외), 미리 보기와 관련하여 이전에 계약자와 Google이 맺은 모든 계약을 완전히 대체합니다.
-
-14.2 계약자는 Google이 라이선스 계약에 포함된(또는 관련 법률에 의해 Google이 향유하는) 법적 권리 또는 구제수단을 행사하거나 집행하지 않더라도, Google이 권리를 공식적으로 포기한 것으로 간주하지 않으며, Google이 계속해서 그러한 권리 또는 구제수단을 이용할 수 있음에 동의합니다.
-
-14.3 본 라이선스 계약의 조항이 무효라고 이 사안에 관한 판결을 할 수 있는 관할권을 가진 법원이 판결할 경우, 그 조항은 라이선스 계약의 나머지 조항에 영향을 미치지 않는 형태로 라이선스 계약에서 제거됩니다. 본 라이선스 계약의 나머지 조항은 여전히 유효하며 집행 가능합니다.
-
-14.4 계약자는 Google이 모회사가 되는 회사 그룹에 속한 각 회사가 본 라이선스 계약의 제3수익자이며, 그러한 다른 회사들이 그들에게 이익(또는 유리한 권리)을 부여하는 본 라이선스 계약의 모든 조항을 직접 행사하고 적용할 수 있는 권리를 가진다는 데 동의합니다. 그 외에는 다른 어떤 개인이나 회사도 본 라이선스 계약의 제3수익자가 될 수 없습니다.
-
-14.5 수출 규제. 미리 보기는 미국의 수출법과 규정의 적용을 받습니다. 계약자는 미리 보기에 적용되는 모든 국내 및 국제 수출법과 규정을 준수해야 합니다. 그러한 법에는 수출 대상국, 최종 사용자 및 최종 용도에 대한 제한이 포함됩니다.
-
-14.6 계약자 또는 Google은 상대 당사자의 사전 서면 승인 없이 본 라이선스 계약에서 부여된 권리를 제3자에게 양도하거나 이전할 수 없으며, 그러한 승인 없이 이루어진 양도 시도는 모두 무효입니다. 계약자는 Google의 사전 승인 없이 본 라이선스 계약 상의 책임 또는 의무를 위임할 수 없습니다.
-
-14.7 본 라이선스 계약, 그리고 본 라이선스 계약 상의 계약자와 Google의 관계는 법률 조항 간의 충돌과는 무관하게 캘리포니아주법에 의한 규제를 받습니다. 계약자와 Google은 본 라이선스 계약으로부터 발생하는 모든 법적 문제 해결을 캘리포니아주 산타 클라라(Santa Clara) 카운티 내에 소재한 전속 관할 법원에 의뢰하는 것에 동의합니다. 위 규정에도 불구하고, 계약자는 Google이 여전히 모든 관할권에서 강제 구제책(또는 동등한 유형의 긴급 법적 구제)을 신청할 수 있음에 동의합니다.
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">본인은 상기 사용 약관을 읽었으며 이에 동의합니다.</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>이 문서의 내용</h2>
-      <ol>
-        <li><a href="#sdk">미리 보기 SDK</a></li>
-        <li><a href="#docs">개발자 관련 문서</a></li>
-        <li><a href="#images">하드웨어 시스템 이미지</a></li>
-      </ol>
-
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  Android M 미리 보기 SDK에는 개발 도구, Android 시스템 파일 및 라이브러리 파일이 포함되어 있어 앱을 테스트하고 플랫폼의 다음 릴리스에 도입되는 새 API를 테스트하는 데 유용합니다.
- 이 문서에서는 미리 보기의 다운로드할 수 있는 구성 요소를 가져와 앱을 테스트하는 방법에 대해 설명합니다.
-
-</p>
-
-
-<h2 id="sdk">미리 보기 SDK</h2>
-
-<p>
-  미리 보기 SDK는 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>를 통해 다운로드할 수 있습니다. 미리 보기 SDK를 다운로드하고 구성하는 데 관한 자세한 정보는 <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">미리 보기 SDK 설정하기</a>를 참조하십시오.
-
-</p>
-
-
-<h2 id="docs">개발자 관련 문서</h2>
-
-<p>
-  개발자 관련 문서 다운로드 패키지에서는 자세한 API 참조 정보와 미리 보기에 대한 API 차이점 보고서를 제공합니다.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">하드웨어 시스템 이미지</h2>
-
-<p>
-  이러한 시스템 이미지를 사용하면 물리적인 기기에서 플랫폼의 미리 보기 버전을 설치하여 테스트할 수 있게 해줍니다.
- 이러한 이미지 중 한 가지로 기기를 구성하면, 앱을 설치하고 테스트하여 앱이 플랫폼의 다음 버전에서 어떤 성능을 보일지 확인할 수 있습니다.
- 기기에 시스템 이미지를 설치하는 과정은<em>기기에서 모든 데이터를 제거하므로</em>, 시스템 이미지를 설치하기에 앞서 데이터를 백업하는 것이 좋습니다.
-
-
-</p>
-
-<p class="warning">
-  <b>경고:</b> 다음 Android 시스템 이미지는 미리 보기이며 사정에 따라 변동될 수 있습니다. 이러한 시스템 이미지를 사용할 때에는 Android SDK 미리 보기 라이선스 계약을 따라야 합니다.
- Android 미리 보기 시스템 이미지는 안정된 릴리스가 아니며, 오류나 결함이 들어있을 수 있고 이 때문에 컴퓨터 시스템, 기기 및 데이터에 손상을 초래할 수 있습니다.
-
- 미리 보기 Android 시스템 이미지는 공장 OS와 같은 테스트를 거치며 전화기 및 설치된 서비스와 애플리케이션의 작동이 중단되는 결과를 낳을 수 있습니다.
-
-
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">기기에 이미지 설치</h3>
-
-<p>
-  기기 이미지를 테스트용으로 사용하려면, 이를 호환되는 기기에 설치해야만 합니다. 시스템 이미지를 설치하려면 아래의 지침을 따르십시오.
-
-</p>
-
-<ol>
-  <li>여기 목록에 나열된 시스템 이미지 중 하나를 다운로드하여 압축을 해제합니다.</li>
-  <li>기기에서 보존하고자 하는 데이터를 모두 백업합니다.</li>
-  <li>이미지를 기기에 플래시하려면 <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>에 있는 지침을 따릅니다.
-
-</li>
-</ol>
-
-<p class="note">
-  <strong>참고:</strong> 일단 개발 기기에 미리 보기 시스템 이미지를 플래시하고 나면 이것은 OTA(over-the-air) 업데이트를 통해 다음 미리 보기 릴리스에 맞춰 자동으로 업그레이드됩니다.
-
-</p>
-
-<h3 id="revertDevice">기기를 공장 사양으로 되돌리기</h3>
-
-<p>
-  미리 보기의 설치를 제거하고 기기를 공장 사양으로 되돌리고자 하는 경우, <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a>를 방문하여 기기에 플래시하고자 하는 이미지를 다운로드하십시오.
-
- 해당 페이지에 있는 지침을 따라 기기에 이미지를 플래시하면 됩니다.
-
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/ko/preview/features/background-optimization.jd b/docs/html-intl/intl/ko/preview/features/background-optimization.jd
deleted file mode 100644
index 3bbc474..0000000
--- a/docs/html-intl/intl/ko/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=백그라운드 최적화
-page.metaDescription=암시적 브로드캐스트에 대한 새로운 제한.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      이 문서의 내용
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">CONNECTIVITY_ACTION에 대한 제한</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">무제한 연결에서 네트워크 작업
-예약</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">앱이 실행되는 중에 네트워크 연결
-모니터링</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">NEW_PICTURE 및 NEW_VIDEO에
-대한 제한</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">새로운 JobInfo 메서드</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">새로운 JobParameter 메서드</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">추가적인 앱 최적화</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  백그라운드 프로세스는 메모리와 배터리를 많이 소모할 수 있습니다. 예를 들어, 암시적 브로드캐스트는
-이 브로드캐스트를 수신하도록 등록된 많은 백그라운드 프로세스를 시작할 수 있지만
-해당 프로세스가 많은 작업을 수행하지 못할 경우가 있습니다. 이로 인해 기기 성능과
- 사용자 환경에 모두 상당한 영향을 미칠 수 있습니다.
-</p>
-
-<p>
-  이 문제를 완화하기 위해, Android N은 다음과 같은 제한을
-적용합니다.
-</p>
-
-<ul>
-  <li>브로드캐스트를 수신하도록 매니페스트에 등록되어 있더라도, Preview를 대상으로 하는 앱은 {@link
- android.net.ConnectivityManager#CONNECTIVITY_ACTION}
- 브로드캐스트를 수신하지 않습니다. 실행 중인 앱은 {@link android.content.Context#registerReceiver Context.registerReceiver()}로
-{@link android.content.BroadcastReceiver}를 등록하여
-여전히 기본 스레드에서 {@code CONNECTIVITY_CHANGE}를 수신할
- 수 있습니다.
-  </li>
-
-  <li>앱은 {@link
- android.hardware.Camera#ACTION_NEW_PICTURE} 또는 {@link
- android.hardware.Camera#ACTION_NEW_VIDEO} 브로드캐스트를 송수신할 수 없습니다. 이 최적화는 Preview를 대상으로
- 하는 앱뿐 아니라 모든 앱에 영향을 미칩니다.
-  </li>
-</ul>
-
-<p>
-  앱이 이들 인텐트 중 하나라도 사용하는 경우에는,
-Android N 기기를 올바로 대상으로 삼을 수 있도록 이들 인텐트에 대한 종속성을 최대한 빨리 제거해야 합니다.
-  Android 프레임워크는 이러한 암시적 브로드캐스트의
- 필요성을 줄이기 위한 여러 가지 해결책을 제공합니다. 예를 들어, {@link android.app.job.JobScheduler}
-및 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a>는 지정된
-조건(예: 비 데이터 통신 네트워크에 연결)이 충족될 경우 네트워크 작업을
-예약할 수 있는 강력한 메커니즘을 제공합니다. 이제 {@link android.app.job.JobScheduler}를
-사용하여 콘텐츠 제공자의 변경에 대응할 수도 있습니다. {@link android.app.job.JobInfo}
-객체는 {@link android.app.job.JobScheduler}가
-작업 예약에 사용하는 매개변수를 캡슐화합니다. 작업 조건이 충족되면 시스템은
-이 작업을 앱의 {@link android.app.job.JobService}에서 실행합니다.
-</p>
-
-<p>
-  이 문서에서는 대체 메서드(예: {@link android.app.job.JobScheduler})를
-사용하여 이러한 새로운 제한에 맞게 앱을 적용하는 방법에 대해
-배워보겠습니다.
-</p>
-
-<h2 id="connectivity-action">
-  CONNECTIVITY_ACTION에 대한 제한
-</h2>
-
-<p>
-  Android N을 대상으로 하는 앱은 {@link
- android.net.ConnectivityManager#CONNECTIVITY_ACTION} 브로드캐스트를 수신하지 않으며(이 브로드캐스트를 수신하도록 매니페스트에 등록하는 경우), 이
-브로드캐스트에 의존하는 프로세스는
-시작되지 않습니다. 이 경우에는 기기가 고정 요금제 네트워크에 연결될 때,
-네트워크 변경 사항을 수신하려는 앱이나 대량의 네트워크 액티비티를
-수행하려는 앱에 문제가 생길 수 있습니다. 이 제한을 해결하기 위한 여러 가지
-해결책이 Android 프레임워크에 이미 있지만, 올바른 해결책을 선택하는 것은
-앱의 용도에 따라 다릅니다.
-</p>
-
-<p class="note">
-  <strong>참고:</strong> {@link android.content.Context#registerReceiver Context.registerReceiver()}로
- 등록된 {@link android.content.BroadcastReceiver}는 앱이
- 실행되는 중에 계속해서 이 브로드캐스트를 수신합니다.
-</p>
-
-<h3 id="sched-jobs">
-  고정 요금제 연결에서 네트워크 작업 예약
-</h3>
-
-<p>
-  {@link android.app.job.JobInfo.Builder JobInfo.Builder} 클래스를
-사용하여 {@link android.app.job.JobInfo} 객체를 빌드하는 경우, {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} 메서드를 적용하고 {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED}를 작업 매개변수로 전달합니다. 다음의 코드 샘플에서는 기기가 비 데이터 통신
-네트워크에 연결되어 충전 중일 때 실행할 서비스를
-예약합니다.
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  작업의 조건이 충족되면, 앱은
-{@link android.app.job.JobService#onStartJob onStartJob()} 메서드를 지정된 {@code JobService.class}에서 실행하기 위한 콜백을
-수신합니다. {@link
-  android.app.job.JobScheduler} 구현의 더 많은 예를 보려면, <a href="{@docRoot}samples/JobScheduler/index.html">JobScheduler 샘플 앱</a>을 참조하세요.
-</p>
-
-<p>
-  GMSCore 서비스를 사용하고 Android 5.0(API 레벨 21) 이하를 대상으로 하는 앱은 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a>를 사용하고 {@code Task.NETWORK_STATE_UNMETERED}를
-지정할 수 있습니다.
-</p>
-
-<h3 id="monitor-conn">
-  앱이 실행되는 중에 네트워크 연결 모니터링
-</h3>
-
-<p>
-  실행 중인 앱은 등록된 {@link android.content.BroadcastReceiver}로 {@code CONNECTIVITY_CHANGE}를 여전히 수신할 수
-있습니다. 하지만 {@link
- android.net.ConnectivityManager} API는 지정된 네트워크 조건이 충족될 경우에만 콜백을 요청하는
- 더욱 강력한 메서드를 제공합니다.
-</p>
-
-<p>
-  {@link android.net.NetworkRequest} 객체는 {@link android.net.NetworkCapabilities}의
-관점에서 네트워크 콜백의 매개변수를 정의합니다. {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder} 클래스로 {@link android.net.NetworkRequest} 객체를
-생성합니다. 이어서 {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
-이 {@link android.net.NetworkRequest} 객체를 시스템에 전달합니다. 네트워크 조건이 충족되면, 앱은 {@link
-  android.net.ConnectivityManager.NetworkCallback} 클래스에 정의된 {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} 메서드를
-실행하기 위한 콜백을
-수신합니다.
-</p>
-
-<p>
-  앱이 종료되거나 앱이 {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}을 호출할 때까지 계속해서
-콜백을 수신합니다.
-</p>
-
-<h2 id="media-broadcasts">
-  NEW_PICTURE 및 NEW_VIDEO에 대한 제한
-</h2>
-
-<p>
-  Android N에서 앱은 {@link
- android.hardware.Camera#ACTION_NEW_PICTURE} 또는 {@link
- android.hardware.Camera#ACTION_NEW_VIDEO} 브로드캐스트를 송수신할 수 없습니다. 이 제한은 새로운 이미지나
- 동영상을 처리하기 위해 여러 앱을 깨워야 하는 경우, 성능 및 사용자 환경에
- 미치는 영향을 줄여줍니다. Android N은
- {@link android.app.job.JobInfo} 및 {@link
- android.app.job.JobParameters}를 확장하여 대체 해결책을 제공합니다.
-</p>
-
-<h3 id="new-jobinfo">
-  새로운 JobInfo 메서드
-</h3>
-
-<p>
-  콘텐츠 URI 변경에 대한 작업을 트리거하기 위해, Android N은
- 다음과 같은 메서드로 {@link android.app.job.JobInfo} API를 확장합니다.
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    콘텐츠 URI 변경에 대한 작업을 트리거하는 데 필요한 매개변수를 캡슐화합니다.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    {@code TriggerContentUri} 객체를 {@link
-    android.app.job.JobInfo}에 전달합니다. {@link android.database.ContentObserver}는
-캡슐화된 콘텐츠 URI를 모니터링합니다. 하나의 작업과 연관된 여러 {@code
-    TriggerContentUri} 객체가 있는 경우, 콘텐츠 URI 중 하나에서만 변경이 보고되더라도 시스템이
-콜백을 제공합니다.
-  </dd>
-
-  <dd>
-    지정된 URI의 하위 항목이 하나라도 변경되면, {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} 플래그를
-추가하여 작업을 트리거합니다. 이 플래그는
-{@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}로 전달된 {@code notifyForDescendants} 매개변수에 해당합니다.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>참고:</strong> {@code TriggerContentUri()}는 {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} 또는 {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}와
-조합으로 사용될 수 없습니다. 콘텐츠 변경을 계속해서 모니터링하려면, 앱의 {@link
-  android.app.job.JobService}가 가장 최근 콜백의 처리를 완료하기 전에 새로운
-{@link android.app.job.JobInfo}를 예약하세요.
-</p>
-
-<p>
-  다음 샘플 코드에서는 콘텐츠 URI, {@code MEDIA_URI}의
-변경을 시스템이 보고할 때 트리거할 작업을 예약합니다.
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  지정된 콘텐츠 URI에서의 변경을 시스템이 보고할 때,
-앱이 콜백을 수신하고 {@link android.app.job.JobParameters} 객체가
-{@code MediaContentJob.class}의 {@link android.app.job.JobService#onStartJob onStartJob()}메서드에
-전달됩니다.
-</p>
-
-<h3 id="new-jobparam">
-  새로운 JobParameter 메서드
-</h3>
-
-<p>
-  또한, Android N에서는 어떤 콘텐츠 기관과
- URI가 해당 작업을 트리거했는지에 대한 유용한 정보를 앱이
- 수신할 수 있도록 {@link android.app.job.JobParameters}를 확장합니다.
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    작업을 트리거한 URI의 배열을 반환합니다. 작업을 트리거한
-URI가 없거나(예: 시한 또는 기타 이유로 인해 작업이 트리거된 경우) 또는
-변경된 URI의 수가 50보다 크면 {@code
-    null}이 됩니다.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    작업을 트리거한 콘텐츠 기관의 문자열 배열을 반환합니다.
-    반환된 배열이 {@code null}이 아닌 경우, {@code getTriggeredContentUris()}를
-사용하여 변경된 URI의 세부정보를 검색합니다.
-  </dd>
-</dl>
-
-<p>
-  다음 샘플 코드에서는 {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} 메서드를 재정의하고
-, 작업을 트리거한 콘텐츠 기관과 URI를 기록합니다.
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  추가적인 앱 최적화
-</h2>
-
-<p>
-  저용량 메모리 기기나 저용량 메모리 조건에서
-앱이 실행되도록 최적화하면 성능과 사용자 환경을 개선할 수 있습니다. 백그라운드 서비스에 대한 종속성과 정적으로 등록된
- 암시적 브로드캐스트 수신기에 대한 종속성을 제거하면 해당 기기에서 앱을
- 더욱 빨리 실행할 수 있습니다. Android N은 이러한 문제 중 일부를 줄이기 위한
- 조치를 취하고 있지만, 백그라운드
- 프로세스를 전혀 사용하지 않고 앱이 실행되도록
- 최적화하는 것이 좋습니다.
-</p>
-
-<p>
-  Android N에서는 백그라운드 프로세스를
-비활성화하고 앱 동작을 테스트하는 데 사용할 수 있는 몇 가지 추가적인 <a href="{@docRoot}tools/help/adb.html">ADB(Android 디버그 브리지)</a> 명령을 도입했습니다.
-</p>
-
-<ul>
-  <li>암시적 브로드캐스트와 백그라운드 서비스를 사용할
-수 없는 조건을 시뮬레이션하려면 다음 명령을 입력합니다.
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>암시적 브로드캐스트와 백그라운드 서비스를 다시 활성화하려면
-다음 명령을 입력합니다.
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/ko/preview/features/icu4j-framework.jd b/docs/html-intl/intl/ko/preview/features/icu4j-framework.jd
deleted file mode 100644
index 921873d..0000000
--- a/docs/html-intl/intl/ko/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=ICU4J Android 프레임워크 API
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>이 문서의 내용</h2>
-<ol>
-    <li><a href="#relation">ICU4J와의 관계</a></li>
-    <li><a href="#migration">android.icu API에서 ICU4J로 마이그레이션</a></li>
-    <li><a href="#licence">라이선스</a></li>
-</ol>
-
-<h2>참고 항목</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">ICU4J 문서</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">
-ICU4J가 지원하는 최신 표준</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J는 오픈 소스이며 널리 사용되는 Java 라이브러리 세트로, 소프트웨어 애플리케이션에 유니코드와
-세계화 지원을 제공합니다. Android N은
-Android 프레임워크에서 앱 개발자가
-{@code android.icu} 패키지에서 사용할 수 있는 ICU4J API의 하위 세트를 노출합니다. 이 API는
-기기의 현지화 데이터를 사용합니다. 따라서 ICU4J 라이브러리를 APK로 컴파일하지 않고
-프레임워크에서 호출하여APK
-풋프린트를 줄일 수 있습니다. (이 경우, Android N 이하 버전의 Android를
-실행하는 사용자가 ICU4J 라이브러리를 포함한 앱 버전을 다운로드할 수 있도록
-<a href="{@docRoot}google/play/publishing/multiple-apks.html">여러 버전의
-APK</a>를 제공해야 할 수도 있습니다.)
-</p>
-
-<p>
-  이 문서에서는 먼저 이 라이브러리 지원에 필요한 최소
-Android API 레벨과 관련된 몇 가지 기본 정보를 제공합니다. 그 후,
-각 Android에서 ICU4J를 구현하는 데 무엇이 필요한지 설명합니다. 마지막으로,
-Android 프레임워크에서 ICU4J API를 사용하는 방법을 설명합니다.
-</p>
-
-<h2 id="relation">ICU4J와의 관계</h2>
-
-<p>
-  Android N은
-<code>com.ibm.icu</code>가 아니라 <code>android.icu</code> 패키지를 통해 ICU4J API의 하위 세트를 노출합니다.
-Android 프레임워크는 여러 가지 이유로
-ICU4J API를 노출하지 않을 수 있습니다. 예컨대 Android N은
-일부 사용 중단된 API나 ICU 팀에서 안정적이라고 선언하지 않은 API를
-노출하지 않습니다. ICU 팀이 이후 API의 사용을 중단하면, Android도
-이를 사용 중단됨으로 표시하지만 계속 포함합니다.
-</p>
-
-<p class="table-caption"><strong>표 1.</strong>
-Android N에서 사용된 ICU 및 CLDR 버전.</p>
-<table>
-<tr>
-<th>Android API 레벨</th>
-<th>ICU 버전</th>
-<th>CLDR 버전</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>중요한 참고 사항:</p>
-
-<ul>
-<li>ICU4J Android 프레임워크 API에는 모든 ICU4J API가 포함되지 않습니다.</li>
-<li>NDK 개발자는 Android ICU4C가 지원되지 않는다는 것을 알아야 합니다.</li>
-<li>Android 프레임워크의 API는 Android의
-<a href="{@docRoot}guide/topics/resources/localization.html">리소스로
-현지화</a> 지원을 대체하지 못합니다.</li>
-</ul>
-
-<h2 id="migration">com.ibm.icu에서 android.icu 패키지로 마이그레이션</h2>
-
-<p>
-  앱에서 이미 ICU4J API를 사용하고 있고
-<code>android.icu</code> API가 요구사항을 충족한다면
-프레임워크 API로 마이그레이션할 때 Java 가져오기를
-<code>com.ibm.icu</code>에서 <code>android.icu</code>로 변경해야 합니다. 그러면 APK에서
-ICU4J 파일 사본을 삭제할 수 있습니다.
-</p>
-
-<p class="note">
-  <b>참고</b>: ICU4J 프레임워크 API는 {@code com.ibm.icu} 대신 {@code android.icu}
-네임스페이스를 사용합니다. 이는 자체 {@code com.ibm.icu} 라이브러리가 포함된 APK에서
-네임스페이스 충돌을 피하기 위해서입니다.
-</p>
-
-<h3 id="migrate-from-android">
-  다른 Android SDK API에서 android.icu API로 마이그레이션
-</h3>
-
-<p>
-  <code>java</code>와 <code>android</code> 패키지의 일부 클래스는
-ICU4J의 클래스와 같습니다. 그러나 ICU4J는 종종 더욱 폭넓은
-표준과 언어를 지원합니다.
-</p>
-<p>시작하기 위한 몇 가지 예시는 다음과 같습니다.</p>
-<table>
-<tr>
-<th>클래스</th>
-<th>대체</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">라이선스</h2>
-
-<p>
-  ICU4J는 ICU 라이선스에 따라 배포됩니다. 자세한 내용은 <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">ICU
- 사용자 가이드</a>를 참조하세요.
-</p>
diff --git a/docs/html-intl/intl/ko/preview/features/multilingual-support.jd b/docs/html-intl/intl/ko/preview/features/multilingual-support.jd
deleted file mode 100644
index 6b3e999..0000000
--- a/docs/html-intl/intl/ko/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=언어 및 로케일
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>이 문서의 내용</h2>
-<ol>
-	  <li><a href="#preN">언어 리소스 결정에서의 과제</a></li>
-    <li><a href="#postN">리소스 결정 전략 개선</a></li>
-    <li><a href="#design">추가 로케일 지원을 위한
-앱 설계</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N에서는 다국어 사용자를 위한 지원이 개선되었으므로
-이러한 사용자가 이제 설정에서 여러 로케일을 선택할 수 있습니다. Android N은
-지원되는 로케일 수를 대폭 확대하고
-시스템이 리소스를 결정하는 방식을 변경하여 이 기능을 제공합니다. 새로 도입된 리소스 결정 방법은
-더욱 안정적이고 기존 APK와 호환되도록 설계되어 있지만
-예상치 못한 동작이 없는지 신중히 살펴봐야 합니다. 예를 들어,
-앱이 예상 언어로 기본 설정되어 있는지 테스트해야 합니다. 또한,
-앱이 여러 언어를 지원한다면
-원하는 대로 작동하는지 확인해야 합니다. 마지막으로
-앱이 지원하도록 명시하지 않은 언어를 무리 없이 처리하는지 확인해야 합니다.</p>
-
-<p>이 문서에서는
-Android N 이전의 리소스 결정 전략을 설명한 뒤에, Android N의 개선된
-리소스 결정 전략을 설명합니다. 마지막으로
-더 많은 다국어 사용자를 지원하기 위해 확장된 로케일을 활용하는 방법을 설명합니다.</p>
-
-<h2 id="preN">언어 리소스 결정에서의 과제</h2>
-
-<p>Android N 이전의 Android에서는
- 앱과 시스템 로케일을 매칭하지 못하는 경우가 가끔 있었습니다.</p>
-
- <p>예를 들어, 다음과 같은 상황이라고 가정해 봅시다.</p>
- <ul>
- <li>앱의 기본 언어가 {@code en_US}(미국 영어)인데
-, {@code es_ES}
- 리소스 파일에 스페인어 문자열도 현지화했습니다.</li>
- <li> 기기는 {@code es_MX}로 설정되어 있습니다. </li>
-
-<p>Java 코드가 문자열을 참조할 때
-앱에서 {@code es_ES} 아래에 스페인어 리소스를 현지화했더라도, 시스템은 기본({@code en_US}) 리소스 파일로부터 문자열을
-로드합니다. 그 이유는 시스템이
-정확한 일치 항목을 찾을 수 없을 때 해당 로케일에서 국가 코드를
-제거하여 리소스를 계속 찾기 때문입니다. 마지막으로, 일치 항목을 찾지 못한 경우 시스템은 기본값({@code en_US})으로 다시
-돌아갑니다. </p>
-
-
-<p>또한, 앱에서 전혀 지원하지 않는 언어(예: 프랑스어)를 사용자가 선택하면 시스템은 기본값을 {@code en_US}로
-설정합니다. 예를 들면 다음과 같습니다.</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>표 1.</strong> 정확한 로케일 일치가 없는 경우 리소스 결정.
-</p>
-<table>
-<tbody>
-<tr>
-<th>사용자 설정</th>
-<th>앱 리소스</th>
-<th>리소스 결정</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-기본값(en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-fr_CH 시도 =&gt; 실패<br>
-fr 시도 =&gt; 실패<br>
-기본값(en) 사용
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>이 예시에서 시스템은
-사용자가 영어를 이해할 수 있는지 여부와 관계없이 영어 문자열을 표시합니다. 현재 이러한 동작이 상당히
-일반적입니다. Android N은 이런
-결과가 나타나는 빈도를 상당히 낮추었습니다.</p>
-
-<h2 id="postN">리소스 결정 전략 개선</h2>
-<p>Android N은 더욱 안정적인 리소스 결정을 사용하고
-자동으로 더욱 알맞은 대안책을 찾습니다. 그러나 결정 속도를 높이고
-관리성을 개선하려면 가장 일반적인 상위 방언에 리소스를 저장해야 합니다.
- 예를 들어, 전에 {@code es-US} 디렉터리에
-스페인어 리소스를 저장했다면 남미 스페인어가 있는 {@code es-419} 디렉터리로 이동합니다.
- 마찬가지로 {@code en-GB}란 폴더에 리소스 문자열이 있다면
-폴더 이름을 {@code en-001}(국제 영어)로 변경합니다.
-<code>en-GB</code> 문자열의 가장 일반적인 상위 리소스는 {@code en-001}이기 때문입니다.
- 다음은 이러한 방법이
-성능과 리소스 결정의 신뢰성을 개선하는 이유를 설명하는 예시입니다.</p>
-
-<h3>리소스 결정 예시</h3>
-
-<p>Android N의 경우, <strong>표 1</strong>의 사례는
-다르게 결정됩니다.</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>표 2.</strong> 정확한 로케일 일치가 없을 경우
-개선된 결정 전략.</p>
-<table>
-<tr>
-<th>사용자 설정</th>
-<th>앱 리소스</th>
-<th>리소스 결정</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-기본값(en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-fr_CH 시도 =&gt; 실패<br>
-fr 시도 =&gt; 실패<br>
-Fr의 하위 리소스 시도 =&gt; fr_FR<br>
-fr_FR 사용
-</td>
-</tr>
-
-</table>
-
-
-<p>이제 사용자는 영어 대신 프랑스어 리소스를 보게 됩니다. 이 예시에서는
-Android N에서 프랑스어 문자열을 {@code fr_FR}
-이 아니라 {@code fr}에 저장해야 하는 이유를 알 수 있습니다. 이러한 동작을 통해 가장 가까운 상위 방언과 일치시켜서
-더욱 빠르고 예측 가능하게 결정합니다.</p>
-
-<p>Android는 이러한 결정 논리를 개선했을 뿐만 아니라
-선택 가능한 언어를 더 많이 제공합니다. 위의 예시에 이탈리아어가 추가 사용자 언어로 지정되었지만
-앱에서 프랑스어를 지정하지 않는 경우를 적용해 보겠습니다.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>표 3.</strong> 앱이 사용자의 두 번째 선호 로케일 설정에만 일치할 때
-리소스 결정.</p>
-<table>
-<tr>
-<th>사용자 설정</th>
-<th>앱 리소스</th>
-<th>리소스 결정</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-기본값(en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-fr_CH 시도 =&gt; 실패<br>
-fr 시도 =&gt; 실패<br>
-fr의 하위 리소스 시도 =&gt; 실패<br>
-it_CH 시도 =&gt; 실패<br>
-it 시도 =&gt; 실패<br>
-it의 하위 리소스 시도 =&gt; it_IT<br>
-it_IT 사용
-</td>
-
-</tr>
-
-</table>
-<p>앱이 프랑스어를 지원하지 않지만
-사용자는 여전히 자신이 이해하는 언어를 볼 수 있습니다.</p>
-
-
-<h2 id="design">추가 로케일 지원을 위한 앱 설계</h2>
-<h3>LocaleList API</h3>
-
-<p>Android N에서는 앱이 사용자가 지정한 언어 목록을 직접 쿼리할 수 있는 새로운 API {@code LocaleList.getDefault()}가
-추가되었습니다. 이 API는
-앱 동작을 더욱 정교하게 해주고
- 콘텐츠 표시를 더 최적화해 줍니다. 예를 들어, 검색 시
-사용자 설정에 따라 여러 언어로 결과를 표시할 수 있습니다.  브라우저 앱은
-사용자가 이미 알고 있는 언어로
-번역 페이지를 제공하지 않고, 키보드 앱은 모든 적절한 레이아웃을 자동 활성화할 수 있습니다. </p>
-
-<h3>포맷터</h3>
-
-<p>Android 6.0(API 레벨 23)까지 Android는 많은 공통 언어(en, es, ar, fr, ru)에 대해
-1~2개의 로케일만
-지원했습니다. 각 언어의 변종은 몇 개뿐이기 때문에
-리소스 파일에 하드코딩된 문자열로 몇 개의 숫자와 날짜를 저장하는 것만으로
-충분했습니다.  그러나 Android에서 지원되는 로케일 세트가 확장되면서
-단일 로케일 내에서조차
-날짜, 시간, 통화 및 유사 정보에
-큰 차이가 생길 수 있게 되었습니다. 형식 하드코딩은
-최종 사용자에게 혼란을 줄 수 있습니다.  그러므로 Android N을 개발할 때는
-숫자와 날짜 문자열을 하드코딩하는 대신 포맷터를 사용하도록 하세요.</p>
-
-<p>가장 좋은 예시로는 아랍어가 있습니다. Android N에서 아랍어 지원이
-{@code ar_EG} 1개에서 27개 아랍어 로케일로 확장되었습니다. 이러한 로케일은 대부분의 리소스를 공유할 수 있지만
-어떤 로케일은 ASCII 숫자를 선호하고 어떤 로케일은 네이티브 숫자를 선호합니다. 예를 들어,
-"4자리 PIN 선택"과 같은 숫자 변수가 포함된 문장을 생성하려면
-아래와 같이 포맷터를 사용합니다.</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/ko/preview/features/notification-updates.jd b/docs/html-intl/intl/ko/preview/features/notification-updates.jd
deleted file mode 100644
index 480eda0..0000000
--- a/docs/html-intl/intl/ko/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,393 +0,0 @@
-page.title=알림
-page.tags=알림
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>이 문서의 내용</h2>
-<ol>
-  <li><a href="#direct">직접 회신</a></li>
-  <li><a href="#bundle">묶음 알림</a></li>
-  <li><a href="#custom">사용자 지정 뷰</a></li>
-  <li><a href="#style">메시지 스타일</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N에서는 가시성과 상호 작용이 뛰어난 알림을
-앱이 게시할 수 있도록 여러 가지 새로운 API를 도입했습니다.</p>
-
-<p>Android N에서는 핸드셋에서 인라인 회신을 지원하기 위해 기존의 {@link android.support.v4.app.RemoteInput}
-알림 API를 확장합니다. 이 기능을 사용하면 앱을 방문하지 않고도 알림 창에서
-신속하게 응답할 수 있습니다.</p>
-
-<p>
-  Android N에서는 또한 비슷한 알림을 묶어서 단일 알림으로
-표시할 수도 있습니다. 이것이 가능하도록, Android N에서는 기존의 {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} 메서드를 사용합니다. 사용자가 각 알림을 확장할 수 있으며, 각 알림에 대해 회신 및
-닫기와 같은 동작을 알림 창에서 개별적으로 수행할
-수 있습니다.
-</p>
-
-<p>마지막으로, Android N에서는 또한 앱의 사용자 지정된 알림
-뷰에서 시스템 장식을 활용할 수 있는 새 API를 추가합니다. 이들 API는 표준 템플릿을 통해 알림 뷰가
-일관된 프레젠테이션을 공유하도록 보장해
-줍니다.</p>
-
-<p>이 문서에서는 새 알림 기능을 앱에서 사용할 때 고려해야
-하는 몇 가지 주요 변경 사항을 중점적으로 다룹니다.</p>
-
-<h2 id="direct">직접 회신</h2>
-
-<p>Android N에 있는 직접 회신 기능을 사용하여, 사용자가 문자
-메시지에 신속하게 응답하거나 알림 인터페이스 내에서 직접
-작업 목록을 업데이트할 수 있습니다. 핸드헬드에서 인라인 회신 동작은 알림에 연결된 추가적인
-버튼으로 나타납니다. 사용자가 키보드를 통해 회신하면
-시스템은 여러분이 알림 동작에 지정했던
-인텐트에 텍스트 응답을 첨부하고 이 인텐트를
- 핸드헬드 앱으로 보냅니다.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>그림 1.</strong> Android N이 <strong>Reply</strong>
- 동작 버튼을 추가합니다.
-</p>
-
-<h3>인라인 회신 동작 추가</h3>
-
-<p>직접 회신을 지원하는 알림 동작을 만들려면:
-</p>
-
-<ol>
-<li>알림 동작에 추가할 수 있는 {@link android.support.v4.app.RemoteInput.Builder}의
-인스턴스를
-만듭니다. 이 클래스의 생성자는 시스템이 텍스트 입력의 키로
- 사용하는 문자열을 수락합니다. 나중에 핸드헬드 앱은 이 키를 사용하여 입력 텍스트를
-검색합니다.
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li><code>addRemoteInput()</code>을 사용하여 {@link android.support.v4.app.RemoteInput}
-객체를 동작에 첨부합니다.
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>동작을 알림에 적용하고 알림을 발생합니다.
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> 시스템이 사용자에게 알림 동작이 트리거될 때 응답을 입력하라는
-메시지를 표시합니다. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>그림 2.</strong> 사용자가 알림 창에서 텍스트를 입력합니다.
-</p>
-
-<h3>
-  인라인 회신에서 사용자 입력을 검색
-</h3>
-
-<p>
-  회신 동작의 인텐트에 선언하셨던 액티비티에 대해 알림
- 인터페이스로부터 사용자 입력을 수신하려면:
-</p>
-
-<ol>
-  <li>알림 동작의 인텐트를 입력 매개변수로서 전달하여 {@link android.support.v4.app.RemoteInput#getResultsFromIntent
- getResultsFromIntent()}를
- 호출합니다. 이 메서드는 텍스트 응답이 포함된 {@link android.os.Bundle}을
- 반환합니다.
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>({@link
- android.support.v4.app.RemoteInput.Builder} 생성자에 제공된) 결과 키를 사용하여 번들에 쿼리를 수행합니다. 다음 코드 조각에서처럼, 메서드를 만들어 이 프로세스를
-완료하고 입력 텍스트를
-검색할 수 있습니다.
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>이전 알림에 대해 제공했던 것과 동일한 알림 ID를
- 사용하여, 다른 알림을 작성하고 발급합니다. 사용자에게 성공적으로 회신했음을
-알려주기 위해 알림 인터페이스에서
-알림 표시기가 사라집니다. 이 새로운 알림으로 작업할 때, 수신기의
-{@code onReceive()} 메서드로 전달되는 컨텍스트를 사용하세요.
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  채팅과 같은 대화형 앱의 경우, 검색된 텍스트를 처리할 때
- 추가 컨텍스트를 포함하는 것이 유용할 수 있습니다. 예를 들어, 이들 앱은 여러 줄의 채팅 기록을
-표시할 수 있습니다. 사용자가 {@link
- android.support.v4.app.RemoteInput}을 통해 응답하는 경우,
-{@code setRemoteInputHistory()} 메서드를 사용하여 회신 기록을 업데이트할 수 있습니다.
-</p>
-
-<p>
-  앱이 원격 입력을 수신한 후에는 알림이 업데이트되거나
- 취소되어야 합니다. 사용자가 Direct Reply를 사용하여 원격 업데이트에
-회신할 때는 알림을
-취소하지 마세요. 그 대신, 사용자의 회신을 표시하도록 알림을 업데이트하세요.
-{@code MessagingStyle}을 사용하는 알림의 경우, 회신을 최신 메시지로서
-추가해야 합니다. 다른 템플릿을 사용할 경우 사용자의
-회신을 원격 입력 기록에 추가할 수 있습니다.
-</p>
-
-<h2 id="bundle">묶음 알림</h2>
-
-<p>Android N에서는 일련의 알림을 표시하기 위한 새로운 방식을
-개발자에게 제공합니다. <i>묶음 알림</i>. 이것은
-Android Wear의 <a href="{@docRoot}training/wearables/notifications/stacks.html">알림
-스택</a> 기능과 유사합니다. 예를 들어, 수신된 메시지에 대해 앱이 알림을 생성하는 경우,
-둘 이상의 메시지가 수신되면 그 알림을 하나의
-단일 그룹으로 묶습니다. 기존의
-{@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} 메서드를 사용하여 유사한 알림을 묶을 수 있습니다.</p>
-
-<p>
-  알림 그룹은 이 그룹을 구성하는 알림을 계층 구조로 만듭니다.
-  계층 구조의 맨 위는 그룹의 요약 정보가 표시되는 상위
-알림입니다. 사용자는 알림 그룹을 점진적으로 확장할 수 있으며, 시스템은
-사용자가 더 깊이 파고들수록 더 많은 정보를
-표시합니다. 사용자가 번들을 확장하면 시스템은 모든 하위 알림에 대해
-더 많은 정보를 표시하며, 사용자가 이들 알림 중 하나를 확장하면
-시스템은 알림의 전체 콘텐츠를 표시합니다.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>그림 3.</strong> 사용자는 알림 그룹을 점진적으로 확장할 수
- 있습니다.
-</p>
-
-<p class="note">
-  <strong>참고:</strong> 동일 앱이 4개 이상의 알림을 보내면서
-그룹화를 지정하지 않으면,
-시스템에서 이들 알림을 자동으로 그룹화합니다.
-</p>
-
-<p>알림을 그룹에 추가하는 방법을 알아보려면
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">각
-알림을 그룹에 추가</a>를 참조하세요.</p>
-
-
-<h3 id="best-practices">묶음 알림의 모범 사례</h3>
-<p>이 섹션에서는 이전 버전의 Android 플랫폼에서
-사용되었던 {@link android.app.Notification.InboxStyle InboxStyle}
-알림 대신에 알림 그룹을 사용할 때의 지침을
-제공합니다.</p>
-
-<h3>묶음 알림을 사용하는 경우</h3>
-
-<p>자신의 사용 사례에서 다음의 모든 조건이 충족되는 경우에만
-알림 그룹을 사용해야 합니다.</p>
-
-<ul>
-  <li>하위 알림은 완전한 알림이며 그룹 요약이 필요 없이
-개별적으로 표시될 수 있습니다.</li>
-  <li>하위 알림을 개별적으로 표시하는 경우 이점이 있습니다. 예를 들면 다음과 같습니다.
-
-  </li>
-  <ul>
-    <li>알림이 실행 가능하며, 각 하위 알림에 맞는 동작이 있습니다.</li>
-    <li>사용자가 읽고 싶어하는 하위 알림에 더 많은 정보가 있습니다.</li>
-  </ul>
-</ul>
-
-<p>알림 그룹의 사용 사례에 대한 좋은 예로는, 수신 메시지의
-목록을 표시하는 메시징 앱이나 수신된 이메일의 목록을 표시하는
-이메일 앱이 있습니다.</p>
-
-<p>
-단일 알림이 바람직한 사례의 예로는, 한 사람이 보낸
-개별 메시지나 1줄 텍스트 항목의 목록 표시가
-있습니다. 이를 수행하기 위해
-({@link android.app.Notification.InboxStyle InboxStyle} 또는
-{@link android.app.Notification.BigTextStyle BigTextStyle})을 사용할
-수 있습니다.
-</p>
-
-<h3 id ="post">묶음 알림 표시</h3>
-
-<p>
-  그룹에 하나의 하위 항목만 포함되어 있더라도 앱은
-항상 그룹 요약을 게시해야 합니다. 하나의 알림만 포함된 경우에는 시스템이 요약을
-억제하고 하위 알림을 직접 표시합니다. 이렇게 하면 사용자가 그룹의
-하위 항목을 스와이프할 때 시스템이 일관된 경험을 제공할 수
-있습니다.
-</p>
-
-<p class="note">
-  <strong>참고:</strong> 이 버전의 Android N에서는 아직 단일 하위
-항목이 포함된 알림 그룹에 대해 요약을 억제하지 않습니다. 이
-기능은 이후 버전의 Android N에 추가될 것입니다.
-</p>
-
-<h3>피킹 알림</h3>
-
-<p>시스템은
-일반적으로 하위 알림을 그룹으로 표시하지만,
-이 알림이 일시적으로 <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">헤드업 알림</a>으로
-나타나도록 설정할 수 있습니다. 이 기능을 사용하면 가장 최근의 하위 항목과 이에
-관련된 동작에 즉시 액세스할 수 있으므로 특히 유용합니다.
-</p>
-
-
-<h3>이전 버전과의 호환성</h3>
-
-<p>
-  Android 5.0(API 레벨 21) 이후로, 알림 그룹과
-원격 입력은 Android Wear 기기를 지원하기 위한 {@link
-  android.app.Notification} API의 일부였습니다. 이미 이들 API로 알림을 작성한 경우 수행할 조치는,
-앱 동작이 위에 설명된 지침과 일치하는지 확인하고 {@code
-  setRemoteInputHistory()} 구현을
-고려하는 것입니다.
-</p>
-
-<p>
-  이전 버전과의 호환성을 지원하기 위해,
-지원 라이브러리의 {@link android.support.v4.app.NotificationCompat}
-클래스로 동일한 API를 사용할 수 있으며, 이전 Android 버전에서 작동하는 알림을 작성할
-수 있습니다. 핸드헬드와 태블릿에서는 요약 알림만 사용자에게 보이므로,
-앱은 해당 그룹의 전체 정보 콘텐츠에 대해 받은편지함
-스타일이나 이와 동등한 알림 표시를 계속 가져야 합니다. Android
-Wear 기기에서는 구형 플랫폼 레벨에서도
-사용자가 모든 하위 알림을 볼 수 있으므로, API 레벨에 상관없이 하위 알림을
-작성해야 합니다.
-</p>
-
-<h2 id="custom"> 사용자 지정 뷰</h2>
-<p>Android N부터는 알림 뷰를 사용자 지정할 수 있으며
-알림 헤더, 동작 및 확장 가능한 레이아웃과 같은 시스템 장식을 계속
-획득할 수 있습니다.</p>
-
-<p>이 기능을 활성화하기 위해, Android N에서는 다음과
-같은 API를 추가하여 사용자 지정 뷰의 스타일을 지정합니다.</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> 미디어 알림 이외의 스타일
-알림.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> 스타일 미디어 알림.</dd>
-</dl>
-
-<p>이 새로운 API를 사용하려면, {@code setStyle()} 메서드를 호출하여,
-원하는 사용자 지정 뷰 스타일에 전달합니다.</p>
-
-<p>이 조각에서는
-{@code DecoratedCustomViewStyle()} 메서드로 사용자 지정 알림 객체를 구성하는 방법을 보여줍니다.</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">메시징 스타일</h2>
-<p>
-  Android N에서는 알림 메시지의 스타일을 사용자 지정하기 위한 새로운 API를 도입했습니다.
-  <code>MessageStyle</code> 클래스를 사용하면 대화 제목, 추가 메시지 및 알림에 대한 콘텐츠 뷰를 비롯하여
-알림 메시지에 표시되는 여러 가지 레이블을
-변경할 수 있습니다.
-</p>
-
-<p>
-  다음 코드 조각에서는
- <code>MessageStyle</code> 클래스를 사용하여 알림 스타일을 사용자 지정하는 방법을 보여 줍니다.
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
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..ff44f6a 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,78 +1,62 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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 +66,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 +77,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..b15ecc8 100644
--- a/docs/html-intl/intl/pt-br/index.jd
+++ b/docs/html-intl/intl/pt-br/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/pt-br/preview/download_mp2.jd b/docs/html-intl/intl/pt-br/preview/download_mp2.jd
deleted file mode 100644
index 12ef194..0000000
--- a/docs/html-intl/intl/pt-br/preview/download_mp2.jd
+++ /dev/null
@@ -1,360 +0,0 @@
-page.title=Downloads
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">Antes de fazer o download ou instalar componentes do Android Preview
- SDK, você deve concordar com os seguintes termos e condições.</p>
-
-    <h2 class="norule">Termos e condições</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-Este é o contrato de licença do Android SDK Preview (o “Contrato de Licença”).
-
-1. Introdução
-
-1.1 O Android SDK Preview (que este Contrato de licença chama de "Preview", incluindo especificamente os arquivos de sistema do Android, APIs integradas e arquivos da biblioteca Preview, se e quando estiverem disponíveis) é licenciado por meio da concordância com os termos deste contrato. O Contrato de licença forma um vínculo contratual legal entre o contratante e a Google em relação ao uso do Preview.
-
-1.2 "Android" se refere à pilha de software do Android para dispositivos, conforme disponibilizado no Projeto de código aberto do Android, localizado no URL a seguir: http://source.android.com/, atualizado periodicamente.
-
-1.3 "Google" refere-se à Google Inc, uma corporação de Delaware, com sede em 1600 Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos.
-
-2. Aceitação do Contrato de Licença
-
-2.1 A fim de usar o Preview, é necessário concordar com este Contrato de licença. O uso do Preview é proibido àqueles que não concordam com este Contrato de licença.
-
-2.2 Ao clicar em aceitar e/ou usar o Preview, você concorda com os termos do Contrato de licença
-
-2.3 É proibido o uso do Preview e a aceitação deste contrato pelo indivíduo que tenha impedimento legal sobre o recebimento do Preview sob as leis dos Estados Unidos ou de outros países, incluindo o país de residência ou no qual usa o Preview.
-
-2.4 Se for usar o Preview internamente na empresa ou organização, você deverá concordar com o vínculo com este contrato em nome do empregador ou de outra entidade e declarar e garantir que tem total autoridade legal para tanto. Se você não tem a autoridade necessária, não deve concordar com este contrato nem usar o Preview em nome do empregador ou de outra entidade.
-
-3. Licença do Preview da Google
-
-3.1 Sujeito aos termos do Contrato de licença, a Google confere uma licença limitada, revogável, livre de taxas, intransmissível, não sub-licenciável e não exclusiva para o uso apenas do Preview, pessoal ou internamente dentro da sua empresa ou organização, para fins de desenvolvimento de aplicativos executados na plataforma do Android.
-
-3.2 Você concorda que a Google ou terceiros detêm todos os direitos legais, títulos e interesses relativos ao Preview, incluindo quaisquer direitos de propriedade intelectual que subsistam no Preview. "Direitos de propriedade intelectual" se referem a todo e qualquer direito sob as leis de patentes, de direitos autorais, de segredo comercial, de marca registrada e todos os outros direitos de propriedade. A Google reserva todos os direitos não conferidos expressamente a você.
-
-3.3 O uso do Preview não é autorizado para qualquer finalidade não expressamente permitida por este Contrato de licença. Salvo na extensão exigida por licenças aplicáveis de terceiros, é proibido: (a) copiar (exceto para fins de cópia de segurança), modificar, adaptar, redistribuir, descompilar, fazer engenharia reversa, desmontar ou criar trabalhos derivados do Preview ou qualquer parte dele; ou (b) carregar qualquer parte do Preview em um aparelho celular ou outro dispositivo de hardware, exceto em computador pessoal, combinar qualquer parte do Preview com outros softwares ou distribuir qualquer software ou dispositivo que contenha uma parte do Preview.
-
-3.4 Você concorda que não tomará quaisquer medidas que possam causar ou resultar em fragmentação do Android, incluindo, sem limitar-se, a distribuição e a participação na criação ou na promoção, sob quaisquer formas, de um conjunto de desenvolvimento de software derivado do Preview.
-
-3.5 O uso, a reprodução e a distribuição de componentes do Preview licenciado sob licença de software de código aberto são regidos exclusivamente pelos termos daquela licença de software de código aberto, e não por este Contrato de licença. Você concorda em manter uma licença em bom estado para as licenças de software de código aberto sob todos os direitos concedidos e deter quaisquer ações que possam limitar, suspender ou romper tais direitos.
-
-3.6 Você concorda que a forma e a natureza do SDK que a Google fornece podem mudar sem aviso prévio e que as versões futuras do SDK podem ser incompatíveis com aplicativos desenvolvidos em versões anteriores do SDK. Você concorda que a Google pode cessar (permanente ou temporariamente) o fornecimento do Preview (ou quaisquer recursos dentro dele) a você ou a usuários em geral sob critério exclusivo da Google, sem aviso prévio.
-
-3.7 Nada neste Contrato de licença confere o direito de uso de quaisquer nomes comerciais, marcas comerciais, marcas de serviço, logomarcas, nomes de domínios e outros recursos de marcas especiais da Google.
-
-3.8 Você concorda que não removerá, ocultará nem alterará quaisquer observações de direitos de propriedade (incluindo observações de direitos autorais e de marcas registradas) que possam estar afixadas ou contidas no Preview.
-
-4. Uso do Preview por você
-
-4.1 A Google compreende que nada no Contrato de licença dá a ela direito, título nem interesse no usuário (ou em seus licenciadores), sob o presente Contrato de licença, no que tange ao desenvolvimento de aplicativos de software através do uso do Preview, incluindo quaisquer direitos de propriedade intelectual que subsistam nos referidos aplicativos.
-
-4.2 Você concorda em usar o Preview e desenvolver aplicativos somente para as finalidades permitidas por (a) este Contrato de licença e (b) quaisquer leis, normas, diretrizes geralmente aceitas ou orientações aplicáveis nas jurisdições relevantes (incluindo quaisquer leis acerca da exportação e da importação de dados ou softwares nos Estados Unidos ou em outros países relevantes).
-
-4.3 Você concorda que, se usar o Preview para o desenvolvimento de aplicativos, deverá proteger a privacidade e os direitos legais destes usuários. Se nomes de usuário, senhas ou outras informações de acesso ou informações pessoais forem fornecidos ao aplicativo, deve-se informá-los de que tais dados estarão disponíveis para o aplicativo, além de fornecer observações de privacidade e proteção legalmente adequadas a esses usuários. Se o aplicativo armazenar informações pessoais ou confidenciais fornecidas pelos usuários, deve fazê-lo com segurança. Se o usuário fornecer informações da conta do Google, o aplicativo poderá usar essas informações exclusivamente para acessar a conta da Google do usuário quando houver autorização para fazê-lo e para os fins limitados pela autorização.
-
-4.4 Você concorda que não se envolverá em qualquer atividade com o Preview, incluindo o desenvolvimento e a distribuição de um aplicativo que interfira, perturbe, danifique ou acesse, de modo não autorizado, servidores, redes ou outras propriedades ou serviços da Google ou qualquer outro terceiro.
-
-4.5 Você concorda que é exclusivamente responsável por (e que a Google não tem qualquer responsabilidade com você ou terceiro) quaisquer dados, conteúdo ou recursos que criar, transmitir ou exibir por meio do Android e/ou de aplicativos do Android e pelas consequências que suas ações (incluindo perda ou dano que a Google possa sofrer) podem gerar.
-
-4.6 Você concorda que é exclusivamente responsável por (e que a Google não tem qualquer responsabilidade com você ou terceiro) qualquer violação das obrigações exigidas neste Contrato de licença, qualquer contrato ou termos de serviço aplicáveis a terceiros, qualquer lei ou norma aplicável e pelas consequências (incluindo a perda ou dano que a Google ou qualquer terceiro possa sofrer) de quaisquer violações.
-
-4.7 O Preview está em desenvolvimento e o seu teste e feedback são uma parte importante deste processo. Ao usar o Preview, você está ciente de que a implementação de alguns recursos ainda estão em desenvolvimento e que não se deve confiar que o Preview tem a funcionalidade completa de uma versão estável. Você concorda em não distribuir nem enviar publicamente quaisquer aplicativos usando este Preview, pois ele não será mais suportado após o lançamento oficial do Android SDK.
-
-5. Suas credenciais de desenvolvedor
-
-5.1 Você é responsável pela manutenção da confidencialidade de quaisquer credenciais de desenvolvedor que possam ser emitidas pela Google ou escolhidas por você e será o único responsável por todos os aplicativos que forem desenvolvidos sob suas credenciais de desenvolvedor.
-
-6. Privacidade e informações
-
-6.1 A fim de inovar e aprimorar continuamente o Preview, a Google pode coletar certas estatísticas de uso do software, incluindo, sem limitar-se, um identificador exclusivo, endereço IP associado, número de versão do software e informações sobre quais ferramentas e/ou serviços no Preview estão sendo usados e como estão sendo usados. Antes de coletar quaisquer dessas informações, o Preview o notificará e buscará seu consentimento. Se você recusar, as informações não serão coletadas.
-
-6.2 Os dados coletados são examinados coletivamente para aprimorar o Preview e são mantidos em conformidade com a Política de privacidade da Google acessível em http://www.google.com/policies/privacy/.
-
-7. Aplicativos de terceiros
-
-7.1 Ao usar o Preview para executar aplicativos desenvolvidos por terceiros ou que acessam dados, conteúdo ou recursos fornecidos por terceiros, você concorda que a Google não é responsável por tais aplicativos, dados, conteúdo ou recursos. Você compreende que quaisquer dados, conteúdo ou recursos passíveis de aceitação por meio de tais aplicativos de terceiros imputam responsabilidade exclusiva ao indivíduo que os originou. A Google não é responsável por qualquer perda ou dano que possa ocorrer como resultado do uso ou acesso de quaisquer aplicativos, dados, conteúdo ou recursos de terceiros.
-
-7.2 Você deve estar ciente de que os dados, conteúdo e recursos apresentados a você por aplicativos de terceiros podem ser protegidos pelos direitos de propriedade intelectual de posse dos fornecedores (ou de outras pessoas ou empresas em seus nomes). Não é permitido modificar, alugar, arrendar, emprestar, vender, distribuir nem criar trabalhos derivados com base nestes dados, conteúdo ou recursos (na totalidade ou em parte), salvo se houver permissão explícita especificada pelos respectivos detentores de direitos.
-
-7.3 Você reconhece que o uso de tais aplicativos, dados, conteúdo ou recursos de terceiros pode estar sujeito a termos adicionais entre você e o terceiro em questão.
-
-8. Uso de APIs da Google
-
-8.1 APIs da Google
-
-8.1.1 Ao usar qualquer API para recuperar dados da Google, você reconhece que eles podem ser protegidos por direitos de propriedade intelectual de posse da Google ou dos terceiros que fornecem os dados (ou de pessoas ou empresas em nomes deles). O uso de tal API pode estar sujeito a termos de serviço adicionais. Não é permitido modificar, alugar, arrendar, emprestar, vender, distribuir nem criar trabalhos derivados baseados nesses dados (na totalidade ou em parte), salvo se permitido pelos termos de serviço pertinentes.
-
-8.1.2 Se você usar qualquer API para recuperar dados de um usuário a partir da Google, reconhece e concorda que deve recuperar dados somente com consentimento explícito do usuário e somente quando, e para os fins limitados aos quais, o usuário conceder permissão para fazê-lo.
-
-9. Rescisão do Contrato de licença
-
-9.1 O Contrato de licença continuará a se aplicar até que ocorra uma rescisão sua ou da Google, como definido abaixo.
-
-9.2 Caso queira rescindir o Contrato de licença, você pode fazer isto cessando o uso do Preview e de qualquer credencial de desenvolvedor relevante.
-
-9.3 A Google pode, a qualquer momento, rescindir o Contrato de licença, com ou sem causa, com uma notificação.
-
-9.4 O Contrato de licença será encerrado automaticamente sem aviso ou outras ações na ocorrência de:
-(A) a Google interromper o fornecimento do Preview ou de determinadas partes do Preview aos usuários no país em que você reside ou de onde o serviço é usado; e
-(B) a Google emitir uma versão de lançamento final do Android SDK.
-
-9.5 Quando o Contrato de licença é rescindido, a licença concedida a você no Contrato de licença é finalizada, todo o uso do Preview será interrompido e as provisões dos parágrafos 10, 11, 12 e 14 deverão permanecer indefinidamente.
-
-10. EXCLUSÕES
-
-10.1 VOCÊ COMPREENDE E CONCORDA EXPRESSAMENTE QUE O RISCO DO USO DO PREVIEW É EXCLUSIVAMENTE SEU E QUE O PREVIEW É FORNECIDO NA FORMA EM QUE SE ENCONTRA E COMO DISPONIBILIZADO, SEM GARANTIA DE QUALQUER TIPO DA GOOGLE.
-
-10.2 O USO DO PREVIEW E DE QUALQUER MATERIAL BAIXADO OU OBTIDO DE OUTRO MODO PELO USO DO PREVIEW ESTÁ A SEU CRITÉRIO E RISCO E VOCÊ É O ÚNICO RESPONSÁVEL POR QUALQUER DANO AO SEU SISTEMA OPERACIONAL OU OUTRO DISPOSITIVO OU PELA PERDA DE DADOS QUE RESULTEM DE TAL USO. SEM LIMITAR OS PRECEDENTES, VOCÊ ENTENDE QUE O PREVIEW NÃO É UMA VERSÃO ESTÁVEL E QUE PODE CONTER ERROS, DEFEITOS E VULNERABILIDADES DE SEGURANÇA QUE PODEM RESULTAR EM DANOS SIGNIFICANTES, INCLUINDO A PERDA IRRECUPERÁVEL OU COMPLETA DO USO DO SISTEMA DO COMPUTADOR OU DE OUTROS DISPOSITIVOS.
-
-10.3 A GOOGLE EXCLUI EXPRESSAMENTE TODAS AS GARANTIAS E CONDIÇOES DE QUALQUER TIPO, EXPRESSAS OU IMPLÍCITAS, INCLUINDO, MAS NÃO LIMITADO A, GARANTIAS E CONDIÇÕES DE COMERCIALIZAÇÃO IMPLÍCITAS, ADEQUAÇÃO A UMA FINALIDADE PARTICULAR E A NÃO VIOLAÇÃO.
-
-11. LIMITAÇÃO DE RESPONSABILIDADE
-
-11.1 VOCÊ COMPREENDE E CONCORDA EXPRESSAMENTE QUE A GOOGLE, SUAS SUBSIDIÁRIAS, AFILIADAS E SEUS LICENCIADORES NÃO SERÃO RESPONSABILIZADOS POR VOCÊ SOB QUALQUER TEORIA DE RESPONSABILIDADE POR QUAISQUER DANOS, SEJAM ELES DIRETOS, INDIRETOS, INCIDENTAIS, ESPECIAIS, CONSEQUENCIAIS OU DE EXEMPLO QUE POSSAM INCORRER, INCLUINDO QUALQUER PERDA DE DADOS, INDEPENDENTE DE AVISO À GOOGLE OU A SEUS REPRESENTANTES OU DA NECESSIDADE DE AVISO SOBRE A POSSIBILIDADE DA INCORRÊNCIA DE TAIS PERDAS.
-
-12. Indenização
-
-12.1 Ao limite máximo permitido por lei, você concorda em defender, indenizar e isentar a Google, suas afiliadas e respectivos conselheiros, diretores, empregados e agentes com relação a todas e quaisquer reivindicações, ações, processos ou procedimentos, bem como todas e quaisquer perdas, responsabilidades, danos, custos e despesas (incluindo honorários advocatícios) decorrentes ou provenientes de: (a) seu uso do Preview, (b) qualquer aplicativo desenvolvido no Preview que infrinja direitos de propriedade intelectual de qualquer pessoa, difame qualquer pessoa ou viole seus direitos de publicidade ou privacidade e (c) qualquer não cumprimento deste Contrato de licença.
-
-13. Mudanças no Contrato de licença
-
-13.1 A Google pode realizar mudanças no Contrato de licença à medida que distribui novas versões do Preview. Quando essas mudanças forem realizadas, a Google fará uma nova versão do Contrato de licença disponível no site em que o Preview estiver disponível.
-
-14. Termos legais gerais
-
-14.1 Esse Contrato de licença constitui o contrato legal integral entre você e a Google e rege o uso do Preview (excluindo quaisquer serviços que a Google possa fornecer a você sob um contrato escrito em separado), e substitui inteiramente quaisquer contratos anteriores entre você e a Google em relação ao Preview.
-
-14.2 Você concorda que, se a Google não exercer nem impetrar qualquer direito ou recurso legal que esteja contido no Contrato de licença (ou que a Google detenha direitos nos termos de qualquer lei aplicável), não se considerará esse fato como uma renúncia formal aos direitos da Google e esses direitos ou recursos continuarão disponíveis à Google.
-
-14.3 Se qualquer tribunal de justiça que tiver a competência para decidir sobre esse tema determinar que qualquer cláusula do Contrato de licença é inválida, tal cláusula será removida do contrato sem afetar as cláusulas restantes ou sua vigência. As cláusulas restantes do Contrato de licença continuarão válidas e obrigatórias.
-
-14.4 Você reconhece e concorda que cada membro do grupo de empresas das quais a Google é a empresa controladora deve ser beneficiário terceiro do Contrato de licença e que essas outras empresas terão o poder de aplicar diretamente, e apoiar-se em, qualquer cláusula do Contrato de licença que confira um direito (ou direitos em favor) deles. Além disso, nenhuma outra pessoa nem empresa deve ser beneficiário terceiro do Contrato de licença.
-
-14.5 RESTRIÇÕES DE EXPORTAÇÃO. O PREVIEW ESTÁ SUJEITO ÀS LEIS E NORMAS DE EXPORTAÇÃO DOS ESTADOS UNIDOS. VOCÊ DEVE CUMPRIR TODAS AS LEIS E NORMAS DOMÉSTICAS E INTERNACIONAIS QUE SE APLICAREM AO PREVIEW. ESSAS LEIS INCLUEM RESTRIÇÕES SOBRE DESTINOS, USUÁRIOS FINAIS E USO FINAL.
-
-14.6 O Contrato de licença não pode ser atribuído nem transferido por você sem a aprovação prévia por escrito da Google. Qualquer tentativa de atribuição sem a aprovação será inválida. Você não deve delegar as próprias responsabilidades ou obrigações nos termos do Contrato de licença sem aprovação prévia por escrito da Google.
-
-14.7 O Contrato de licença e sua relação com a Google nos termos do contrato serão regidos pelas leis do estado da Califórnia sem considerar conflitos de disposições legais. Você e a Google concordam em se submeter à competência exclusiva dos tribunais localizados na comarca de Santa Clara, Califórnia, para dirimir quaisquer questões legais decorrentes do Contrato de licença. Não obstante a isso, você concorda que a Google continua habilitada a impetrar medidas cautelares (ou mecanismo legal urgente equivalente) em qualquer jurisdição.
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">Li e concordo com todos os termos e condições expressos acima</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>Neste documento</h2>
-      <ol>
-        <li><a href="#sdk">Preview SDK</a></li>
-        <li><a href="#docs">Documentação do desenvolvedor</a></li>
-        <li><a href="#images">Imagens do sistema de hardware</a></li>
-      </ol>
-
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  O Android M Preview SDK inclui ferramentas de desenvolvimento, arquivos de sistema do Android e arquivos da biblioteca
- para ajudar você a testar o aplicativo e novas APIs da próxima versão da plataforma. Este documento
- descreve como adquirir os componentes disponíveis para download da prévia para o teste do aplicativo.
-</p>
-
-
-<h2 id="sdk">Preview SDK</h2>
-
-<p>
-  O Preview SDK está disponível para download no <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>. Para obter mais informações
- sobre o download e a configuração do Preview SDK, consulte <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Configuração do Preview SDK</a>.
-</p>
-
-
-<h2 id="docs">Documentação do desenvolvedor</h2>
-
-<p>
-  O pacote de download da documentação do desenvolvedor fornece informações de referência de API detalhadas e um relatório de diferença de API para a prévia.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">Imagens do sistema de hardware</h2>
-
-<p>
-  Essas imagens do sistema permitem que você instale uma versão de prévia da plataforma em um dispositivo físico
-para fins de teste. Ao configurar um dispositivo com uma dessas imagens, é possível instalar e testar o aplicativo
- para verificar o seu desempenho na próxima versão da plataforma. O processo de instalação de uma imagem do sistema
- em um dispositivo <em>remove todos os dados do dispositivo</em>. Portanto, deve-se realizar um backup dos dados
- antes de instalar uma imagem do sistema.
-</p>
-
-<p class="warning">
-  <b>Aviso:</b> as seguintes imagens do sistema Android são prévias e estão sujeitas a alterações. O uso
- dessas imagens do sistema são governadas pelo Contrato de licença do Android SDK Preview. As imagens do sistema do Android Preview
- não são versões estáveis e podem conter erros e defeitos que podem resultar
- em danos aos sistemas do computador, aos dispositivos e aos dados. As imagens do sistema Android Preview
- não estão sujeitas ao mesmo teste do sistema operacional de fábrica e podem fazer com que o telefone e aplicativos e os serviços
- instalados parem de funcionar.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">Instalar uma imagem no dispositivo</h3>
-
-<p>
-  Para usar uma imagem de dispositivo para testes, deve-se instalá-lo em um dispositivo compatível. Siga
- as instruções abaixo para instalar uma imagem de sistema.
-</p>
-
-<ol>
-  <li>Faça o download e descompacte um dos pacotes de imagem do sistema listados aqui.</li>
-  <li>Faça um backup dos dados do dispositivo que deseja preservar.</li>
-  <li>Siga as instruções em
- <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
-  para programar em flash a imagem no dispositivo.</li>
-</ol>
-
-<p class="note">
-  <strong>Observação:</strong> ao programar em flash a imagem do sistema de prévia no dispositivo de desenvolvimento,
- ele é atualizado automaticamente com o próximo lançamento da prévia por meio de atualizações over-the-air (OTA).
-</p>
-
-<h3 id="revertDevice">Reverter um dispositivo para as especificações de fábrica</h3>
-
-<p>
-  Caso queira desinstalar a prévia e reverter o dispositivo para as especificações de fábrica, acesse
- <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> e
- faça o download da imagem que deseja programar em flash no dispositivo. Siga as instruções nesta página
- para programar em flash a imagem no dispositivo.
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/pt-br/preview/features/background-optimization.jd b/docs/html-intl/intl/pt-br/preview/features/background-optimization.jd
deleted file mode 100644
index cf4bbe9..0000000
--- a/docs/html-intl/intl/pt-br/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=Otimizações em segundo plano
-page.metaDescription=Novas restrições a transmissões implícitas.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      Neste documento
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">Restrições sobre CONNECTIVITY_ACTION</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">Agendamento de trabalhos de rede em conexões
- ilimitadas</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Monitoramento de conectividade de rede durante a execução
- do aplicativo</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">Restrições sobre NEW_PICTURE e
- NEW_VIDEO</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">Novos métodos JobInfo</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">Novos métodos JobParameter</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">Otimização adicional do aplicativo</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  Os processos em segundo plano podem fazer uso intensivo de memória e bateria. Por exemplo, uma
- transmissão implícita poderá iniciar diversos processos em segundo plano registrados
- para escutá-la, mesmo se esses processos não forem muito usados. Isso pode afetar
- substancialmente o desempenho do dispositivo e a experiência do usuário.
-</p>
-
-<p>
-  Para aliviar esse problema, o Android N aplica as seguintes
-restrições:
-</p>
-
-<ul>
-  <li>Os aplicativos direcionados ao Preview não receberão transmissões {@link
- android.net.ConnectivityManager#CONNECTIVITY_ACTION} se estiverem
- registrados para recebê-las no seu manifesto. Os aplicativos em execução ainda
-poderão escutar {@code CONNECTIVITY_CHANGE} no encadeamento principal registrando um
-{@link android.content.BroadcastReceiver} em {@link
- android.content.Context#registerReceiver Context.registerReceiver()}.
-  </li>
-
-  <li>Os aplicativos não podem enviar nem receber transmissões {@link
- android.hardware.Camera#ACTION_NEW_PICTURE} ou {@link
- android.hardware.Camera#ACTION_NEW_VIDEO}. Essa otimização
- afeta todos os aplicativos e não apenas os direcionados ao Preview.
-  </li>
-</ul>
-
-<p>
-  Se o seu aplicativo usar qualquer uma dessas intenções, remova as dependências delas
- assim que possível para direcionar corretamente os dispositivos Android N.
-  A estrutura do Android oferece diversas soluções para reduzir a necessidade dessas
- transmissões implícitas. Por exemplo, {@link android.app.job.JobScheduler}
- e <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> oferecem mecanismos robustos para agendar operações
- de rede quando ocorrem condições especificadas, como conexão a uma
- rede ilimitada. Agora, você também pode usar {@link android.app.job.JobScheduler}
- para reagir a mudanças em provedores de conteúdo. Os objetos {@link android.app.job.JobInfo}
- encapsulam os parâmetros usados por {@link android.app.job.JobScheduler}
- para agendar o seu trabalho. Quando as condições do trabalho forem atendidas, o sistema
- executará o trabalho no {@link android.app.job.JobService} do seu aplicativo.
-</p>
-
-<p>
-  Neste documento, veremos como usar métodos alternativos, como
- {@link android.app.job.JobScheduler}, para adaptar seu aplicativo a essas novas
- restrições.
-</p>
-
-<h2 id="connectivity-action">
-  Restrições sobre CONNECTIVITY_ACTION
-</h2>
-
-<p>
-  Os aplicativos direcionados ao Android N não receberão transmissões {@link
- android.net.ConnectivityManager#CONNECTIVITY_ACTION} se estiverem
- registrados para recebê-las no seu manifesto e os processos que dependerem dessas
- transmissões não serão iniciados. Isso pode ser um problema para aplicativos que quiserem
- escutar mudanças de rede ou executar atividades de rede em massa quando o
- dispositivo se conectar a uma rede ilimitada. Já existem várias soluções para contornar essa
- restrição na estrutura do Android, mas a escolha da solução correta
- depende do que o aplicativo pretende realizar.
-</p>
-
-<p class="note">
-  <strong>Observação:</strong> Um {@link android.content.BroadcastReceiver} registrado em
- {@link android.content.Context#registerReceiver Context.registerReceiver()}
- continuará a receber essas transmissões enquanto o aplicativo estiver em execução.
-</p>
-
-<h3 id="sched-jobs">
-  Agendamento de trabalhos de rede em conexões ilimitadas
-</h3>
-
-<p>
-  Ao usar a classe {@link android.app.job.JobInfo.Builder JobInfo.Builder}
- para compilar o objeto {@link android.app.job.JobInfo}, aplique o método {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} e passe {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} como parâmetro do trabalho. O código a seguir
- agendará a execução de um serviço quando o dispositivo se conectar a uma rede
- ilimitada e estiver carregando:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  Quando as condições para o trabalho forem atendidas, o aplicativo receberá um retorno de chamada para executar
- o método {@link android.app.job.JobService#onStartJob onStartJob()} na
- {@code JobService.class} especificada. Para ver mais exemplos da implementação de {@link
-  android.app.job.JobScheduler}, consulte o <a href="{@docRoot}samples/JobScheduler/index.html">aplicativo de exemplo do JobScheduler</a>.
-</p>
-
-<p>
-  Os aplicativos que usarem serviços do GMSCore e forem direcionados ao Android 5.0 (nível da API 21)
- ou anterior poderão usar <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> e especificar {@code Task.NETWORK_STATE_UNMETERED}.
-</p>
-
-<h3 id="monitor-conn">
-  Monitoramento de conectividade de rede durante a execução do aplicativo
-</h3>
-
-<p>
-  Os aplicativos em execução ainda poderão escutar {@code CONNECTIVITY_CHANGE} com um
- {@link android.content.BroadcastReceiver} registrado. No entanto, a API {@link
- android.net.ConnectivityManager} oferece um método mais robusto para solicitar
- um retorno de chamada apenas quando condições de rede especificadas são atendidas.
-</p>
-
-<p>
-  Os objetos {@link android.net.NetworkRequest} definem os parâmetros do
- retorno de chamada de rede em termos de {@link android.net.NetworkCapabilities}. Objetos
- {@link android.net.NetworkRequest} são criados com a classe {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder}. Em seguida, {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
- passa o objeto {@link android.net.NetworkRequest} ao sistema. Quando
- as condições de rede forem atendidas, o aplicativo receberá um retorno de chamada para executar o
- método {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} definido em sua classe {@link
-  android.net.ConnectivityManager.NetworkCallback}.
-</p>
-
-<p>
-  O aplicativo continuará a receber retornos de chamada até que o aplicativo encerre ou chame
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}.
-</p>
-
-<h2 id="media-broadcasts">
-  Restrições sobre NEW_PICTURE e NEW_VIDEO
-</h2>
-
-<p>
-  No Android N, os aplicativos não conseguem enviar nem receber transmissões {@link
- android.hardware.Camera#ACTION_NEW_PICTURE} ou {@link
- android.hardware.Camera#ACTION_NEW_VIDEO}. Essa restrição ajuda a
- aliviar os impactos no desempenho e na experiência de usuário quando vários aplicativos devem
- despertar para processar uma nova imagem ou vídeo. O Android N
- estende {@link android.app.job.JobInfo} e {@link
- android.app.job.JobParameters} para oferecer uma solução alternativa.
-</p>
-
-<h3 id="new-jobinfo">
-  Novos métodos JobInfo
-</h3>
-
-<p>
-  Para acionar trabalhos em mudanças de URI de conteúdo, o Android N estende
- a API {@link android.app.job.JobInfo} com os seguintes métodos:
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    Encapsula os parâmetros necessários para acionar um trabalho quando ocorrem mudanças de URI de conteúdo.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    Passa um objeto {@code TriggerContentUri} para {@link
-    android.app.job.JobInfo}. Um {@link android.database.ContentObserver}
- monitora o URI de conteúdo encapsulado. Se houver vários objetos {@code
-    TriggerContentUri} associados a um trabalho, o sistema fornecerá um
- retorno de chamada, mesmo se indicar uma mudança em apenas um dos URIs de conteúdo.
-  </dd>
-
-  <dd>
-    Adicione o sinalizador {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} para
- acionar o trabalho em caso de mudança em qualquer um dos descendentes do URI especificado. Esse indicador
- corresponde ao parâmetro {@code notifyForDescendants} passado para {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>Observação:</strong> não é possível usar {@code TriggerContentUri()}
- juntamente com {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} ou {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}. Para monitorar continuamente mudanças de conteúdo, agende um novo
- {@link android.app.job.JobInfo} antes que o {@link
-  android.app.job.JobService} do aplicativo encerre o processamento do retorno de chamada mais recente.
-</p>
-
-<p>
-  O exemplo de código a seguir agenda um trabalho que será acionado quando o sistema indicar
- uma mudança no URI de conteúdo {@code MEDIA_URI}:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  Quando o sistema indicar uma mudança nos URIs de conteúdo especificados, o aplicativo
- receberá um retorno de chamada e um objeto {@link android.app.job.JobParameters} será
- passado para o método {@link android.app.job.JobService#onStartJob onStartJob()}
- na {@code MediaContentJob.class}.
-</p>
-
-<h3 id="new-jobparam">
-  Novos métodos JobParameter
-</h3>
-
-<p>
-  O Android N também estende {@link android.app.job.JobParameters} para
- permitir que o aplicativo receba informações úteis sobre quais autoridades de conteúdo
- e URIs acionaram o trabalho:
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    Retorna uma matriz de URIs que acionaram o trabalho. O retorno será {@code
-    null} se o trabalho não foi acionado por URIs (por exemplo, o trabalho foi
- acionado devido a um prazo ou por outro motivo) ou o número de URIs modificados
- for maior que 50.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    Retorna uma matriz de strings de autoridades de conteúdo que acionaram o trabalho.
-    Se a matriz retornada não for {@code null}, use {@code getTriggeredContentUris()}
- para recuperar os detalhes sobre quais URIs foram modificados.
-  </dd>
-</dl>
-
-<p>
-  O exemplo de código a seguir substitui o método {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} e
- registra as autoridades de conteúdo e URIs que acionaram o trabalho:
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  Otimização adicional do aplicativo
-</h2>
-
-<p>
-  A otimização dos aplicativos para execução em dispositivos com pouca memória ou em
- condições de pouca memória pode melhorar o desempenho e a experiência do usuário. A remoção de
- dependências de serviços em segundo plano e receptores de transmissão
- implícita registrados estatisticamente pode aprimorar a execução do aplicativo nesses dispositivos. Embora
- o Android N avance na redução de alguns desses problemas,
- recomendamos que você otimize os aplicativos para execução sem o uso desses
- processos em segundo plano.
-</p>
-
-<p>
-  O Android N introduz alguns comandos adicionais do <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> que
- podem ser usados para testar o comportamento do aplicativo de teste com esses processos em segundo plano desativados:
-</p>
-
-<ul>
-  <li>Para simular condições em que transmissões implícitas e serviços em segundo plano
- não estão disponíveis, insira o seguinte comando:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>Para reativar transmissões implícitas e serviços em segundo plano, insira o
- seguinte comando:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/pt-br/preview/features/icu4j-framework.jd b/docs/html-intl/intl/pt-br/preview/features/icu4j-framework.jd
deleted file mode 100644
index df5c3a4..0000000
--- a/docs/html-intl/intl/pt-br/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=ICU4J Android Framework APIs
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Neste documento:</h2>
-<ol>
-    <li><a href="#relation">Relação com o ICU4J</a></li>
-    <li><a href="#migration">Migrar para APIs android.icu do ICU4J </a></li>
-    <li><a href="#licence">Licenciamento</a></li>
-</ol>
-
-<h2>Veja também</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">Documentação para ICU4J</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">Últimos padrões com suporte
- do ICU4J</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  O ICU4J é um conjunto de bibliotecas Java de código aberto e amplamente usadas que fornecem suporte para Unicode
- e globalização para aplicativos de software. O Android N
- expõe um subconjunto de APIs do ICU4J na estrutura do Android para uso dos desenvolvedores de aplicativos
- no pacote {@code android.icu}. Essas APIs usam
- dados de localização presentes no dispositivo. Consequentemente, você pode reduzir o uso de APK
- ao não compilar as bibliotecas do ICU4J no seu APK. Em vez disso, pode
- simplesmente chamá-las na estrutura. (Neste caso, pode ser conveniente fornecer
- <a href="{@docRoot}google/play/publishing/multiple-apks.html">várias versões
- do seu APK</a> para que os usuários que tenham versões inferiores ao Android N
- possam fazer o download de uma versão do aplicativo que contenha as bibliotecas do ICU4J.)
-</p>
-
-<p>
-  Este documento começa fornecendo informações básicas sobre os níveis mínimos da
- Android API necessários para oferecer suporte a essas bibliotecas. Em seguida, ele explica o que
- você deve saber sobre a implementação do ICU4J específica do Android. Por fim,
- ele informa como usar as APIs do ICU4J na estrutura do Android.
-</p>
-
-<h2 id="relation">Relação com o ICU4J</h2>
-
-<p>
-  O Android N expõe um subconjunto de APIs do ICU4J por meio do pacote
- <code>android.icu</code>, não do <code>com.ibm.icu</code>. A
- estrutura do Android pode optar por não
- expor as APIs do ICU4J por diversos motivos. Por exemplo, o Android N não expõe
- algumas APIs obsoletas ou que a equipe do ICU ainda não declarou como
- estáveis. Conforme a equipe do ICU torna APIs obsoletas, o Android também as marcará
- como obsoletas, mas continuará incluindo-as.
-</p>
-
-<p class="table-caption"><strong>Tabela 1.</strong> Versões ICU e CLDR usadas
- no Android N.</p>
-<table>
-<tr>
-<th>Nível da Android API</th>
-<th>Versão ICU</th>
-<th>Versão CLDR</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>Algumas observações importantes:</p>
-
-<ul>
-<li>As APIs de estrutura do Android para ICU4J não incluem todas as APIs do ICU4J.</li>
-<li>Desenvolvedores de NDK devem saber que o Android ICU4C não é compatível.</li>
-<li>As APIs da estrutura do Android não substituem o suporte do Android para a
-<a href="{@docRoot}guide/topics/resources/localization.html">localização com
-recursos</a>.</li>
-</ul>
-
-<h2 id="migration">Migrar do pacote com.ibm.icu para o android.icu</h2>
-
-<p>
-  Se você já estiver usando as APIs do ICU4J no seu aplicativo e as APIs
- <code>android.icu</code> atenderem aos seus requisitos, a migração para
- as APIs de estrutura exigirão que você altere as importações Java
- de <code>com.ibm.icu</code> para <code>android.icu</code>. Você, então, poderá
- remover sua própria cópia dos arquivos do ICU4J do APK.
-</p>
-
-<p class="note">
-  <b>Observação</b>: As APIs de estrutura do ICU4J usam o namespace {@code android.icu}
- em vez de {@code com.ibm.icu}. Isso ocorre para evitar conflitos
- de namespace em APKs que contêm as próprias bibliotecas {@code com.ibm.icu}.
-</p>
-
-<h3 id="migrate-from-android">
-  Migrar para APIs android.icu de outras APIs do Android SDK
-</h3>
-
-<p>
-  Algumas classes dos pacotes <code>java</code> e <code>android</code> têm
- equivalentes para as encontradas no ICU4J. No entanto, o ICU4J frequentemente fornece um suporte
- mais amplo para padrões e linguagens.
-</p>
-<p>Alguns exemplos para você começar:</p>
-<table>
-<tr>
-<th>Classe</th>
-<th>Alternativas</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">Licenciamento</h2>
-
-<p>
-  O ICU4J é liberado sob a licença do ICU. Para saber mais, consulte o <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">Guia do usuário do
- ICU.</a>
-</p>
diff --git a/docs/html-intl/intl/pt-br/preview/features/multilingual-support.jd b/docs/html-intl/intl/pt-br/preview/features/multilingual-support.jd
deleted file mode 100644
index c00eb9b..0000000
--- a/docs/html-intl/intl/pt-br/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=Idioma e localidades
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Neste documento:</h2>
-<ol>
-	  <li><a href="#preN">Desafios ao resolver recursos de idioma</a></li>
-    <li><a href="#postN">Melhorias na estratégia de resolução de recursos</a></li>
-    <li><a href="#design">Projetar seu aplicativo para oferecer suporte a
- localidades adicionais</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>O Android N oferece suporte avançado para usuários multilíngues,
-permitindo que eles selecionem várias localidades nas configurações. O Android N
-fornece esse recurso ao expandir significativamente a quantidade de localidades com suporte
-e mudando a forma como o sistema resolve recursos. O novo método para resolver
-recursos é mais robusto e foi projetado para ser compatível com APKs existentes, mas
-tenha cuidado adicional para identificar comportamentos inesperados. Por exemplo, você
-deve testar para garantir que seu aplicativo assuma o idioma esperado por padrão. Além disso,
-se seu aplicativo oferecer suporte a vários idiomas, você deverá garantir que esse suporte funcione da maneira
-esperada. Por fim, garanta que seu aplicativo possa lidar corretamente
-com idiomas que ele não tenha sido explicitamente projetado para suportar.</p>
-
-<p>Este documento começa explicando a estratégia de resolução de recursos anterior ao
-Android N. Em seguida, ele descreve a estratégia
-de resolução de recursos aprimorada do Android N. Por fim, ele explica como aproveitar as vantagens
-do maior número de localidades para oferecer suporte a usuários multilíngues.</p>
-
-<h2 id="preN">Desafios ao resolver recursos de idioma</h2>
-
-<p>Antes do Android N, o Android nem sempre conseguia
- fazer a correspondência correta entre aplicativos e localidades do sistema.</p>
-
- <p>Considere, por exemplo, que temos a seguinte situação:</p>
- <ul>
- <li>o idioma padrão do seu aplicativo é {@code en_US} (inglês - EUA), mas ele também tem
- strings em espanhol localizadas em arquivos de recursos {@code es_ES}
-.</li>
- <li> Um dispositivo está definido para {@code es_MX}. </li>
-
-<p>Quando seu código Java usa strings como referência, o sistema carrega
-strings do arquivo de recursos padrão ({@code en_US}), mesmo que o aplicativo tenha recursos em
-espanhol localizados em {@code es_ES}. Isso acontece porque, quando
- não consegue encontrar uma correspondência exata, o sistema continua procurando recursos após extrair o
- código do país da localidade. Por fim, se não há correspondência, o sistema volta
- ao padrão, que é {@code en_US}. </p>
-
-
-<p>O sistema também usaria {@code en_US} como padrão se o usuário escolhesse um idioma
- não suportado pelo aplicativo, como o francês. Por exemplo:</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>Tabela 1.</strong> Resolução de recurso sem uma correspondência exata de localidade.
-</p>
-<table>
-<tbody>
-<tr>
-<th>Configurações do usuário</th>
-<th>Recursos do aplicativo</th>
-<th>Resolução do recurso</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-padrão (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-Tentativa de fr_CH =&gt; Falha<br>
-Tentativa de fr =&gt; Falha<br>
-Usar o padrão (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>Neste exemplo, o sistema exibe strings em inglês sem saber
-se o usuário entende inglês. Esse comportamento é bastante comum
-hoje em dia. O Android N deverá reduzir de forma significativa a frequência de
-resultados como esse.</p>
-
-<h2 id="postN">Melhorias na estratégia de resolução de recursos</h2>
-<p>O Android N proporciona uma resolução de recurso mais robusta e
-encontra soluções alternativas melhores. No entanto, para agilizar a resolução e melhorar
- a capacidade de manutenção, você deve armazenar os recursos no dialeto pai mais comum.
- Por exemplo, se você estava armazenando recursos em espanhol no diretório {@code es-US}
- antes, mova-os para o diretório {@code es-419}, que contém o espanhol latino-americano.
- Da mesma maneira, se você tiver strings de recurso em uma pasta {@code en-GB}, renomeie
- essa pasta para {@code en-001} (inglês internacional), pois o pai mais comum
- para strings <code>en-GB</code> é {@code en-001}.
- O exemplo a seguir explica por que essas práticas melhoram o desempenho e
-a confiabilidade da resolução de recursos.</p>
-
-<h3>Exemplos de resolução de recursos</h3>
-
-<p>Com o Android N, o caso descrito na <strong>Tabela 1</strong> é resolvido
-de forma diferente:</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>Tabela 2.</strong> Uma estratégia de resolução melhorada para quando não há
-uma correspondência exata para a localidade.</p>
-<table>
-<tr>
-<th>Configurações do usuário</th>
-<th>Recursos do aplicativo</th>
-<th>Resolução do recurso</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-padrão (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-Tentativa de fr_CH =&gt; Falha<br>
-Tentativa de fr =&gt; Falha<br>
-Tentativa de filhos de fr =&gt; fr_FR<br>
-Usar fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>Agora o usuário obtém recursos em francês em vez de inglês. Esse exemplo também mostra
- por que você deve armazenar strings em francês em {@code fr} em vez de em {@code fr_FR}
- para o Android N. Nesse caso, a ação necessária é fazer a correspondência com o dialeto pai mais próximo,
- tornando a resolução mais rápida e mais previsível.</p>
-
-<p>Além dessa lógica de resolução melhorada, agora o Android oferece mais
- idiomas de usuário dentre os quais escolher. Vamos experimentar o exemplo acima novamente com o italiano
- especificado como um idioma de usuário adicional, mas sem suporte para francês no aplicativo.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>Tabela 3.</strong> Resolução de recurso quando o aplicativo faz a correspondência apenas da
-segunda configuração de localidade preferencial do usuário.</p>
-<table>
-<tr>
-<th>Configurações do usuário</th>
-<th>Recursos do aplicativo</th>
-<th>Resolução do recurso</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-padrão (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-Tentativa de fr_CH =&gt; Falha<br>
-Tentativa de fr =&gt; Falha<br>
-Tentativa de filhos de fr =&gt; Falha<br>
-Tentativa de it_CH =&gt; Falha<br>
-Tentativa de it =&gt; Falha<br>
-Tentativa de filhos de it =&gt; it_IT<br>
-Usar it_IT
-</td>
-
-</tr>
-
-</table>
-<p>O usuário obtém um idioma que ele compreende, mesmo que o aplicativo não tenha suporte para
-o francês.</p>
-
-
-<h2 id="design">Projetar seu aplicativo para oferecer suporte a localidades adicionais</h2>
-<h3>LocaleList API</h3>
-
-<p>O Android N adiciona uma nova API {@code LocaleList.getDefault()}
-que permite que os aplicativos façam uma consulta direta na lista de idiomas especificados por um usuário. Essa API
-permite que você crie um comportamento mais sofisticado
- para o aplicativo e uma exibição de conteúdo mais otimizada. Por exemplo, uma pesquisa
- pode mostrar resultados em vários idiomas com base nas configurações do usuário.  Aplicativos de navegador
- podem evitar ofertas de tradução de páginas em um idioma que o usuário conhece
- e os aplicativos de teclado também podem ativar todos os layouts apropriados automaticamente. </p>
-
-<h3>Formatadores</h3>
-
-<p>Até o Android 6.0 (nível da API 23), o Android oferecia suporte para apenas uma ou duas localidades
- para muitos idiomas comuns
-(en, es, ar, fr, ru). Como só existiam poucas variantes de cada idioma,
-os aplicativos podiam armazenar alguns números e datas como strings no código
-nos arquivos de recurso.  No entanto, com o conjunto mais amplo de localidades suportadas do Android,
-podem existir
-diferenças significativas nos formatos de data, hora, moeda e informações
-similares dentro da mesma localidade. Colocar formatos no código pode produzir uma
-experiência confusa para os usuários.  Portanto, ao desenvolver para o Android N,
-não deixe de usar formatadores em vez de strings no código para números e datas.</p>
-
-<p>Um bom exemplo é o árabe, cujo suporte no Android N foi expandido de
-uma {@code ar_EG} para 27 localidades de árabe. Essas localidades podem compartilhar a maioria dos recursos,
-mas algumas preferem dígitos ASCII, enquanto outras preferem dígitos nativos. Por exemplo,
-quando você quer criar uma frase com uma variável em dígito, como
-“Choose a 4 digit pin”, use formatadores como mostrado abaixo:</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/pt-br/preview/features/notification-updates.jd b/docs/html-intl/intl/pt-br/preview/features/notification-updates.jd
deleted file mode 100644
index 36988da..0000000
--- a/docs/html-intl/intl/pt-br/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=Notificações
-page.tags=notificações
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>Este documento inclui</h2>
-<ol>
-  <li><a href="#direct">Resposta direta</a></li>
-  <li><a href="#bundle">Notificações empacotadas</a></li>
-  <li><a href="#custom">Visualizações personalizadas</a></li>
-  <li><a href="#style">Estilo de mensagem</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>O Android N introduz diversas APIs novas que permitem que aplicativos publiquem
- notificações altamente visíveis e interativas.</p>
-
-<p>O Android N estende a API de notificação {@link android.support.v4.app.RemoteInput}
- atual para permitir respostas em linha em celulares. Esse recurso permite que os usuários
- respondam rapidamente na aba de notificações sem acessar o aplicativo.</p>
-
-<p>
-  O Android N permite empacotar notificações semelhantes para
- exibição como única notificação. Para que isso seja possível, o Android N usa o método {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} existente. Os usuários podem expandir todas as
- notificações, executando ações como responder e descartar em cada uma
- delas individualmente na aba de notificações.
-</p>
-
-<p>Por fim, o Android N também adiciona várias APIs que permitem usar decorações
- do sistema nas visualizações de notificação personalizadas do aplicativo. Essas APIs ajudam
- a garantir que as visualizações de notificação compartilhem uma apresentação consistente com os
- modelos padrão.</p>
-
-<p>Este documento destaca algumas principais mudanças que você deve considerar
- ao usar os novos recursos de notificação em aplicativos.</p>
-
-<h2 id="direct">Resposta direta</h2>
-
-<p>Com o recurso de resposta direta no Android N, os usuários podem responder
- rapidamente a mensagens de texto ou atualizar listas de tarefas diretamente na interface de
- notificação. Em um dispositivo portátil, a ação de resposta em linha aparece como botão adicional
- anexado à notificação. Quando um usuário responde pelo teclado, o sistema anexa
- a resposta de texto à intenção especificada como ação de notificação e envia a intenção ao aplicativo no dispositivo.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>Figura 1.</strong>O Android N adiciona o botão de ação <strong>Reply</strong>
-.
-</p>
-
-<h3>Adição de ações de resposta em linha</h3>
-
-<p>Para criar uma ação de notificação com suporte à resposta direta:
-</p>
-
-<ol>
-<li>Crie uma instância de {@link android.support.v4.app.RemoteInput.Builder}
- que possa ser adicionada à ação de
- notificação. O construtor dessa classe aceita uma string, usada pelo sistema como chave
- da entrada de texto. Posteriormente, o aplicativo no dispositivo usará essa chave para recuperar o texto
- da entrada.
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>Anexe o objeto {@link android.support.v4.app.RemoteInput}
- a uma ação usando <code>addRemoteInput()</code>.
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>Aplique a ação a uma notificação e emita a notificação.
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> O sistema solicita que o usuário informe uma resposta quando acionar a
- ação de notificação. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Figura 2.</strong> O usuário insere texto na aba de notificações.
-</p>
-
-<h3>
-  Recuperação da entrada do usuário na resposta em linha
-</h3>
-
-<p>
-  Para receber a entrada do usuário da interface de notificação para a atividade
- declarada na intenção de ação de resposta:
-</p>
-
-<ol>
-  <li>Chame {@link android.support.v4.app.RemoteInput#getResultsFromIntent
- getResultsFromIntent()} passando a intenção da ação de notificação como
- parâmetro de entrada. Esse método retorna um {@link android.os.Bundle} que
- contém a resposta de texto.
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>Consulte a resposta usando a chave de resultado (fornecida ao construtor {@link
- android.support.v4.app.RemoteInput.Builder}). Você pode concluir
- este processo e recuperar o texto de entrada criando um método, como no
- snippet de código a seguir:
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>Crie e emita outra notificação usando o mesmo código que
- você forneceu para a notificação anterior. O indicador de progresso
- desaparece da interface de notificação para informar os usuários que houve uma resposta
- bem-sucedida. Ao trabalhar com esta nova notificação, use o contexto que é passado
- ao método {@code onReceive()} do receptor.
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  Para aplicativos interativos, como bate-papos, pode ser útil incluir contexto
- adicional ao lidar com texto recebido. Por exemplo, estes aplicativos podem exibir
- várias linhas de histórico de bate-papo. Quando o usuário responde por {@link
- android.support.v4.app.RemoteInput}, você pode atualizar o histórico de respostas
- usando o método {@code setRemoteInputHistory()}.
-</p>
-
-<p>
-  A notificação precisará ser atualizada ou cancelada depois que o aplicativo tiver
- recebido a entrada remota. Quando o usuário responde a uma atualização remota
- usando uma Resposta direta,
- não cancele a notificação. Em vez disso, atualize a notificação para exibir a resposta do usuário.
-Para notificações que usam {@code MessagingStyle}, adicione
- a resposta como última mensagem. Ao usar outros modelos, você pode
-anexar a resposta do usuário ao histórico da entrada remota.
-</p>
-
-<h2 id="bundle">Notificações empacotadas</h2>
-
-<p>O Android N oferece aos desenvolvedores uma nova forma de representar
- uma fila de notificações: <i>notificações empacotadas</i>. Essa forma é semelhante ao recurso
-  <a href="{@docRoot}training/wearables/notifications/stacks.html">Pilhas
- de Notificações</a> no Android Wear. Por exemplo, se o aplicativo criar notificações
- para mensagens recebidas, quando mais de uma mensagem for recebida, empacote as
- notificações como um único grupo. Você pode
- usar o método existente {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} para empacotar notificações semelhantes.</p>
-
-<p>
-  Um grupo de notificações impõe uma hierarquia nas notificações que o compõe.
-  Na parte superior dessa hierarquia, está a notificação pai, que exibe informações
- resumidas para o grupo. O usuário pode expandir
- progressivamente o grupo de notificações e o sistema mostra mais informações à medida que o
- usuário aumenta o detalhamento. Quando o usuário expande o pacote, o sistema revela
- mais informações para todas as notificações filhas. Quando o usuário
- expande uma das notificações, o sistema revela todo o seu conteúdo.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Figura 3.</strong> O usuário pode expandir progressivamente o grupo
- de notificações.
-</p>
-
-<p class="note">
-  <strong>Observação:</strong> Se o mesmo aplicativo enviar quatro ou mais notificações
- e não especificar um agrupamento, o
- sistema as agrupará automaticamente.
-</p>
-
-<p>Para saber como adicionar notificações a um grupo, consulte
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">Adicionar
-cada notificação a um grupo</a>.</p>
-
-
-<h3 id="best-practices">Práticas recomendadas para notificações empacotadas</h3>
-<p>Esta seção oferece diretrizes sobre quando usar grupos de notificações em vez
- de notificações {@link android.app.Notification.InboxStyle InboxStyle}
- que foram disponibilizadas em versões anteriores da
- plataforma Android.</p>
-
-<h3>Quando usar notificações empacotadas</h3>
-
-<p>Você deve usar grupos de notificações apenas quando todas as condições a seguir forem
- verdadeiras para o seu caso de uso:</p>
-
-<ul>
-  <li>As notificações filhas são notificações completas e podem ser exibidas
- individualmente sem necessidade de um resumo do grupo.</li>
-  <li>A exibição individual de notificações filhas pode ser vantajosa. Por
- exemplo:
-  </li>
-  <ul>
-    <li>Elas são acionáveis, sem ações específicas para cada filha.</li>
-    <li>Há mais informações na filha que as que o usuário quer ler.</li>
-  </ul>
-</ul>
-
-<p>Os exemplos de bons casos de uso para grupos de notificações incluem: um aplicativo de mensagens
- exibindo uma lista de mensagens recebidas ou um aplicativo de e-mail exibindo uma lista de
- e-mails recebidos.</p>
-
-<p>
-Os exemplos de casos em que uma única notificação é preferível
- incluem mensagens individuais de uma única pessoa ou uma representação em lista
- de itens de texto com uma única linha. Você pode usar
-({@link android.app.Notification.InboxStyle InboxStyle} ou
- {@link android.app.Notification.BigTextStyle BigTextStyle}) para
- isso.
-</p>
-
-<h3 id ="post">Exibição de notificações empacotadas</h3>
-
-<p>
-  O aplicativo deve sempre publicar um resumo do grupo, mesmo se o grupo tiver apenas uma
- única filha. O sistema suprimirá o resumo e exibirá diretamente a
- notificação filha se ela contiver apenas uma única notificação. Isso garante
- que o sistema possa oferecer uma experiência consistente quando o usuário deslizar por
- filhas de um grupo.
-</p>
-
-<p class="note">
-  <strong>Observação:</strong> esta versão do Android N ainda não
- elimina o resumo de grupos de notificações contendo uma única filha. Essa
- funcionalidade será adicionada em uma versão posterior do Android N.
-</p>
-
-<h3>Observação de notificações</h3>
-
-<p>Embora o sistema normalmente exiba notificações filhas como grupo, você pode
- configurá-las para exibição temporária como
- <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">
- notificações heads-up</a>. Esse recurso é particularmente útil porque permite
- acesso imediato à filha mais recente e a suas ações associadas.
-</p>
-
-
-<h3>Compatibilidade com versões anteriores</h3>
-
-<p>
-  Os grupos de notificações e as entradas remotas fazem parte da API {@link
-  android.app.Notification} desde o Android 5.0 (nível da API 21) para oferecer suporte a
- dispositivos Android Wear. Se você já criou notificações com essas APIs,
- a única ação necessária é verificar se o comportamento do aplicativo corresponde
- às diretrizes descritas acima e considerar a implementação de {@code
-  setRemoteInputHistory()}.
-</p>
-
-<p>
-  Para compatibilidade com versões anteriores, as mesmas APIs estão disponíveis com
- a classe {@link android.support.v4.app.NotificationCompat} da biblioteca de suporte,
- permitindo criar notificações que funcionem em versões anteriores do
- Android. Em celulares e tablets, os usuários somente visualizam as notificações resumidas.
- Portanto, um aplicativo deve ter uma notificação no estilo de caixa de entrada ou equivalente,
- representativa de todo o conteúdo de informações do grupo. Como os dispositivos Android
- Wear permitem que os usuários vejam todas as notificações filhas, mesmo em níveis
- de plataforma antigos, você deve criar notificações filhas independentemente do nível
- da API.
-</p>
-
-<h2 id="custom"> Visualizações personalizadas</h2>
-<p>Começando com o Android N, é possível personalizar visualizações de notificação e
- continuar obtendo decorações de sistema, como cabeçalhos de notificação, ações e layouts
- expansíveis.</p>
-
-<p>Para ativar esses recursos, o Android N adiciona as seguintes APIs para aplicar estilo à
- visualização personalizada:</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> Aplica estilo a notificações que não sejam notificações
- de mídia.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> Aplica estilo a notificações de mídia.</dd>
-</dl>
-
-<p>Para usar essa nova API, chame o método {@code setStyle()}, passando o
- estilo de visualização personalizada desejado.</p>
-
-<p>O snippet mostra como construir um objeto de notificação personalizada com o método
-{@code DecoratedCustomViewStyle()}.</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">Estilo de mensagens</h2>
-<p>
-  O Android N traz uma nova API para personalização do estilo de uma notificação.
-  Usando a classe <code>MessageStyle</code>, você pode alterar vários
-rótulos exibidos na notificação, incluindo o título da conversa,
- mensagens adicionais e a visualização de conteúdo para a notificação.
-</p>
-
-<p>
-  O seguinte snippet de código demonstra como personalizar o estilo de uma
- notificação usando a classe <code>MessageStyle</code>.
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
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..0365061 100644
--- a/docs/html-intl/intl/ru/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
@@ -1,78 +1,62 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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>
           Вступить в сообщество разработчиков
@@ -82,39 +66,45 @@
   </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">
+<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>
 
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Сообщить о проблеме
-        </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        См. примечания к выпуску
-        </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Вступить в сообщество разработчиков
-        </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
-<section class="dac-section dac-light"><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/ru/index.jd b/docs/html-intl/intl/ru/index.jd
index e917a8d..83a506e 100644
--- a/docs/html-intl/intl/ru/index.jd
+++ b/docs/html-intl/intl/ru/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/ru/preview/download_mp2.jd b/docs/html-intl/intl/ru/preview/download_mp2.jd
deleted file mode 100644
index 13872d1..0000000
--- a/docs/html-intl/intl/ru/preview/download_mp2.jd
+++ /dev/null
@@ -1,359 +0,0 @@
-page.title=Загрузки
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">Прежде чем приступить к загрузке и установке компонентов пакета SDK Android Preview,
-примите следующие положения и условия.</p>
-
-    <h2 class="norule">Положения и условия</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-Это лицензионное соглашение для пакета SDK Android Preview (далее «Лицензионное соглашение»).
-
-1. Введение
-
-1.1. Лицензия на пакет SDK Android Preview (далее по тексту настоящего Лицензионного соглашения – «Preview», который включает системные файлы Android, пакеты API-интерфейсов и файлы библиотеки Preview, если такие доступны) передается в соответствии с положениями настоящего Лицензионного соглашения. Настоящее Лицензионное соглашение является юридически обязывающим договором между компанией Google и любым лицом, использующим Preview.
-
-1.2. В настоящем Лицензионном соглашении термин «Android» означает набор программного обеспечения Android для устройств, предлагаемый к использованию в рамках проекта Android Open Source Project, который доступен на веб-сайте http://source.android.com/ (сведения, размещенные на этом сайте, могут периодически обновляться).
-
-1.3. Под термином «Google» понимается корпорация Google Inc., главный офис которой находится по адресу 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States (США).
-
-2. Принятие лицензионного соглашения
-
-2.1. Использование Preview возможно только после принятия условий настоящего Лицензионного соглашения. Запрещается использовать Preview, если вы не согласны с указанными в настоящем документе условиями и положениями.
-
-2.2. Нажатие кнопки принятия условий и/или использование Preview означает, что вы согласны с положениями настоящего Лицензионного соглашения.
-
-2.3. Вы не вправе использовать Preview и принимать условия данного Лицензионного соглашения, если по законам США или иных стран, включая страну вашего проживания или использования Preview, запрещается передавать Preview в ваш адрес.
-
-2.4. Если вы используете Preview в рамках своей компании или организации, вы соглашаетесь взять на себя обязательства по соблюдению настоящего Лицензионного соглашения от имени своего работодателя или другого юридического лица, и вы тем самым подтверждаете и гарантируете, что обладаете полными юридическими полномочиями связать вашего работодателя или иное подобное юридическое лицо обязательствами по настоящему Лицензионному соглашению. Если вы не обладаете необходимыми полномочиями, вы не вправе принимать указанные в настоящем документе условия и положения или использовать Preview от имени вашего работодателя или другого юридического лица.
-
-3. Лицензия на Preview от Google
-
-3.1. В соответствии с условиями настоящего Лицензионного соглашения Google предоставляет вам ограниченную, бесплатную и неэксклюзивную лицензию без права передачи и подлежащую отмене, на использование Preview, лично или в рамках своей компании или организации, исключительно в целях разработки приложений для платформы Android.
-
-3.2. Вы соглашаетесь с тем, что Google или третьим сторонам принадлежат все юридические и имущественные права, а также правовой интерес в отношении Preview, в том числе любые права на объекты интеллектуальной собственности, которые имеются в Preview. Термин «Права на интеллектуальную собственность» означает все возможные права в рамках патентного права, авторского права, закона о коммерческой тайне, закона о товарных знаках, а также иные возможные имущественные права. Google оставляет за собой все права, не предоставленные вам в явном виде.
-
-3.3. Вам запрещается использовать Preview в любых целях, которые однозначно не определены в настоящем Лицензионном соглашении. За исключением случаев, предусмотренных применимыми сторонними лицензиями, вам запрещается: (a) копировать (кроме случаев резервного копирования), изменять, адаптировать, повторно распространять, декомпилировать, осуществлять инженерный анализ, деассемблировать или создавать производные элементы Preview или иной его части; а также (b) загружать любую часть Preview в мобильные телефоны или иные устройства, помимо персонального компьютера, объединять любые части Preview с другим программным обеспечением, распространять любое программное обеспечение или устройства, содержащие части Preview.
-
-3.4. Вы соглашаетесь с тем, что не будете предпринимать никаких действий, которые прямо или косвенно могут привести к фрагментированию платформы Android, включая помимо прочего распространение набора средств разработки программного обеспечения, полученного из Preview, участие в создании таких средств и содействие их продвижению в любой форме.
-
-3.5. Использование, воспроизведение и распространение компонентов Preview, на которые распространяется лицензия на программное обеспечение с открытым исходным кодом, регулируются исключительно положениями и условиями такой лицензии на программное обеспечение с открытым исходным кодом, а не настоящим Лицензионным соглашением. Вы соглашаетесь обеспечивать хорошую репутацию получателя лицензии в отношении таких лицензии на программное обеспечение с открытым исходным кодом в рамках всех предоставленных ему прав, а также не допускать каких-либо действий, которые могут привести к аннулированию, приостановлению или нарушению таких прав
-
-3.6. Вы соглашаетесь с тем, что форма и содержание Preview , предоставляемого Google, могут быть изменены без предварительного уведомления, а также с тем, что будущие версии Preview могут оказаться несовместимыми с приложениями, разработанными в предыдущих версиях Preview. Вы соглашаетесь с тем, что Google вправе по собственному усмотрению и без предварительного уведомления прекратить (временно или навсегда) предоставление Preview (или любых функций в составе Preview) вам или пользователям.
-
-3.7. Ни одна из частей настоящего Лицензионного соглашения не предусматривает предоставления вам права использовать любые торговые наименования, товарные знаки, знаки обслуживания, логотипы, имена доменов или иные отличительные фирменные знаки, принадлежащие Google.
-
-3.8. Вы соглашаетесь с тем, что обязуетесь не удалять, не скрывать или не изменять любые уведомления об имущественных правах (включая уведомления об авторских правах и товарных знаках), которые могут сопровождать Preview или содержаться в нем.
-
-4. Использование Preview
-
-4.1. Компания Google выражает согласие с тем, что ни по какому положению настоящего Лицензионного соглашения не получает от вас (или ваших лицензиаров) каких-либо юридических и имущественных прав, а также правового интереса в отношении любых программных приложений, разработанных вами с помощью Preview, включая любые права на объекты интеллектуальной собственности, которые имеются в таких приложениях.
-
-4.2. Вы соглашаетесь использовать Preview и создавать приложения исключительно в целях, предусмотренных (a) настоящим Лицензионным соглашением и (b) любым применимым законом, нормативным актом или общепринятыми правилами или рекомендациями в соответствующей юрисдикции (включая любые законы, касающиеся экспорта данных или программного обеспечения из США или иных соответствующих стран, а также импорта в них).
-
-4.3. Вы соглашаетесь с тем, что при использовании Preview для разработки приложений вы обязуетесь обеспечивать конфиденциальность и защищать юридические права пользователей. В случае, если пользователи предоставляют вам свои имена, пароли или иные данные для входа либо свои персональные данные, вы обязуетесь уведомить пользователей о том, что такая информация будет присутствовать в вашем приложении, и вы также обязуетесь предоставить пользователям юридически соответствующие уведомление о конфиденциальности и средства правовой защиты. Если в вашем приложении хранится личная или конфиденциальная информация, предоставленная пользователями, вы обязуетесь обеспечить ее надлежащую защиту. Если пользователь предоставляет вам сведения о своей учетной записи Google, то ваше приложение может использовать такую информацию для доступа к учетной записи Google пользователя только при условии, что пользователь предоставил вам разрешение на это, и только в тех целях, которые обозначил пользователь.
-
-4.4. Вы соглашаетесь с тем, что обязуетесь не использовать Preview для любого рода деятельности, в том числе для разработки или распространения приложений, в целях нарушения работы и повреждения серверов, сетей или иной собственности или служб Google или любой третьей стороны.
-
-4.5. Вы соглашаетесь с тем, что несете единоличную ответственность (и признаете, что компания Google не несет ответственности ни перед вами, ни перед любой третьей стороной) за любые данные, содержимое или ресурсы, которые вы создаете, передаете или демонстрируете посредством Android и/или приложений для Android, а также за любые последствия ваших действий, связанных с этим (в том числе за любые убытки и любой ущерб, которые могут быть причинены Google).
-
-4.6. Вы соглашаетесь с тем, что несете единоличную ответственность (и признаете, что компания Google не несет ответственности ни перед вами, ни перед любой третьей стороной) за любое несоблюдение обязательств по настоящему Лицензионному соглашению, обязательств по любому применимому договору с третьей стороной или предусмотренных Условиями и положениями, за нарушение любых применимых законов или нормативных актов, а также за любые последствия ваших действий, связанных с таким нарушением (в том числе за любые убытки и любой ущерб, которые могут быть причинены Google).
-
-4.7 Preview находится на стадии разработки, поэтому ваши отзывы и результаты тестирования являются важной частью процесса разработки. Используя Preview, вы признаете, что реализация некоторых функций по-прежнему находится на этапе разработки и вам не следует рассчитывать на полную функциональность стабильной версии. Вы соглашаетесь не распространять или предоставлять любые приложения, использующие Preview, поскольку поддержка Preview будет прекращена после выпуска официальной версии пакета SDK Android.
-
-5. Ваши учетные данные разработчика
-
-5.1. Вы соглашаетесь с тем, что несете ответственность за обеспечение конфиденциальности любых учетных данных разработчика, которые компания Google может вам предоставить или которые вы можете самостоятельно выбрать, а также с тем, что вы несете единоличную ответственность за все приложения, разработанные с использованием ваших учетных данных разработчика.
-
-6. Конфиденциальность и личная информация
-
-6.1. В целях постоянного совершенствования и улучшения Preview компания Google вправе собирать определенные статистические данные об использовании программного обеспечения, включая уникальный идентификатор, связанный IP-адрес, номер версии программного обеспечения, а также сведения об используемых в Preview инструментах и/или службах и способах их применения. Перед тем как любые из таких данных будут отправлены в Google, в Preview отобразится соответствующее уведомление с просьбой дать свое согласие. В случае вашего отказа предоставить такие сведения соответствующие данные собираться не будут.
-
-6.2. Собранные данные изучаются в обобщенном виде с целью улучшения Preview и хранятся в соответствии с Политикой конфиденциальности Google, которая опубликована на веб-сайте по адресу http://www.google.com/policies/privacy/.
-
-7. Сторонние приложения
-
-7.1. Если вы используете Preview для запуска приложений, разработанных третьими сторонами или получающих доступ к данным, содержимому или ресурсам, предоставляемым третьей стороной, вы соглашаетесь с тем, что Google не несет ответственности за такие приложения, данные, содержимое или ресурсы. Вы осознаете, что единоличную ответственность за все данные, содержимое или ресурсы, доступ к которым вы можете получить посредством таких приложений третьих сторон, несет лицо, предоставившее их, а также то, что Google не несет ответственности за любые убытки или любой ущерб, которые могут возникнуть в результате использования вами любых таких сторонних приложений, данных, содержимого или ресурсов и в результате обращения к ним.
-
-7.2. Вы должны быть осведомлены о том, что данные, содержимое и ресурсы, предоставляемые вам посредством таких сторонних приложений, могут быть защищены правами на объекты интеллектуальной собственности, принадлежащие предоставляющим их лицам (или иным лицам либо компаниям от их имени). Вам запрещается изменять, сдавать в аренду, передавать, продавать, распространять такие данные, содержимое или ресурсы (полностью или частично), а также создавать на их основе производные элементы, если у вас нет на это разрешения от соответствующих владельцев.
-
-7.3. Вы осознаете, что использование вами таких сторонних приложений, данных или ресурсов может регулироваться отдельными условиями, заключенными между вами и соответствующей третьей стороной.
-
-8. Использование API-интерфейсов Google
-
-8.1. API-интерфейсы для получения данных Google.
-
-8.1.1. В случае использования вами любых API для получения данных из Google вы осознаете, что такие данные могут быть защищены правами на объекты интеллектуальной собственности, принадлежащие Google или предоставляющим их сторонам (или иным лицам либо компаниям от их имени). Использование вами подобных API может регулироваться дополнительными Условиями использования. Вам запрещается изменять, сдавать в аренду, передавать, продавать, распространять такие данные (полностью или частично), а также создавать на их основе производные элементы, если это не разрешено соответствующими Условиями использования.
-
-8.1.2. Если вы используете какие-либо API-интерфейсы для получения данных пользователя из Google, вы осознаете и соглашаетесь с тем, что вы обязуетесь получать такие данные исключительно с прямого согласия пользователя и только в тех целях, которые обозначил пользователь.
-
-9. Прекращение действия Лицензионного соглашения
-
-9.1 Настоящее Лицензионное соглашение остается в силе до тех пор, пока его действие не будет прекращено вами или Google, как указано ниже.
-
-9.2. Если вы желаете прекратить действие настоящего Лицензионного соглашения, вы вправе сделать это, прекратив использование Preview и любых соответствующих учетных данных разработчика.
-
-9.3. Google вправе в любое время прекратить действие настоящего Лицензионного соглашения, отправив предварительное уведомление или без него.
-
-9.4 Действие настоящего Лицензионного соглашения автоматически прекращается без предварительного уведомления или выполнения иных действий сразу после любого из следующих событий:
-(A) компания Google прекращает предоставление Preview или определенных частей Preview пользователям на территории страны, в которой вы проживаете или используете услуги компании;
-(B) компания Google выпускает окончательную версию SDK Android.
-
-9.5 В случае прекращения действия настоящего Лицензионного соглашения прекращается действие лицензии, предоставленной в рамках Лицензионного соглашения, и вам следует незамедлительно прекратить любое использование Preview, тогда как положения, изложенные в разделах 10, 11, 12 и 14 продолжают действовать бессрочно.
-
-10. ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ
-
-10.1. ВЫ ЧЕТКО ОСОЗНАЕТЕ И БЕЗОГОВОРОЧНО СОГЛАШАЕТЕСЬ С ТЕМ, ЧТО ВЫ ИСПОЛЬЗУЕТЕ PREVIEW ИСКЛЮЧИТЕЛЬНО НА СВОЙ СТРАХ И РИСК И ЧТО PREVIEW ПРЕДОСТАВЛЯЕТСЯ ВАМ НА УСЛОВИЯХ «КАК ЕСТЬ» И «КАК ДОСТУПНО» БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ СО СТОРОНЫ КОМПАНИИ GOOGLE.
-
-10.2 ИСПОЛЬЗОВАНИЕ ВАМИ PREVIEW И ЗАГРУЗКА ЛЮБЫХ МАТЕРИАЛОВ И ИХ ПОЛУЧЕНИЕ ИНЫМ СПОСОБОМ С ПОМОЩЬЮ PREVIEW ВЫПОЛНЯЕТСЯ ПО ВАШЕМУ СОБСТВЕННОМУ УСМОТРЕНИЮ НА СВОЙ СТРАХ И РИСК. ВСЯ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБОЙ УЩЕРБ, ПРИЧИНЕННЫЙ ВАШЕЙ ВЫЧИСЛИТЕЛЬНОЙ СИСТЕМЕ ИЛИ ДРУГОМУ ОБОРУДОВАНИЮ, А ТАКЖЕ ЗА ПОТЕРЮ ДАННЫХ, ВЫЗВАННУЮ ПОДОБНЫМ ИСПОЛЬЗОВАНИЕМ, ВОЗЛАГАЕТСЯ НА ВАС. НЕ ОГРАНИЧИВАЯ ВЫШЕСКАЗАННОЕ, ВЫ ПОНИМАЕТЕ, ЧТО PREVIEW НЕ ЯВЛЯЕТСЯ СТАБИЛЬНЫМ ВЫПУСКОМ И МОЖЕТ СОДЕРЖАТЬ ОШИБКИ, ДЕФЕКТЫ И УЯЗВИМОСТИ В СИСТЕМЕ БЕЗОПАСНОСТИ, КОТОРЫЕ МОГУТ ПРИВЕСТИ К СЕРЬЕЗНЫМ ПОВРЕЖДЕНИЯМ, ВКЛЮЧАЯ ПОЛНУЮ И БЕЗВОЗВРАТНУЮ ПОТЕРЮ РАБОТОСПОСОБНОСТИ ВАШЕГО КОМПЬЮТЕРА ИЛИ ИНОГО УСТРОЙСТВА.
-
-10.3. КОМПАНИЯ GOOGLE БЕЗОГОВОРОЧНО ОТКАЗЫВАЕТСЯ ОТ ЯВНЫХ И НЕЯВНЫХ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, ВКЛЮЧАЯ ПОМИМО ПРОЧЕГО НЕЯВНЫЕ ГАРАНТИИ И УСЛОВИЯ ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ СОБСТВЕННОСТИ.
-
-11. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ
-
-11.1. ВЫ ЧЕТКО ОСОЗНАЕТЕ И БЕЗОГОВОРОЧНО СОГЛАШАЕТЕСЬ С ТЕМ, ЧТО КОМПАНИЯ GOOGLE, ЕЕ ДОЧЕРНИЕ И АФФИЛИРОВАННЫЕ КОМПАНИИ И ЛИЦЕНЗИАРЫ НЕ НЕСУТ ПЕРЕД ВАМИ ОТВЕТСТВЕННОСТИ, НЕЗАВИСИМО ОТ ЕЕ ПРИЧИНЫ И ВИДА, ЗА КАКИЕ-ЛИБО ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОПОСРЕДОВАННЫЕ И ШТРАФНЫЕ УБЫТКИ, ПОНЕСЕННЫЕ ВАМИ, ВКЛЮЧАЯ ПОТЕРЮ ДАННЫХ, ВНЕ ЗАВИСИМОСТИ ОТ ТОГО, БЫЛА ЛИ КОМПАНИЯ GOOGLE ИЛИ ЕЕ ПРЕДСТАВИТЕЛИ ИЗВЕЩЕНЫ О ВОЗМОЖНОСТИ ТАКОГО УЩЕРБА.
-
-12 Освобождение от ответственности
-
-12.1. В максимально допустимой законом степени вы соглашаетесь защищать, освобождать от ответственности и возможных претензий компанию Google, ее аффилированные компании и их соответствующих руководителей, служащих, сотрудников и агентов от всех возможных правовых требований, действий, судебных исков или разбирательств, а также от всех возможных убытков, обязательств, ущерба, издержек и расходов (включая обоснованные вознаграждения для адвокатов), возникающих в связи (a) с использованием вами Preview, (b) любыми приложениями, разрабатываемыми вами с помощью Preview и нарушающими любые права на объекты интеллектуальной собственности любого лица, а также порочащие любое лицо либо нарушающие права таких лиц на публичность и конфиденциальность, а также (c) в связи с любым несоблюдением вами положений настоящего Лицензионного соглашения.
-
-13. Изменения в Лицензионном соглашении
-
-13.1. Компания Google вправе вносить изменения в настоящее Лицензионное соглашение по мере выхода новых версий Preview. При внесении изменений Google создает новую версию Лицензионного соглашения и размещает ее на веб-сайте, на котором размещен Preview.
-
-14. Общие правовые условия
-
-14.1. Настоящее Лицензионное соглашение составляет полный текст юридического соглашения между вами и компанией Google, регулирует использование вами Preview (за исключением услуг, которые Google предоставляет на основании отдельного письменного соглашения) и полностью заменяет собой все предыдущие соглашения между вами и компанией Google в отношении Preview.
-
-14.2. Вы соглашаетесь с тем, что отсутствие каких-либо действий или судебных исков со стороны Google, направленных на соблюдение каких-либо правовых норм или исполнение средств правовой защиты, установленных настоящим Лицензионным соглашением (или которыми Google обладает в соответствии с каким-либо действующим законом), не означает отказ компании Google от своих прав и не препятствует компании Google использовать эти права или средства защиты.
-
-14.3. Если какой-либо судебный орган, уполномоченный рассматривать этот вопрос, признает недействительность какого-либо положения данного Лицензионного соглашения, то соответствующее положение будет исключено из Лицензионного соглашения с сохранением действия всех остальных его положений. Остальные положения Лицензионного соглашения по-прежнему будут действовать, и их соблюдение может обеспечиваться в судебном порядке.
-
-14.4. Вы признаете и соглашаетесь с тем, что все участники группы компаний, среди которых Google является материнской компанией, являются сторонними бенефициарами Лицензионного соглашения и что эти компании имеют право пользоваться привилегиями (или правами), предоставляемыми по настоящему Лицензионному соглашению, и напрямую требовать их соблюдения в судебном порядке. Все остальные физические и юридические лица не являются сторонними бенефициарами Лицензионного соглашения.
-
-14.5. ОГРАНИЧЕНИЯ НА ЭКСПОРТ. ИСПОЛЬЗОВАНИЕ PREVIEW РЕГУЛИРУЕТСЯ ЗАКОНАМИ И НОРМАТИВНЫМИ АКТАМИ США, КАСАЮЩИМИСЯ ЭКСПОРТА. ВЫ ОБЯЗУЕТЕСЬ СОБЛЮДАТЬ ВСЕ НАЦИОНАЛЬНЫЕ И МЕЖДУНАРОДНЫЕ ЗАКОНЫ ОБ ЭКСПОРТЕ, ПРИМЕНИМЫЕ К PREVIEW. ДАННЫЕ ЗАКОНЫ НАЛАГАЮТ ОГРАНИЧЕНИЯ НА РЕГИОНЫ, КРУГ ЛИЦ И СПОСОБ КОНЕЧНОГО ИСПОЛЬЗОВАНИЯ.
-
-14.6. Вы не вправе переуступать либо передавать права, предоставляемые по настоящему Лицензионному соглашению, без предварительного письменного согласия Google; любые попытки переуступки без такого согласия считаются недействительными. Вы обязуетесь не делегировать свои полномочия или обязательства по настоящему Лицензионному соглашению без предварительного письменного согласия Google.
-
-14.7. Лицензионное соглашение, а также взаимоотношения между вами и компанией Google в рамках настоящего Лицензионного соглашения регулируются законодательством штата Калифорния за исключением его норм коллизионного права. Вы и компания Google признаете, что урегулирование любых правовых вопросов, связанных с данным Лицензионным соглашением, относится исключительно к юрисдикции судов округа Санта-Клара, штат Калифорния. Несмотря на это, вы соглашаетесь с тем, что компания Google по-прежнему имеет право обращаться за наложением судебного запрета (или за получением аналогичного вида неотложной судебной защиты) в суды любой юрисдикции.
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">Я прочитал(а) и принимаю изложенные выше положения и условия</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>Содержание документа</h2>
-      <ol>
-        <li><a href="#sdk">SDK Preview</a></li>
-        <li><a href="#docs">Документация для разработчиков</a></li>
-        <li><a href="#images">Системные образы оборудования</a></li>
-      </ol>
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  В состав SDK Android M Preview входят инструменты для разработки, системные файлы Android и файлы библиотеки, призванные
-помочь вам в тестировании ваших приложений и новых API-интерфейсов, которые будут реализованы в предстоящем выпуске платформы. В этом документе
-рассказывается, как загрузить необходимые компоненты Preview для тестирования ваших приложений.
-</p>
-
-
-<h2 id="sdk">SDK Preview</h2>
-
-<p>
-  Загрузить SDK Preview можно с помощью <a href="{@docRoot}tools/help/sdk-manager.html">менеджера SDK Android</a>. Дополнительные сведения
-о загрузке и настройке SDK Preview представлены в статье <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Настройка SDK Preview</a>.
-</p>
-
-
-<h2 id="docs">Документация для разработчиков</h2>
-
-<p>
-  В пакете документации для разработчиков, который доступен для загрузки, представлены подробные сведения об API-интерфейсах, а также о различиях между API-интерфейсами для Preview.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">Системные образы оборудования</h2>
-
-<p>
-  С помощью этих системных образов можно установить предварительную версию платформы на физическое устройство для
-тестирования. Используя один из этих образов для настройки устройства, вы можете установить и протестировать ваше приложение, чтобы узнать, как оно будет работать в будущей версии
-платформы. В процессе установки системного образа
-<em>на устройстве удаляются все данные</em>, поэтому перед установкой образа обязательно сделайте резервное копирование данных.
-
-</p>
-
-<p class="warning">
-  <b>Предупреждение.</b> Перечисленные ниже системные образы Android являются предварительными и могут быть изменены. Использование вами
-этих образов регулируется Лицензионным соглашением на использование пакета SDK Android Preview. Системные образы предварительной версии Android
-не являются стабильными и могут содержать ошибки и дефекты,
-способные повредить ваши компьютеры, устройства и данные. Системные образы предварительной версии Android не проходят такое же тестирование,
-как заводская ОС. Поэтому в результате использования этих образов ваш телефон и установленные на нем приложения
-и службы могут перестать работать.
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-      </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">Установка образа на устройство</h3>
-
-<p>
-  Чтобы воспользоваться образом устройства для тестирования, установите его на совместимое устройство. Следуйте
-инструкциям по установке системного образа.
-</p>
-
-<ol>
-  <li>Загрузите и распакуйте один из указанных выше пакетов с системным образом.</li>
-  <li>Создайте резервные копии данных, которые хотите сохранить.</li>
-  <li>Следуйте инструкциям, приведенным на сайте
-<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>,
-чтобы прошить ваше устройство с использованием выбранного образа.</li>
-</ol>
-
-<p class="note">
-  <strong>Примечание.</strong> После прошивки устройства для разработки с использованием системного образа с предварительной версией платформы
-она будет автоматически обновлена до следующего выпуска Preview по беспроводной сети.
-</p>
-
-<h3 id="revertDevice">Сброс параметров устройства до заводских настроек</h3>
-
-<p>
-  Чтобы удалить Preview и восстановить заводские настройки устройства, перейдите на сайт
-<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a>
-и загрузите образ, который требуется использовать для прошивки. Следуйте инструкциям, приведенным на странице,
-чтобы прошить ваше устройство с использованием выбранного образа.
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/ru/preview/features/background-optimization.jd b/docs/html-intl/intl/ru/preview/features/background-optimization.jd
deleted file mode 100644
index b84e785..0000000
--- a/docs/html-intl/intl/ru/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,390 +0,0 @@
-page.title=Оптимизация фоновых процессов
-page.metaDescription=Новые ограничения для неявных широковещательных сообщений.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      Содержание документа
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">Ограничения для CONNECTIVITY_ACTION</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">Планирование сетевых заданий для безлимитных
-подключений</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Отслеживание сетевого подключения во время работы
-приложения</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">Ограничения для NEW_PICTURE и
-NEW_VIDEO</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">Новые методы JobInfo</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">Новые методы JobParameter</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">Дальнейшая оптимизация приложения</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  Фоновые процессы могут потреблять много памяти и заряда аккумулятора. Например,
-неявное широковещательное сообщение может запускать множество фоновых процессов,
-которые его прослушивают, даже если они сами не выполняют полезной работы. Это
-может значительно снизить производительность устройства и быстродействие пользовательского интерфейса.
-</p>
-
-<p>
-  Чтобы устранить подобные проблемы, в N Developer Preview применяются следующие
-ограничения.
-</p>
-
-<ul>
-  <li>Приложения для версии Preview не получают рассылок {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION}, если они
-зарегистрированы для их получения в манифесте. Приложения в активном режиме
-по-прежнему могут прослушивать {@code CONNECTIVITY_CHANGE} в главном потоке,
-зарегистрировав {@link android.content.BroadcastReceiver} с помощью метода {@link
-android.content.Context#registerReceiver Context.registerReceiver()}.
-  </li>
-
-  <li>Приложения не могут отправлять или получать широковещательные сообщения {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} и {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Эта оптимизация
-затрагивает все приложения, а не только предназначенные для версии Preview.
-  </li>
-</ul>
-
-<p>
-  Платформа Android предоставляет несколько решений, позволяющих отказаться
-от таких неявных рассылок. Например, в {@link android.app.job.JobScheduler}
-и <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> реализованы надежные механизмы для планирования сетевых
-операций, которые запускаются при выполнении определенных условий, таких как наличие безлимитной
-сети. Теперь вы также можете использовать {@link android.app.job.JobScheduler}
-, чтобы реагировать на изменения поставщиков контента. В объектах {@link android.app.job.JobInfo}
-инкапсулированы параметры, которые {@link android.app.job.JobScheduler}
-использует для планирования заданий. Если условия задания выполнены, система
-выполняет его через {@link android.app.job.JobService} вашего приложения.
-</p>
-
-<p>
-  Здесь мы рассмотрим, как использовать альтернативные методы, такие как
-{@link android.app.job.JobScheduler}, для адаптации приложения к новым
-ограничениям.
-</p>
-
-<h2 id="connectivity-action">
-  Ограничения для CONNECTIVITY_ACTION
-</h2>
-
-<p>
-  Приложения для N Developer Preview не получают широковещательные сообщения {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION}, если они
-зарегистрированы для их получения в своем манифесте. При этом процессы, которые зависят от этого
-широковещательного сообщения, не запускаются. Это может вызвать проблемы для приложений, которым необходимо
-прослушивать изменения сети или выполнять
-массовые сетевые операции, когда устройство подключается к безлимитной сети. Платформа Android уже предоставляет ряд способов обойти
-это ограничение, но выбор нужного метода
-зависит от того, чего вы хотите добиться от приложения.
-</p>
-
-<p class="note">
-  <strong>Примечание.</strong> Объект {@link android.content.BroadcastReceiver}, зарегистрированный с помощью метода
-{@link android.content.Context#registerReceiver Context.registerReceiver()},
-продолжает получать такие рассылки, если приложение работает в активном режиме.
-</p>
-
-<h3 id="sched-jobs">
-  Планирование сетевых заданий для безлимитных подключений
-</h3>
-
-<p>
-  При использовании класса {@link android.app.job.JobInfo.Builder JobInfo.Builder} для создания
-объекта {@link android.app.job.JobInfo} примените метод {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} и передайте {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} в качестве параметра задания. В следующем примере кода
-служба запускается, если устройство подключается к безлимитной
-сети и заряжается:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  Если условия задания выполнены, приложение получает обратный вызов для запуска
-метода {@link android.app.job.JobService#onStartJob onStartJob()} в указанном
-классе {@code JobService.class}. Другие примеры реализации {@link
-  android.app.job.JobScheduler} см. в <a href="{@docRoot}samples/JobScheduler/index.html">примере приложения JobScheduler</a>.
-</p>
-
-<p>
-  В приложениях, использующих службы GMSCore и предназначенных для Android 5.0 (уровень API 21)
-или предыдущих версий, можно воспользоваться <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> и указать {@code Task.NETWORK_STATE_UNMETERED}.
-</p>
-
-<h3 id="monitor-conn">
-  Отслеживание сетевого подключения во время работы приложения
-</h3>
-
-<p>
-  Приложения в активном режиме по-прежнему могут прослушивать {@code
-  CONNECTIVITY_CHANGE} с помощью зарегистрированного объекта {@link
-  android.content.BroadcastReceiver}. Однако в API-интерфейсе {@link
-  android.net.ConnectivityManager} есть более надежный метод для запроса
-обратного вызова только при выполнении указанных сетевых условий.
-</p>
-
-<p>
-  В объектах {@link android.net.NetworkRequest} параметры
-сетевого обратного вызова задаются с помощью {@link android.net.NetworkCapabilities}. Объекты {@link android.net.NetworkRequest} создаются
-с использованием класса {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder}. Затем метод {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
- передает объект {@link android.net.NetworkRequest} системе. Если
-сетевые условия выполнены, приложение получает обратный вызов для выполнения метода
-  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()}, определенного в своем классе {@link
-  android.net.ConnectivityManager.NetworkCallback}.
-</p>
-
-<p>
-  Приложение продолжает получать обратные вызовы, пока оно не будет закрыто или не будет вызван метод
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}.
-</p>
-
-<h2 id="media-broadcasts">
-  Ограничения для NEW_PICTURE и NEW_VIDEO
-</h2>
-
-<p>
-  В N Developer Preview приложения не могут отправлять или получать широковещательные сообщения {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} и {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Это ограничение
- позволяет улучшить производительность, если для обработки нового изображения или видео должны
- активироваться несколько приложений. N Developer Preview
- расширяет классы {@link android.app.job.JobInfo} и {@link
-  android.app.job.JobParameters}, что дает разработчикам альтернативное решение.
-</p>
-
-<h3 id="new-jobinfo">
-  Новые методы JobInfo
-</h3>
-
-<p>
-  Для активации заданий при изменении URI контента в N Developer Preview
- были добавлены следующие методы для API-интерфейса {@link android.app.job.JobInfo}.
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    Инкапсулирует параметры, необходимые для активации задания при изменении URI контента.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    Передает объект {@code TriggerContentUri} в контейнер {@link
-    android.app.job.JobInfo}. Объект {@link android.database.ContentObserver}
-    отслеживает инкапсулированный URI контента. Если с заданием связано несколько объектов {@code
-    TriggerContentUri}, система предоставляет
- обратный вызов, даже если изменился только один из URI контента.
-  </dd>
-
-  <dd>
-    Добавьте флаг {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS}, чтобы
- активировать задание при изменении любых потомков указанного URI. Этот флаг
- соответствует параметру {@code notifyForDescendants}, переданному методу {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>Примечание.</strong> Метод {@code TriggerContentUri()} не может использоваться
- вместе с {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} или {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}. Чтобы непрерывно отслеживать изменения контента, запланируйте новый объект задания
-  {@link android.app.job.JobInfo}, прежде чем {@link
-  android.app.job.JobService} завершит обработку последнего обратного вызова.
-</p>
-
-<p>
-  В следующем примере кода планируется задание, которое активируется, когда система сообщает
- об изменении URI контента {@code MEDIA_URI}:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MEDIA_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  Если система сообщает об изменении указанных URI контента, приложение
- получает обратный вызов, а объект {@link android.app.job.JobParameters} передается
- методу {@link android.app.job.JobService#onStartJob onStartJob()}
- в {@code MediaContentJob.class}.
-</p>
-
-<h3 id="new-jobparam">
-  Новые методы JobParameter
-</h3>
-
-<p>
-  В N Developer Preview также расширен класс {@link android.app.job.JobParameters}, чтобы
- приложения могли получать полезные сведения о том, какие источники контента
- и URI инициировали задание.
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    Возвращает массив URI, которые активировали задание. Возвращается значение {@code
-    null}, если ни один URI не инициировал задание (например, задание было
-    активировано по времени или из-за другой причины), или число измененных
-    URI больше 50.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    Возвращает строковый массив источников контента, которые активировали задание.
-    Если возвращенный массив не равен {@code null}, используйте метод {@code getTriggeredContentUris()},
-    чтобы получить сведения об измененных URI.
-  </dd>
-</dl>
-
-<p>
-  В следующем примере кода перегружается метод {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} и
- записываются источники и URI контента, вызвавшие задание:
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  Дальнейшая оптимизация приложения
-</h2>
-
-<p>
-  Оптимизация приложений для устройств с малым объемом памяти
- или для условий с ограниченным объемом памяти помогает улучшить производительность и удобство работы пользователей. Удаление
- зависимостей от фоновых служб и статически зарегистрированных приемников неявных широковещательных сообщений
- способно помочь приложению более эффективно работать на таких устройствах. Хотя
- на платформе N Developer Preview приняты меры для устранения некоторых из этих проблем,
- рекомендуется оптимизировать приложения, полностью отказавшись
- от подобных фоновых процессов.
-</p>
-
-<p>
-  В N Developer Preview представлен ряд дополнительных команд <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a>, с помощью
- которых можно тестировать поведение приложения с отключенными фоновыми процессами.
-</p>
-
-<ul>
-  <li>Для эмуляции условий, в которых неявные широковещательные сообщения и фоновые службы
- недоступны, введите следующую команду:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>Чтобы снова включить неявные широковещательные сообщения и фоновые службы, введите
- следующую команду:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
\ No newline at end of file
diff --git a/docs/html-intl/intl/ru/preview/features/icu4j-framework.jd b/docs/html-intl/intl/ru/preview/features/icu4j-framework.jd
deleted file mode 100644
index 7d22408..0000000
--- a/docs/html-intl/intl/ru/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,160 +0,0 @@
-page.title=API-интерфейсы ICU4J в платформе Android
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Содержание документа:</h2>
-<ol>
-    <li><a href="#relation">Связь с ICU4J</a></li>
-    <li><a href="#migration">Переход на API-интерфейсы android.icu с ICU4J</a></li>
-    <li><a href="#licence">Лицензирование</a></li>
-</ol>
-
-<h2>См. также:</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">Документация по ICU4J</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">Последние стандарты, поддерживаемые
-ICU4J</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J — широко используемый набор библиотек Java с открытым кодом, обеспечивающий для приложений поддержку формата Unicode
-и глобализации. Android N
-открывает в платформе Android частичный набор API-интерфейсов ICU4J, который разработчики приложений
-могут использовать в составе пакета {@code android.icu}. Эти API используют
-данные локализации, присутствующие на устройстве. Это позволяет уменьшить размеры APK
-, не компилируя библиотеки ICU4J в APK, а
-просто вызывая их в платформе. (В этом случае может оказаться удобно предоставлять
-<a href="{@docRoot}google/play/publishing/multiple-apks.html">несколько версий
-вашего APK</a>, чтобы пользователи с версиями Android ниже Android N
-могли загружать версию приложения, содержащую библиотеки ICU4J.)
-</p>
-
-<p>
-  В начале этого документа предоставляется базовая информация по минимальным уровням
-Android API, которые требуются для поддержки этих библиотек. Далее приводятся необходимые пояснения
-о реализации ICU4J в Android. В заключение
-в нем рассказывается, как использовать API-интерфейсы ICU4J в платформе Android.
-</p>
-
-<h2 id="relation">Связь с ICU4J</h2>
-
-<p>
-  В Android N частичный набор API-интерфейсов ICU4J открывается через пакет
-  <code>android.icu</code>, а не через <code>com.ibm.icu</code>. Для платформы
-Android может быть принято решение не
-открывать API-интерфейсы ICU4J по различным причинам. Например, Android N не открывает
-некоторые устаревшие API-интерфейсы, а также те, которые рабочая группа ICU еще не объявила
-стабильными. По мере того, как рабочая группа ICU будет объявлять API-интерфейсы устаревшими, они будут так же помечаться и в Android,
-но при этом будут и дальше входить в состав платформы.
-</p>
-
-<p class="table-caption"><strong>Таблица 1.</strong> Версии ICU и CLDR, используемые
-в Android N.</p>
-<table>
-<tr>
-<th>Уровень Android API</th>
-<th>Версия ICU</th>
-<th>Версия CLDR</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>Следует отметить несколько важных моментов:</p>
-
-<ul>
-<li>В состав API-интерфейсов ICU4J платформы Android входят не все API-интерфейсы ICU4J.</li>
-<li>Разработчикам NDK следует помнить, что Android ICU4C не поддерживается.</li>
-<li>API-интерфейсы в платформе Android не заменяют поддержку
-<a href="{@docRoot}guide/topics/resources/localization.html">локализации с
-ресурсами</a> в Android.</li>
-</ul>
-
-<h2 id="migration">Переход на пакет android.icu с com.ibm.icu</h2>
-
-<p>
-  Если вы уже используете в своем приложении API-интерфейсы ICU4J, и если API
-  <code>android.icu</code> соответствуют вашим требованиям, то для перехода на
-API-интерфейсы платформы вам нужно будет изменить импорт Java
-с <code>com.ibm.icu</code> на <code>android.icu</code>. После этого вы сможете
-удалить свои копии файлов ICU4J из APK.
-</p>
-
-<p class="note">
-  <b>Примечание</b>. API-интерфейсы ICU4J в платформе используют пространство имен {@code android.icu}
-вместо {@code com.ibm.icu}. Это позволяет избежать конфликтов пространств имен
-в пакетах APK, содержащих собственные библиотеки {@code com.ibm.icu}.
-</p>
-
-<h3 id="migrate-from-android">
-  Переход на API-интерфейсы android.icu с других API Android SDK
-</h3>
-
-<p>
-  Некоторые классы в пакетах <code>java</code> и <code>android</code> имеют
-эквиваленты в ICU4J. Однако ICU4J обычно обеспечивает более широкую
-поддержку стандартов и языков.
-</p>
-<p>Ниже приведены несколько примеров для начала работы:</p>
-<table>
-<tr>
-<th>Класс</th>
-<th>Альтернативы</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">Лицензирование</h2>
-
-<p>
-  ICU4J выпускается по лицензии ICU. Более подробную информацию можно найти в <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">Руководстве пользователя
-ICU.</a>
-</p>
diff --git a/docs/html-intl/intl/ru/preview/features/multilingual-support.jd b/docs/html-intl/intl/ru/preview/features/multilingual-support.jd
deleted file mode 100644
index 83e9968..0000000
--- a/docs/html-intl/intl/ru/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,217 +0,0 @@
-page.title=Язык и языковой стандарт
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Содержание документа:</h2>
-<ol>
-	  <li><a href="#preN">Сложности с разрешением языковых ресурсов</a></li>
-    <li><a href="#postN">Улучшение стратегии разрешения ресурсов</a></li>
-    <li><a href="#design">Проектирование приложения для поддержки дополнительных
- языковых стандартов</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N обеспечивает расширенную поддержку многоязычных пользователей,
-позволяя им выбирать в настройках из нескольких языковых стандартов. Эта возможность реализована в Android N
-за счет значительного увеличения числа поддерживаемых языковых стандартов
-и изменения способа разрешения ресурсов в системе. Новый метод разрешения
-ресурсов более надежен и разработан с учетом совместимости с существующими APK. Тем не менее,
-при его использовании следует очень внимательно следить за признаками непредвиденного поведения приложения. Например, при его использовании
-следует провести тесты и убедиться, что приложение по умолчанию использует ожидаемый язык. Если
-ваше приложение поддерживает несколько языков, нужно убедиться, что поддержка работает
-ожидаемым образом. Также следует попытаться обеспечить корректную работу приложения с
-языками, поддержка которых не предусматривалась явным образом в его коде.</p>
-
-<p>В начале этого документа рассказывается о стратегии разрешения ресурсов, которая использовалась до появления
-Android N. Далее в нем описывается улучшенная стратегия
-разрешения ресурсов в Android N. В последней части документа рассказывается о том, как использовать
-дополнительные языковые стандарты для поддержки большего числа многоязычных пользователей.</p>
-
-<h2 id="preN">Сложности с разрешением языковых ресурсов</h2>
-
-<p>До выпуска Android N в Android не всегда удавалось успешно сопоставлять
- языковые стандарты приложений и системы. Допустим, по умолчанию в вашем приложении используется английский язык
- (США), но оно также содержит строки на испанском, локализованные в файлах ресурсов {@code es_ES}.
-</p>
-<p>В коде Java разрешение языков строк происходило следующим
-образом:</p>
-<ul>
-<li>Если на устройстве был установлен язык {@code es_MX} (испанский, Мексика), Android загружал
-строки из файлов ресурсов {@code es_ES}.</li>
-<li>Если на устройстве был установлен язык {@code en_AU}, Android возвращался к языку {@code
-en_US}. Также система использовала по умолчанию язык {@code en_US}, если пользователь выбирал язык,
-который вообще не поддерживался приложением, например, французский.</li>
-</ul>
-
-
-<p>Проблемы с разрешением возникали из-за того, что система удаляла код страны
- из строки языкового стандарта при отсутствии точного совпадения.  Например:</p>
-<p class="table-caption" id="t-resource-res">
-<strong>Таблица 1.</strong> Разрешение ресурсов без точного совпадения языковых стандартов.
-</p>
-<table>
-<tbody>
-<tr>
-<th>Пользовательские настройки</th>
-<th>Ресурсы приложения</th>
-<th>Разрешение ресурсов</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-по умолчанию (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-Попытка использования fr_CH =&gt; Отказ<br>
-Попытка использования fr =&gt; Отказ<br>
-Использование языка по умолчанию (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>В этом примере система отображает строки на английском,
-не зная, понимает ли пользователь английский язык. Такое поведение приложений сейчас довольно
-распространено. С выпуском Android N подобные ситуации
-будут возникать намного реже.</p>
-
-<h2 id="postN">Улучшение стратегии разрешения ресурсов</h2>
-<p>В Android N используется более надежная система разрешения ресурсов,
-которая автоматически находит более подходящие альтернативные варианты. Однако для ускорения процесса разрешения и упрощения
- обслуживания ресурсы следует хранить на наиболее распространенном языке верхнего уровня.
- Например, если вы хранили ресурсы на испанском в каталоге{@code es-US}
-, их следует переместить в каталог {@code es-419}, где содержатся ресурсы на латиноамериканском диалекте испанского языка.
- Аналогичным образом, если вы хранили строки ресурсов в папке {@code en-GB}, вам следует изменить название папки
- на {@code en-001} (международная версия английского языка), поскольку {@code en-001} — наиболее распространенный
- язык верхнего уровня для строк <code>en-GB</code>.
- В следующих примерах объясняется, почему такая практика повышает производительность и
-надежность процесса разрешения ресурсов.</p>
-
-<h3>Примеры разрешения ресурсов</h3>
-
-<p>В Android N ситуация, описанная в <strong>Таблице 1</strong>, разрешается
-иначе:</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>Таблица 2.</strong> Улучшенная стратегия разрешения при отсутствии
-точного совпадения языкового стандарта.</p>
-<table>
-<tr>
-<th>Пользовательские настройки</th>
-<th>Ресурсы приложения</th>
-<th>Разрешение ресурсов</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-по умолчанию (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-Попытка использования fr_CH =&gt; Отказ<br>
-Попытка использования fr =&gt; Отказ<br>
-Попытка использования диалекта fr =&gt; fr_FR<br>
-Использование fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>В этом примере пользователь получает ресурсы на французском языке, а не на английском. В этом примере также показано, почему для Android N
- следует хранить строки на французском языке в каталоге {@code fr}, а не в каталоге {@code fr_FR}.
-Здесь целью разрешения является нахождение наиболее близкого диалекта верхнего уровня,
- что ускоряет процесс разрешения и делает его более предсказуемым.</p>
-
-<p>Помимо улучшенной логики разрешения в Android добавлены
- дополнительные языки. Рассмотрим предыдущий пример в ситуации, когда итальянский
- указан как дополнительный язык пользователя, а приложение не поддерживает французский язык.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>Таблица 3.</strong> Разрешение ресурсов в ситуации, когда приложение находит соответствие только для
-второго предпочитаемого пользователем языкового стандарта.</p>
-<table>
-<tr>
-<th>Пользовательские настройки</th>
-<th>Ресурсы приложения</th>
-<th>Разрешение ресурсов</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-по умолчанию (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-Попытка использования fr_CH =&gt; Отказ<br>
-Попытка использования fr =&gt; Отказ<br>
-Попытка использования диалекта fr =&gt; Отказ<br>
-Попытка использования it_CH =&gt; Отказ<br>
-Попытка использования it =&gt; Отказ<br>
-Попытка использования диалекта it =&gt; it_IT<br>
-Использование it_IT
-</td>
-
-</tr>
-
-</table>
-<p>Пользователь получает данные на понятном ему языке, хотя приложение и не
-поддерживает французский язык.</p>
-
-
-<h2 id="design">Проектирование приложения для поддержки дополнительных языковых стандартов</h2>
-<h3>API LocaleList</h3>
-
-<p>В Android N добавлен новый API {@code LocaleList.GetDefault()},
- позволяющий приложениям напрямую запрашивать список языков, выбранных пользователем. Этот API
-позволяет реализовать более сложное поведение
- приложений и лучше оптимизировать отображение содержимого на экране. Например, результаты поиска
- могут отображаться на разных языках в зависимости от пользовательских настроек.  Приложения в браузере
- могут не предлагать пользователю перевести приложения на знакомый ему язык,
- а приложения, использующие клавиатуру, могут автоматически включать все подходящие раскладки. </p>
-
-<h3>Средства форматирования</h3>
-
-<p>Версии Android до 6.0 включительно (уровень API 23) поддерживали только один или два языковых стандарта
- для большинства распространенных языков
-(en, es, ar, fr, ru). Поскольку у каждого языка имелось лишь немного вариантов,
-приложения могли хранить числа и даты в виде жестко закодированных строк
-в файлах ресурсов.  Однако с расширением числа поддерживаемых Android языковых стандартов
-могут возникнуть
-значительные различия форматов даты, времени, валюты и другой подобной
-информации даже в рамках одного языкового стандарта. Жесткое кодирование форматов может запутать
-конечных пользователей.  Поэтому при разработке приложений для Android N
-следует использовать средства форматирования, а не жесткое кодирование строк с числами и датами.</p>
-
-<p>В качестве наглядного примера можно привести арабский язык, поддержка которого в Android N расширена
-с одного {@code ar_EG} до 27 языковых стандартов. Большинство ресурсов этих языковых стандартов общие, но
-в некоторых из них используются цифры формата ASCII, а в других — собственные цифры. Например,
-если вы хотите создать предложение с числовой переменной
-"Выберите ПИН-код из 4 цифр", вам нужно использовать средства форматирования следующим образом:</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/ru/preview/features/notification-updates.jd b/docs/html-intl/intl/ru/preview/features/notification-updates.jd
deleted file mode 100644
index 54b3bc3..0000000
--- a/docs/html-intl/intl/ru/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,328 +0,0 @@
-page.title=Уведомления
-page.tags=notifications
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>Содержание:</h2>
-<ol>
-  <li><a href="#direct">Прямой ответ</a></li>
-  <li><a href="#bundle">Группы уведомлений</a></li>
-  <li><a href="#custom">Собственные представления</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>В Android N представлено несколько новых API-интерфейсов, позволяющих
-публиковать заметные и интерактивные уведомления.</p>
-
-<p>Существующий API-интерфейс уведомлений {@link android.support.v4.app.RemoteInput}
-в Android N расширен для поддержки внутренних ответов на смартфонах. С помощью этой возможности
- пользователи могут быстро отвечать на сообщения в панели уведомлений, не открывая приложение.</p>
-
-<p>
-  Android N также позволяет группировать несколько похожих
-  уведомлений, чтобы они отображались как одно. Для этого в Android N используется существующий метод {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()}. Пользователи могут развернуть все
-  уведомления и выполнить различные действия, например ответить на сообщение
-  или закрыть каждое из уведомлений по отдельности в панели уведомлений.
-</p>
-
-<p>Наконец, в Android N представлены новые API-интерфейсы, позволяющие
-использовать системные элементы в собственных представлениях уведомлений вашего приложения. Благодаря им
-уведомления отображаются единообразно на основе
-стандартных шаблонов.</p>
-
-<p>В этом документе рассматриваются некоторые наиболее важные изменения,
- которые следует учитывать при использовании новых уведомлений в приложениях.</p>
-
-<h2 id="direct">Прямой ответ</h2>
-
-<p>С помощью прямых ответов пользователи
- Android N могут быстро отвечать на текстовые сообщения и обновлять списки задач непосредственно в интерфейсе
-уведомлений. На мобильных устройствах действие внутреннего ответа обозначается
- как дополнительная кнопка в уведомлении. Если пользователь набирает ответ на клавиатуре, система
- прикрепляет текст ответа к намерению,
- указанному для действия уведомления, и передает намерение в ваше
- приложение.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>Рисунок 1.</strong> В Android N добавлена кнопка <strong>Reply</strong>.
-
-</p>
-
-<h3>Добавление действий внутренних ответов</h3>
-
-<p>Создание действия уведомления, которое поддерживает прямой ответ:
-</p>
-
-<ol>
-<li>Создайте экземпляр класса {@link android.support.v4.app.RemoteInput.Builder},
- который можно добавить в действие
-уведомления. Конструктор класса принимает строку, которую система использует как
- ключ для введенного текста. Потом ваше приложение использует этот ключ для получения
- текста.
-
-<pre>
-// Key for the string that's delivered in the action's intent
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>Прикрепите объект {@link android.support.v4.app.RemoteInput}
- к действию с помощью метода <code>addRemoteInput()</code>.
-
-<pre>
-// Create the reply action and add the remote input
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>Примените действие к уведомлению и отправьте его.
-
-<pre>
-// Build the notification and add the action
-Notification notification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, notification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> Система запрашивает у пользователя ввод ответа, если он инициирует
-действие уведомления. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Рисунок 2.</strong> Пользователь вводит текст в панели уведомлений.
-</p>
-
-<h3>Получение введенного пользователем текста из внутреннего ответа</h3>
-
-<p>Получение введенного пользователем текста из интерфейса
-уведомлений в операции, объявленной в намерении действия:</p>
-<ol>
-<li> Вызовите метод {@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()}, передав намерение действия уведомления
- в качестве входного параметра. Этот метод возвращает объект {@link android.os.Bundle},
- содержащий текст ответа.
-</li>
-
-<pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-
-<li>Запросите группу, используя ключ результата (предоставленный конструктору {@link
-  android.support.v4.app.RemoteInput.Builder}).
-</li>
-</ol>
-
-<p>В следующем фрагменте кода показано, как метод извлекает введенный
-текст из группы:</p>
-
-<pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-            return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-            }
-    return null;
- }
-</pre>
-
-<p>Приложения могут применять логику, чтобы определить, какие действия следует выполнить с полученным
-текстом.
-Для интерактивных приложений (например, чатов) предоставьте больше контекста в самом уведомлении
- (например, несколько строк истории чата, в том числе собственные сообщения пользователя),
- чтобы у пользователя было достаточно информации для ответа.
-Когда пользователь отвечает через {@link android.support.v4.app.RemoteInput},
- добавьте текст в историю ответов, применив метод {@code setRemoteInputHistory()}.
-</p>
-
-<h2 id="bundle">Группы уведомлений</h2>
-
-<p>Android N предоставляет разработчикам новый способ отображения
- очереди уведомлений: <i>группы уведомлений</i>. Они похожи на
-  <a href="{@docRoot}training/wearables/notifications/stacks.html">стеки
- уведомлений</a> в Android Wear. Например, если приложение создает уведомления
- для входящих сообщений и получено несколько сообщений, объедините
- уведомления в одну группу. Для группировки похожих уведомлений используйте
- существующий метод {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()}.</p>
-
-<p>
-  Уведомления в группе формируют иерархию,
-  на вершине которой находится родительское уведомление, отображающее
- сводную информацию о группе. Пользователь может постепенно
- раскрывать группу уведомлений, при этом система показывает дополнительные
-  сведения. Если пользователь раскрывает группу, система отображает больше
- информации о всех дочерних уведомлениях. Если же пользователь
- развернет одно из уведомлений, его содержимое показывается полностью.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Рисунок 3.</strong> Пользователь может постепенно раскрывать группу уведомлений.
-
-</p>
-
-<p>Добавление уведомлений в группу описано в разделе
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">Добавление
-каждого уведомления в группу</a>.</p>
-
-
-<h3 id="best-practices">Рекомендации по работе с группами уведомлений</h3>
-<p>В этом разделе описываются рекомендации по использованию групп
-уведомлений вместо уведомлений {@link android.app.Notification.InboxStyle InboxStyle},
- которые были доступны в предыдущих версиях платформы
- Android.</p>
-
-<h3>Ситуации, в которых следует использовать группы уведомлений</h3>
-
-<p>Вам следует использовать группы уведомлений, только если выполняются
-все следующие условия.</p>
-
-<ul>
-  <li>Дочерние уведомления являются полноценными уведомлениями, которые можно
- показать отдельно без сводной информации о группе.</li>
-  <li>Отображение дочерних уведомлений по отдельности имеет смысл. Например:
-
-  </li>
-  <ul>
-    <li>в дочерних уведомлениях можно выполнять какие-либо соответствующие им действия;</li>
-    <li>дочернему уведомлению предшествует больше информации, чем требуется пользователю.</li>
-  </ul>
-</ul>
-
-<p>Примером использования групп уведомлений может служить приложение
-для обмена сообщениями, которое показывает список входящих сообщений,
-или почтовое приложение, отображающее список полученных писем.</p>
-
-<p>
-К примерам ситуаций, когда предпочтительнее использовать одно
- уведомление, относятся отдельные сообщения от одного пользователя или
- списочное представление однострочных текстовых элементов. Для них можно использовать
-{@link android.app.Notification.InboxStyle InboxStyle} или
-{@link android.app.Notification.BigTextStyle BigTextStyle}.
-
-</p>
-
-<h3 id ="post">Отображение группы уведомлений</h3>
-
-<p>
-  Приложение всегда должно публиковать сводную информацию группы, даже если эта группа содержит
- всего одно дочернее уведомление. В этом случае система не показывает сводную информацию, а
- непосредственно отображает это уведомление. Это обеспечивает
- единообразие интерфейса при
- пролистывании дочернего элемента группы.
-</p>
-
-<p class="note">
-  <strong>Примечание.</strong> Эта версия Android N пока еще не
- блокирует отображение сводной информации для групп уведомлений, содержащих только один дочерний элемент. Эта
- возможность будет добавлена в следующих версиях Android N.
-</p>
-
-<h3>Всплывающие уведомления</h3>
-
-<p>Хотя система обычно отображает дочерние уведомления в виде группы,
- их можно временно показывать в виде
- <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">всплывающих
-уведомлений</a>. Эта возможность очень удобна, так как позволяет
- быстро получить доступ к последнему дочернему уведомлению и связанным с ним действиям.
-</p>
-
-
-<h3>Обратная совместимость</h3>
-
-<p>
-  И группы уведомлений, и удаленный ввод входили в состав API {@link
-  android.app.Notification} для поддержки устройств
- Android Wear, начиная с Android 5.0 (уровень API 21). Если вы уже использовали эти API-интерфейсы для создания уведомлений,
- вам нужно только убедиться, что поведение приложения соответствует
- описанным выше рекомендациям, и рассмотреть возможность реализации {@code
-  setRemoteInputHistory()}.
-</p>
-
-<p>
-  Для поддержки обратной совместимости те же API-интерфейсы доступны в
- классе {@link android.support.v4.app.NotificationCompat}
- вспомогательной библиотеки, что позволяет реализовать уведомления, работающие в предыдущих версиях Android.
- На смартфонах и планшетах пользователи видят только сводное уведомление,
- поэтому в приложении все равно должно быть уведомление
- в стиле Inbox или аналогичное уведомление, содержащее всю информацию о группе. Так как устройства Android
-Wear позволяют пользователям видеть все дочерние уведомления даже
- на более ранних уровнях платформы, эти уведомления следует создавать независимо от уровня API.
-
-</p>
-
-<h2 id="custom"> Собственные представления</h2>
-<p>Начиная с Android N, вы можете настраивать представления уведомлений
-и по-прежнему получать системные элементы, такие как заголовки уведомлений, действия и
-расширяемые макеты.</p>
-
-<p>Для этого в Android N добавлены следующие API-интерфейсы, позволяющие
- настраивать собственные представления.</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> Определяет стиль для всех уведомлений, кроме
-уведомлений мультимедиа.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> Определяет стиль для уведомлений мультимедиа.</dd>
-</dl>
-
-<p>Чтобы воспользоваться этим новым API-интерфейсом, вызовите метод {@code setStyle()}, передав в него
-нужный стиль собственного представления.</p>
-
-<p>В этом фрагменте показано, как создать собственный объект уведомления с помощью метода
-{@code DecoratedCustomViewStyle()}.</p>
-
-<pre>
-Notification noti = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
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..2d57fa6 100644
--- a/docs/html-intl/intl/vi/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
@@ -1,78 +1,63 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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
@@ -82,39 +67,44 @@
   </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">
+<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>
 
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Báo cáo vấn đề
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Xem ghi chú phát hành
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Tham gia cộng đồng nhà phát triển
-      </a></div>
-    </div><!-- end .actions -->
-  </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-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/vi/preview/features/background-optimization.jd b/docs/html-intl/intl/vi/preview/features/background-optimization.jd
deleted file mode 100644
index 39e1c15..0000000
--- a/docs/html-intl/intl/vi/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,390 +0,0 @@
-page.title=Tối ưu hóa Chạy ngầm
-page.metaDescription=Các hạn chế mới đối với truyền phát không biểu thị.
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      Trong tài liệu này
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">Các hạn chế về CONNECTIVITY_ACTION</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">Lên lịch Tác vụ Mạng trên Kết nối
-        Không đo lưu lượng</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Theo dõi Kết nối Mạng Trong khi Ứng dụng
-        đang Chạy</a>
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">Các hạn chế về NEW_PICTURE và
-        NEW_VIDEO</a>
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">Các phương thức JobInfo Mới</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">Các phương thức JobParameter Mới</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">Tối ưu hóa thêm Ứng dụng của bạn</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  Các tiến trình chạy ngầm có thể tiêu tốn bộ nhớ và pin. Ví dụ, một
-  truyền phát không biểu thị có thể bắt đầu nhiều tiến trình chạy ngầm đã đăng ký
-  để theo dõi chúng, ngay cả khi các tiến trình đó có thể không làm việc nhiều. Điều này có thể có
-  ảnh hưởng lớn đến cả hiệu suất của thiết bị lẫn trải nghiệm của người dùng.
-</p>
-
-<p>
-  Để loại bỏ vấn đề này, N Developer Preview áp dụng các hạn chế
-  sau:
-</p>
-
-<ul>
-  <li>Các ứng dụng nhắm đến Preview không nhận được truyền phát {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} nếu chúng
-  đăng ký nhận truyền phát trong bản kê khai của chúng. Các ứng dụng đang chạy ở tiền cảnh
-  vẫn có thể theo dõi {@code CONNECTIVITY_CHANGE} trên luồng chính của chúng bằng cách
-  đăng ký{@link android.content.BroadcastReceiver} với {@link
-  android.content.Context#registerReceiver Context.registerReceiver()}.
-  </li>
-
-  <li>Ứng dụng không thể gửi hoặc nhận các truyền phát {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} hoặc {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Việc tối ưu này
-  tác động đến mọi ứng dụng, không chỉ các ứng dụng nhắm đến Preview.
-  </li>
-</ul>
-
-<p>
-  Khuôn khổ Android cung cấp một số giải pháp để giảm thiểu sự cần thiết đối với
-  các truyền phát không biểu thị. Ví dụ, {@link android.app.job.JobScheduler}
-  và <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> cung cấp một cơ chế lên lịch hiệu quả
-  cho các hoạt động mạng khi đáp ứng các điều kiện được chỉ định, ví dụ như kết nối tới mạng
- không đo lưu lượng. Bây giờ bạn cũng có thể sử dụng {@link android.app.job.JobScheduler}
-  để phản ứng lại với các thay đổi đối với các trình cung cấp nội dung. Các đối tượng {@link android.app.job.JobInfo}
-  gói gọn các tham số {@link android.app.job.JobScheduler}
-  dùng để lên lịch tác vụ của bạn. Khi đáp ứng được các điều kiện của tác vụ, hệ thống
-  sẽ thực thi tác vụ này trên {@link android.app.job.JobService} của ứng dụng của bạn.
-</p>
-
-<p>
-  Trong tài liệu này, chúng ta sẽ tìm hiểu cách sử dụng các phương thức thay thế, chẳng hạn như
-  {@link android.app.job.JobScheduler}, để thích ứng ứng dụng của bạn với các hạn chế
-  mới này.
-</p>
-
-<h2 id="connectivity-action">
-  Các hạn chế về CONNECTIVITY_ACTION
-</h2>
-
-<p>
-  Các ứng dụng nhắm đến N Developer Preview không nhận được truyền phát {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} nếu chúng
-  đăng ký nhận truyền phát trong bản kê khai của chúng, và các tiến trình phụ thuộc vào truyền phát này
-  sẽ không khởi động. Điều này cũng đặt ra một vấn đề cho ứng dụng
-  về việc theo dõi thay đổi mạng hoặc thực hiện các hoạt động mạng hàng loạt khi
-  thiết bị kết nối với một mạng không đo lưu lượng. Một số giải pháp để tránh khỏi hạn chế này
-  đã tồn tại trong khuôn khổ Android, nhưng chọn được một giải pháp phù hợp
-  phụ thuộc vào những gì bạn muốn ứng dụng của bạn hoàn thành.
-</p>
-
-<p class="note">
-  <strong>Lưu ý:</strong> Một{@link android.content.BroadcastReceiver} có đăng ký
-  {@link android.content.Context#registerReceiver Context.registerReceiver()}
-  tiếp tục nhận các truyền phát này trong khi ứng dụng đang ở tiền cảnh.
-</p>
-
-<h3 id="sched-jobs">
-  Lên lịch Tác vụ Mạng trên Kết nối Không đo lưu lượng
-</h3>
-
-<p>
-  Khi sử dụng lớp{@link android.app.job.JobInfo.Builder JobInfo.Builder}
-  để xây dựng đối tượng {@link android.app.job.JobInfo} của bạn, hãy áp dụng phương thức {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} và chuyển {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} dưới dạng một tham số tác vụ. Đoạn mã mẫu sau
-  lên lịch một dịch vụ để chạy khi thiết bị kết nối với một mạng
-  không đo lưu lượng và đang sạc:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  Khi các điều kiện cho tác vụ của bạn đã được đáp ứng, ứng dụng của bạn sẽ nhận được lệnh gọi lại để chạy
-  phương thức{@link android.app.job.JobService#onStartJob onStartJob()}trong
-  {@code JobService.class} được chỉ định. Để xem thêm các ví dụ về triển khai {@link
-  android.app.job.JobScheduler} , hãy xem <a href="{@docRoot}samples/JobScheduler/index.html">ứng dụng mẫu JobScheduler</a>.
-</p>
-
-<p>
-  Các ứng dụng sử dụng dịch vụ GMSCore, và nhắm đến Android 5.0 (API mức 21)
-  hoặc thấp hơn, có thể sử dụng <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> và quy định {@code Task.NETWORK_STATE_UNMETERED}.
-</p>
-
-<h3 id="monitor-conn">
-  Theo dõi Kết nối Mạng Trong khi Ứng dụng đang Chạy
-</h3>
-
-<p>
-  Các ứng dụng đang chạy ở tiền cảnh vẫn có thể theo dõi {@code
-  CONNECTIVITY_CHANGE} bằng một{@link
-  android.content.BroadcastReceiver} đã đăng ký. Tuy nhiên, API {@link
-  android.net.ConnectivityManager} cung cấp phương thức yêu cầu lệnh gọi lại hiệu quả hơn
-  chỉ khi đáp ứng được các điều kiện được chỉ định.
-</p>
-
-<p>
-  Các đối tượng {@link android.net.NetworkRequest} định nghĩa các tham số của
-  lệnh gọi lại mạng xét về  {@link android.net.NetworkCapabilities}. Bạn
-  tạo các đối tượng {@link android.net.NetworkRequest} bằng lớp {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder}. {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
-  rồi chuyển đối tượng{@link android.net.NetworkRequest} sang hệ thống. Khi
-  đáp ứng được các điều kiện mạng, ứng dụng nhận lệnh gọi lại để thực thi phương thức
-  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} như được định nghĩa trong lớp {@link
-  android.net.ConnectivityManager.NetworkCallback} của nó.
-</p>
-
-<p>
-  Ứng dụng tiếp tục nhận lệnh gọi lại cho đến khi ứng dụng tồn tại hoặc nó gọi
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()}.
-</p>
-
-<h2 id="media-broadcasts">
-  Các hạn chế về NEW_PICTURE và NEW_VIDEO
-</h2>
-
-<p>
-  Trong N Developer Preview, ứng dụng không thể gửi hoặc nhận các truyền phát {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} hoặc {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO}. Hạn chế này giúp
-  loại bỏ các tác động về hiệu suất và trải nghiệm của người dùng khi một số ứng dụng phải
-  thức dậy để xử lý một ảnh hoặc video mới. N Developer Preview
-  mở rộng {@link android.app.job.JobInfo} và {@link
-  android.app.job.JobParameters} để cung cấp một giải pháp thay thế.
-</p>
-
-<h3 id="new-jobinfo">
-  Các phương thức JobInfo Mới
-</h3>
-
-<p>
-  Để kích hoạt tác vụ khi thay đổi URI nội dung, N Developer Preview sẽ mở rộng
-  API{@link android.app.job.JobInfo} bằng các phương thức sau:
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    Gói gọn các tham số yêu cầu để kích hoạt tác vụ khi thay đổi URI nội dung.
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    Chuyển một đối tượng {@code TriggerContentUri} đến {@link
-    android.app.job.JobInfo}. Một {@link android.database.ContentObserver}
-    sẽ theo dõi URI nội dung được gói gọn. Nếu có nhiều đối tượng {@code
-    TriggerContentUri} được liên kết với một tác vụ, hệ thống sẽ cung cấp
-    lệnh gọi lại ngay cả khi hệ thống báo cáo có sự thay đổi chỉ ở trong một trong những URI nội dung.
-  </dd>
-
-  <dd>
-    Thêm cờ {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} để
-    kích hoạt tác vụ nếu bất kỳ kế nhiệm nào của URI đã cho thay đổi. Cờ này
-    tương ứng với tham số {@code notifyForDescendants} đã chuyển đến {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()}.
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>Lưu ý:</strong> {@code TriggerContentUri()} không thể được sử dụng
-  kết hợp với {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} hoặc {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()}. Để tiếp tục theo dõi các thay đổi nội dung, hãy lên lịch một
-  {@link android.app.job.JobInfo} mới trước khi {@link
-  android.app.job.JobService} của ứng dụng hoàn thành xử lý lệnh gọi lại gần đây nhất.
-</p>
-
-<p>
-  Đoạn mã mẫu sau lên lịch kích hoạt một tác vụ khi hệ thống báo cáo
-  có sự thay đổi về URI nội dung, {@code MEDIA_URI}:
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MEDIA_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  Khi hệ thống báo cáo có sự thay đổi trong (các) URI nội dung được chỉ định, ứng dụng của bạn
-  sẽ nhận được lệnh gọi lại và một đối tượng {@link android.app.job.JobParameters} được chuyển sang
-  phương thức {@link android.app.job.JobService#onStartJob onStartJob()}
-  trong {@code MediaContentJob.class}.
-</p>
-
-<h3 id="new-jobparam">
-  Các phương thức JobParameter Mới
-</h3>
-
-<p>
-  N Developer Preview cũng mở rộng {@link android.app.job.JobParameters} để
-  cho phép ứng dụng của bạn nhận thông tin hữu ích về những gì thẩm quyền nội dung
-  và các URI đã kích hoạt tác vụ:
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    Trả về mảng URI đã kích hoạt tác vụ đó. Kết quả trả về có thể bằng {@code
-    null} nếu không có URI nào kích hoạt  tác vụ (ví dụ như, tác vụ đã được
-    kích hoạt do thời hạn hoặc lý do khác), hoặc số các URI
-    bị thay đổi nhiều hơn 50.
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    Trả về mảng xâu thẩm quyền nội dung đã kích hoạt tác vụ đó.
-    Nếu mảng được trả về không phải {@code null}, hãy dùng {@code getTriggeredContentUris()}
-    để truy xuất chi tiết về URI nào đã thay đổi.
-  </dd>
-</dl>
-
-<p>
-  Mã mẫu sau sẽ ghi đè lên phương thức {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} và
-  và ghi lại các thẩm quyền nội dung và URI đã kích hoạt tác vụ.
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  Tối ưu hóa thêm Ứng dụng của bạn
-</h2>
-
-<p>
-  Tối ưu hóa ứng dụng của bạn để chạy trên các thiết bị có bộ nhớ ít, hoặc đang trong điều kiện
-  bộ nhớ ít có thể cải thiện hiệu suất và trải nghiệm của người dùng. Loại bỏ
-  các thành phần phụ thuộc trên các dịch vụ chạy ngầm và bộ thu truyền phát không biểu thị đã đăng ký tĩnh
-  có thể giúp ứng dụng của bạn chạy tốt hơn trên các thiết bị như vậy. Mặc dù
-  N Developer Preview thực hiện các bước để giảm bớt một vài trong số các vấn đề này, nhưng chúng tôi
-  khuyến nghị bạn nên tối ưu ứng dụng của bạn để chạy hoàn toàn không cần sử dụng
-  các tiến trình chạy ngầm này.
-</p>
-
-<p>
-  N Developer Preview giới thiệu một số lệnh <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> bổ sung mà
-  bạn có thể sử dụng để kiểm thử hành vi của ứng dụng bằng các tiến trình chạy ngầm đã bị vô hiệu hóa đó:
-</p>
-
-<ul>
-  <li>Để mô phỏng các điều kiện trong đó các truyền phát không biểu thị và dịch vụ chạy ngầm
-  không có sẵn, hãy nhập lệnh sau:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>Để kích hoạt lại các truyền phát không biểu thị và dịch vụ chạy ngầm, hãy nhập
-  lệnh sau:
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
\ No newline at end of file
diff --git a/docs/html-intl/intl/vi/preview/features/icu4j-framework.jd b/docs/html-intl/intl/vi/preview/features/icu4j-framework.jd
deleted file mode 100644
index ffb5799..0000000
--- a/docs/html-intl/intl/vi/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,160 +0,0 @@
-page.title=API Khuôn khổ Android ICU4J
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Trong tài liệu này:</h2>
-<ol>
-    <li><a href="#relation">Liên quan đến ICU4J</a></li>
-    <li><a href="#migration">Chuyển nhập từ ICU4J sang API android.icu</a></li>
-    <li><a href="#licence">Cấp phép</a></li>
-</ol>
-
-<h2>Xem thêm</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">Tài liệu cho ICU4J</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">Các tiêu chuẩn mới nhất được ICU4J
-   hỗ trợ</a>
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J là bộ thư viện Java mã nguồn mở được sử dụng rộng rãi để cung cấp hỗ trợ Unicode
-  và toàn cầu hóa cho các ứng dụng phần mềm. Android N
-  cung cấp một tập nhỏ các API ICU4J trong khuôn khổ Android cho các nhà phát triển ứng dụng
-   sử dụng trong gói {@code android.icu}. Các API này sử dụng
-   dữ liệu bản địa hóa có trong thiết bị. Do đó, bạn có thể giảm kích thước tệp APK
-   bằng cách không biên dịch các thư viện ICU4J vào tệp APK; thay vào đó bạn có thể
-  gọi chúng trong khuôn khổ một cách đơn giản. (Trong trường hợp này, bạn có thể muốn cung cấp
-   <a href="{@docRoot}google/play/publishing/multiple-apks.html">nhiều phiên bản
-   tệp APK</a> để những người dùng chạy phiên bản Android thấp hơn Android N
-  có thể tải phiên bản ứng dụng có chứa các thư viện ICU4J.)
-</p>
-
-<p>
-  Tài liệu này sẽ bắt đầu bằng việc cung cấp thông tin cơ bản về các mức Android API
-  tối thiểu cần để hỗ trợ các thư viện này. Sau đó tài liệu sẽ giải thích những gì
-   bạn cần để hiểu được công việc triển khai ICU4J liên quan cụ thể đến Android. Cuối cùng,
-    tài liệu sẽ cho bạn biết cách sử dụng các API ICU4J trong khuôn khổ Android.
-</p>
-
-<h2 id="relation">Liên quan đến ICU4J</h2>
-
-<p>
-  Android N cung cấp một tập nhỏ các API ICU4J thông qua
-  gói <code>android.icu</code> thay vì gói <code>com.ibm.icu</code>.
-Khuôn khổ Android có thể chọn không
-   cung cấp các API ICU4J vì nhiều lý do; ví dụ, Android N không cung cấp
-   một số API bị loại bỏ hoặc những API chưa được đội ngũ ICU công bố là
-   bản ổn định. Vì nhóm ICU sẽ loại bỏ các API này trong tương lai do đó Android cũng sẽ đánh dấu
-   chúng là bị loại bỏ nhưng vẫn tiếp tục thêm vào.
-</p>
-
-<p class="table-caption"><strong>Bảng 1.</strong> Các phiên bản ICU và CLDR được sử dụng
-  trong Android N.</p>
-<table>
-<tr>
-<th>Mức Android API</th>
-<th>Phiên bản ICU</th>
-<th>Phiên bản CLDR</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>Sau đây là một vài lưu ý quan trọng:</p>
-
-<ul>
-<li>Các API khuôn khổ Android ICU4J không có tất cả các API của ICU4J.</li>
-<li>Các nhà phát triển NDK cần biết rằng ICU4C Android không được hỗ trợ.</li>
-<li>Các API trong khuôn khổ Android không thay thế hỗ trợ của Android cho
-<a href="{@docRoot}guide/topics/resources/localization.html">việc bản địa hóa bằng
-các tài nguyên</a>.</li>
-</ul>
-
-<h2 id="migration">Chuyển nhập sang gói android.icu từ com.ibm.icu</h2>
-
-<p>
-  Nếu bạn đã sử dụng các API ICU4J trong ứng dụng và
-   các API <code>android.icu</code> đáp ứng yêu cầu của bạn thì việc chuyển nhập sang
-  các API của khuôn khổ đòi hỏi bạn phải thay đổi thành phần nhập vào của Java
-  từ <code>com.ibm.icu</code> sang <code>android.icu</code>. Khi đó bạn có thể
-  xóa các tệp ICU4J của bạn khỏi tệp APK.
-</p>
-
-<p class="note">
-  <b>Lưu ý</b>: Các API khuôn khổ ICU4J sử dụng không gian tên {@code android.icu}
-  thay vì {@code com.ibm.icu}. Điều này là để tránh xung đột
-  không gian tên trong các tệp APK có chứa các thư viện {@code com.ibm.icu} của riêng chúng.
-</p>
-
-<h3 id="migrate-from-android">
-  Chuyển nhập sang các API android.icu từ các API Android SDK khác
-</h3>
-
-<p>
-  Một số lớp trong gói <code>java</code> và<code>android</code> có
-  các lớp tương ứng với các lớp trong ICU4J. Tuy nhiên, ICU4J thường cung cấp hỗ trợ
-   rộng hơn cho các tiêu chuẩn và ngôn ngữ.
-</p>
-<p>Sau đây là một số ví dụ để giúp bạn bắt đầu:</p>
-<table>
-<tr>
-<th>Lớp</th>
-<th>Thay thế</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">Cấp phép</h2>
-
-<p>
-  ICU4J được phát hành theo giấy phép ICU. Hãy xem <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">Hướng dẫn sử dụng
-  ICU</a> để biết thêm chi tiết.
-</p>
diff --git a/docs/html-intl/intl/vi/preview/features/multilingual-support.jd b/docs/html-intl/intl/vi/preview/features/multilingual-support.jd
deleted file mode 100644
index 94a7127..0000000
--- a/docs/html-intl/intl/vi/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,217 +0,0 @@
-page.title=Ngôn ngữ và Bản địa
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Trong tài liệu này:</h2>
-<ol>
-	  <li><a href="#preN">Thử thách phân giải tài nguyên ngôn ngữ</a></li>
-    <li><a href="#postN">Các cải tiến đối với Chiến lược phân giải tài nguyên</a></li>
-    <li><a href="#design">Thiết kế ứng dụng để hỗ trợ các bản địa
-      bổ sung</a></li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N cung cấp hỗ trợ cải tiến cho người dùng sử dụng nhiều ngôn ngữ,
-cho phép họ chọn nhiều bản địa trong phần cài đặt. Android N
-cung cấp khả năng này bằng cách mở rộng số lượng lớn các bản địa được hỗ trợ
-và thay đổi cách hệ thống phân giải tài nguyên. Phương thức phân giải tài nguyên
-mới hoạt động mạnh mẽ hơn và được thiết kế để tương thích với các tệp APK có sẵn. Tuy nhiên
-bạn cần kiểm tra thêm để phát hiện mọi hành vi không mong muốn. Ví dụ, bạn
-cần kiểm thử để đảm bảo rằng ứng dụng của mình sẽ thiết lập mặc định cho ngôn ngữ mong muốn. Ngoài ra,
-nếu ứng dụng của bạn hỗ trợ đa ngôn ngữ thì bạn cần đảm bảo rằng việc hỗ trợ này hoạt động như
-dự kiến. Cuối cùng, bạn cần cố gắng đảm bảo rằng ứng dụng sẽ xử lý tinh tế
-những ngôn ngữ mà bạn không có ý định thiết kế ứng dụng để hỗ trợ.</p>
-
-<p>Tài liệu này sẽ bắt đầu bằng việc giải thích về chiến lược phân giải tài nguyên trong phiên bản trước
-Android N. Tiếp theo, tài liệu sẽ mô tả chiến lược phân giải tài nguyên
-được cải tiến của Android N. Cuối cùng, tài liệu sẽ giải thích cách sử dụng
-số lượng các bản địa được mở rộng để hỗ trợ thêm nhiều người dùng đa ngữ.</p>
-
-<h2 id="preN">Thử thách phân giải tài nguyên ngôn ngữ</h2>
-
-<p>Trước Android N, không phải lúc nào Android cũng có thể so khớp
-thành công ứng dụng với các bản địa của hệ thống. Ví dụ, giả sử ngôn ngữ mặc định của ứng dụng của bạn
-  là Tiếng Anh (Mỹ) nhưng ứng dụng cũng có các xâu văn bản Tiếng Tây Ban Nha được bản địa hóa trong các tệp tài nguyên {@code es_ES}
-.</p>
-<p>Khi mã nguồn Java tham chiếu đến các xâu đó thì nó sẽ phân giải các ngôn ngữ của xâu như
-sau:</p>
-<ul>
-<li>Nếu một thiết bị được đặt thành {@code es_MX} (Tiếng Tây Ban Nha-Mêxicô) thì Android sẽ tải
-xâu từ các tệp tài nguyên {@code es_ES}.</li>
-<li>Nếu thiết bị được đặt thành {@code en_AU} thì Android sẽ trả về {@code
-en_US}. Hệ thống cũng sẽ đặt mặc định thành {@code en_US} nếu người dùng chọn một
-ngôn ngữ mà ứng dụng không hỗ trợ chút nào, ví dụ như Tiếng Pháp.</li>
-</ul>
-
-
-<p>Các vấn đề phân giải này phát sinh bởi vì hệ thống sẽ gỡ mã quốc gia
- khỏi bản địa nếu nó không tìm thấy sự trùng khớp tuyệt đối.  Ví dụ:</p>
-<p class="table-caption" id="t-resource-res">
-<strong>Bảng 1.</strong> Phân giải tài nguyên không có trùng khớp bản địa tuyệt đối.
-</p>
-<table>
-<tbody>
-<tr>
-<th>Cài đặt Người dùng</th>
-<th>Tài nguyên Ứng dụng</th>
-<th>Phân giải tài nguyên</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-mặc định (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-Thử fr_CH =&gt; Không được<br>
-Thử fr =&gt; Không được<br>
-Sử dụng mặc định (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>Trong ví dụ này, hệ thống hiển thị các xâu Tiếng Anh mà không
-xác định được liệu người dùng có biết Tiếng Anh hay không. Đây là hành vi khá phổ biến
-ngày nay. Android N cần phải giảm bớt đáng kể tần suất
-của những kết quả như vậy.</p>
-
-<h2 id="postN">Các cải tiến đối với Chiến lược phân giải tài nguyên</h2>
-<p>Android N mang đến cách thức phân giải tài nguyên mạnh mẽ hơn, và
-tìm các giải pháp thay thế hiệu quả hơn một cách tự động. Tuy nhiên, để tăng tốc việc phân giải và nâng cao
-khả năng bảo trì, bạn cần lưu trữ các tài nguyên trong những nhánh ngôn ngữ mẹ phổ biến nhất.
- Ví dụ, nếu trước đây lưu tài nguyên Tiếng Tây Ban Nha trong thư mục {@code es-US}
- thì hãy chuyển chúng vào trong thư mục {@code es-419}, nơi chứa Tiếng Tây Ban Nha Mỹ La-tinh.
- Tương tự, nếu bạn có các xâu tài nguyên trong một thư mục có tên {@code en-GB} thì hãy đổi tên
- thư mục đó thành {@code en-001} (Tiếng Anh quốc tế) bởi vì nhánh mẹ
-phổ biến nhất cho chuỗi <code>en-GB</code> là {@code en-001}.
- Các ví dụ sau sẽ giải thích tại sao các thực hành này sẽ nâng cao hiệu năng và
-độ ổn định của việc phân giải tài nguyên.</p>
-
-<h3>Các ví dụ về phân giải tài nguyên</h3>
-
-<p>Với Android N, trường hợp được mô tả trong <strong>Bảng 1</strong> được phân giải
-theo cách khác:</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>Bảng 2.</strong> Một chiến lược phân giải cải tiến khi không có
-trùng khớp bản địa tuyệt đối.</p>
-<table>
-<tr>
-<th>Cài đặt Người dùng</th>
-<th>Tài nguyên Ứng dụng</th>
-<th>Phân giải tài nguyên</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-mặc định (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-Thử fr_CH =&gt; Không được<br>
-Thử fr =&gt; Không được<br>
-Thử nhánh con của fr =&gt; fr_FR<br>
-Sử dụng fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>Bây giờ thì người dùng sẽ nhận được tài nguyên Tiếng Pháp thay vì Tiếng Anh. Ví dụ này cũng cho thấy
- lý do bạn nên lưu trữ các xâu Tiếng Pháp trong {@code fr} thay vì {@code fr_FR}
- cho Android N. Phương pháp ở đây là ghép nhánh ngôn ngữ mẹ gần nhất,
- giúp cho việc phân giải nhanh hơn và dễ dự đoán hơn.</p>
-
-<p>Ngoài lôgic phân giải được cải tiến này, Android giờ đây cung cấp thêm nhiều
-ngôn ngữ cho người dùng lựa chọn. Chúng ta hãy thử lại ví dụ trên với Tiếng Ý
-  được xác định là một ngôn ngữ người dùng bổ sung nhưng không được ứng dụng hỗ trợ cho Tiếng Pháp.  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>Bảng 3.</strong> Phân giải tài nguyên khi ứng dụng chỉ khớp
-với cài đặt bản địa được ưu tiên thứ hai của người dùng.</p>
-<table>
-<tr>
-<th>Cài đặt Người dùng</th>
-<th>Tài nguyên Ứng dụng</th>
-<th>Phân giải tài nguyên</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-mặc định (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-Thử fr_CH =&gt; Không được<br>
-Thử fr =&gt; Không được<br>
-Thử nhánh con của fr =&gt; Không được<br>
-Thử it_CH =&gt; Không được<br>
-Thử it =&gt; Không được<br>
-Thử nhánh con của it =&gt; it_IT<br>
-Sử dụng it_IT
-</td>
-
-</tr>
-
-</table>
-<p>Người dùng vẫn nhận được ngôn ngữ họ biết mặc dù ứng dụng không
-hỗ trợ Tiếng Pháp.</p>
-
-
-<h2 id="design">Thiết kế ứng dụng để hỗ trợ các bản địa bổ sung</h2>
-<h3>API LocaleList</h3>
-
-<p>Android N bổ sung thêm một API {@code LocaleList.GetDefault()}
- mới cho phép các ứng dụng truy vấn trực tiếp danh sách các ngôn ngữ mà người dùng đã chỉ định. API này
-cho phép bạn tạo hành vi ứng dụng
-phức tạp hơn và hiển thị nội dung được tối ưu hóa tốt hơn. Ví dụ, Tìm kiếm
-  có thể hiển thị các kết quả bằng nhiều ngôn ngữ dựa trên cài đặt của người dùng.  Các ứng dụng trình duyệt
-  có thể tránh đề nghị dịch trang web sang một ngôn ngữ mà người dùng đó đã biết,
- và các ứng dụng bàn phím có thể tự động bật tất cả các bố trí phù hợp. </p>
-
-<h3>Bộ định dạng</h3>
-
-<p>Tính tới Android 6.0 (API mức 23), Android 6.0 chỉ hỗ trợ một hoặc hai bản địa
-cho nhiều ngôn ngữ phổ biến
-(en, es, ar, fr, ru). Bởi vì chỉ có một vài biến thể của từng ngôn ngữ,
-các ứng dụng không gặp vấn đề gì với việc lưu trữ một số chữ số và ngày tháng dưới dạng xâu được chèn trực tiếp khi viết mã
-trong các tệp tài nguyên.  Tuy nhiên, với tập hợp mở rộng các bản địa được hỗ trợ bởi Android,
-có thể có
-nhiều khác biệt lớn về các định dạng ngày tháng, thời gian, tiền tệ và thông tin
-tương tự ngay cả trong một bản địa. Chèn trực tiếp các định dạng có thể khiến
-người dùng cuối bối rối.  Do đó, khi phát triển cho Android N
-hãy đảm bảo sử dụng các bộ định dạng thay vì các xâu chữ số và ngày tháng được chèn trực tiếp khi viết mã.</p>
-
-<p>Một ví dụ điển hình là Tiếng Ả-rập với được Android N hỗ trợ mở rộng từ
-một {@code ar_EG} tới 27 bản địa Tiếng Ả-rập. Các bản địa này có thể chia sẻ hầu hết các tài nguyên,
-nhưng một số bản địa ưu tiên chữ số ASCII trong khi những bản địa khác lại ưu tiên con số truyền thống. Ví dụ,
-khi bạn muốn soạn một câu có biến bằng số, như
-"Choose a 4 digit pin" thì bạn hãy sử dụng bộ định dạng như sau:</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/vi/preview/features/notification-updates.jd b/docs/html-intl/intl/vi/preview/features/notification-updates.jd
deleted file mode 100644
index f60646a..0000000
--- a/docs/html-intl/intl/vi/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,328 +0,0 @@
-page.title=Thông báo
-page.tags=notifications
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>Tài liệu này gồm có</h2>
-<ol>
-  <li><a href="#direct">Trả lời Trực tiếp</a></li>
-  <li><a href="#bundle">Thông báo Gộp</a></li>
-  <li><a href="#custom">Dạng xem Tùy chỉnh</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N giới thiệu một số API mới cho phép ứng dụng đăng
-các thông báo có khả năng hiển thị và tương tác cao.</p>
-
-<p>Android N mở rộng API thông báo {@link android.support.v4.app.RemoteInput}
-hiện có để hỗ trợ trả lời giữa dòng trên thiết bị cầm tay. Tính năng này cho phép người dùng
- phản hồi nhanh chóng từ khu vực hiển thị thông báo mà không cần truy cập ứng dụng của bạn.</p>
-
-<p>
-  Android N cũng cho phép bạn gộp các thông báo tương tự nhau để
-  xuất hiện dưới dạng một thông báo đơn lẻ. Để điều này có thể xảy ra, Android N sử dụng phương thức {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} hiện có. Người dùng có thể mở rộng mỗi
-  thông báo, và thực hiện các hành động như trả lời và bỏ qua trên mỗi
-  thông báo, từng thông báo một từ khu vực hiển thị thông báo.
-</p>
-
-<p>Cuối cùng, Android N cũng thêm các API mới cho phép bạn tận dụng các trang trí
-của hệ thống trong các dạng xem thông báo tùy chỉnh của ứng dụng của bạn. Các API này giúp
-đảm bảo rằng dạng xem thông báo có chung một cách trình bày nhất quán
-với các mẫu tiêu chuẩn.</p>
-
-<p>Tài liệu này nêu bật một số các thay đổi chính mà bạn cần cân nhắc
- khi sử dụng các tính năng thông báo mới trong ứng dụng của mình.</p>
-
-<h2 id="direct">Trả lời Trực tiếp</h2>
-
-<p>Với tính năng Trả lời Trực tiếp trong Android N, người dùng có thể
-phản hồi lại tin nhắn văn bản hoặc cập nhật danh sách tác vụ trực tiếp trong giao diện
-của thông báo. Trên thiết bị cầm tay, hành động trả lời giữa dòng xuất hiện dưới dạng một nút bổ sung
- được gắn kèm với thông báo đó. Khi người dùng trả lời qua bàn phím, hệ thống sẽ đính kèm
-  phản hồi bằng văn bản với ý định
-    bạn đã quy định cho hành động thông báo và gửi ý định đến ứng dụng cầm tay
-     của bạn.
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>Hình 1.</strong> Android N thêm nút hành động <strong>Reply</strong>
-.
-</p>
-
-<h3>Thêm các hành động trả lời giữa dòng</h3>
-
-<p>Để tạo một hành động thông báo hỗ trợ trả lời trực tiếp:
-</p>
-
-<ol>
-<li>Tạo thực thể{@link android.support.v4.app.RemoteInput.Builder}
-  mà bạn có thể thêm vào hành động
-thông báo của bạn. Hàm dựng của lớp này sẽ chấp nhận xâu mà hệ thống sử dụng làm khóa
- cho nhập liệu văn bản. Sau đó, ứng dụng cầm tay của bạn sử dụng khóa đó để truy xuất văn bản
-  nhập liệu.
-
-<pre>
-// Key for the string that's delivered in the action's intent
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>Đính kèm đối tượng {@link android.support.v4.app.RemoteInput}
- với một hành động bằng cách sử dụng <code>addRemoteInput()</code>.
-
-<pre>
-// Create the reply action and add the remote input
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>Áp dụng hành động cho thông báo và phát hành thông báo.
-
-<pre>
-// Build the notification and add the action
-Notification notification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, notification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> Hệ thống sẽ nhắc người dùng nhập liệu một phản hồi khi chúng kích hoạt
-hành động thông báo. </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Hình 2.</strong> Người dùng nhập liệu văn bản từ khu vực hiển thị thông báo.
-</p>
-
-<h3>Truy xuất mục nhập của người dùng từ trả lời giữa dòng</h3>
-
-<p>Để nhận mục nhập của người dùng từ giao diện thông báo đến hoạt động bạn
-đã khai báo trong ý định của hành động trả lời:</p>
-<ol>
-<li> Gọi {@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()} bằng cách chuyển ý định của hành động thông báo dưới dạng
- tham số đầu vào. Phương thức này trả về {@link android.os.Bundle}
- có chứa phản hồi văn bản.
-</li>
-
-<pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-
-<li>Truy vấn gói bằng cách sử dụng khóa kết quả (đã cung cấp cho hàm dựng {@link
-  android.support.v4.app.RemoteInput.Builder}).
-</li>
-</ol>
-
-<p>Đoạn mã sau minh họa cách thức một phương thức truy xuất văn bản đầu vào
-từ một gói:</p>
-
-<pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-            return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-            }
-    return null;
- }
-</pre>
-
-<p>Ứng dụng có thể áp dụng lô-gic để quyết định hành động nào nên lấy trên văn bản
-được truy xuất.
-Đối với các ứng dụng tương tác (chẳng hạn như trò chuyện), hãy cung cấp thêm ngữ cảnh trong chính thông báo
- (ví dụ như nhiều dòng lịch sử trò chuyện, gồm có các tin nhắn của riêng người dùng)
-  để người dùng có thể phản hồi phù hợp.
-Khi người dùng phản hồi qua {@link android.support.v4.app.RemoteInput},
- hãy bao gồm văn bản trong lịch sử trả lời bằng phương thức {@code setRemoteInputHistory()}
-.</p>
-
-<h2 id="bundle">Thông báo Gộp</h2>
-
-<p>Android N cung cấp cho các nhà phát triển một cách mới để hiển thị
- hàng đợi thông báo: <i>thông báo gộp</i>. Cách hiển thị này tương tự với tính năng
-  <a href="{@docRoot}training/wearables/notifications/stacks.html">Ngăn xếp
-  Thông báo</a> có trong Android Wear. Ví dụ, nếu ứng dụng của bạn tạo thông báo
-  cho tin nhắn nhận được, khi có nhiều hơn một tin nhắn nhận được, hãy gói
- các thông báo lại với nhau thành một nhóm đơn lẻ. Bạn có thể
- sử dụng phương thức {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} hiện có để gói các thông báo tương tự.</p>
-
-<p>
-  Nhóm thông báo sẽ quy định phân cấp trên các thông báo bao gồm nó.
-  Ở trên cùng của phân cấp là thông báo mẹ hiển thị tóm tắt
-  thông tin cho nhóm đó. Người dùng có thể mở rộng
-  nhóm thông báo tăng dần lên, và hệ thống sẽ hiển thị thêm thông tin khi
-  người dùng truy sâu hơn. Khi người dùng mở rộng gói này, hệ thống sẽ lộ ra thêm
-  thông tin cho tất cả các thông báo con của gói, khi người dùng
-  mở rộng một trong những thông báo đó, hệ thống sẽ lộ ra toàn bộ nội dung của nó.
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>Hình 3.</strong> Người dùng có thể mở rộng nhóm
-  thông báo tăng dần lên.
-</p>
-
-<p>Để tìm hiểu cách thêm thông báo vào một nhóm, xem
-<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">Thêm
-Mỗi Thông báo vào một Nhóm</a>.</p>
-
-
-<h3 id="best-practices">Thực hành tốt nhất cho thông báo gộp</h3>
-<p>Mục này sẽ cung cấp hướng dẫn về việc khi nào sử dụng nhóm thông báo thay vì
- các thông báo{@link android.app.Notification.InboxStyle InboxStyle}
-có sẵn trong các phiên bản cũ hơn của
-nền tảng Android.</p>
-
-<h3>Khi nào nên sử dụng thông báo gộp</h3>
-
-<p>Bạn nên sử dụng các nhóm thông báo chỉ khi tất cả các điều kiện sau là
-đúng đối với trường hợp sử dụng của bạn:</p>
-
-<ul>
-  <li>Thông báo con là loại thông báo đầy đủ và có thể được hiển thị
-   riêng rẽ mà không cần tóm tắt nhóm.</li>
-  <li>Sẽ có lợi khi làm nổi lên các thông báo con một cách riêng rẽ. Ví
-dụ:
-  </li>
-  <ul>
-    <li>Các thông báo này có thể hành động được, bằng các hành động cụ thể cho mỗi thông báo con.</li>
-    <li>Có nhiều thông tin hơn đối với thông báo con mà người dùng sẽ muốn đọc.</li>
-  </ul>
-</ul>
-
-<p>Các ví dụ về các trường hợp sử dụng tốt nhóm thông báo bao gồm: ứng dụng nhắn tin
-hiển thị danh sách các tin nhắn đến, hoặc ứng dụng email hiển thị danh sách
-các email đã nhận được.</p>
-
-<p>
-Ví dụ về các trường hợp trong đó một thông báo đơn lẻ được ưu tiên
- bao gồm tin nhắn riêng từ một người đơn lẻ, hoặc biểu diễn danh sách
- các mục văn bản một hàng. Bạn có thể sử dụng
-({@link android.app.Notification.InboxStyle InboxStyle} hoặc
-{@link android.app.Notification.BigTextStyle BigTextStyle}) để hoàn thành
-việc này.
-</p>
-
-<h3 id ="post">Hiển thị Thông báo gộp</h3>
-
-<p>
-  Ứng dụng sẽ luôn đăng tóm tắt nhóm, ngay cả khi nhóm chỉ chứa
-  một thông báo con duy nhất. Hệ thống này sẽ ngăn chặn tóm tắt và hiển thị trực tiếp
-  thông báo con nếu nó chỉ chứa một thông báo duy nhất. Điều này đảm bảo
-  rằng hệ thống có thể cung cấp một trải nghiệm nhất quán khi người dùng trượt nhanh khỏi
-  thông báo con của nhóm.
-</p>
-
-<p class="note">
-  <strong>Lưu ý:</strong> Phiên bản Android N này không
-  ngăn chặn tóm tắt cho nhóm thông báo có chứa một thông báo con duy nhất. Chức năng
-  này sẽ được thêm vào trong phiên bản sau của Android N.
-</p>
-
-<h3>Thông báo lướt nhanh</h3>
-
-<p>Trong khi hệ thống thường hiển thị các thông báo con dưới dạng một nhóm, bạn có thể đặt
- chúng tạm thời hiển thị dưới dạng
- <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">
- thông báo cảnh báo</a>. Tính năng này đặc biệt hữu ích bởi vì nó cho phép
-  truy cập ngay lập tức thông báo con gần đây nhất và các hành động liên kết với thông báo con đó.
-</p>
-
-
-<h3>Tính tương thích ngược</h3>
-
-<p>
-  Cả nhóm thông báo và đầu vào từ xa đều là một phần của API {@link
-  android.app.Notification} vì Android 5.0 (API mức 21) hỗ trợ
-  các thiết bị Android Wear. Nếu bạn đã dựng các thông báo bằng các API này,
-  hành động duy nhất bạn cần phải thực hiện là xác minh rằng ứng dụng có hành vi tương ứng
-  với các hướng dẫn đã mô tả ở trên, và cân nhắc việc triển khai {@code
-  setRemoteInputHistory()}.
-</p>
-
-<p>
-  Để hỗ trợ tính tương thích ngược, các API giống vậy sẽ được cung cấp cho
-  lớp {@link android.support.v4.app.NotificationCompat}
-  của thư viện hỗ trợ, cho phép bạn dựng các thông báo hoạt động trên các phiên bản
-  Android cũ hơn. Trên máy tính bảng và thiết bị cầm tay, người dùng chỉ nhìn thấy thông báo tóm tắt,
-  vì vậy ứng dụng vẫn có kiểu hòm thư hoặc thông báo tương tự
-  biểu diễn cho toàn bộ nội dung thông tin của nhóm. Vì các thiết bị Android
-  Wear cho phép người dùng xem các thông báo con thậm chí trên
-  các mức nền tảng thấp hơn, bạn nên dựng các thông báo con dù cho mức API
-  là mức nào.
-</p>
-
-<h2 id="custom"> Dạng xem Tùy chỉnh</h2>
-<p>Bắt đầu từ Android N, bạn có thể tùy chỉnh dạng xem và
-vẫn có các trang trí hệ thống như tiêu đề thông báo, hành động, và
-các bố trí mở rộng được.</p>
-
-<p>Để kích hoạt khả năng này, Android N thêm các API sau để tạo kiểu cho dạng xem tùy chỉnh
-  của bạn:</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> Thông báo kiểu khác với thông báo
-media.</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> Thông báo media tạo kiểu.</dd>
-</dl>
-
-<p>Để sử dụng API mới này, hãy gọi phương thức {@code setStyle()}, chuyển nó sang
-kiểu dạng xem tùy chỉnh mong muốn.</p>
-
-<p>Đoạn mã này cho biết cách dựng đối tượng thông báo tùy chỉnh bằng phương thức
-{@code DecoratedCustomViewStyle()}.</p>
-
-<pre>
-Notification noti = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
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..5619de8 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,78 +1,63 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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>
           加入开发者社区
@@ -82,26 +67,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>
-        报告问题
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        查阅版本说明
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        加入开发者社区</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">最新</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +78,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/distribute/tools/promote/badges.jd b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
index 1c82161..cc1234d 100644
--- a/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
+++ b/docs/html-intl/intl/zh-cn/distribute/tools/promote/badges.jd
@@ -35,7 +35,7 @@
   vertical-align: middle;
   margin: 0 5px 0 0;
 }
-#jd-content div.button-row img {
+#body-content div.button-row img {
   margin: 0;
   vertical-align: middle;
 }
diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
index ca3a84b..c1a5d6f 100644
--- a/docs/html-intl/intl/zh-cn/index.jd
+++ b/docs/html-intl/intl/zh-cn/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/zh-cn/preview/download_mp2.jd b/docs/html-intl/intl/zh-cn/preview/download_mp2.jd
deleted file mode 100644
index ba5249a..0000000
--- a/docs/html-intl/intl/zh-cn/preview/download_mp2.jd
+++ /dev/null
@@ -1,359 +0,0 @@
-page.title=下载
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">在下载和安装预览版 Android SDK 的组件之前,您必须同意下列条款和条件。
-</p>
-
-    <h2 class="norule">条款和条件</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-本协议是 Android SDK 预览版许可协议(以下称为“许可协议”)。
-
-1. 简介
-
-1.1 Android SDK 预览版(在本许可协议中简称为“预览版”,具体包括 Android 系统文件、封装 API 以及预览版库文件(若可用))依据本许可协议的条款授权您使用。本许可协议在您与 Google 之间就您对“预览版”的使用构成具有法律约束力的合约。
-
-1.2 “Android”是指以 Android 开源项目(项目网址为 http://source.android.com/,其内容会不时更新)名义提供、面向设备的 Android 软件栈。
-
-1.3 “Google”是指 Google Inc.,是一家特拉华州公司,主要营业地位于:1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。
-
-2. 接受许可协议
-
-2.1 要使用“预览版”,您必须先同意本许可协议。如果您不接受本许可协议,则不得使用“预览版”。
-
-2.2 点击接受并/或使用“预览版”,即表示您特此同意本许可协议的条款。
-
-2.3 如果依照美国或其他国家/地区(包括您居住或您使用“预览版”所在的国家/地区)的法律,您被禁止获取“预览版”,则您不得使用“预览版”,也不得接受本许可协议。
-
-2.4 如果您将在贵公司或组织内部使用“预览版”,则您同意代表您的雇主或其他实体接受本许可协议的约束,并且您表示并保证您拥有完全的合法授权令您的雇主或上述实体受本许可协议的约束。如果您不具备必要的授权,则不得代表您的雇主或其他实体接受本许可协议或使用“预览版”。
-
-3. Google 预览版许可
-
-3.1 Google 依据本许可协议的条款授予您个人或在贵公司或组织内部有限使用“预览版”的免版税、不可转让、非独占性、不可再授权且可撤销的许可,其用途仅限开发在 Android 平台上运行的应用。
-
-3.2 您同意 Google 或第三方拥有“预览版”中存在或相关的全部合法权利、所有权和利益,包括“预览版”中存在的任何知识产权。“知识产权”是指根据专利法、版权法、商业机密法、商标法享有的任何及全部权利,以及其他任何及全部专有权利。Google 保留所有未明确授予您的权利。
-
-3.3 您不得将“预览版”用于本许可协议未明确允许的任何用途。您不得:(a) 对“预览版”或“预览版”的任何部分进行复制(备份用途除外)、修改、改编、再分发、反编译、逆向工程、反汇编或创建其衍生品;或 (b) 将“预览版”的任何部分加载到移动手持终端或除个人计算机之外的任何其他硬件设备上,将“预览版”的任何部分与其他软件合并,或者发行任何融入“预览版”某一部分的软件或设备。
-
-3.4 您同意您将不会进行任何可能引起或导致 Android 碎片化的行动,包括但不限于分发、参与创建或以任何方式推广从“预览版”衍生的软件开发工具包。
-
-3.5 对于依据开源软件许可授权的“预览版”组件,其使用、复制和分发仅受该开源软件许可条款的制约,不受本许可协议的约束。您同意在依照被授予的所有权利作为被许可方期间,在遵守此类开源软件许可协议方面始终保持良好的信誉,并避免进行任何可能导致终止、暂停或违反此类权利的行动。
-
-3.6 您同意 Google 所提供“预览版”的形式和性质可随时发生变更,而无需事先通知您,并且未来的“预览版”版本可能会与在之前的“预览版”版本上开发的应用不兼容。您同意 Google 可单方面决定在未事先通知您的情况下全面停止(永久性或暂时性)向您或用户提供“预览版”(或“预览版”内的任何功能)。
-
-3.7 本许可协议内没有任何条款授予您使用 Google 的任何商品名、商标、服务标志、徽标、域名或其他独特品牌特征的权利。
-
-3.8 您同意您不会移除、遮盖或篡改“预览版”上可能贴有或“预览版”内可能包含的任何专有权利声明(包括版权声明和商标声明)。
-
-4. 您对“预览版”的使用
-
-4.1 Google 同意本许可协议中的任何条款均未授予 Google 从您(或您的许可方)处获取您依照本许可协议使用“预览版”开发的任何软件应用中存在或与其相关的权利、所有权或利益,包括这些应用中存在的任何知识产权。
-
-4.2 您同意只出于 (a) 本许可协议和 (b) 相关管辖区域内任何适用法律、法规或公认惯例或准则(包括有关向美国或其他相关国家/地区出口数据或软件或从美国或其他相关国家/地区进口数据或软件的任何法律)所允许的目的而使用“预览版”和编写应用。
-
-4.3 您同意,如果您使用“预览版”开发应用,您将会保护用户的隐私权和合法权利。如果用户向您提供用户名、密码或其他登录信息或个人信息,您必须确保用户知晓这些信息将供您的应用使用,并且您必须为这些用户提供足以满足法律要求的隐私声明和保护。如果您的应用存储由用户提供的个人信息或敏感信息,其存储方式必须安全。如果用户向您提供 Google 帐户信息,您的应用只能在用户允许时出于用户所许可的有限目的使用该信息访问用户的 Google 帐户。
-
-4.4 您同意您不会利用“预览版”从事任何干扰、中断、损坏或以未经授权方式访问 Google 或任何第三方的服务器、网络或其他财产或服务的Activity(包括应用的开发或分发)。
-
-4.5 您同意您对通过 Android 和/或 Android 应用创建、传输或显示的任何数据、内容或资源以及您的行为所导致的后果(包括 Google 可能遭受的任何损失或损害)负全责(Google 在上述方面对您或任何第三方不承担任何责任)。
-
-4.6 您同意您为违反本许可协议、任何适用的第三方合约或服务条款或任何适用法律或法规下的义务以及任何上述违规行为所导致的后果(包括 Google 或任何第三方可能遭受的任何损失或损害)负全责(Google 在上述方面对您或任何第三方不承担任何责任)。
-
-4.7 “预览版”正在开发中,您的测试和反馈是开发过程的重要环节。使用“预览版”,即表示您承认某些功能仍在开发实现之中,您不应期望“预览版”具备稳定版本的全部功能。您同意不使用此“预览版”公开发布或发运任何应用,因为此“预览版”在 Android SDK 正式发行之后将不再受支持。
-
-5. 您的开发者凭据
-
-5.1 您同意,对于 Google 可能向您发放或可能由您自行选择的任何开发者凭据,您有责任保持其机密性,并且您对以您的开发者凭据名义开发的所有应用负全责。
-
-6. 隐私权和信息
-
-6.1 为持续创新和改进“预览版”,Google 可能会从软件收集某些使用统计数据,包括但不限于唯一标识符、关联的 IP 地址、软件的版本号以及有关软件使用了“预览版”中哪些工具和/或服务及其使用方式的信息。在收集任何上述信息之前,“预览版”都会通知您并征求您的同意。如果您拒绝同意,我们将不会收集这些信息。
-
-6.2 我们会对收集的数据进行汇总调查,以便改进“预览版”,并会按照 Google 的隐私政策(网址为 http://www.google.com/policies/privacy/)维护数据。
-
-7. 第三方应用
-
-7.1 如果您使用“预览版”运行由第三方开发或访问由第三方提供的数据、内容或资源的应用,您同意 Google 对这些应用、数据、内容或资源不承担任何责任。您理解,您通过上述第三方应用可能访问到的所有数据、内容或资源由其提供者负全责,Google 对您因使用或访问其中任何第三方应用、数据、内容或资源而遭受的任何损失或损害不承担任何责任。
-
-7.2 您应知晓,通过此类第三方应用提供给您的数据、内容和资源可能受提供商(或代表他们的其他人员或公司)所拥有的知识产权的保护。除非相关所有者明确给予许可,否则您不得修改、出租、租赁、借出、出售、分发这些数据、内容或资源(的全部或部分),或以其为基础创建衍生品。
-
-7.3 您承认您对上述第三方应用、数据、内容或资源的使用可能受到您与相关第三方之间单独订立的条款的制约。
-
-8. 使用 Google API
-
-8.1 Google API
-
-8.1.1 如果您使用任何 API 从 Google 检索数据,即表示您承认这些数据可能受到 Google 或这些数据提供方(或代表他们的其他人员或公司)拥有的知识产权的保护。您对任何上述 API 的使用可能受到附加服务条款的制约。除非相关服务条款允许,否则您不得修改、出租、租赁、借出、出售、分发这些数据(的全部或部分),或以其为基础创建衍生品。
-
-8.1.2 如果您使用任何 API 从 Google 检索用户数据,即表示您承认并同意您只有在征得用户明确同意时才会检索数据,并且只能在用户允许时出于用户许可的有限目的检索数据。
-
-9. 终止许可协议
-
-9.1 本许可协议将持续有效,直至您或 Google 按以下规定终止本协议。
-
-9.2 如果您想终止本许可协议,可通过停止使用“预览版”以及任何相关开发者凭据予以终止。
-
-9.3 Google 有权在向您在作出通知后,有理由或无理由地随时终止与您订立的这份许可协议。
-
-9.4 本许可协议将在下列情况下自动终止,而无需另行通知或采取其他行动,以先符合条件者为准:
-(A) Google 在您居住或使用服务所在国家/地区停止向用户提供“预览版”或“预览版”的某些部分;
-(B) Google 发行 Android SDK 的最终版本。
-
-9.5 在本许可协议终止时,本许可协议中向您授予的许可将终止,您应立即完全停止使用“预览版”,并且第 10、11、12 和 14 节的条款将无限期继续存在。
-
-10. 免责声明
-
-10.1 您明确理解并同意,您使用“预览版”的风险将由您自行承担,并且“预览版”是按“原样”和“现状”提供,Google 不提供任何类型的担保。
-
-10.2 您对“预览版”的使用以及通过使用“预览版”下载或以其他方式获得的任何材料由您自行决定,风险自负,并且对于因此类使用而对您的计算机系统或其他设备造成的任何损害或数据损失由您单方面负责。在不对上文所述予以限制的条件下,您了解“预览版”并非稳定版本,可能存在将导致重大损害的错误、缺陷和安全漏洞,包括无法挽回地完全无法使用您的计算机系统或其他设备。
-
-10.3 Google 进一步明确拒绝任何类型的所有担保和条件,无论明示或暗示,包括但不限于有关适销性、特定用途适用性以及非侵权的暗示担保和条件。
-
-11. 有限责任
-
-11.1 您明确理解并同意,对于您可能遭遇的任何直接、间接、附带、特殊、继发或惩罚性损害(包括任何数据损失),Google 及其子公司和附属公司以及其许可方在任何责任理论下对您概不承担任何责任,无论 Google 或其代表是否已被告知或是否本应知晓发生任何上述损失的可能性。
-
-12. 赔偿
-
-12.1 您同意,在法律所允许的最大限度内,为 Google、其附属公司及其各自的董事、高管、员工和代理商提供辩护,使其免于因下列情况引起或产生的任何及所有索赔、诉讼、起诉或诉讼程序以及任何及所有损失、债务、损害、成本和费用(包括合理的律师费用)而承担责任或遭受损害:(a) 您对“预览版”的使用;(b) 您在“预览版”上开发的任何应用侵犯任何人的任何知识产权或诽谤任何人或侵犯其公开权或隐私权;以及 (c) 您的任何行为有悖于本许可协议
-
-13. 许可协议的更改
-
-13.1 Google 可能会在分发新版本“预览版”时对许可协议做出更改。做出这些更改后,Google 将在提供“预览版”的网站上公布新版本的许可协议。
-
-14. 一般法律条款
-
-14.1 本许可协议构成您与 Google 之间的完整法律协议,管辖您对“预览版”(不包括 Google 可能依据另外的书面协议向您提供的任何服务)的使用,并完全取代您之前与 Google 之间签订的、与“预览版”有关的任何协议。
-
-14.2 您同意,如果 Google 未行使或未强制执行本许可协议包含的任何法定权利或救济(或 Google 在任何适用法律下享有的相关利益),不得视为 Google 正式放弃这些权利,Google 仍可获得这些权利或救济。
-
-14.3 如果任何拥有管辖权的法院将本许可协议的任何条款裁定为无效,则该条款将从本许可协议中删除,而不会影响本许可协议的其余部分。本许可协议的其余条款将继续有效且可强制执行。
-
-14.4 您承认并同意,Google 集团旗下的每一家公司都将成为本许可协议的第三方受益人,并且此类其他公司将有权直接强制执行和依赖本许可协议中任何授予其利益(或支持其权利)的条款。除此之外,任何其他人员或公司均不得成为本许可协议的第三方受益人。
-
-14.5 出口限制。“预览版”受美国出口法律和法规的制约。您必须遵守适用于“预览版”的所有国内和国际出口法律和法规。这些法律包括目的地、最终用户和最终用途方面的限制。
-
-14.6 未经 Google 事先书面批准,您不得擅自转让或转移本许可协议,未经此类批准而试图进行的任何转让均为无效。未经 Google 事先书面批准,您不得委托您依据本许可协议所应承担的责任或义务。
-
-14.7 本许可协议以及您与 Google 依据本许可协议而建立的关系受加利福尼亚州法律管辖,而无论其是否与其他法律条款冲突。您与 Google 同意服从位于加利福尼亚州圣克拉拉县内法院的专属司法管辖权,以解决本许可协议引起的任何法律事务。尽管有上述规定,您同意仍允许 Google 在任何管辖区域申请禁令救济(或同等类型的紧急法律救济)。
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">我已阅读并同意上述条款和条件</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>本文内容</h2>
-      <ol>
-        <li><a href="#sdk">预览版 SDK</a></li>
-        <li><a href="#docs">开发者文档</a></li>
-        <li><a href="#images">硬件系统映像</a></li>
-      </ol>
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  Android M 预览版 SDK 包括开发工具、Android 系统文件和库文件,旨在帮助您在下一版本的平台中测试您的应用以及该平台提供的新 API。
-本文旨在介绍如何获得“预览版”的可下载组件,以便测试您的应用。
-
-</p>
-
-
-<h2 id="sdk">预览版 SDK</h2>
-
-<p>
-  预览版 SDK 可通过 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下载。如需了解有关下载和配置预览版 SDK 的详细信息,请参阅<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">设置预览版 SDK</a>。
-
-</p>
-
-
-<h2 id="docs">开发者文档</h2>
-
-<p>
-  开发者文档下载软件包提供详细的 API 参考信息和“预览版”的 API 差异报告。
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">硬件系统映像</h2>
-
-<p>
-  这些系统映像允许您在实际设备上安装预览版平台,以便进行测试。
-通过使用这些映像之一配置设备,您可以安装并测试您的应用,以了解其在下一版本平台上的性能表现。
-在设备上安装系统映像的过程会<em>删除设备中的所有数据</em>,因此您应该在安装系统映像之前备份数据。
-
-
-</p>
-
-<p class="warning">
-  <b>警告:</b>以下 Android 系统映像是预览版,可能会随时发生变化。您对这些系统映像的使用受 Android SDK 预览版许可协议的制约。
-Android 预览版系统映像并非稳定版本,可能包含会对您的计算机系统、设备和数据造成损害的错误和缺陷。
-
-Android 预览版系统映像未经过与出厂操作系统相同的测试,可能会导致您的手机和安装的服务与应用停止工作。
-
-
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">将映像安装到设备</h3>
-
-<p>
-  要使用设备映像进行测试,您必须将其安装到兼容设备上。请按照下面的说明安装系统映像:
-
-</p>
-
-<ol>
-  <li>下载并解压此处列出的系统映像包之一。</li>
-  <li>备份设备中您希望予以保留的任何数据。</li>
-  <li>按照
-<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
- 中的说明将映像刷入设备中。</li>
-</ol>
-
-<p class="note">
-  <strong>注:</strong>为开发设备刷入预览版系统映像之后,它将通过无线 (OTA) 更新自动升级到下一个预览版本。
-
-</p>
-
-<h3 id="revertDevice">将设备还原至出厂规格</h3>
-
-<p>
-  如果您想要卸载预览版并将设备还原至出厂规格,请转到
-<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> 并下载要为设备刷入的映像。
-按照该页面上的说明将映像刷入设备中。
-
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/zh-cn/preview/features/background-optimization.jd b/docs/html-intl/intl/zh-cn/preview/features/background-optimization.jd
deleted file mode 100644
index 4ce58aa..0000000
--- a/docs/html-intl/intl/zh-cn/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,391 +0,0 @@
-page.title=后台优化
-page.metaDescription=隐式广播的新限制。
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      本文内容
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">对 CONNECTIVITY_ACTION 的限制</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">安排连入无限流量连接时的网络作业</a>
-
-      </li>
-
-      <li>
-        <a href="#monitor-conn">在应用运行时监控网络连接</a>
-
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">对 NEW_PICTURE 和 NEW_VIDEO 的限制</a>
-
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">新的 JobInfo 方法</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">新的 JobParameter 方法</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">进一步优化您的应用</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  后台进程非常耗费内存和电池。例如,隐式广播可以启动许多已注册侦听它的后台进程,即使这些进程可能没有执行许多工作。
-
-这会严重影响设备性能和用户体验。
-
-</p>
-
-<p>
-  为缓解这个问题,Android N 应用了以下限制:
-
-</p>
-
-<ul>
-  <li>面向 Preview 的应用不会收到 {@link
-android.net.ConnectivityManager#CONNECTIVITY_ACTION} 广播,即使它们在清单中注册接收这些广播。
-运行的应用如果使用 {@link android.content.Context#registerReceiver Context.registerReceiver()} 注册
-{@link android.content.BroadcastReceiver},则仍可在主线程上侦听 {@code CONNECTIVITY_CHANGE}。
-
-
-  </li>
-
-  <li>应用无法发送或接收 {@link
-android.hardware.Camera#ACTION_NEW_PICTURE} 或 {@link
-android.hardware.Camera#ACTION_NEW_VIDEO} 广播。此项优化会影响所有应用,而不仅仅是面向 Preview 的应用。
-
-  </li>
-</ul>
-
-<p>
-  如果您的应用使用任何 Intent,您仍需要尽快移除它们的依赖关系,以正确适配 Android N 设备。
-
-  Android 框架提供多个解决方案来缓解对这些隐式广播的需求。
-例如,{@link android.app.job.JobScheduler}
-和<a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> 提供了一个稳健可靠的机制来安排满足指定条件(例如连入无限流量网络)时所执行的网络操作。
-
-现在,您还可以使用 {@link android.app.job.JobScheduler}
-来响应内容提供程序所发生的变更。{@link android.app.job.JobInfo}
-对象封装了 {@link android.app.job.JobScheduler}
-用来安排您的作业的参数。如果符合作业条件,系统将在应用的 {@link android.app.job.JobService} 上执行此作业。
-
-</p>
-
-<p>
-  在本文档中,我们将学习如何使用备用方法(如 {@link android.app.job.JobScheduler})调整您的应用以符合这些新限制。
-
-
-</p>
-
-<h2 id="connectivity-action">
-  对 CONNECTIVITY_ACTION 的限制
-</h2>
-
-<p>
-  面向 Android N 的应用不会收到 {@link
-android.net.ConnectivityManager#CONNECTIVITY_ACTION} 广播,即使它们在清单中注册接收这些广播亦是如此,依赖此广播的流程也不会启动。
-
-这可能会给需要侦听网络变化或者需要在设备接入无限流量网络时执行批量网络活动的应用造成问题。
-
-Android 框架中已存在多个可绕过此限制的解决方案,但需要根据您想要应用实现的目标来选择正确的解决方案。
-
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>当应用运行时,通过
-{@link android.content.Context#registerReceiver Context.registerReceiver()}
-中注册的 {@link android.content.BroadcastReceiver} 将继续接收这些广播。
-</p>
-
-<h3 id="sched-jobs">
-  安排连入无限流量连接时的网络作业
-</h3>
-
-<p>
-  使用 {@link android.app.job.JobInfo.Builder JobInfo.Builder} 类构建
-{@link android.app.job.JobInfo} 对象时,应用 {@link
-android.app.job.JobInfo.Builder#setRequiredNetworkType
-setRequiredNetworkType()} 方法,并将 {@link android.app.job.JobInfo
-JobInfo.NETWORK_TYPE_UNMETERED} 作为作业参数传递。以下代码示例展示如何安排当设备接入无限流量网络且正在充电时要运行的服务:
-
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  当符合作业条件时,应用会收到回调以运行指定的{@code JobService.class} 中的 {@link android.app.job.JobService#onStartJob onStartJob()} 方法。
-
-如需查看 {@link
-  android.app.job.JobScheduler} 实现的更多示例,请参阅 <a href="{@docRoot}samples/JobScheduler/index.html">JobScheduler 示例应用</a>。
-</p>
-
-<p>
-  使用 GMSCore 服务且面向 Android 5.0(API 级别 21)或更低版本系统的应用可以使用<a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-{@code GcmNetworkManager}</a> 并指定 {@code Task.NETWORK_STATE_UNMETERED}。
-
-</p>
-
-<h3 id="monitor-conn">
-  在应用运行时监控网络连接
-</h3>
-
-<p>
-  注册了 {@link android.content.BroadcastReceiver} 的运行的应用仍可侦听 {@code CONNECTIVITY_CHANGE}。
-不过,{@link
-android.net.ConnectivityManager} API 提供了一个更稳健可靠的方法,可以仅在符合指定的网络条件时才请求回调。
-
-</p>
-
-<p>
-  {@link android.net.NetworkRequest} 对象根据 {@link android.net.NetworkCapabilities} 定义网络回调的参数。
-使用 {@link
-android.net.NetworkRequest.Builder NetworkRequest.Builder} 类创建 {@link android.net.NetworkRequest} 对象。然后,{@link
-android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
-将 {@link android.net.NetworkRequest} 对象传递给系统。
-当符合网络条件时,应用会收到回调以执行在其 {@link
-android.net.ConnectivityManager.NetworkCallback} 类中定义的
-{@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-onAvailable()} 方法。
-
-</p>
-
-<p>
-  应用继续接收回调,直至应用退出或调用
-{@link android.net.ConnectivityManager#unregisterNetworkCallback
-unregisterNetworkCallback()}。
-</p>
-
-<h2 id="media-broadcasts">
-  对 NEW_PICTURE 和 NEW_VIDEO 的限制
-</h2>
-
-<p>
-  在 Android N 中,应用无法发送或接收 {@link
-android.hardware.Camera#ACTION_NEW_PICTURE} 或 {@link
-android.hardware.Camera#ACTION_NEW_VIDEO} 广播。此限制有助于缓解必须唤醒多个应用以处理新图像或视频时对性能和用户体验造成的影响。
-
-Android N 扩展了 {@link android.app.job.JobInfo} 和 {@link
-android.app.job.JobParameters} 以提供备用解决方案。
-
-</p>
-
-<h3 id="new-jobinfo">
-  新的 JobInfo 方法
-</h3>
-
-<p>
-  为了针对内容 URI 变化触发作业,Android N 使用以下方法扩展了 {@link android.app.job.JobInfo} API:
-
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    封装针对内容 URI 变化触发作业所需的参数。
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    将 {@code TriggerContentUri} 对象传递给 {@link
-android.app.job.JobInfo}。{@link android.database.ContentObserver}
-监控已封装的内容 URI。如果存在多个与某个作业关联的 {@code
-TriggerContentUri} 对象,则系统会提供一个回调,即使其报告仅一个内容 URI 发生变化。
-
-  </dd>
-
-  <dd>
-    如果给定 URI 的任何子级发生变化,则添加 {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} 标志以触发作业。
-此标志对应于传递给 {@link
-android.content.ContentResolver#registerContentObserver    registerContentObserver()} 的
-{@code notifyForDescendants} 参数。
-
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>注:</strong> {@code TriggerContentUri()} 无法与 {@link android.app.job.JobInfo.Builder#setPeriodic
-setPeriodic()} 或 {@link android.app.job.JobInfo.Builder#setPersisted
-setPersisted()} 结合使用。
-若要持续监控内容变化,则可在应用的 {@link
-android.app.job.JobService} 完成处理最新的回调前安排新的
-{@link android.app.job.JobInfo}。
-</p>
-
-<p>
-  以下示例代码展示如何安排当系统报告内容 URI {@code MEDIA_URI} 所发生变化时要触发的作业:
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  当系统报告指定内容 URI 所发生变化时,应用将收到一个回调,并向 {@code MediaContentJob.class} 中的 {@link android.app.job.JobService#onStartJob onStartJob()}
-方法传递一个 {@link android.app.job.JobParameters} 对象。
-
-
-</p>
-
-<h3 id="new-jobparam">
-  新的 JobParameter 方法
-</h3>
-
-<p>
-  Android N 也扩展了{@link android.app.job.JobParameters},以允许应用接收有关哪些内容权限和 URI 已触发作业的有用信息:
-
-
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    返回已触发作业的 URI 数组。如果没有任何 URI 触发作业(例如,作业是因截止期限或其他一些原因触发的),或者已更改的 URI 数量超过 50,该数组将为 {@code
-null}。
-
-
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    返回已触发作业的内容权限的字符串数组。
-    如果返回的数组不是 {@code null},请使用 {@code getTriggeredContentUris()}
-检索有关哪些 URI 已更改的详细信息。
-  </dd>
-</dl>
-
-<p>
-  以下示例代码重写 {@link
-android.app.job.JobService#onStartJob JobService.onStartJob()} 方法并记录已触发作业的内容权限和 URI:
-
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  进一步优化您的应用
-</h2>
-
-<p>
-  优化您的应用以在低内存设备上或在低内存条件下运行,这样可以提升性能和用户体验。
-删除后台服务依赖关系和静态注册的隐式广播接收器可帮助您的应用在此类设备上运行得更好。
-
-尽管 Android N 采取了措施以减少部分问题,但建议您优化自己的应用,使其能够在完全不使用这些后台进程的情况下运行。
-
-
-
-</p>
-
-<p>
-  Android N 推出了一些附加 <a href="{@docRoot}tools/help/adb.html">Android 调试桥 (ADB)</a> 命令,您可以使用这些命令测试在禁用那些后台进程情况下的应用行为:
-
-</p>
-
-<ul>
-  <li>要模拟隐式广播和后台服务不可用的条件,请输入以下命令:
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>要重新启用隐式广播和后台服务,请输入以下命令:
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
diff --git a/docs/html-intl/intl/zh-cn/preview/features/icu4j-framework.jd b/docs/html-intl/intl/zh-cn/preview/features/icu4j-framework.jd
deleted file mode 100644
index 9a1dfa8..0000000
--- a/docs/html-intl/intl/zh-cn/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-page.title=ICU4J Android 框架 API
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>本文内容:</h2>
-<ol>
-    <li><a href="#relation">与 ICU4J 的关系</a></li>
-    <li><a href="#migration">从 ICU4J 迁移至 android.icu API </a></li>
-    <li><a href="#licence">授权</a></li>
-</ol>
-
-<h2>另请参阅</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">ICU4J 的文档</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">ICU4J 支持的最新标准</a>
-
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J 是一个广泛使用的开源 Java 库集合,为软件应用提供 Unicode 和全球化支持。
-Android N 在 {@code android.icu} 软件包下显示 Android 框架中的 ICU4J API 子集,供应用开发者使用。
-
-这些 API 使用设备上具有的本地化数据。
-因此,您可以通过不将 ICU4J 库编译到 APK 来减少 APK 占用空间;相反,您可以只在框架中调用它们。
-
-(在此情况下,您可能想要提供<a href="{@docRoot}google/play/publishing/multiple-apks.html">多个版本的 APK</a>,这样,运行比 Android N 低的 Android 版本的用户可以下载包含 ICU4J 库的应用版本。)
-
-
-
-</p>
-
-<p>
-  本文档开头提供了有关支持这些库所需的最低 Android API 级别的一些基本信息。
-然后,介绍关于 Android 特定的 ICU4J 实现您需要了解的内容。
-最后,介绍如何在 Android 框架中使用 ICU4J API。
-
-</p>
-
-<h2 id="relation">与 ICU4J 的关系</h2>
-
-<p>
-  Android N 通过
-<code>android.icu</code> 软件包(而非 <code>com.ibm.icu</code>)显示 ICU4J API 的子集。由于种种原因,Android 框架可能选择不显示 ICU4J API;例如,Android N 不显示一些已弃用的 API 或 ICU 团队尚未将其声明为“稳定”的 API。
-
-
-
-由于 ICU 团队将来会弃用这些 API,因此,Android 也会将其标记为已弃用,但将继续包含它们。
-
-</p>
-
-<p class="table-caption"><strong>表 1.</strong> Android N 中使用的 ICU 和 CLDR 版本。
-</p>
-<table>
-<tr>
-<th>Android API 级别</th>
-<th>ICU 版本</th>
-<th>CLDR 版本</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>以下是几点注意事项:</p>
-
-<ul>
-<li>ICU4J Android 框架 API 不包含所有的 ICU4J API。</li>
-<li>NDK 开发者应了解 Android ICU4C 不受支持。</li>
-<li>Android 框架中的 API 不会取代 Android 对<a href="{@docRoot}guide/topics/resources/localization.html">使用资源进行本地化</a>的支持。
-
-</li>
-</ul>
-
-<h2 id="migration">从 com.ibm.icu 迁移至 android.icu 软件包</h2>
-
-<p>
-  如果您已在应用中使用 ICU4J API,且
-<code>android.icu</code> API 符合您的要求,那么要迁移至框架 API,需要将 Java 导入从 <code>com.ibm.icu</code> 更改为 <code>android.icu</code>。
-
-然后,您可以从 APK 移除您自己的 ICU4J 文件的副本。
-
-</p>
-
-<p class="note">
-  <b>注</b>:ICU4J 框架 API 使用 {@code android.icu}
-命名空间,而不是 {@code com.ibm.icu}。这是为了避免在包含自己的 {@code com.ibm.icu} 库的 APK 中出现命名空间冲突。
-
-</p>
-
-<h3 id="migrate-from-android">
-  从其他 Android SDK API 迁移至 android.icu API
-</h3>
-
-<p>
-  <code>java</code> 和 <code>android</code> 软件包中的某些类与在 ICU4J 中找到的一些类等效。
-不过,ICU4J 通常为标准和语言提供更广泛的支持。
-
-</p>
-<p>下面是一些入门示例:</p>
-<table>
-<tr>
-<th>类</th>
-<th>替代项</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">授权</h2>
-
-<p>
-  ICU4J 按照 ICU 许可发布。如需了解详情,请参阅 <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">ICU 用户指南</a>。
-
-</p>
diff --git a/docs/html-intl/intl/zh-cn/preview/features/multilingual-support.jd b/docs/html-intl/intl/zh-cn/preview/features/multilingual-support.jd
deleted file mode 100644
index 248d6a0..0000000
--- a/docs/html-intl/intl/zh-cn/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,221 +0,0 @@
-page.title=语言和区域设置
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>本文内容:</h2>
-<ol>
-	  <li><a href="#preN">解析语言资源所面临的挑战</a></li>
-    <li><a href="#postN">对资源解析策略的改进</a></li>
-    <li><a href="#design">设计您的应用以支持附加区域设置</a>
-</li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N 为多语言用户提供增强的支持,让他们可以在设置中选择多个区域设置。
-Android N 通过大幅扩展受支持的区域设置数量并更改系统解析资源的方式来提供此功能。
-
-全新的解析资源方法更加稳健,并且设计为与现有 APK 兼容,但要格外细心,以发现任何异常行为。
-
-例如,您应进行测试,以确保应用默认显示预期的语言。
-另外,如果应用支持多语言,您应确保此支持合乎预期。
-
-最后,对于您没有将其显式设计为支持的语言,应设法确保应用能够妥善地处理它们。
-</p>
-
-<p>本文档开头介绍 Android N 之前的资源解析策略。接下来介绍 Android N 改进的资源解析策略。
-
-最后,介绍如何充分利用扩展的区域设置数量来支持更多的多语言用户。
-</p>
-
-<h2 id="preN">解析语言资源所面临的挑战</h2>
-
-<p>在 Android N 之前,Android 并非始终能够成功匹配应用和系统区域设置。
-</p>
-
- <p>例如,假设您遇到了以下情况:</p>
- <ul>
- <li>您的应用的默认语言为{@code en_US}“US English”,但它也在 {@code es_ES}资源文件中对西班牙字符串进行了本地化。
-
-</li>
- <li> 将设备设置为 {@code es_MX} </li>
-
-<p>当您的 Java 代码引用字符串时,系统会从默认 ({@code en_US}) 资源文件加载字符串,即使应用在 {@code es_ES} 下有本地化的西班牙语资源。
-
-这是因为当系统无法找到精确匹配时,它会继续通过将国家/地区代码从区域设置中剥离来查找资源。
-
-最后,如果未找到匹配,系统会恢复为默认模式,即 {@code en_US}。
- </p>
-
-
-<p>如果用户选择应用根本不支持的语言(如法语),则系统也会默认显示 {@code en_US}。
-例如:</p>
-
-<p class="table-caption" id="t-resource-res">
-<strong>表 1.</strong> 没有精确区域设置匹配项的资源解析。
-</p>
-<table>
-<tbody>
-<tr>
-<th>用户设置</th>
-<th>应用资源</th>
-<th>资源解析</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-默认值 (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-尝试 fr_CH =&gt; 失败<br>
-尝试 fr =&gt; 失败<br>
-使用默认值 (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>在此示例中,系统在不知道用户是否理解英语的情况下显示英语字符串。
-目前,此行为很常见。
-Android N 应该会大幅减少出现此类结果的频率。
-</p>
-
-<h2 id="postN">对资源解析策略的改进</h2>
-<p>Android N 可提供更稳健的资源解析,并自动查找更好的备用方法。
-不过,为了加速解析和提升可维护性,您应以最常用的母语存储资源。
-
- 例如,如果您之前将西班牙语资源存储在 {@code es-US} 目录中,请将它们移动到 {@code es-419} 目录,该目录包含拉丁美洲西班牙语。
-
- 同理,如果您在名为 {@code en-GB} 的文件夹中存储有资源字符串,则将此文件夹重命名为 {@code en-001}(国际英语),因为 <code>en-GB</code> 字符串的最常用母语为 {@code en-001}。
-
-
- 以下示例介绍为什么这些做法可提升性能和资源解析的可靠性。
-</p>
-
-<h3>资源解析示例</h3>
-
-<p>使用 Android N,以不同的方式解析<strong>表 1</strong> 中所描述的案例:
-</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>表 2.</strong> 针对没有精确区域设置匹配项时改进的资源解析策略。
-</p>
-<table>
-<tr>
-<th>用户设置</th>
-<th>应用资源</th>
-<th>资源解析</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-默认值 (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-尝试 fr_CH =&gt; 失败<br>
-尝试 fr =&gt; 失败<br>
-尝试 fr 的子项 =&gt; fr_FR<br>
-使用 fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>现在,用户获得的是法语资源而不是英语。此示例还表明对于 Android N,您为什么应将法语字符串存储在 {@code fr}(而非 {@code fr_FR})中。此处的做法是匹配最接近的母语,从而使解析更快速且更具预见性。
-
-
-</p>
-
-<p>除了这个改进的解析逻辑外,Android 现在还提供更多的用户语言以供选择。
-下面,我们将意大利语指定为附加用户语言,但假设应用不支持法语,再次尝试上面的示例。
-  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>表 3.</strong> 应用仅与用户的次优区域设置匹配时的资源解析。
-</p>
-<table>
-<tr>
-<th>用户设置</th>
-<th>应用资源</th>
-<th>资源解析</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-默认值 (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-尝试 fr_CH =&gt; 失败<br>
-尝试 fr =&gt; 失败<br>
-尝试 fr 的子项 =&gt; 失败<br>
-尝试 it_CH =&gt; 失败<br>
-尝试 it =&gt; 失败<br>
-尝试 it 的子项 =&gt; it_IT<br>
-使用 it_IT
-</td>
-
-</tr>
-
-</table>
-<p>用户仍会获取他们理解的语言,即使应用不支持法语。
-</p>
-
-
-<h2 id="design">设计您的应用以支持附加区域设置</h2>
-<h3>LocaleList API</h3>
-
-<p>Android N 添加了新的 API {@code LocaleList.getDefault()},从而让应用可以直接查询用户已指定的语言列表。
-您可以使用此 API 创建更成熟的应用行为和更优化的内容显示。
-
-例如,搜索可以基于用户的设置以多种语言显示结果。
-浏览器应用可避免翻译以用户理解的语言显示的页面,键盘应用可自动启用所有适用的布局。
-
- </p>
-
-<h3>格式化程序</h3>
-
-<p>直到 Android 6.0(API 级别 23),Android 仅支持许多常用语言(en、es、ar、fr、ru)的一个或两个区域设置。
-
-由于每种语言只有几种变体,因此,应用可以通过在资源文件中将一些数字和日期存储为硬编码字符串解决此问题。
-
-不过,随着 Android 扩展了支持的区域设置集,即使在一个区域设置中,日期、时间、货币及类似信息也会存在显著差异。
-
-
-对您的格式进行硬编码会让最终用户困惑不已。
-因此,在针对 Android N 开发应用时请务必使用格式化程序代替硬编码数字和日期字符串。
-</p>
-
-<p>阿拉伯语就是最好的例子,Android N 将对其的支持从一个 {@code ar_EG} 扩展到 27 个阿拉伯语区域设置。
-这些区域设置可以共享大多数资源,但其中一些资源首选 ASCII 数字,另一些则首选本地数字。
-例如,如果您想要创建一个具有数字变量的句子,如“Choose a 4 digit pin”,则按如下所示使用格式化程序:
-
-</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/zh-cn/preview/features/notification-updates.jd b/docs/html-intl/intl/zh-cn/preview/features/notification-updates.jd
deleted file mode 100644
index 900eea6..0000000
--- a/docs/html-intl/intl/zh-cn/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,393 +0,0 @@
-page.title=通知
-page.tags=通知
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>本文内容包括</h2>
-<ol>
-  <li><a href="#direct">直接回复</a></li>
-  <li><a href="#bundle">捆绑通知</a></li>
-  <li><a href="#custom">自定义视图</a></li>
-  <li><a href="#style">消息样式</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N 引入了一些新 API,允许应用发布具有高度可见性和交互性的通知。
-</p>
-
-<p>Android N 扩展了现有 {@link android.support.v4.app.RemoteInput} 通知 API,以支持手持式设备上的内联回复。
-此功能允许用户从通知栏快速进行回复,无需访问应用。
-</p>
-
-<p>
-  此外,Android N 还允许捆绑类似的通知并将它们显示为一则通知。
-为了实现此功能,Android N 使用现有的 {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} 方法。用户可以从通知栏展开各通知,并分别对每则通知进行回复和清除等操作。
-
-
-</p>
-
-<p>最后,Android N 还添加了一些新 API,允许您在应用的自定义通知视图中使用系统装饰元素。
-这些 API 可帮助确保通知视图与标准模板的展示效果相一致。
-
-</p>
-
-<p>本文重点介绍您在应用中使用新通知功能时应加以考虑的一些重要变更。
-</p>
-
-<h2 id="direct">直接回复</h2>
-
-<p>利用 Android N 中的直接回复功能,用户可以直接在通知界面内快速回复短信或更新任务列表。
-
-在手持式设备上,可通过通知中另外附加的按钮进行内联回复操作。
-当用户通过键盘回复时,系统会将文本回复附加到您为通知操作指定的 Intent,并将 Intent 发送到手持式设备应用。
-
-
-
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>图 1.</strong>Android N 添加了 <strong>Reply</strong> 操作按钮。
-
-</p>
-
-<h3>添加内联回复操作</h3>
-
-<p>要创建支持直接回复的通知操作:
-</p>
-
-<ol>
-<li>创建一个可添加到通知操作的 {@link android.support.v4.app.RemoteInput.Builder} 实例。
-
-该类的构造函数接受系统用作文本输入密钥的字符串。
-之后,手持式设备应用使用该密钥检索输入的文本。
-
-
-<pre>
-// Key for the string that's delivered in the action's intent.
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>使用 <code>addRemoteInput()</code> 向操作附加 {@link android.support.v4.app.RemoteInput} 对象。
-
-
-<pre>
-// Create the reply action and add the remote input.
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>对通知应用操作并发出通知。
-
-<pre>
-// Build the notification and add the action.
-Notification newMessageNotification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification.
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, newMessageNotification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> 在触发通知操作时系统提示用户输入回复。
- </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>图 2.</strong>用户从通知栏输入文本。
-</p>
-
-<h3>
-  从内联回复检索用户输入
-</h3>
-
-<p>
-  要从通知界面接收用户输入并发送到在回复操作的 Intent 中声明的 Activity:
-
-</p>
-
-<ol>
-  <li>通过传递通知操作的 Intent 作为输入参数来调用 {@link android.support.v4.app.RemoteInput#getResultsFromIntent
- getResultsFromIntent()}。
-该方法返回含有文本回复的 {@link android.os.Bundle}。
-
-
-    <pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-  </li>
-
-  <li>使用产生的密钥查询捆绑包(提供给 {@link
- android.support.v4.app.RemoteInput.Builder} 构造函数)。以下代码段说明了方法如何从捆绑包检索输入文本:
-
-
-
-    <pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-        return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-    }
-    return null;
- }
-</pre>
-  </li>
-
-  <li>使用您为上一项通知提供的相同的通知 ID 来建立和发布另一项通知。
-进度指示器从通知界面消失,以告知用户已回复成功。
-
-在处理这项新通知时,使用被传递到接收器 {@code onReceive()} 方法的上下文。
-
-
-    <pre>
-// Build a new notification, which informs the user that the system
-// handled their interaction with the previous notification.
-Notification repliedNotification =
-        new Notification.Builder(context)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentText(getString(R.string.replied))
-                .build();
-
-// Issue the new notification.
-NotificationManager notificationManager =
-        NotificationManager.from(context);
-notificationManager.notify(notificationId, repliedNotification);
-</pre>
-  </li>
-</ol>
-
-<p>
-  对于交互式应用(例如聊天),这可以用来在处理检索到的文本时添加其他上下文。
-例如,这些应用可以显示多行聊天记录。
-当用户通过 {@link
-  android.support.v4.app.RemoteInput} 回复时,您可以使用 {@code setRemoteInputHistory()} 方法更新回复历史。
-
-</p>
-
-<p>
-  在应用收到远程输入后,必须更新或取消通知。
-如果用户使用直接回复来对远程更新进行回复,则不可取消通知。
-
-否则,更新通知以显示用户的回复。对于使用 {@code MessagingStyle} 的通知,您应该添加回复来作为最新消息。
-
-当使用其它模板时,您可以将用户的回复追加到远程输入历史。
-
-</p>
-
-<h2 id="bundle">捆绑通知</h2>
-
-<p>Android N 为开发者提供了表示通知队列的新方法:
- <i>捆绑通知</i>。这类似于 Android Wear 中的<a href="{@docRoot}training/wearables/notifications/stacks.html">通知堆栈</a>功能。
-
-例如,如果应用为接收的消息创建通知,那么在接收到多个消息时,应用会将通知捆绑在一起成为一个群组。
-
-您可以使用现有的 {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} 方法捆绑类似的通知。
-</p>
-
-<p>
-  通知组对组内的通知施加层次结构。
-  层次结构的顶层是父级通知,其显示该群组的摘要信息。
-用户可以逐步展开通知组,随着用户深入展开,系统将显示更多信息。
-
-当用户展开捆绑包时,系统将显示其所有子通知的更多信息;当用户展开其中一则通知时,系统显示该通知的所有内容。
-
-
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>图 3.</strong>用户可以逐步展开通知组。
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>如果同一应用发送了四条或以上通知,并且未指定分组,系统会自动将它们分到一组。
-
-
-</p>
-
-<p>如需了解如何将通知添加到组,请参阅<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">将各通知添加到组</a>。
-
-</p>
-
-
-<h3 id="best-practices">捆绑通知最佳做法</h3>
-<p>本节提供了有关何时使用通知组而非早期版本 Android 平台中的 {@link android.app.Notification.InboxStyle InboxStyle} 通知的指南。
-
-
-</p>
-
-<h3>何时使用捆绑通知</h3>
-
-<p>只有在您的用例满足以下所有条件时才应使用通知组:
-</p>
-
-<ul>
-  <li>子通知为完整通知,且可以单独显示,无需群组摘要。
-</li>
-  <li>单独显示子通知更合理。例如:
-
-  </li>
-  <ul>
-    <li>子通知可操作,且每个子通知均有特定的操作。</li>
-    <li>子通知中包含用户想要查看的更多信息。</li>
-  </ul>
-</ul>
-
-<p>好的通知组用例示例包括:显示传入消息列表的短信应用,或显示收到的电子邮件列表的电子邮件应用。
-
-</p>
-
-<p>
-适合显示单一通知的用例示例包括:从某一个人收到的单独消息,或以列表表示的单行文本项目。
-
-您可以使用 {@link android.app.Notification.InboxStyle InboxStyle} 或
-{@link android.app.Notification.BigTextStyle BigTextStyle} 实现此功能。
-
-
-</p>
-
-<h3 id ="post">显示捆绑通知</h3>
-
-<p>
-  即使组内仅含有一则子通知,应用也应发布组摘要。
-如果只含有一则通知,系统将取消摘要并直接显示子通知。
-这样可确保用户在滑动切换组内的子通知时,系统仍可以提供一致的用户体验。
-
-
-</p>
-
-<p class="note">
-  <strong>注:</strong>本版本 Android N 目前还无法在仅含一则子通知时取消通知组的摘要。
-我们将在之后版本的 Android N 中添加此功能。
-
-</p>
-
-<h3>扫视通知</h3>
-
-<p>虽然系统通常以群组的方式显示子通知,但您可以进行设置,使其暂时作为<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">浮动通知</a>显示。
-
-
-该功能非常实用,因为其允许用户立即访问最近的子通知以及与其相关的操作。
-
-</p>
-
-
-<h3>后向兼容性</h3>
-
-<p>
-  自 Android 5.0(API 级别 21)起,{@link
-  android.app.Notification} API 中就添加了通知组和远程输入,以支持 Android Wear 设备。
-如果您已经使用这些 API 构建通知,则只需验证应用行为是否符合上述指南,并考虑实现 {@code
-  setRemoteInputHistory()}。
-
-
-</p>
-
-<p>
-  为了支持后向兼容性,支持库的 {@link android.support.v4.app.NotificationCompat} 类中提供了相同的 API,以便您构建可在早期 Android 版本中运行的通知。
-
-
-在手持式设备和平板电脑上,用户只能看到摘要通知,因此应用应仍提供收件箱式或类似形式的通知显示模式,以显示群组的全部信息内容。
-
-鉴于 Android Wear 设备允许用户查看所有子通知,包括更早级别平台上的通知,您应在不依赖 API 级别的基础上构建子通知。
-
-
-
-</p>
-
-<h2 id="custom"> 自定义视图</h2>
-<p>从 Android N 开始,您将可以自定义通知视图,同时仍可以使用系统装饰元素,例如通知标头、操作和可展开的布局。
-
-</p>
-
-<p>为启用该功能,Android N 添加了以下 API,以便您样式化自己的自定义视图:
-</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> 样式化除媒体通知外的其他通知。
-</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> 样式化媒体通知。</dd>
-</dl>
-
-<p>如需使用这些新 API,可调用 {@code setStyle()} 方法,并向其传递所需的自定义视图样式。
-</p>
-
-<p>此代码段显示了如何使用 {@code DecoratedCustomViewStyle()} 方法构建自定义通知对象。
-</p>
-
-<pre>
-Notification notification = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
-
-<h2 id="style">消息传递样式</h2>
-<p>
-  Android N 引入了一项新的 API 来自定义通知样式。
-  使用 <code>MessageStyle</code> 类,您可以更改在通知中显示的多个标签,包括会话标题、其他消息和通知的内容视图。
-
-
-</p>
-
-<p>
-  以下代码段演示了如何使用 <code>MessageStyle</code> 类来自定义通知样式。
-
-</p>
-
-<pre>
-  Notification notification = new Notification.Builder()
-             .setStyle(new Notification.MessagingStyle("Me")
-                 .setConversationTitle("Team lunch")
-                 .addMessage("Hi", timestamp1, null) // Pass in null for user.
-                 .addMessage("What's up?", timestamp2, "Coworker")
-                 .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
-</pre>
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..ae9e164 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,120 +1,110 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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 -->
 </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">
+<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>
 
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        回報問題</a>
-</div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        查看版本資訊</a>
-</div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        加入開發人員社群</a>
-</div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
-<section class="dac-section dac-light"><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-tw/guide/components/intents-filters.jd b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
index d3edac3..7e61f5e 100644
--- a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
+++ b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
@@ -76,7 +76,7 @@
 <li><b>如何傳送廣播:</b>
 <p>廣播是指任何應用程式都可接收的訊息。系統會傳送各種系統事件廣播,例如系統開機或裝置開始充電。
 您可以將 {@link android.content.Intent} 傳送至 {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、
-{@link android.content.Context#sendOrderedBroadcast(Intent, String) 或{@link
+{@link android.content.Context#sendOrderedBroadcast(Intent, String)} 或{@link
 android.content.Context#sendStickyBroadcast sendStickyBroadcast()},以向其他應用程式傳送廣播。
 
 
diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
index a5772ef..022df77 100644
--- a/docs/html-intl/intl/zh-tw/index.jd
+++ b/docs/html-intl/intl/zh-tw/index.jd
@@ -5,49 +5,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -75,28 +62,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
-    </a>
-    <div class="actions">
-      <div><a href="{@docRoot}sdk/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get the SDK
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html-intl/intl/zh-tw/preview/download_mp2.jd b/docs/html-intl/intl/zh-tw/preview/download_mp2.jd
deleted file mode 100644
index 3b54080..0000000
--- a/docs/html-intl/intl/zh-tw/preview/download_mp2.jd
+++ /dev/null
@@ -1,359 +0,0 @@
-page.title=下載
-page.image=images/cards/card-download_16-9_2x.png
-
-@jd:body
-
-<div style="position:relative; min-height:600px">
-
-  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
-
-    <p class="sdk-terms-intro">在下載和安裝 Android 預覽版
-SDK 的元件之前 ,您必須同意遵守下列條款和條件。</p>
-
-    <h2 class="norule">條款和條件</h2>
-
-    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
-這是「Android SDK 預覽版授權協議」(以下稱「授權協議」)。
-
-1.簡介
-
-1.1「Android SDK 預覽版」(在「授權協議」中稱為「預覽版」,包括 (如果有可用的) Android 系統檔案、經過封裝的 API 和預覽版程式庫檔案) 是在「授權協議」之條款的約束下授權給您使用。「授權協議」就您對「預覽版」的使用,構成您與 Google 間具法律約束力之合約。
-
-1.2「Android」係指「Android 軟體開放原始碼專案」(http://source.android.com/) 所提供的 Android 裝置軟體堆疊 (不定期更新)。
-
-1.3「Google」係指 Google Inc.,是一家在美國德拉瓦州註冊的公司,地址為 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。
-
-2.接受「授權協議」
-
-2.1 必須先同意遵守「授權協議」,才能使用此「預覽版」。如果不接受「授權協議」,您就無法使用此「預覽版」。
-
-2.2 按一下 [接受] 且/或使用「預覽版」,即表示您同意「授權協議」的條款。
-
-2.3 如果您是美國或其他國家/地區 (包括您所居住或使用此「預覽版」的國家/地區) 的法律所禁止接收此「預覽版」的人員,就不得使用此「預覽版」及接受「授權協議」。
-
-2.4 如果您將在公司或組織內部使用「預覽版」,您就要代表雇主或其他實體同意受「授權協議」約束,且您代表並保證具備完整法定權限來約束您的雇主或這類實體遵守「授權協議」。如果您不具備必要的權限,就不得代表您的雇主或其他實體接受「授權協議」或使用此「預覽版」。
-
-3.Google 的預覽版授權
-
-3.1 在「授權協議」之條款的約束下,Google 授權您使用此「預覽版」,此授權為買斷式、不可轉讓、非獨占性、不可轉授權、有限且可撤銷,僅在您公司或組織內部私下或內部使用。此「預覽版」僅供您用於開發在 Android 平台上執行的應用程式。
-
-3.2 您同意 Google 或第三方對此「預覽版」擁有一切法定權利及權益,包括存在於此「預覽版」中的任何「智慧財產權」。「智慧財產權」係指專利法、著作權法、商業秘密法、商標法及任何和所有其他專利權下的任何及一切權利。Google 保留一切未明確授予您的權利。
-
-3.3 您不得將此「預覽版」用於「授權協議」未明文許可的任何用途。除非適用的第三方授權所需,否則您不得:(a) 對此「預覽版」或其任何部分進行複製 (備份用途除外)、修改、改編、轉散佈、反向組譯、還原工程、解編或製作衍生成品;或是 (b) 將此「預覽版」的任何部分載入至行動電話或個人電腦以外的任何其他硬體裝置、將此「預覽版」的任何部分與其他軟體結合,或散佈包含此「預覽版」之任一部分的任何軟體或裝置。
-
-3.4 您同意不會從事任何可能導致或造成 Android 分裂的活動,包括但不限於以任何形式散佈從此「預覽版」衍生的軟體開發套件、參其製作或宣傳。
-
-3.5 對開放原始碼軟體授權下所授權之「預覽版」的使用、複製及散佈,完全受該開放原始碼軟體授權的條款管制,而不受「授權協議」管制。您同意遵守從這類開放原始碼軟體授權獲得的所有權利,並且避免採取任何可能終止、中止或侵害這類權利的行為。
-
-3.6 您同意 Google 可在不事先通知您的情況下變更其所提供之「預覽版」的形式和本質,且此「預覽版」的未來版本可與在此「預覽版」的先前版本上開發的應用程式不相容。您同意 Google 通常可全權斟酌永久或暫時停止提供此「預覽版」(或此「預覽版」的任何功能) 給您或使用者,毋須事先通知。
-
-3.7「授權協議」中的所有條款皆未授予您任何使用 Google 之商業名稱、商標、服務標章、標誌、網域名稱或其他明確品牌特徵的權利。
-
-3.8 您同意不會移除、遮蔽或更改可能附加至或內含在此「預覽版」中的任何專利權通知 (包括著作權和商標通知)。
-
-4.您對「預覽版」的使用
-
-4.1 Google 同意在「授權協議」下,任何條款皆未從您 (或您的授權人) 賦予 Google 對您使用此「預覽版」開發之任何軟體應用程式的任何權利及權益,包括存在於這些應用程式中的任何智慧財產權。
-
-4.2 您同意只就 (a)「授權協議」和 (b) 相關管轄權中任何適用法律、規定或是普遍獲得接受之慣例或指導方針 (包括任何有關將資料或軟體輸出或輸入美國或其他相關國家/地區的法律) 所允許的用途使用此「預覽版」及撰寫應用程式。
-
-4.3 您同意如果使用此「預覽版」開發應用程式,您將保護使用者的隱私權和法定權利。如果使用者提供您使用者名稱、密碼或是其他登入資訊或個人資訊,您必須告知使用者這類資訊將提供給您的應用程式使用,並且必須為這些使用者提供法定充分的隱私權通知和保護。如果您的應用程式會儲存使用者所提供的個人或敏感資訊,它必須確保這些資訊安全無虞。如果使用者提供 Google 帳戶資訊給您,則只有在每個使用者已授權您存取其 Google 帳戶並僅限用於使用者所授權之用途的情況下,您的應用程式才能使用該資訊來存取使用者的 Google 帳戶。
-
-4.4 您同意不會使用此「預覽版」從事任何不當Activity,例如開發或散佈會以未經授權的方式干擾、妨礙、損害或存取 Google 或任何第三方之伺服器、網路或是其他財產或服務的應用程式。
-
-4.5 您同意對您透過 Android 裝置和 (或) Android 應用程式建立、傳輸或顯示的任何資料、內容或資源,以及上述行為造成的後果 (包括 Google 可能蒙受的任何損失或損害) 負起全責 (而 Google 對您或任何第三方就上述一切不需負任何責任)。
-
-4.6 您同意對違反在此「授權協議」、任何適用之第三方合約或《服務條款》或是任何適用之法律或規定下所必須遵守的義務,以及違反相關義務造成的後果 (包括 Google 或任何第三方可能蒙受的任何損失或損害) 負起全責 (而 Google 對您或任何第三方就上述一切不需負任何責任)。
-
-4.7「預覽版」目前正在開發中,因此您的測試與意見反應對開發程序非常重要。使用「預覽版」,您即認同某些功能仍處於開發階段,因此您不應期待「預覽版」擁有穩定版本的完整功能。在官方 Android SDK 發行之後,此「預覽版」不再受到支援時,您同意不使用此「預覽版」公開散佈或隨附任何應用程式。
-
-5.您的開發人員認證
-
-5.1 您同意負責保密 Google 可能核發給您或您自己選擇的任何開發人員認證,並且對在您開發人員認證名義下開發的所有應用程式負起全責。
-
-6.隱私權和資訊
-
-6.1 為了持續更新及改進此「預覽版」,Google 可能會從軟體收集某些使用狀況統計數據,包括但不限於軟體的唯一識別碼、相關 IP 位址、版本號碼,以及有關使用此「預覽版」中的哪些工具和 (或) 服務及其使用方式的相關資訊。在收集這類資訊之前,此「預覽版」會先通知您並徵求您的同意。如果您不同意,Google 將不會收集這類資訊。
-
-6.2 Google 會彙總並檢查收集到的資料,據以改善此「預覽版」,並且會依據《Google 隱私權政策》(http://www.google.com/policies/privacy/) 加以妥善保存。
-
-7.第三方應用程式
-
-7.1 如果您使用此「預覽版」來執行第三方開發的應用程式,或是執行會存取第三方所提供之資料、內容或資源的應用程式,您同意 Google 不需對這類應用程式、資料、內容或資源負任何責任。您瞭解您透過第三方應用程式存取的所有資料、內容或資源是由其提供者負起全責,而 Google 對您因使用或存取任何這些第三方應用程式、資料、內容或資源所造成的損失或損害不需負任何責任。
-
-7.2 您瞭解第三方應用程式提供給您的資料、內容或資源可能受到提供者 (或代表他們的其他人員或公司) 所擁有的智慧財產權保護。您不得根據這類資料、內容或資源 (不論是整個或部分) 修改、出租、出借、販售、散佈或製作衍生成品,除非相關擁有者明確授權您從事上述活動。
-
-7.3 您瞭解使用第三方應用程式、資料、內容或資源可能受到您與相關第三方之間的個別條款約束。
-
-8.使用 Google API
-
-8.1 Google API
-
-8.1.1 如果您使用任何 API 從 Google 擷取資料,您瞭解這些資料可能受到 Google 或資料提供者 (或代表他們的其他人員或公司) 所擁有的智慧財產權保護。您對任何這類 API 的使用可能受到其他《服務條款》約束。除非相關《服務條款》明文允許,否則您不得根據這類資料 (不論是整個或部分) 修改、出租、出借、販售、散佈或製作衍生成品。
-
-8.1.2 使用任何 API 從 Google 擷取使用者的資料時,您瞭解並同意只有在該使用者明確同意且授權您擷取其資料,而且僅限用於使用者所授權之用途的情況下,您才能擷取資料。
-
-9.終止「授權協議」
-
-9.1 除非您或 Google 終止「授權協議」(請見下方說明),否則「授權協議」將持續具有效力。
-
-9.2 如果想終止「授權協議」,只要停止使用此「預覽版」及任何相關的開發人員憑證即可。
-
-9.3 Google 可隨時通知您終止「授權協議」,無論有無原因。
-
-9.4「授權協議」在先發生下列任一情況時,將自動終止而不另行通知或採取其他行動:
-(A) Google 決定不再提供此「預覽版」或此「預覽版」的特定部分給您所居住或使用此服務之國家/地區的使用者;或
-(B) Google 發行最終版本的 Android SDK。
-
-9.5 當「授權條款」終止時,您在「授權協議」所獲得的授權也將會一併終止,您將立即停止「預覽版」的所有使用,而第 10、11、12 和 14 項的條款將無限期持續適用。
-
-10.免責聲明
-
-10.1 您明確瞭解並同意完全自負使用此「預覽版」的風險,並且此「預覽版」是依「現況」和「可提供性」提供,Google 不負任何擔保責任。
-
-10.2 您對使用此「預覽版」及透過此「預覽版」以下載或其他方式取得的任何內容,需自行斟酌和自負風險,而且您對因這類使用而對您的電腦系統或其他裝置所造成的任何損害或資料遺失,需負起全責。不限於前述,您瞭解此「預覽版」不是穩定的版本,可能會包含許多錯誤、瑕疵和安全性弱點而對您的電腦系統或其他裝置造成嚴重的損害,包括完全、不可回復的損失。
-
-10.3 Google 進一步明確表示不提供任何形式的瑕疵擔保和條件 (不論明示或默示),包括但不限於適售性、適合特定用途及未侵權的默示擔保和條件。
-
-11.責任限制
-
-11.1 您明確瞭解並同意在任何歸責理論下,就可能由您引起的任何直接、間接、附隨性、特殊性、衍生性或懲罰性損害賠償 (包括任何資料遺失),不論 Google 或其代表是否已獲告知或應已瞭解發生任何這類損失的可能性,Google、其子公司和關係企業及其授權人不必對您負起任何責任。
-
-12.賠償
-
-12.1 在法律允許的最大範圍內,您同意為 Google、其子公司及其個別董監事、主管、員工和代理人,就任何和一切索賠、法律行動、訴訟或訴訟程序,以及因下列原因而引起的任何和一切損失、責任、損害賠償、費用及開支 (包括合理的律師費),提供辯護、賠償損失並確保其免於承擔賠償責任:(a) 您使用此「預覽版」;(b) 您使用此「預覽版」開發的應用程式侵害任何人的任何智慧財產權,或是詆毀任何人或違反其公開權或隱私權;以及 (c) 您未遵守「授權協議」。
-
-13.對「授權協議」做出的變更
-
-13.1 Google 可在散佈此「預覽版」的新版本時修改「授權協議」。做出這類變更後,Google 會在提供此「預覽版」的網站上提供「授權協議」的新版本。
-
-14.一般法律條款
-
-14.1「授權協議」構成您與 Google 之間的法律協議,用於管制您對此「預覽版」(不包括 Google 依據個別書面協議提供給您的任何服務) 的使用,並完全取代先前您與 Google 之間就此「預覽版」簽署的相關協議。
-
-14.2 您同意如果 Google 未行使或執行「授權協議」所含的任何法律權利或救濟 (或在任何適用法律下對 Google 有利的權益),並不代表 Google 正式放棄權利,Google 日後仍可行使這些權利或救濟。
-
-14.3 如果經任何法院 (就此事宜依管轄權決定) 裁決「授權協議」中有任何條款無效,則該條款將自「授權協議」中移除,「授權協議」的其餘部分則不受影響。「授權協議」的其餘條款將持續具有效力且可執行。
-
-14.4 您瞭解並同意 Google 旗下子公司體系的每位成員都是「授權協議」的第三方受益人,而且這類其他公司有權直接執行和依據「授權協議」中對其授予權益 (或對其有利之權利) 的任何條款。除此之外的任何其他人員或公司皆非「授權協議」的第三方受益人。
-
-14.5 出口限制。此「預覽版」受美國出口法規約束。您必須遵守適用於此「預覽版」的所有國內和國際出口法規。這些法律包括對目的地、使用者及最終用途的限制。
-
-14.6 未事先取得 Google 事先書面核准的情況下,您不得轉讓或轉移「授權協議」,未經這類核准的任何轉讓將會失效。您不得在未事先取得 Google 書面核准的情況下,委派其「授權協議」涵蓋的責任或義務。
-
-14.7「授權協議」以及您與 Google 就「授權協議」構成的關係皆受加州法律管轄,毋須理會其法律牴觸條款。您和 Google 同意服從位於加州聖塔克拉拉 (Santa Clara, California) 郡內法院的專屬管轄權,以解決由「授權協議」產生的任何法律事務。儘管如此,您同意 Google 仍可在任何管轄權中申請禁制令救濟 (或同等類型的緊急法定救濟)。
-  </div><!-- sdk terms -->
-
-
-
-    <div id="sdk-terms-form">
-      <p>
-        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
-        <label id="agreeLabel" for="agree">我已閱讀並同意上述條款及細則</label>
-      </p>
-      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
-    </div>
-
-
-  </div><!-- end TOS -->
-
-
-  <div id="landing">
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>本文件內容</h2>
-      <ol>
-        <li><a href="#sdk">預覽版 SDK</a></li>
-        <li><a href="#docs">開發人員文件</a></li>
-        <li><a href="#images">硬體系統映像</a></li>
-      </ol>
-     <h2>Legacy downloads</h2>
-        <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
-        </ol>
-  </div>
-</div>
-
-
-<p>
-  Android M 預覽版 SDK 有開發工具、Android 系統檔案以及程式庫檔案,可以幫助測試您的應用程式和下一個平台版本隨附的新 API。
-本文件會說明如何取得可下載的預覽版元件來測試您的應用程式。
-
-</p>
-
-
-<h2 id="sdk">預覽版 SDK</h2>
-
-<p>
-  預覽版 SDK 可透過 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下載取得。如需有關下載和設定預覽版 SDK 的詳細資訊,請參閱<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">設定預覽版 SDK</a>。
-
-</p>
-
-
-<h2 id="docs">開發人員文件</h2>
-
-<p>
-  開發人員文件下載套件提供詳細的 API 參考資料和預覽版的 API 差異報告。
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Description</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
-    </td>
-  </tr>
-</table>
-
-
-<h2 id="images">硬體系統映像</h2>
-
-<p>
-  這些系統映像可以讓您在實體裝置上安裝預覽版的平台來進行測試。
-使用其中一個映像設定裝置,您就可以安裝並測試您的應用程式,瞭解應用程式在下一個版本的平台上表現如何。
-在裝置上安裝系統映像的過程中,會「移除裝置當中所有的資料」,因此您應該在安裝系統映像之前備份您的資料。<em></em>
-
-
-</p>
-
-<p class="warning">
-  <b>警告:</b>下列 Android 系統映像是預覽版,可能隨時會有變更。使用這些系統映像受到「Android SDK 預覽版授權協議」的約束。
-Android 預覽版系統映像還不是穩定的版本,可能會包含許多錯誤和瑕疵而對您的電腦系統、裝置和資料造成損害。
-
-預覽版的 Android 系統映像與出廠作業系統的測試不同,可能會導致您的手機和安裝的服務與應用程式停止運作。
-
-
-</p>
-
-<table>
-  <tr>
-    <th scope="col">Device</th>
-    <th scope="col">Download / Checksums</th>
-  </tr>
-  <tr id="hammerhead">
-    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
-    </td>
-  </tr>
-  <tr id="shamu">
-    <td>Nexus 6 <br>"shamu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
-    </td>
-  </tr>
-  <tr id="volantis">
-    <td>Nexus 9 <br>"volantis"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
-    </td>
-  </tr>
-
-  <tr id="fugu">
-    <td>Nexus Player <br>"fugu"</td>
-    <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
-    </td>
-  </tr>
-
-</table>
-
-<h3 id="install-image">在裝置上安裝映像</h3>
-
-<p>
-  如果要使用裝置映像進行測試,您必須先在相容的裝置上安裝映像。請依照下面的指示安裝系統映像:
-
-</p>
-
-<ol>
-  <li>下載此處列出的其中一個系統映像,然後解壓縮。</li>
-  <li>備份您要保留的所有裝置資料。</li>
-  <li>依照
-<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
-的指示,將映像更新到您的裝置。</li>
-</ol>
-
-<p class="note">
-  <strong>注意:</strong>在您使用預覽版系統映像更新開發裝置之後,裝置就會透過無線 (OTA) 更新方式自動升級為下一個預覽版版本。
-
-</p>
-
-<h3 id="revertDevice">將裝置還原成出廠規格</h3>
-
-<p>
-  如果您要解除安裝預覽版並將裝置還原成出廠規格,請至
-<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> 並下載您要為裝置更新的映像。
-依照該頁面的指示,將映像更新到您的裝置。
-
-</p>
-
-  </div><!-- landing -->
-
-</div><!-- relative wrapper -->
-
-
-
-<script>
-  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
-  function onDownload(link) {
-
-    $("#downloadForRealz").html("Download " + $(link).text());
-    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
-
-    $("#tos").fadeIn('fast');
-    $("#landing").fadeOut('fast');
-
-    return true;
-  }
-
-
-  function onAgreeChecked() {
-    /* verify that the TOS is agreed */
-    if ($("input#agree").is(":checked")) {
-      /* reveal the download button */
-      $("a#downloadForRealz").removeClass('disabled');
-    } else {
-      $("a#downloadForRealz").addClass('disabled');
-    }
-  }
-
-  function onDownloadForRealz(link) {
-    if ($("input#agree").is(':checked')) {
-    /*
-      $("#tos").fadeOut('fast');
-      $("#landing").fadeIn('fast');
-    */
-
-      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
-
-    /*
-      location.hash = "";
-    */
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  $(window).hashchange( function(){
-    if (location.hash == "") {
-      location.reload();
-    }
-  });
-
-</script>
diff --git a/docs/html-intl/intl/zh-tw/preview/features/background-optimization.jd b/docs/html-intl/intl/zh-tw/preview/features/background-optimization.jd
deleted file mode 100644
index 123498b..0000000
--- a/docs/html-intl/intl/zh-tw/preview/features/background-optimization.jd
+++ /dev/null
@@ -1,390 +0,0 @@
-page.title=背景最佳化
-page.metaDescription=對隱含式廣播的新限制。
-page.keywords="android N", "implicit broadcasts", "job scheduler"
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>
-      此文件內容
-    </h2>
-
-    <ol>
-      <li>
-        <a href="#connectivity-action">CONNECTIVITY_ACTION 上的限制</a>
-      </li>
-
-      <li>
-        <a href="#sched-jobs">在非計量付費連線上排程網路工作</a>
-
-      </li>
-
-      <li>
-        <a href="#monitor-conn">監視應用程式執行時的網路連線能力</a>
-
-      </li>
-
-      <li>
-        <a href="#media-broadcasts">NEW_PICTURE 與 NEW_VIDEO 上的限制</a>
-
-      </li>
-
-      <li>
-        <a href="#new-jobinfo">新的 JobInfo 方法</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">新的 JobParameter 方法</a>
-      </li>
-
-      <li>
-        <a href="#further-optimization">進一步最佳化您的應用程式</a>
-      </li>
-    </ol>
-  </div>
-</div>
-
-<p>
-  背景處理程序可能耗用大量的記憶體或電池電力。例如,隱含式廣播可能會啟動許多已註冊要接聽它的背景處理程序,即使那些處理程序可能不會執行太多工作。
-
-這可能會對裝置效能與使用者體驗兩者造成實質影響。
-
-</p>
-
-<p>
-  為減輕此問題,N Developer Preview 套用下列限制:
-
-</p>
-
-<ul>
-  <li>目標為 Preview 的應用程式,如果在宣示說明中註冊以接收廣播,則不會收到 {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} 廣播。
-在前景執行的應用程式,只要使用 {@link
-  android.content.Context#registerReceiver Context.registerReceiver()} 註冊 {@link android.content.BroadcastReceiver},即可在主要執行緒中接聽 {@code CONNECTIVITY_CHANGE}。
-
-
-  </li>
-
-  <li>應用程式無法傳送或接收 {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} 或 {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO} 廣播。這種最佳化方式會影響所有應用程式,而不只是目標為 Preview 的應用程式。
-
-  </li>
-</ul>
-
-<p>
-  Android 架構提供數種解決方案來減少這些隱含式廣播的需求。
-例如,{@link android.app.job.JobScheduler} 與 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> 提供的健全機制,可在符合指定條件 (例如,連線到非計量付費網路) 的情況下排程網路操作。
-
-
-您甚至可以使用 {@link android.app.job.JobScheduler} 對內容提供者的變更採取因應動作。{@link android.app.job.JobInfo} 物件會封裝 {@link android.app.job.JobScheduler} 用來排程您的工作的參數。
-
-
-符合工作的條件時,系統會在應用程式的 {@link android.app.job.JobService} 上執行此工作。
-
-</p>
-
-<p>
-  在此文件中,我們將學習如何使用替代方法 (例如
-  {@link android.app.job.JobScheduler}) 改寫您的應用程式以配合這些新的限制。
-
-</p>
-
-<h2 id="connectivity-action">
-  CONNECTIVITY_ACTION 上的限制
-</h2>
-
-<p>
-  目標為 N Developer Preview 的應用程式,如果在宣示說明中註冊以接收廣播,則不會收到 {@link
-  android.net.ConnectivityManager#CONNECTIVITY_ACTION} 廣播,而相依於此廣播的處理程序將不會啟動。
-
-這可能會在裝置連線到非計量付費網路時,對想要接聽網路變更或執行大量網路活動的應用程式造成問題。
-
-Android 架構中已經有數個可以避過此限制的解決方案,但是選擇適當的方法取決於您想要應用程式完成什麼工作。
-
-
-</p>
-
-<p class="note">
-  <strong>注意:</strong>使用
-  {@link android.content.Context#registerReceiver Context.registerReceiver()}
- 註冊的 {@link android.content.BroadcastReceiver} 會在應用程式位於前景時繼續接收這些廣播。
-</p>
-
-<h3 id="sched-jobs">
-  在非計量付費連線上排程網路工作
-</h3>
-
-<p>
-  使用 {@link android.app.job.JobInfo.Builder JobInfo.Builder} 類別建置 {@link android.app.job.JobInfo} 物件時,請套用 {@link
-  android.app.job.JobInfo.Builder#setRequiredNetworkType
-  setRequiredNetworkType()} 方法並傳遞 {@link android.app.job.JobInfo
-  JobInfo.NETWORK_TYPE_UNMETERED} 當做工作參數。
-下列程式碼範例會排程服務,讓它在裝置連線到非計量付費網路和收費時執行:
-
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo job = new JobInfo.Builder(
-    MY_BACKGROUND_JOB,
-    new ComponentName(context, MyJobService.class))
-      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
-      .setRequiresCharging(true)
-      .build();
-  js.schedule(job);
-}
-</pre>
-
-<p>
-  符合您工作的條件時,您的應用程式會收到一個回呼,在指定的 {@code JobService.class} 中執行{@link android.app.job.JobService#onStartJob onStartJob()} 方法。
-
-如果要檢視更多 {@link
-  android.app.job.JobScheduler} 實作的範例,請參閱 <a href="{@docRoot}samples/JobScheduler/index.html">JobScheduler 範例應用程式</a>。
-</p>
-
-<p>
-  使用 GMSCore 服務且目標為 Android 5.0 (API 層級 21) 或更低的應用程式,可以使用 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
-  {@code GcmNetworkManager}</a> 並指定 {@code Task.NETWORK_STATE_UNMETERED}。
-
-</p>
-
-<h3 id="monitor-conn">
-  監視應用程式執行時的網路連線能力
-</h3>
-
-<p>
-  在前景執行的應用程式,只要使用註冊的 {@link
-  android.content.BroadcastReceiver} ,仍然可以接聽 {@code
-  CONNECTIVITY_CHANGE}。然而,{@link
-  android.net.ConnectivityManager} API 提供更建全的方法,只在符合指定的網路條件時才要求回呼。
-
-</p>
-
-<p>
-  {@link android.net.NetworkRequest} 物件以 {@link android.net.NetworkCapabilities} 的方式定義網路回呼的參數。
-您使用 {@link
-  android.net.NetworkRequest.Builder NetworkRequest.Builder} 類別建立{@link android.net.NetworkRequest} 物件。接著 {@link
-  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
-  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
- 會將 {@link android.net.NetworkRequest} 物件傳遞到系統。
-符合網路條件時,應用程式會收到回呼,執行它的 {@link
-  android.net.ConnectivityManager.NetworkCallback} 類別中定義的
-  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
-  onAvailable()} 方法。
-
-</p>
-
-<p>
-  應用程式會持續收到回呼,直到應用程式結束或呼叫
-  {@link android.net.ConnectivityManager#unregisterNetworkCallback
-  unregisterNetworkCallback()} 才停止。
-</p>
-
-<h2 id="media-broadcasts">
-  NEW_PICTURE 與 NEW_VIDEO 上的限制
-</h2>
-
-<p>
-  在 N Developer Preview 中,應用程式無法傳送或接收 {@link
-  android.hardware.Camera#ACTION_NEW_PICTURE} 或 {@link
-  android.hardware.Camera#ACTION_NEW_VIDEO} 廣播。在必須喚醒數個應用程式來處理新的影像或視訊時,此限制有助於降低對效能與使用者體驗的影響。
-
-N Developer Preview 擴充 {@link android.app.job.JobInfo} 與 {@link
-  android.app.job.JobParameters} 來提供替代解決方案。
-
-</p>
-
-<h3 id="new-jobinfo">
-  新的 JobInfo 方法
-</h3>
-
-<p>
-  為了在內容 URI 變更時觸發工作,N Developer Preview 使用下列方法擴充 {@link android.app.job.JobInfo} API:
-
-</p>
-
-<dl>
-  <dt>
-    {@code JobInfo.TriggerContentUri()}
-  </dt>
-
-  <dd>
-    封裝在內容 URI 變更時觸發工作所需的參數。
-  </dd>
-
-  <dt>
-    {@code JobInfo.Builder.addTriggerContentUri()}
-  </dt>
-
-  <dd>
-    將 {@code TriggerContentUri} 物件傳遞到 {@link
-    android.app.job.JobInfo}。{@link android.database.ContentObserver} 會監視封裝的內容 URI。
-如果有多個 {@code
-    TriggerContentUri} 物件與工作關聯,即使系統只回報其中一個內容 URI 中的變更,也會提供一個回呼。
-
-  </dd>
-
-  <dd>
-    新增 {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} 旗標,以在特定 URI 的任何子系變更時觸發工作。
-此旗標對應傳遞到 {@link
-    android.content.ContentResolver#registerContentObserver
-    registerContentObserver()} 的 {@code notifyForDescendants} 參數。
-
-  </dd>
-</dl>
-
-<p class="note">
-  <strong>注意:</strong>{@code TriggerContentUri()} 無法與 {@link android.app.job.JobInfo.Builder#setPeriodic
-  setPeriodic()} 或 {@link android.app.job.JobInfo.Builder#setPersisted
-  setPersisted()} 結合使用。
-為了持續監視內容變更,請在應用程式的 {@link
-  android.app.job.JobService} 完成處理最近的回呼之前,排程新的
-  {@link android.app.job.JobInfo}。
-</p>
-
-<p>
-  下列範例程式碼會排程一個工作,在系統回報內容 URI {@code MEDIA_URI} 變更時觸發該工作:
-
-</p>
-
-<pre>
-public static final int MY_BACKGROUND_JOB = 0;
-...
-public static void scheduleJob(Context context) {
-  JobScheduler js =
-          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-  JobInfo.Builder builder = new JobInfo.Builder(
-          MY_BACKGROUND_JOB,
-          new ComponentName(context, MediaContentJob.class));
-  builder.addTriggerContentUri(
-          new JobInfo.TriggerContentUri(MEDIA_URI,
-          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
-  js.schedule(builder.build());
-}
-</pre>
-<p>
-  當系統回報指定內容 URI 中有變更時,您的應用程式會收到一個回呼,而且會傳遞一個 {@link android.app.job.JobParameters} 物件到 {@code MediaContentJob.class} 中的 {@link android.app.job.JobService#onStartJob onStartJob()} 方法。
-
-
-
-</p>
-
-<h3 id="new-jobparam">
-  新的 JobParameter 方法
-</h3>
-
-<p>
-  N Developer Preview 也擴充 {@link android.app.job.JobParameters} 以允許您的應用程式接收有關內容授權單位與觸發工作之 URI 的實用資訊:
-
-
-</p>
-
-<dl>
-  <dt>
-    {@code Uri[] getTriggeredContentUris()}
-  </dt>
-
-  <dd>
-    傳回觸發工作之 URI 的陣列。如果沒有 URI 觸發工作 (例如,工作是因為期限到了或一些其他原因而觸發),或是變更的 URI 數目大於 50 時,這將會是 {@code
-    null}。
-
-
-  </dd>
-
-  <dt>
-    {@code String[] getTriggeredContentAuthorities()}
-  </dt>
-
-  <dd>
-    傳回觸發工作之內容授權單位的字串陣列。
-    如果傳回的陣列不是 {@code null},請使用 {@code getTriggeredContentUris()} 來擷取變更的 URI 的詳細資訊。
-
-  </dd>
-</dl>
-
-<p>
-  下列範例程式碼會覆寫 {@link
-  android.app.job.JobService#onStartJob JobService.onStartJob()} 方法,並記錄觸發工作的內容授權單位與 URI:
-
-</p>
-
-<pre>
-&#64;Override
-public boolean onStartJob(JobParameters params) {
-  StringBuilder sb = new StringBuilder();
-  sb.append("Media content has changed:\n");
-  if (params.getTriggeredContentAuthorities() != null) {
-      sb.append("Authorities: ");
-      boolean first = true;
-      for (String auth :
-          params.getTriggeredContentAuthorities()) {
-          if (first) {
-              first = false;
-          } else {
-             sb.append(", ");
-          }
-           sb.append(auth);
-      }
-      if (params.getTriggeredContentUris() != null) {
-          for (Uri uri : params.getTriggeredContentUris()) {
-              sb.append("\n");
-              sb.append(uri);
-          }
-      }
-  } else {
-      sb.append("(No content)");
-  }
-  Log.i(TAG, sb.toString());
-  return true;
-}
-</pre>
-
-<h2 id="further-optimization">
-  進一步最佳化您的應用程式
-</h2>
-
-<p>
-  最佳化您的應用程式,讓它可以在低記憶體裝置上或低記憶體狀況下執行,這樣可以改進效能與使用者體驗。
-移除背景服務上的相依性與靜態註冊的隱含式廣播接收器,有助於讓您的應用程式在此類裝置上執行得更順暢。
-
-雖然 N Developer Preview 採取一些步驟來減少一些此類問題,但是還是建議您最佳化您的應用程式,讓它完全不必使用這些背景處理程序。
-
-
-
-</p>
-
-<p>
-  N Developer Preview 引進一些額外的 <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> 命令,您可以使用這些命令測試在那些背景處理程序停用時的應用程式行為:
-
-</p>
-
-<ul>
-  <li>如果要模擬隱含式廣播與背景服務無法使用的情況,請輸入下列命令:
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND ignore}
-</pre>
-  </li>
-
-  <li>如果要重新啟用隱含式廣播與背景服務,請輸入下列命令:
-
-  </li>
-
-  <li style="list-style: none; display: inline">
-<pre class="no-pretty-print">
-{@code $ adb shell cmd appops set RUN_IN_BACKGROUND allow}
-</pre>
-  </li>
-</ul>
\ No newline at end of file
diff --git a/docs/html-intl/intl/zh-tw/preview/features/icu4j-framework.jd b/docs/html-intl/intl/zh-tw/preview/features/icu4j-framework.jd
deleted file mode 100644
index b6816b8..0000000
--- a/docs/html-intl/intl/zh-tw/preview/features/icu4j-framework.jd
+++ /dev/null
@@ -1,160 +0,0 @@
-page.title=ICU4J Android 架構 API
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>此文件內容:</h2>
-<ol>
-    <li><a href="#relation">與 ICU4J 的關係</a></li>
-    <li><a href="#migration">從 ICU4J 遷移到 android.icu API</a></li>
-    <li><a href="#licence">授權</a></li>
-</ol>
-
-<h2>另請參閱</h2>
-<ol>
-  <li>
-    <a class="external-link" href="http://userguide.icu-project.org">ICU4J 文件</a>
-  </li>
-
-  <li>
-    <a class="external-link" href="http://site.icu-project.org/#TOC-What-is-ICU-">ICU4J 支援的最新標準</a>
-
-  </li>
-</ol>
-</div>
-</div>
-
-<p>
-  ICU4J 是廣為使用的一組開放原始碼 Java 程式庫,為軟體應用程式提供 Unicode 與全球化支援。
-Android N 在 Android 架構中公開一個 ICU4J API 的子集,供應用程式開發人員在 {@code android.icu} 套件下使用。
-
-這些 API 使用裝置上呈現的當地語系化資料。
-因此,您可以不用將 ICU4J 程式庫編譯到 APK 而降低 APK 的使用;相反地,您只需在架構中呼叫這些程式庫
-
-(在此情況中,您可能要提供<a href="{@docRoot}google/play/publishing/multiple-apks.html">多個版本的 APK</a>,這樣執行低於 Android N 之 Android 版本的使用者即可下載包含 ICU4J 程式庫的應用程式版本)。
-
-
-
-</p>
-
-<p>
-  此文件一開始先提供支援這些程式庫所需之最低 Android API 層級的一些基本資訊。
-接著它說明 Android 特定實作 ICU4J 的相關須知事項。
-最後,它告訴您如何在 Android 架構中使用 ICU4J API。
-
-</p>
-
-<h2 id="relation">與 ICU4J 的關係</h2>
-
-<p>
-  Android N 透過
-  <code>android.icu</code> 套件 (而非 <code>com.ibm.icu</code>) 公開一個 ICU4J API 的子集。Android 架構可能因為各種原因選擇不公開 ICU4J API;例如,Android N 沒有公開一些已過時的 API 或 ICU 團隊尚未宣布為穩定的 API。
-
-
-
-因為 ICU 團隊將來會將 API 視為過時,所以 Android 也會將這些 API 標示為已過時但繼續包含它們。
-
-</p>
-
-<p class="table-caption"><strong>表 1.</strong> Android N 中使用的 ICU 與 CLDR 版本。
-</p>
-<table>
-<tr>
-<th>Android API 層級</th>
-<th>ICU 版本</th>
-<th>CLDR 版本</th>
-</tr>
-<tr>
-<td>Android N</td>
-<td>56</td>
-<td>28</td>
-</tr>
-</table>
-
-<p>以下是一些必須注意的重要事項:</p>
-
-<ul>
-<li>ICU4J Android 架構 API 不包含所有 ICU4J API。</li>
-<li>NDK 開發人員應該知道 Android ICU4C 不被支援。</li>
-<li>Android 架構中的 API 沒有取代 Android 對<a href="{@docRoot}guide/topics/resources/localization.html">使用資源進行當地語系化</a>的支援。
-
-</li>
-</ul>
-
-<h2 id="migration">從 com.ibm.icu 遷移到 android.icu 套件</h2>
-
-<p>
-  如果您已經在應用程式中使用 ICU4J API,而且
-  <code>android.icu</code> API 符合您的需求,那麼遷移到架構 API 需要您將 Java 匯入從 <code>com.ibm.icu</code> 變更為 <code>android.icu</code>。
-
-接著您可以從 APK 移除您自己的 ICU4J 檔案。
-
-</p>
-
-<p class="note">
-  <b>注意</b>:ICU4J 架構 API 使用 {@code android.icu} 命名空間而非 {@code com.ibm.icu}。
-這是為了避免包含自己的 {@code com.ibm.icu} 程式庫的 APK 中發生命名空間衝突。
-
-</p>
-
-<h3 id="migrate-from-android">
-  從其他 Android SDK API 遷移到 android.icu API
-</h3>
-
-<p>
-  <code>java</code> 與 <code>android</code> 套件中的一些類別包含可在 ICU4J 中找到的同等項目。
-然而,ICU4J 通常為標準與語言提供更廣泛的支援。
-
-</p>
-<p>以下提供一些快速入門範例:</p>
-<table>
-<tr>
-<th>類別</th>
-<th>替代項目</th>
-</tr>
-<tr>
-<td><code>java.lang.Character</code> </td>
-<td><code>android.icu.lang.UCharacter</code> </td>
-</tr>
-<tr>
-<td><code>java.text.BreakIterator</code> </td>
-<td><code>android.icu.text.BreakIterator</code> </td>
-</tr>
-<tr>
-<td><code>java.text.DecimalFormat</code> </td>
-<td><code>android.icu.text.DecimalFormat</code> </td>
-</tr>
-<tr>
-<td><code>java.util.Calendar</code></td>
-<td>
-<code>android.icu.util.Calendar</code></td>
-</tr>
-<tr>
-<td><code>android.text.BidiFormatter</code>
- </td>
-<td><code>android.icu.text.Bidi</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateFormat</code>
- </td>
-<td><code>android.icu.text.DateFormat</code>
- </td>
-</tr>
-<tr>
-<td><code>android.text.format.DateUtils</code> </td>
-<td><code>android.icu.text.DateFormat</code>
-<code>android.icu.text.RelativeDateTimeFormatter</code>
-</td>
-</tr>
-</table>
-
-<h2 id="licence">授權</h2>
-
-<p>
-  ICU4J 是根據 ICU 授權而發行。如需詳細資料,請參閱 <a class="external-link" href="http://userguide.icu-project.org/icufaq#TOC-How-is-the-ICU-licensed-">ICU 使用者指南</a>。
-
-</p>
diff --git a/docs/html-intl/intl/zh-tw/preview/features/multilingual-support.jd b/docs/html-intl/intl/zh-tw/preview/features/multilingual-support.jd
deleted file mode 100644
index 5570b4d..0000000
--- a/docs/html-intl/intl/zh-tw/preview/features/multilingual-support.jd
+++ /dev/null
@@ -1,217 +0,0 @@
-page.title=語言和地區設定
-page.tags=androidn
-page.image=images/cards/card-nyc_2x.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>此文件內容:</h2>
-<ol>
-	  <li><a href="#preN">解析語言資源中的挑戰</a></li>
-    <li><a href="#postN">對資源解析策略所做的改進</a></li>
-    <li><a href="#design">設計您的應用程式支援其他地區設定</a>
-</li>
-
-</ol>
-
-</div>
-</div>
-
-<p>Android N 增強對多語言使用者的支援,讓他們可在設定中選取多個地區設定。
-Android N 藉由擴充支援的地區設定數量和改變系統解析資源的方式來提供多語言支援。
-
-解析資源的新方法更加健全,而且它的設計是與現有 APK 相容,但是您應該特別注意任何未預期的行為。
-
-例如,您應該進行測試,確認應用程式預設在預期的語言。
-此外,如果您的應用程式支援多個語言,則應該確保這項支援也能如預定方式運作。
-
-最後,您應該試著確認應用程式可以順暢地處理沒有明確設計要支援的語言。
-</p>
-
-<p>本文件一開始會先說明在 Android N 之前的資源解析策略。接下來,它會描述 Android N 的已改進的資源解析策略。
-
-最後,它會說明如何利用擴充的地區設定數量來支援更多的多語言使用者。
-</p>
-
-<h2 id="preN">解析語言資源中的挑戰</h2>
-
-<p>在 Android N 之前,Android 並不總能成功地對應應用程式與系統地區設定。
-舉例來說,假設您應用程式的預設語言的是 US English,但是它的 {@code es_ES} 資源檔案中也包含當地語言化的西班牙文字串。
-
-</p>
-<p>當您的 Java 程式碼參考這些字串時,它會以下列方式來解析字串語言:
-</p>
-<ul>
-<li>如果裝置設定為 {@code es_MX} (Spanish-Mexico),Android 會從 {@code es_ES} 資源檔案載入字串。
-</li>
-<li>如果裝置設定為 {@code en_AU},Android 會返回使用 {@code
-en_US}。如果使用者選擇應用程式完全不支援的語言 (如法文),系統也會預設成 {@code en_US}。
-</li>
-</ul>
-
-
-<p>出現這些解析問題的原因,是如果系統找不到符合的項目,它會剝除地區設定中的國家/地區代碼。
-例如:</p>
-<p class="table-caption" id="t-resource-res">
-<strong>表 1.</strong> 沒有完全符合的地區設定的資源解析。
-</p>
-<table>
-<tbody>
-<tr>
-<th>使用者設定</th>
-<th>應用程式資源</th>
-<th>資源解析</th>
-</tr>
-<tr>
-<td>fr_CH</td>
-<td>
-預設 (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
- <td>
-嘗試 fr_CH =&gt; 失敗<br>
-嘗試 fr =&gt; 失敗<br>
-使用預設 (en)
-</td>
- </tr>
- </tbody>
-</table>
-
-
-<p>在此例中,系統會顯示英文字串,而不知道使用者是否了解英文。
-現在這種行為相當常見。
-Android N 可以大幅降低出現這類結果的頻率。
-</p>
-
-<h2 id="postN">對資源解析策略所做的改進</h2>
-<p>Android N 帶來更健全的資源解析,而且會自動發現更佳的遞補。
-然而,為了加速解析和改進維護能力,您應該將資源存放在最常用的父系語言中。
-
- 例如,如果之前將西班牙文資源存放在 {@code es-US} 目錄,請將它們移到包含拉丁美洲西班牙文的 {@code es-419} 目錄。
-
- 同樣地,如果在名為 {@code en-GB} 的資料夾中包含資源字串,請將資料夾重新命名為 {@code en-001} (國際英文),因為 <code>en-GB</code> 字串的最常見父系為 {@code en-001}。
-
-
- 下列範例說明為什麼這些做法可改善資源解析的效能和可靠性。
-</p>
-
-<h3>資源解析範例</h3>
-
-<p>在 Android N 中,<strong>表 1</strong> 中所述的案例會用不同的方式解析:
-</p>
-
-<p class="table-caption" id="t-improved-res">
-<strong>表 2.</strong> 沒有完全符合的地區設定的已改進解析策略。
-</p>
-<table>
-<tr>
-<th>使用者設定</th>
-<th>應用程式資源</th>
-<th>資源解析</th>
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-</ol>
-</td>
-<td>
-預設 (en)<br>
-de_DE<br>
-es_ES<br>
-fr_FR<br>
-it_IT<br>
-</td>
-<td>
-嘗試 fr_CH =&gt; 失敗<br>
-嘗試 fr =&gt; 失敗<br>
-嘗試 fr 的子項 =&gt; fr_FR<br>
-使用 fr_FR
-</td>
-</tr>
-
-</table>
-
-
-<p>現在使用者會取得法文資源而非英文資源。這個範例也顯示為什麼在 Android N 中,您應該將法文字串存放在 {@code fr} 而非 {@code fr_FR} 中。以下是比對最接近父系語言的動作步驟,這些步驟可讓解析更快、更容易預測。
-
-
-</p>
-
-<p>除了這個已改進的解析邏輯之外,現在 Android 還提供更多使用者語言供您選擇。
-讓我們指定義大利文做為額外的使用者語言但應用程式不支援法文的情況,再試一次上述的範例。
-  </p>
-
-<p class="table-caption" id="t-2d-choice">
-<strong>表 3.</strong> 應用程式只比對到符合使用者第二個慣用地區設定時的資源解析。
-</p>
-<table>
-<tr>
-<th>使用者設定</th>
-<th>應用程式資源</th>
-<th>資源解析</th>
-
-</tr>
-<tr>
-<td><ol>
-<li> fr_CH</li>
-<li> it_CH</li>
-</ol>
-</td>
-<td>
-預設 (en)<br>
-de_DE<br>
-es_ES<br>
-it_IT<br>
-</td>
-<td>
-嘗試 fr_CH =&gt; 失敗<br>
-嘗試 fr =&gt; 失敗<br>
-嘗試 fr 的子項 =&gt; 失敗<br>
-嘗試 it_CH =&gt; 失敗<br>
-嘗試 it =&gt; 失敗<br>
-嘗試 it 的子項 =&gt; it_IT<br>
-使用 it_IT
-</td>
-
-</tr>
-
-</table>
-<p>即使應用程式不支援法文,但是使用者仍然取得他們了解的語言。
-</p>
-
-
-<h2 id="design">設計您的應用程式支援其他地區設定</h2>
-<h3>LocaleList API</h3>
-
-<p>Android N 增加了新的 API {@code LocaleList.GetDefault()}
-,讓應用程式直接查詢使用者指定的語言清單。這個 API 可讓您建立更精細的應用程式行為,也能更好的最佳化內容的顯示方式。
-
-例如,搜尋可以根據使用者的設定以多語言顯示結果。
-瀏覽器應用程式可以避免提供以使用者已知語言來翻譯網頁的選項,鍵盤應用程式可以自動啟用所有適當的版面配置。
-
- </p>
-
-<h3>格式設定</h3>
-
-<p>直到 Android 6.0 (API 層級 23),Android 還只支援許多常用語言 (en、es、ar、fr、ru) 的一或兩個地區設定。
-
-因為每種語言只有幾種變體,所以應用程式不用在資源檔案中將一些數字和日期儲存為硬式編碼字串。
-
-然而,隨著 Android 擴充了支援的地區設定之後,即使在單一地區設定中,日期、時間、貨幣和類似資訊的格式可能會有顯著的差異。
-
-
-硬式編碼您的格式會對使用者產生令人混淆的體驗。
-因此,針對 Android N 進行開發時,請務必使用格式子,而不要硬式編碼數字和日期字串。
-</p>
-
-<p>最主要的範例是阿拉伯文,它對 Android N 的支援從一個 {@code ar_EG} 擴充到 27 個阿拉伯地區設定。
-這些地區設定可以共用大多數的資源,但是有些地區設定慣用 ASCII 數字,而其他地區設定慣用當地數字。
-例如,在您想要建立一個包含數字變數的句子時,例如 "Choose a 4 digit pin",請使用如下所示的格式設定:
-
-</p>
-
-<pre> format(locale, "Choose a %d-digit PIN", 4)</pre>
diff --git a/docs/html-intl/intl/zh-tw/preview/features/notification-updates.jd b/docs/html-intl/intl/zh-tw/preview/features/notification-updates.jd
deleted file mode 100644
index 5ebcebb..0000000
--- a/docs/html-intl/intl/zh-tw/preview/features/notification-updates.jd
+++ /dev/null
@@ -1,328 +0,0 @@
-page.title=通知
-page.tags=notifications
-helpoutsWidget=true
-page.image=/preview/images/notifications-card.png
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<!-- table of contents -->
-<h2>本文件包括</h2>
-<ol>
-  <li><a href="#direct">直接回覆</a></li>
-  <li><a href="#bundle">整合式通知</a></li>
-  <li><a href="#custom">自訂檢視</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>Android N 引進數個新 API,允許應用程式張貼相當顯眼且互動式的通知。
-</p>
-
-<p>Android N 擴充現有的 {@link android.support.v4.app.RemoteInput}
-通知 API,支援在手機上內嵌回覆。此功能允許使用者從通知欄快速回應,而不必造訪您的應用程式。
-</p>
-
-<p>
-  Android N 也允許您將類似的通知結合成單一通知。
-Android N 使用現有的 {@link
-  android.support.v4.app.NotificationCompat.Builder#setGroup
-  NotificationCompat.Builder.setGroup()} 方法來實現此目標。使用者能擴充每個通知,並可個別從通知欄執行動作,例如回覆和關閉每一個通知。
-
-
-</p>
-
-<p>最後,Android N 還新增 API 讓您在應用程式的自訂通知檢視中利用系統的裝飾。
-這些 API 可協助確保通知檢視和標準範本的呈現方式一致。
-
-</p>
-
-<p>本文件將強調說明一些重要變更,您應該在應用程式中使用新的通知功能時納入考量。
-</p>
-
-<h2 id="direct">直接回覆</h2>
-
-<p>使用 Android N 中的直接回覆功能,使用者可直接在通知介面內快速回應文字訊息或更新工作清單。
-
-在手持式裝置上,內嵌回覆動作看起來就像是通知附加的額外按鈕。
-當使用者透過鍵盤回覆時,系統會在您為通知動作指定的意圖附加文字回應,然後將意圖傳送給您的手持裝置應用程式。
-
-
-
-
-
-<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x,
-  {@docRoot}preview/images/inline-reply_2x.png 2x" width="400">
-<p class="img-caption">
-  <strong>圖 1.</strong> Android N 新增「回覆」<strong></strong>
-  操作按鈕.
-</p>
-
-<h3>新增內嵌回覆動作</h3>
-
-<p>建立支援直接回覆的通知動作:
-</p>
-
-<ol>
-<li>建立您可以新增至通知動作的 {@link android.support.v4.app.RemoteInput.Builder}
-  實例。
-此類別的建構函式接受字串,系統可當成文字輸入的金鑰使用。
-稍後,您的手持裝置應用程式會使用該金鑰,擷取輸入的文字。
-
-
-<pre>
-// Key for the string that's delivered in the action's intent
-private static final String KEY_TEXT_REPLY = "key_text_reply";
-String replyLabel = getResources().getString(R.string.reply_label);
-RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-</li>
-<li>使用 <code>addRemoteInput()</code> 將 {@link android.support.v4.app.RemoteInput}
- 物件附加到動作。
-
-<pre>
-// Create the reply action and add the remote input
-Notification.Action action =
-        new Notification.Action.Builder(R.drawable.ic_reply_icon,
-                getString(R.string.label), replyPendingIntent)
-                .addRemoteInput(remoteInput)
-                .build();
-</pre>
-</li>
-
-<li>將動作套用到通知並發出通知。
-
-<pre>
-// Build the notification and add the action
-Notification notification =
-        new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_message)
-                .setContentTitle(getString(R.string.title))
-                .setContentText(getString(R.string.content))
-                .addAction(action))
-                .build();
-
-// Issue the notification
-NotificationManager notificationManager =
-        NotificationManager.from(mContext);
-notificationManager.notify(notificationId, notification);
-
-</pre>
-</li>
-
-</ol>
-
-
-<p> 當使用者觸發通知動作時,系統會提示使用者輸入回應。
- </p>
-
-<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x,
-    {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>圖 2.</strong> 使用者從通知欄輸入文字。
-</p>
-
-<h3>從內嵌回覆擷取使用者輸入</h3>
-
-<p>從您在回覆動作的意圖中所宣告動作的通知介面接收使用者輸入:
-</p>
-<ol>
-<li> 透過將通知動作的意圖傳遞為輸入參數,來呼叫 {@link android.support.v4.app.RemoteInput#getResultsFromIntent
-  getResultsFromIntent()}。
-這個方法會傳回包含文字回應的 {@link android.os.Bundle}。
-
-</li>
-
-<pre>
-Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-</pre>
-
-<li>使用 (提供給 {@link
-  android.support.v4.app.RemoteInput.Builder} 建構函式的) 結果金鑰查詢組合。
-</li>
-</ol>
-
-<p>下列程式碼片段說明方法如何從組合中擷取輸入文字:
-</p>
-
-<pre>
-// Obtain the intent that started this activity by calling
-// Activity.getIntent() and pass it into this method to
-// get the associated string.
-
-private CharSequence getMessageText(Intent intent) {
-    Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-    if (remoteInput != null) {
-            return remoteInput.getCharSequence(KEY_TEXT_REPLY);
-            }
-    return null;
- }
-</pre>
-
-<p>應用程式可以套用邏輯,決定擷取文字時要採取的動作。對於互動式應用程式 (像是聊天),要在通知本身提供更多內容 (例如,多行聊天歷程記錄,包括使用者自己的訊息),使用者才能適當回應。當使用者透過 {@link android.support.v4.app.RemoteInput} 回應時,請使用 {@code setRemoteInputHistory()}
- 方法在回覆歷程記錄中包括文字。
-
-
-
-
-
-</p>
-
-<h2 id="bundle">整合式通知</h2>
-
-<p>Android N 提供開發人員呈現通知佇列的全新方式:
- <i>整合式通知</i>。這類似於 Android Wear
-  中的<a href="{@docRoot}training/wearables/notifications/stacks.html">通知堆疊</a>。
-例如,若您的應用程式會為接收的訊息建立通知,收到多個訊息時,會將通知結合成單一群組。
-
-您可以使用現有的 {@link android.support.v4.app.NotificationCompat.Builder#setGroup
-Builder.setGroup()} 方法,結合類似的通知。
-</p>
-
-<p>
-  通知群組會對其中所含的通知強制施行階層。
-  階層的最上方是上層通知,顯示該群組的摘要資訊。
-使用者可以逐漸擴充通知群組,而系統會在使用者更深入探查時顯示更多資訊。
-
-當使用者擴充組合時,系統會為所有子通知揭露更多資訊。當使用者擴充當中的其中一個通知時,系統會顯示該通知的所有內容。
-
-
-</p>
-
-<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x,
-          {@docRoot}preview/images/bundles_2x.png 2x" width="300">
-<p class="img-caption">
-  <strong>圖 3.</strong> 使用者可以逐漸擴充通知群組。
-
-</p>
-
-<p>若要了解如何將通知新增至群組,請參閱<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">將每個通知新增至群組</a>。
-
-</p>
-
-
-<h3 id="best-practices">整合式通知最佳做法</h3>
-<p>本節提供使用通知群組時的指導方針,而不是舊版 Android 平台可用的 {@link android.app.Notification.InboxStyle InboxStyle}
-通知。
-
-</p>
-
-<h3>使用整合式通知的時機</h3>
-
-<p>只有當您的使用案例與下列條件全部相符時,才應該使用通知群組:
-</p>
-
-<ul>
-  <li>子通知是完整通知,也能個別顯示,而不需要群組摘要。
-</li>
-  <li>讓子通知個別出現有其優點。例如:
-
-  </li>
-  <ul>
-    <li>能以特定動作來對每個子通知執行動作。</li>
-    <li>可讓使用者想讀取的子通知能有更多資訊。</li>
-  </ul>
-</ul>
-
-<p>良好的通知群組使用案例範例包括:顯示一連串傳入訊息的訊息傳送應用程式,或顯示一系列所接收電子郵件清單的電子郵件應用程式。
-
-</p>
-
-<p>
-建議使用的單一通知案例範例包括:來自單人的個別訊息,或以清單呈現單行的文字項目。
-
-您可以使用
-({@link android.app.Notification.InboxStyle InboxStyle} 或
-{@link android.app.Notification.BigTextStyle BigTextStyle}) 來完成。
-
-</p>
-
-<h3 id ="post">顯示整合式通知</h3>
-
-<p>
-  應用程式應一律張貼群組摘要,即使群組當中只包含單一子項。
-如果只包含單一通知,系統會抑制摘要,並直接顯示子通知。
-這可確保當使用者滑動離開群組子項時,系統能提供一致的體驗。
-
-
-</p>
-
-<p class="note">
-  <strong>注意:</strong>本版 Android N 還不會抑制包含單一子通知的通知群組摘要。
-更新的 Android N 版本才會新增此功能。
-
-</p>
-
-<h3>預覽通知</h3>
-
-<p>雖然系統通常會將子通知顯示為群組,但您可以設定子通知,暫時顯示為<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">抬頭通知</a>
-。
-
-此功能允許立即存取最新的子通知和與它相關的動作,因此特別實用。
-
-</p>
-
-
-<h3>回溯相容性</h3>
-
-<p>
-  自從 Android 5.0 (API 層級 21) 支援 Android Wear 裝置以來,通知群組與遠端輸入都是 {@link
-  android.app.Notification} API 的一部分。
-如果您已使用這些 API 建置通知,您必須採取的動作只有確認應用程式行為符合上述的指導方針,以及考慮實作 {@code
-  setRemoteInputHistory()}。
-
-
-</p>
-
-<p>
-  為了支援回溯相容性,相同的 API 可與支援程式庫的 {@link android.support.v4.app.NotificationCompat}
- 類別搭配使用,讓您建置能在舊版 Android 上運作的通知。
-
-在手持裝置與平板電腦上,使用者只會看到摘要通知,應用程式應仍要為群組的完整資訊內容提供收件匣樣式或同等的通知呈現方式。
-
-雖然 Android
-  Wear 裝置即使在較舊的平台層級上,也允許使用者查看所有子通知,但不論 API 層級為何,您都應該建置子通知。
-
-
-</p>
-
-<h2 id="custom"> 自訂檢視</h2>
-<p>從 Android N 開始,您可以自訂通知檢視,也仍然可以取得系統裝飾,例如通知標題、動作及可擴充的版面配置。
-
-</p>
-
-<p>若要啟用此功能,Android N 新增下列 API 供您設定自訂檢視的樣式:
-</p>
-
-<dl>
-<dt>
-{@code DecoratedCustomViewStyle()}</dt>
-<dd> 設定媒體通知以外的通知樣式。
-</dd>
-<dt>
-{@code DecoratedMediaCustomViewStyle()}</dt>
-<dd> 設定媒體通知樣式</dd>
-</dl>
-
-<p>若要使用這個新 API,請呼叫 {@code setStyle()} 方法,再傳遞給想要的自訂檢視樣式。
-</p>
-
-<p>此程式碼片段顯示如何使用
-{@code DecoratedCustomViewStyle()} 方法,建構自訂通知物件。</p>
-
-<pre>
-Notification noti = new Notification.Builder()
-           .setSmallIcon(R.drawable.ic_stat_player)
-           .setLargeIcon(albumArtBitmap))
-           .setCustomContentView(contentView);
-           .setStyle(new Notification.DecoratedCustomViewStyle())
-           .build();
-
-</pre>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index fd54b7d..3a993d7 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -1,6 +1,8 @@
 # For information about this file's format, see
 # https://developers.google.com/internal/publishing/redirects
 redirects:
+- from: /guide/topics/fundamentals/fragments.html
+  to: /guide/components/fragments.html
 - from: /about/versions/index.html
   to: /about/index.html
 - from: /about/versions/api-levels.html
@@ -25,6 +27,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
@@ -39,8 +43,8 @@
   to: /studio/intro/update.html
 - from: /sdk/ndk/overview.html
   to: /ndk/index.html
-- from: /sdk/ndk/
-  to: /ndk/
+- from: /sdk/ndk/...
+  to: /ndk/...
 - from: /go/vulkan
   to: /ndk/guides/graphics/index.html
 - from: /tools/sdk/win-usb.html
@@ -99,18 +103,18 @@
   to: /training/testing/unit-testing/index.html
 - from: /training/activity-testing/activity-functional-testing.html
   to: /training/testing/ui-testing/index.html
-- from: /guide/market/
-  to: /google/play/
+- from: /guide/market/...
+  to: /google/play/...
 - from: /guide/google/play/services.html
   to: https://developers.google.com/android/guides/overview
-- from: /guide/google/
-  to: /google/
-- from: /training/id-auth/...
+- from: /guide/google/...
+  to: /google/...
+- from: /training/id-auth/
   to: /google/auth/http-auth.html
 - from: /google/play-services/auth.html
   to: https://developers.google.com/android/guides/http-auth
 - from: /google/play-services/games.html
-  to: https://developers.google.com/games/services/
+  to: https://developers.google.com/games/services
 - from: /google/play-services/location.html
   to: /training/location/index.html
 - from: /google/play-services/plus.html
@@ -118,21 +122,21 @@
 - from: /google/play-services/maps.html
   to: /training/maps/index.html
 - from: /google/play-services/drive.html
-  to: https://developers.google.com/drive/android/
+  to: https://developers.google.com/drive/android
 - from: /google/play-services/cast.html
-  to: https://developers.google.com/cast/
+  to: https://developers.google.com/cast
 - from: /google/play-services/ads.html
-  to: https://developers.google.com/mobile-ads-sdk/
+  to: https://developers.google.com/mobile-ads-sdk
 - from: /google/play-services/wallet.html
-  to: https://developers.google.com/wallet/instant-buy/
+  to: https://developers.google.com/wallet/instant-buy
 - from: /google/play-services/id.html
   to: https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient
 - from: /google/play/safetynet/...
   to: /training/safetynet/index.html
 - from: /google/gcm/...
-  to: https://developers.google.com/cloud-messaging/
+  to: https://developers.google.com/cloud-messaging/...
 - from: /google/gcs/...
-  to: https://developers.google.com/datastore/
+  to: https://developers.google.com/datastore/...
 - from: /google/play-services/safetynet.html
   to: /training/safetynet/index.html
 - from: /google/play/billing/v2/api.html
@@ -153,30 +157,32 @@
   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/
+  to: /studio/command-line/...
 - from: /guide/developing/...
-  to: /studio/
+  to: /studio/...
 - from: /tools/aidl.html
   to: /guide/components/aidl.html
 - from: /guide/market/publishing/multiple-apks.html
   to: /google/play/publishing/multiple-apks.html
 - from: /guide/publishing/publishing.html
   to: /distribute/tools/launch-checklist.html
-- from: /guide/publishing/
+- from: /guide/publishing/...
   to: /studio/publish/index.html
 - from: /guide/topics/fundamentals.html
   to: /guide/components/fundamentals.html
 - from: /guide/topics/intents/intents-filters.html
   to: /guide/components/intents-filters.html
-- from: /guide/topics/fundamentals/
-  to: /guide/components/
+- from: /guide/topics/fundamentals/...
+  to: /guide/components/...
 - from: /guide/topics/clipboard/copy-paste.html
   to: /guide/topics/text/copy-paste.html
 - from: /guide/topics/ui/notifiers/index.html
   to: /guide/topics/ui/notifiers/notifications.html
-- from: /guide/topics/wireless/
-  to: /guide/topics/connectivity/
+- from: /guide/topics/wireless/...
+  to: /guide/topics/connectivity/...
 - from: /guide/topics/drawing/...
   to: /guide/topics/graphics/opengl.html
 - from: /guide/topics/connectivity/usb/adk.html
@@ -213,8 +219,8 @@
   to: /training/articles/security-tips.html
 - from: /guide/appendix/market-filters.html
   to: /google/play/filters.html
-- from: /guide/topics/testing/
-  to: /studio/test/
+- from: /guide/topics/testing/...
+  to: /studio/test/...
 - from: /guide/topics/graphics/animation.html
   to: /guide/topics/graphics/overview.html
 - from: /guide/topics/graphics/renderscript/compute.html
@@ -231,24 +237,24 @@
   to: /guide/topics/renderscript/reference/overview.html
 - from: /guide/topics/location/obtaining-user-location.html
   to: /guide/topics/location/strategies.html
-- from: /guide/topics/nfc/
-  to: /guide/topics/connectivity/nfc/
-- from: /guide/topics/wireless/
-  to: /guide/topics/connectivity/
-- from: /guide/topics/network/
-  to: /guide/topics/connectivity/
+- from: /guide/topics/nfc/...
+  to: /guide/topics/connectivity/nfc/...
+- from: /guide/topics/wireless/...
+  to: /guide/topics/connectivity/...
+- from: /guide/topics/network/...
+  to: /guide/topics/connectivity/...
 - from: /resources/articles/creating-input-method.html
   to: /guide/topics/text/creating-input-method.html
 - from: /resources/articles/spell-checker-framework.html
   to: /guide/topics/text/spell-checker-framework.html
-- from: /resources/tutorials/notepad/
+- from: /resources/tutorials/notepad/...
   to: https://developer.android.com/training/basics/firstapp/index.html
-- from: /resources/faq/
-  to: /guide/faq/
+- from: /resources/faq/...
+  to: /guide/faq/...
 - from: /resources/tutorials/hello-world.html
   to: /training/basics/firstapp/index.html
-- from: /guide/practices/design/
-  to: /guide/practices/
+- from: /guide/practices/design/...
+  to: /guide/practices/...
 - from: /guide/practices/accessibility.html
   to: /guide/topics/ui/accessibility/index.html
 - from: /guide/practices/app-design/performance.html
@@ -357,8 +363,8 @@
   to: /training/wearables/notifications/pages.html
 - from: /wear/notifications/stacks.html
   to: /training/wearables/notifications/stacks.html
-- from: /reference/android/preview/support/
-  to: /reference/android/support/
+- from: /reference/android/preview/support/...
+  to: /reference/android/support/...
 - from: /wear/license.html
   to: /wear/index.html
 - from: /resources/dashboard/...
@@ -367,8 +373,8 @@
   to: /support.html
 - from: /community/index.html
   to: /support.html
-- from: /guide/tutorials/
-  to: /resources/tutorials/
+- from: /guide/tutorials/...
+  to: /resources/tutorials/...
 - from: /resources/tutorials/views/hello-linearlayout.html
   to: /guide/topics/ui/layout/linear.html
 - from: /resources/tutorials/views/hello-relativelayout.html
@@ -408,11 +414,9 @@
 - from: /resources/samples/...
   to: /samples/index.html
 - from: /resources/...
-  to: /training/
+  to: /training/...
 - from: /tools/samples/index.html
   to: /samples/index.html
-- from: /guide/publishing/publishing.html\#BuildaButton
-  to: https://play.google.com/intl/en_us/badges/
 - from: /distribute/essentials/best-practices/games.html
   to: /distribute/googleplay/guide.html
 - from: /distribute/essentials/best-practices/apps.html
@@ -426,13 +430,19 @@
 - from: /training/cloudsync/aesync.html
   to: /google/gcm/index.html
 - from: /training/cloudsync/index.html
-  to: /training/backup/index.html
-- from: /training/basics/location/
-  to: /training/location/
+  to: /guide/topics/data/backup.html
+- from: /training/backup/index.html
+  to: /guide/topics/data/backup.html
+- from: /training/backup/autosyncapi.html
+  to: /guide/topics/data/autobackup.html
+- from: /training/backup/backupapi.html
+  to: /guide/topics/data/keyvaluebackup.html
+- from: /training/basics/location/...
+  to: /training/location/...
 - from: /training/monetization/index.html
   to: /distribute/monetize/index.html
 - from: /training/monetization/ads-and-ux.html
-  to: https://developers.google.com/mobile-ads-sdk/
+  to: https://developers.google.com/mobile-ads-sdk/index.html
 - from: /training/notepad/...
   to: https://developer.android.com/training/basics/firstapp/index.html
 - from: /training/basics/actionbar/setting-up.html
@@ -443,8 +453,8 @@
   to: /training/appbar/index.html
 - from: /distribute/open.html
   to: /distribute/tools/open-distribution.html
-- from: /distribute/googleplay/promote/
-  to: /distribute/tools/promote/
+- from: /distribute/googleplay/promote/...
+  to: /distribute/tools/promote/...
 - from: /distribute/googleplay/publish/preparing.html
   to: /distribute/tools/launch-checklist.html
 - from: /distribute/googleplay/publish/index.html
@@ -473,8 +483,8 @@
   to: /distribute/monetize/index.html
 - from: /distribute/googleplay/about/distribution.html
   to: /distribute/googleplay/developer-console.html
-- from: /distribute/googleplay/spotlight/
-  to: /distribute/stories/
+- from: /distribute/googleplay/spotlight/...
+  to: /distribute/stories/...
 - from: /distribute/stories/localization.html
   to: /distribute/stories/index.html
 - from: /distribute/stories/tablets.html
@@ -536,11 +546,11 @@
 - from: /videos/index.html
   to: /develop/index.html
 - from: /live/index.html
-  to: https://developers.google.com/live/
-- from: /intl/zh-CN/
-  to: /intl/zh-cn/
-- from: /intl/zh-TW/
-  to: /intl/zh-tw/
+  to: https://developers.google.com/live/index.html
+- from: /intl/zh-CN/...
+  to: /intl/zh-cn/...
+- from: /intl/zh-TW/...
+  to: /intl/zh-tw/...
 - from: /4.2
   to: /about/versions/android-4.2.html
 - from: /4.1
@@ -549,111 +559,111 @@
   to: /about/versions/android-4.0.html
 - from: /5
   to: /about/versions/android-5.0.html
-- from: /5/
+- from: /5/...
   to: /about/versions/android-5.0.html
 
 - from: /m
   to: /about/versions/marshmallow/index.html
-- from: /m/
+- from: /m/...
   to: /about/versions/marshmallow/index.html
 - from: /mm
   to: /about/versions/marshmallow/index.html
-- from: /mm/
+- from: /mm/...
   to: /about/versions/marshmallow/index.html
 - from: /marshmallow
   to: /about/versions/marshmallow/index.html
-- from: /marshmallow/
+- from: /marshmallow/...
   to: /about/versions/marshmallow/index.html
 
 - from: /l
   to: /about/versions/lollipop.html
-- from: /l/
+- from: /l/...
   to: /about/versions/lollipop.html
 - from: /ll
   to: /about/versions/lollipop.html
-- from: /ll/
+- from: /ll/...
   to: /about/versions/lollipop.html
 - from: /lp
   to: /about/versions/lollipop.html
-- from: /lp/
+- from: /lp/...
   to: /about/versions/lollipop.html
 - from: /lollipop
   to: /about/versions/lollipop.html
-- from: /lollipop/
+- from: /lollipop/...
   to: /about/versions/lollipop.html
 
 - from: /k
   to: /about/versions/kitkat.html
-- from: /k/
+- from: /k/...
   to: /about/versions/kitkat.html
 - from: /kk
   to: /about/versions/kitkat.html
-- from: /kk/
+- from: /kk/...
   to: /about/versions/kitkat.html
 - from: /kitkat
   to: /about/versions/kitkat.html
-- from: /kitkat/
+- from: /kitkat/...
   to: /about/versions/kitkat.html
 
 - from: /j
   to: /about/versions/jelly-bean.html
-- from: /j/
+- from: /j/...
   to: /about/versions/jelly-bean.html
 - from: /jj
   to: /about/versions/jelly-bean.html
-- from: /jj/
+- from: /jj/...
   to: /about/versions/jelly-bean.html
 - from: /jellybean
   to: /about/versions/jelly-bean.html
-- from: /jellybean/
+- from: /jellybean/...
   to: /about/versions/jelly-bean.html
 
 - from: /i
   to: /about/versions/android-4.0-highlights.html
-- from: /i/
+- from: /i/...
   to: /about/versions/android-4.0-highlights.html
 - from: /ics
   to: /about/versions/android-4.0-highlights.html
-- from: /ics/
+- from: /ics/...
   to: /about/versions/android-4.0-highlights.html
 - from: /icecreamsandwich
   to: /about/versions/android-4.0-highlights.html
-- from: /icecreamsandwich/
+- from: /icecreamsandwich/...
   to: /about/versions/android-4.0-highlights.html
 
 - from: /%2B
   to: https://plus.google.com/108967384991768947849/posts
-- from: /%2B/
+- from: /%2B/...
   to: https://plus.google.com/108967384991768947849/posts
 - from: /blog
-  to: https://android-developers.blogspot.com/
+  to: https://android-developers.blogspot.com
 - from: /stats
   to: /about/dashboards/index.html
 - from: /youtube
   to: https://www.youtube.com/user/androiddevelopers
 - from: /playbadge
-  to: https://play.google.com/intl/en_us/badges/
-- from: /playbadge/
-  to: https://play.google.com/intl/en_us/badges/
+  to: https://play.google.com/intl/en_us/badges
+- from: /playbadge/...
+  to: https://play.google.com/intl/en_us/badges/...
 - from: /distribute/tools/promote/badges.html
-  to: https://play.google.com/intl/en_us/badges/
+  to: https://play.google.com/intl/en_us/badges
 - from: /deviceart
   to: /distribute/tools/promote/device-art.html
-- from: /deviceart/
+- from: /deviceart/...
   to: /distribute/tools/promote/device-art.html
 - from: /distribute/promote/device-art.html
   to: /distribute/tools/promote/device-art.html
 - from: /edu/signup
   to: https://services.google.com/fb/forms/playedu
-- from: /edu/signup/
+- from: /edu/signup/...
   to: https://services.google.com/fb/forms/playedu
 - from: /edu
   to: /distribute/googleplay/edu/about.html
-- from: /edu/
+- from: /edu/...
   to: /distribute/googleplay/edu/about.html
 - from: /families
   to: /distribute/googleplay/families/about.html
-- from: /families/
+- from: /families/...
   to: /distribute/googleplay/families/about.html
 - from: /preview/google-play-services-wear.html
   to: /training/building-wearables.html
@@ -709,9 +719,9 @@
   to: /training/material/animations.html
 - from: /preview/material/compatibility.html
   to: /training/material/compatibility.html
-- from: /preview/material/
+- from: /preview/material/...
   to: /design/material/index.html
-- from: /auto/overview/
+- from: /auto/overview/...
   to: /training/auto/start/index.html
 - from: /training/location/activity-recognition.html
   to: /training/location/index.html
@@ -734,9 +744,9 @@
 - from: /training/enterprise/work-policy-ctrl.html
   to: https://developers.google.com/android/work/build-dpc
 - from: /distribute/tools/promote/badge-files.html
-  to: https://play.google.com/intl/en_us/badges/
+  to: https://play.google.com/intl/en_us/badges
 - from: /google/gcm/...
-  to: https://developers.google.com/cloud-messaging/
+  to: https://developers.google.com/cloud-messaging
 - from: /training/cloudsync/gcm.html
   to: /training/cloudsync/index.html
 
@@ -792,29 +802,32 @@
 - from: /preview/features/app-linking.html
   to: /training/app-links/index.html
 - from: /preview/backup/index.html
-  to: /training/backup/autosyncapi.html
+  to: /guide/topics/data/backup/autobackup.html
 - from: /preview/features/power-mgmt.html
   to: /training/monitoring-device-state/doze-standby.html
 - 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
-- 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://source.android.com/source/report-bugs.html
 - from: /preview/bugreport
-  to: https://code.google.com/p/android/issues/entry?template=Developer%20preview%20report
-- 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://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/
+- from: /preview/bugs/...
   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
 - from: /preview/bugreports
   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
-- from: /preview/bugreports/
+- from: /preview/bugreports/...
   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
+- from: /preview/setup-sdk.html
+  to: /studio/index.html
 - from: /2016/03/first-preview-of-android-n-developer.html
   to: http://android-developers.blogspot.com/2016/03/first-preview-of-android-n-developer.html
+
 - from: /reference/org/apache/http/...
   to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
 - from: /shareables/...
@@ -835,6 +848,10 @@
   to: /topic/performance/power/network/gather-data.html
 - from: /training/performance/battery/network/index.html
   to: /topic/performance/power/network/index.html
+- from: /training/articles/memory.html
+  to: /topic/performance/memory.html
+- from: /topic/performance/optimizing-view-hierarchies.html
+  to: /topic/performance/rendering/optimizing-view-hierarchies.html
 
 # Redirects for the new [dac]/topic/libraries/ area
 
@@ -1149,72 +1166,132 @@
 # Vanity urls
 - from: /background_optimizations
   to: /preview/features/background-optimization.html
-- from: /background_optimizations/
+- from: /background_optimizations/...
   to: /preview/features/background-optimization.html
 - from: /bgopt
   to: /preview/features/background-optimization.html
-- from: /bgopt/
+- from: /bgopt/...
   to: /preview/features/background-optimization.html
 
 
 
 # Android Studio help button redirects
 - from: /r/studio-ui/vector-asset-studio.html
-  to: /studio/write/vector-asset-studio.html?utm_medium=android-studio
+  to: /studio/write/vector-asset-studio.html?utm_source=android-studio
 - from: /r/studio-ui/image-asset-studio.html
-  to: /studio/write/image-asset-studio.html?utm_medium=android-studio
+  to: /studio/write/image-asset-studio.html?utm_source=android-studio
 - from: /r/studio-ui/project-structure.html
-  to: /studio/projects/index.html?utm_medium=android-studio
+  to: /studio/projects/index.html?utm_source=android-studio
 - from: /r/studio-ui/android-monitor.html
-  to: /studio/profile/android-monitor.html?utm_medium=android-studio
+  to: /studio/profile/android-monitor.html?utm_source=android-studio
 - from: /r/studio-ui/am-logcat.html
-  to: /studio/debug/am-logcat.html?utm_medium=android-studio
+  to: /studio/debug/am-logcat.html?utm_source=android-studio
 - from: /r/studio-ui/am-memory.html
-  to: /studio/profile/am-memory.html?utm_medium=android-studio
+  to: /studio/profile/am-memory.html?utm_source=android-studio
 - from: /r/studio-ui/am-cpu.html
-  to: /studio/profile/am-cpu.html?utm_medium=android-studio
+  to: /studio/profile/am-cpu.html?utm_source=android-studio
 - from: /r/studio-ui/am-gpu.html
-  to: /studio/profile/am-gpu.html?utm_medium=android-studio
+  to: /studio/profile/am-gpu.html?utm_source=android-studio
 - from: /r/studio-ui/am-network.html
-  to: /studio/profile/am-network.html?utm_medium=android-studio
+  to: /studio/profile/am-network.html?utm_source=android-studio
 - from: /r/studio-ui/am-hprof.html
-  to: /studio/profile/am-hprof.html?utm_medium=android-studio
+  to: /studio/profile/am-hprof.html?utm_source=android-studio
 - from: /r/studio-ui/am-allocation.html
-  to: /studio/profile/am-allocation.html?utm_medium=android-studio
+  to: /studio/profile/am-allocation.html?utm_source=android-studio
 - from: /r/studio-ui/am-methodtrace.html
-  to: /studio/profile/am-methodtrace.html?utm_medium=android-studio
+  to: /studio/profile/am-methodtrace.html?utm_source=android-studio
 - from: /r/studio-ui/am-sysinfo.html
-  to: /studio/profile/am-sysinfo.html?utm_medium=android-studio
+  to: /studio/profile/am-sysinfo.html?utm_source=android-studio
 - from: /r/studio-ui/am-screenshot.html
-  to: /studio/debug/am-screenshot.html?utm_medium=android-studio
+  to: /studio/debug/am-screenshot.html?utm_source=android-studio
 - from: /r/studio-ui/am-video.html
-  to: /studio/debug/am-video.html?utm_medium=android-studio
+  to: /studio/debug/am-video.html?utm_source=android-studio
 - from: /r/studio-ui/avd-manager.html
-  to: /studio/run/managing-avds.html?utm_medium=android-studio
+  to: /studio/run/managing-avds.html?utm_source=android-studio
 - from: /r/studio-ui/rundebugconfig.html
-  to: /studio/run/rundebugconfig.html?utm_medium=android-studio
+  to: /studio/run/rundebugconfig.html?utm_source=android-studio
 - from: /r/studio-ui/devicechooser.html
-  to: /studio/run/emulator.html?utm_medium=android-studio
+  to: /studio/run/emulator.html?utm_source=android-studio
 - from: /r/studio-ui/virtualdeviceconfig.html
-  to: /studio/run/managing-avds.html?utm_medium=android-studio
+  to: /studio/run/managing-avds.html?utm_source=android-studio
 - from: /r/studio-ui/emulator.html
-  to: /studio/run/emulator.html?utm_medium=android-studio
+  to: /studio/run/emulator.html?utm_source=android-studio
 - from: /r/studio-ui/instant-run.html
-  to: /studio/run/index.html?utm_medium=android-studio#instant-run
+  to: /studio/run/index.html?utm_source=android-studio#instant-run
 - from: /r/studio-ui/test-recorder.html
-  to: http://tools.android.com/tech-docs/test-recorder
+  to: /studio/test/espresso-test-recorder.html?utm_source=android-studio
 - from: /r/studio-ui/export-licenses.html
   to: http://tools.android.com/tech-docs/new-build-system/license
 - from: /r/studio-ui/experimental-to-stable-gradle.html
   to: http://tools.android.com/tech-docs/new-build-system/gradle-experimental/experimental-to-stable-gradle
 - from: /r/studio-ui/sdk-manager.html
-  to: /studio/intro/update.html?utm_medium=android-studio#sdk-manager
+  to: /studio/intro/update.html?utm_source=android-studio#sdk-manager
 - from: /r/studio-ui/newjclass.html
-  to: /studio/write/index.html?utm_medium=android-studio
+  to: /studio/write/create-java-class.html?utm_source=android-studio
 - from: /r/studio-ui/menu-help.html
-  to: /studio/intro/index.html?utm_medium=android-studio
+  to: /studio/intro/index.html?utm_source=android-studio
 - from: /r/studio-ui/menu-start.html
-  to: /training/index.html?utm_medium=android-studio
+  to: /training/index.html?utm_source=android-studio
+- from: /r/studio-ui/run-with-work-profile.html
+  to: /studio/run/index.html?utm_source=android-studio#ir-work-profile
+- from: /r/studio-ui/am-gpu-debugger.html
+  to: /studio/profile/am-gpu.html?utm_source=android-studio
+- from: /r/studio-ui/theme-editor.html
+  to: /studio/write/theme-editor.html?utm_source=android-studio
+- from: /r/studio-ui/translations-editor.html
+  to: /studio/write/translations-editor.html?utm_source=android-studio
+- from: /r/studio-ui/debug.html
+  to: /studio/debug/index.html?utm_source=android-studio
+- from: /r/studio-ui/run.html
+  to: /studio/run/index.html?utm_source=android-studio
+- from: /r/studio-ui/layout-editor.html
+  to: /studio/write/layout-editor.html?utm_source=android-studio
+- from: /r/studio-ui/project-window.html
+  to: /studio/projects/index.html?utm_source=android-studio
+- from: /r/studio-ui/lint-inspection-results.html
+  to: /studio/write/lint.html?utm_source=android-studio
+- from: /r/studio-ui/gradle-console.html
+  to: /studio/run/index.html?utm_source=android-studio#gradle-console
+- from: /r/studio-ui/app-indexing-test.html
+  to: /studio/write/app-link-indexing.html#appindexingtest?utm_source=android-studio
+- from: /r/studio-ui/vcs.html
+  to: /studio/intro/index.html#version_control_basics?utm_source=android-studio
+- from: /r/studio-ui/create-new-module.html
+  to: /studio/projects/index.html#ApplicationModules?utm_source=android-studio
+- from: /r/studio-ui/build-variants.html
+  to: /studio/run/index.html#changing-variant?utm_source=android-studio
+- from: /r/studio-ui/generate-signed-apk.html
+  to: /studio/publish/app-signing.html#release-mode?utm_source=android-studio
+- from: /r/studio-ui/import-project-vcs.html
+  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
+- from: /r/studio-ui/apk-analyzer.html
+  to: /studio/build/apk-analyzer.html?utm_source=android-studio
+- from: /r/studio-ui/breakpoints.html
+  to: /studio/debug/index.html#breakPointsView?utm_source=android-studio
+- from: /r/studio-ui/attach-debugger-to-process.html
+  to: /studio/debug/index.html?utm_source=android-studio
+- from: /r/studio-ui/import-sample.html
+  to: /samples/index.html?utm_source=android-studio
+- from: /r/studio-ui/import-module.html
+  to: /studio/projects/add-app-module.html#ImportAModule?utm_source=android-studio
+- from: /r/studio-ui/import-project.html
+  to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
+- from: /r/studio-ui/create-project.html
+  to: /studio/projects/create-project.html?utm_source=android-studio
+- from: /r/studio-ui/new-activity.html
+  to: /studio/projects/template.html?utm_source=android-studio
+- from: /r/studio-ui/new-resource-file.html
+  to: /studio/write/add-resources.html?utm_source=android-studio
+- from: /r/studio-ui/new-resource-dir.html
+  to: /studio/write/add-resources.html#add_a_resource_directory?utm_source=android-studio
+- from: /r/studio-ui/configure-component.html
+  to: /studio/write/add-resources.html?utm_source=android-studio
+- from: /r/studio-ui/ninepatch.html
+  to: /studio/write/draw9patch.html?utm_source=android-studio
+- from: /r/studio-ui/firebase-assistant.html
+  to: /studio/write/firebase.html?utm_source=android-studio
+- from: /r/studio-ui/ir-flight-recorder.html
+  to: /studio/run/index.html?utm_source=android-studio#submit-feedback
 
 # Redirects from (removed) N Preview documentation
 - from: /preview/features/afw.html
@@ -1248,7 +1325,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
@@ -1257,4 +1334,3 @@
   to: /topic/performance/background-optimization.html
 - from: /preview/features/data-saver.html
   to: /training/basics/network-ops/data-saver.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/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index f5d23e8..2721c85 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -59,7 +59,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -81,7 +81,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016.
 
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
@@ -101,7 +101,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A44.9%2C42.3%2C12.8&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -119,21 +119,21 @@
 </tr>
 <tr>
 <td>2.0</td>
-<td>46.0%</td>
+<td>44.9%</td>
 </tr>
 <tr>
 <td>3.0</td>
-<td>42.6%</td>
+<td>42.3%</td>
 </tr>
 <tr>
 <td>3.1</td>
-<td>11.4%</td>
+<td>12.8%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016</em></p>
 
 
 
@@ -147,19 +147,19 @@
       "Large": {
         "hdpi": "0.5",
         "ldpi": "0.2",
-        "mdpi": "4.3",
+        "mdpi": "4.1",
         "tvdpi": "2.1",
         "xhdpi": "0.5"
       },
       "Normal": {
-        "hdpi": "40.0",
-        "mdpi": "3.8",
-        "tvdpi": "0.1",
-        "xhdpi": "27.3",
+        "hdpi": "39.5",
+        "mdpi": "3.5",
+        "tvdpi": "0.2",
+        "xhdpi": "28.4",
         "xxhdpi": "15.5"
       },
       "Small": {
-        "ldpi": "1.8"
+        "ldpi": "1.6"
       },
       "Xlarge": {
         "hdpi": "0.3",
@@ -167,8 +167,8 @@
         "xhdpi": "0.7"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c",
-    "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c"
+    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A1.8%2C10.5%2C2.3%2C40.4%2C29.6%2C15.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250",
+    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A3.9%2C7.4%2C87.2%2C1.6&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250"
   }
 ];
 
@@ -176,7 +176,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c",
+    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chd=t%3A0.1%2C1.5%2C1.4%2C15.6%2C27.7%2C35.0%2C18.7&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=500x250",
     "data": [
       {
         "api": 8,
@@ -186,47 +186,47 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "1.7"
+        "perc": "1.5"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "1.6"
+        "perc": "1.4"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "6.0"
+        "perc": "5.6"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "8.3"
+        "perc": "7.7"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "2.4"
+        "perc": "2.3"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "29.2"
+        "perc": "27.7"
       },
       {
         "api": 21,
         "name": "Lollipop",
-        "perc": "14.1"
+        "perc": "13.1"
       },
       {
         "api": 22,
         "name": "Lollipop",
-        "perc": "21.4"
+        "perc": "21.9"
       },
       {
         "api": 23,
         "name": "Marshmallow",
-        "perc": "15.2"
+        "perc": "18.7"
       }
     ]
   }
diff --git a/docs/html/about/versions/android-1.5.jd b/docs/html/about/versions/android-1.5.jd
index 45a27ee..6db5472 100644
--- a/docs/html/about/versions/android-1.5.jd
+++ b/docs/html/about/versions/android-1.5.jd
@@ -101,7 +101,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-1.6-highlights.jd b/docs/html/about/versions/android-1.6-highlights.jd
index 9179579..f594449 100644
--- a/docs/html/about/versions/android-1.6-highlights.jd
+++ b/docs/html/about/versions/android-1.6-highlights.jd
@@ -6,8 +6,8 @@
 
 
 <style type="text/css">
-#jd-content div.screenshot,
-#jd-content div.video {
+#body-content div.screenshot,
+#body-content div.video {
   float:right;
   clear:right;
   padding:15px 70px;
@@ -15,11 +15,11 @@
   font-weight:bold;
   line-height:1.7em;
 }
-#jd-content div.video {
+#body-content div.video {
   padding-top:0;
   margin-top:-15px;
 }
-#jd-content div.screenshot img {
+#body-content div.screenshot img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-1.6.jd b/docs/html/about/versions/android-1.6.jd
index 970c343..a84c225 100755
--- a/docs/html/about/versions/android-1.6.jd
+++ b/docs/html/about/versions/android-1.6.jd
@@ -103,7 +103,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.0-highlights.jd b/docs/html/about/versions/android-2.0-highlights.jd
index 3f7e1c8..017b16f 100644
--- a/docs/html/about/versions/android-2.0-highlights.jd
+++ b/docs/html/about/versions/android-2.0-highlights.jd
@@ -6,8 +6,8 @@
 
 
 <style type="text/css">
-#jd-content div.screenshot,
-#jd-content div.video {
+#body-content div.screenshot,
+#body-content div.video {
   float:right;
   clear:right;
   padding:15px 60px;
@@ -15,15 +15,15 @@
   font-weight:bold;
   line-height:1.7em;
 }
-#jd-content div.video {
+#body-content div.video {
   padding-top:0;
   margin-top:-15px;
 }
-#jd-content div.screenshot.second {
+#body-content div.screenshot.second {
   clear:none;
   padding:15px 0 15px 60px;
 }
-#jd-content div.screenshot img {
+#body-content div.screenshot img {
   margin:0;
   border:1px solid #ccc;
 }
diff --git a/docs/html/about/versions/android-2.0.1.jd b/docs/html/about/versions/android-2.0.1.jd
index b0f4db6..21bfa65 100644
--- a/docs/html/about/versions/android-2.0.1.jd
+++ b/docs/html/about/versions/android-2.0.1.jd
@@ -99,7 +99,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.0.jd b/docs/html/about/versions/android-2.0.jd
index 0323686..8029633 100644
--- a/docs/html/about/versions/android-2.0.jd
+++ b/docs/html/about/versions/android-2.0.jd
@@ -92,7 +92,7 @@
 .toggleable.closed .toggleme {
   display:none;
 }
-#jd-content .toggle-img {
+#body-content .toggle-img {
   margin:0;
 }
 </style>
diff --git a/docs/html/about/versions/android-2.2-highlights.jd b/docs/html/about/versions/android-2.2-highlights.jd
index afbf26b..37a7a82 100644
--- a/docs/html/about/versions/android-2.2-highlights.jd
+++ b/docs/html/about/versions/android-2.2-highlights.jd
@@ -5,32 +5,32 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:800px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
   margin-top:-15px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-2.3-highlights.jd b/docs/html/about/versions/android-2.3-highlights.jd
index 582bce9..013ec7f 100644
--- a/docs/html/about/versions/android-2.3-highlights.jd
+++ b/docs/html/about/versions/android-2.3-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 0 0 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-3.0-highlights.jd b/docs/html/about/versions/android-3.0-highlights.jd
index e9d2b39..50d4667 100644
--- a/docs/html/about/versions/android-3.0-highlights.jd
+++ b/docs/html/about/versions/android-3.0-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-3.1-highlights.jd b/docs/html/about/versions/android-3.1-highlights.jd
index 2a70698..22df372 100644
--- a/docs/html/about/versions/android-3.1-highlights.jd
+++ b/docs/html/about/versions/android-3.1-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1200px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 60px 40px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-4.0-highlights.jd b/docs/html/about/versions/android-4.0-highlights.jd
index c980af6..57eb2a3 100755
--- a/docs/html/about/versions/android-4.0-highlights.jd
+++ b/docs/html/about/versions/android-4.0-highlights.jd
@@ -4,31 +4,31 @@
 
 
 <style type="text/css">
-#jd-content {
+#body-content {
   max-width:1024px;
 }
-#jd-content div.screenshot {
+#body-content div.screenshot {
   float:left;
   clear:left;
   padding:15px 30px 15px 0;
 }
-#jd-content div.video {
+#body-content div.video {
   float:right;
   padding:0 0 40px 60px;
 }
-#jd-content table.columns {
+#body-content table.columns {
   margin:0 0 1em 0;
 }
-#jd-content table.columns td {
+#body-content table.columns td {
   padding:0;
 }
-#jd-content table.columns td+td {
+#body-content table.columns td+td {
   padding:0 2em;
 }
-#jd-content table.columns td img {
+#body-content table.columns td img {
   margin:0;
 }
-#jd-content table.columns td+td>*:first-child {
+#body-content table.columns td+td>*:first-child {
   margin-top:-2em;
 }
 .green {
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index bf68584..48afcd4 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -631,8 +631,8 @@
 <p>A new package, {@link android.net.wifi.p2p}, contains all the APIs for performing peer-to-peer
 connections with Wi-Fi. The primary class you need to work with is {@link
 android.net.wifi.p2p.WifiP2pManager}, which you can acquire by calling {@link
-android.app.Activity#getSystemService(java.lang.String) getSystemService(WIFI_P2P_SERVICE)}.
-The {@link android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
+android.app.Activity#getSystemService getSystemService(WIFI_P2P_SERVICE)}. The {@link
+android.net.wifi.p2p.WifiP2pManager} includes APIs that allow you to:</p>
 <ul>
 <li>Initialize your application for P2P connections by calling {@link
 android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</li>
@@ -798,7 +798,7 @@
 android.R.attr#contentDescription android:contentDescription} text is missing or
 insufficient. To add more text description to the
 {@link android.view.accessibility.AccessibilityEvent}, call {@link
-android.view.accessibility.AccessibilityRecord#getText()}.{@link java.util.List#add add()}.</p>
+android.view.accessibility.AccessibilityEvent#getText()}.{@link java.util.List#add add()}.</p>
 </li>
   <li>At this point, the {@link android.view.View} passes the event up the view hierarchy by calling
 {@link android.view.ViewGroup#requestSendAccessibilityEvent requestSendAccessibilityEvent()} on the
diff --git a/docs/html/about/versions/android-4.2.jd b/docs/html/about/versions/android-4.2.jd
index ac84d0f..34fa1d4 100755
--- a/docs/html/about/versions/android-4.2.jd
+++ b/docs/html/about/versions/android-4.2.jd
@@ -213,9 +213,9 @@
 <p>Android now allows your app to display unique content on additional screens that are connected
 to the user’s device over either a wired connection or Wi-Fi.
  To create unique content for a secondary display, extend the {@link android.app.Presentation}
-class and implement the {@link android.app.Dialog#onCreate onCreate()} callback. Within
-{@link android.app.Dialog#onCreate onCreate()}, specify your UI for the secondary display
-by calling {@link android.app.Dialog#setContentView setContentView()}.
+class and implement the {@link android.app.Presentation#onCreate onCreate()} callback. Within
+{@link android.app.Presentation#onCreate onCreate()}, specify your UI for the secondary display
+by calling {@link android.app.Presentation#setContentView setContentView()}.
 As an extension of the {@link android.app.Dialog} class, the {@link
 android.app.Presentation} class provides the region in which your app can display a unique UI on the
 secondary display.</p>
@@ -241,13 +241,13 @@
 
 <p>To detect at runtime when a new display has been connected, create an instance of {@link
 android.media.MediaRouter.SimpleCallback} in which you implement the {@link
-android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
+android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
 onRoutePresentationDisplayChanged()} callback method, which the system will call when a new
 presentation display is connected. Then register the {@link
 android.media.MediaRouter.SimpleCallback} by passing it to {@link
 android.media.MediaRouter#addCallback MediaRouter.addCallback()} along with the {@link
 android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} route type. When you receive a call to
-{@link android.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
+{@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged
 onRoutePresentationDisplayChanged()}, simply call {@link
 android.media.MediaRouter#getSelectedRoute MediaRouter.getSelectedRoute()} as mentioned above.</p>
 
@@ -262,7 +262,7 @@
 likely a different screen density. Because the screen characteristics may different, you should
 provide resources that are optimized specifically for such larger displays. If you need
 to request additional resources from your {@link
-android.app.Presentation}, call {@link android.app.Dialog#getContext()}{@link
+android.app.Presentation}, call {@link android.app.Presentation#getContext()}{@link
 android.content.Context#getResources .getResources()} to get the {@link
 android.content.res.Resources} object corresponding to the display. This provides
 the appropriate resources from your app that are best suited for the
@@ -510,7 +510,7 @@
   <p>To use a script intrinsic, call the static <code>create()</code> method of each instrinsic
   to create an instance of the script. You then call the available <code>set()</code>
   methods of each script intrinsic to set any necessary inputs and options.
-  Finally, call the {@link android.renderscript.Script#forEach forEach()}</code>
+  Finally, call the {@link android.renderscript.ScriptC#forEach forEach()}</code>
   method to execute the script.</p>
   </dd>
 
diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
index 34a701b..547b2f8 100644
--- a/docs/html/about/versions/android-4.3.jd
+++ b/docs/html/about/versions/android-4.3.jd
@@ -907,7 +907,7 @@
 
 <p>To track changes to inserts and updates, you can now include the {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP} parameter with your selection to query only the contacts that have changed since the last time you queried the provider.</p>
 
-<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContactsColumns#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
+<p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContacts#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
 
 <p>Additionally, the Contacts Provider now broadcasts the {@link
 android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user
diff --git a/docs/html/about/versions/marshmallow/android-6.0-changes.jd b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
index 65c976b..b44142e 100644
--- a/docs/html/about/versions/marshmallow/android-6.0-changes.jd
+++ b/docs/html/about/versions/marshmallow/android-6.0-changes.jd
@@ -280,7 +280,7 @@
 If your app uses the
 {@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method and you
 want to override access checks, call the
-{@link java.lang.reflect.AccessibleObject#setAccessible(boolean) setAccessible()} method with the input
+{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} method with the input
 parameter set to {@code true}. If your app uses the
 <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7 appcompat library</a> or the
 <a href="{@docRoot}tools/support-library/features.html#v7-recyclerview">v7 recyclerview library</a>,
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..cb92f19 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>
@@ -184,8 +182,8 @@
 </p>
 
 <p>
-  For more information about background optimizations in N and how to adapt your app,
-  see <a href=
+  For more information about background optimizations in Android 7.0 (API level
+  24) and how to adapt your app, see <a href=
   "{@docRoot}preview/features/background-optimization.html">Background
   Optimizations</a>.
 </p>
@@ -429,12 +427,13 @@
   released apps, a set of libraries that see significant use—such as
   <code>libandroid_runtime.so</code>, <code>libcutils.so</code>,
   <code>libcrypto.so</code>, and <code>libssl.so</code>—are temporarily
-  accessible on N for apps targeting API level 23 or lower. If your app loads
-  one of these libraries, logcat generates a warning and a toast appears on the
-  target device to notify you. If you see these warnings, you should update
-  your app to either include its own copy of those libraries or only use the
-  public NDK APIs. Future releases of the Android platform may restrict the use
-  of private libraries altogether and cause your app to crash.
+  accessible on Android 7.0 (API level 24) for apps targeting API level 23 or
+  lower. If your app loads one of these libraries, logcat generates a warning
+  and a toast appears on the target device to notify you. If you see these
+  warnings, you should update your app to either include its own copy of those
+  libraries or only use the public NDK APIs. Future releases of the Android
+  platform may restrict the use of private libraries altogether and cause your
+  app to crash.
 </p>
 
 <p>
@@ -443,9 +442,9 @@
   <code>System.loadLibrary</code> and <code>dlopen(3)</code> both return
   <code>NULL</code>, and may cause your app to crash. You should review your
   app code to remove use of private platform APIs and thoroughly test your apps
-  using a preview device or emulator. If you are unsure whether your app uses
-  private libraries, you can <a href="#ndk-errors">check logcat</a> to identify
-  the runtime error.
+  using a device or emulator running Android 7.0 (API level 24). If you are
+  unsure whether your app uses private libraries, you can <a href=
+  "#ndk-errors">check logcat</a> to identify the runtime error.
 </p>
 
 <p>
@@ -456,11 +455,6 @@
 
 <table id="ndk-table">
   <col width="15%">
-  <col width="15%">
-  <col width="15%">
-  <col width="20%">
-  <col width="20%">
-  <col width="20%">
   <tr>
     <th scope="col">
       Libraries
@@ -472,10 +466,7 @@
       Runtime access via dynamic linker
     </th>
     <th scope="col">
-      N Developer Preview behavior
-    </th>
-    <th scope="col">
-      Final N Release behavior
+      Android 7.0 (API level 24) behavior
     </th>
     <th scope="col">
       Future Android platform behavior
@@ -502,10 +493,6 @@
   <td style="background-color:#DCEDC8">
     Works as expected
   </td>
-
-  <td style="background-color:#DCEDC8">
-    Works as expected
-  </td>
 </tr>
 
 <tr>
@@ -522,11 +509,6 @@
   </td>
 
   <td style="background-color:#FFF9C4">
-      Works as expected, but you receive a logcat warning and a message on the
-      target device.
-  </td>
-
-  <td style="background-color:#FFF9C4">
     Works as expected, but you receive a logcat warning.
   </td>
 
@@ -555,10 +537,6 @@
   <td style="background-color:#ffcdd2">
     Runtime error
   </td>
-
-  <td style="background-color:#ffcdd2">
-    Runtime error
-  </td>
 </tr>
 
 <tr>
@@ -581,10 +559,6 @@
   <td style="background-color:#ffcdd2">
     Runtime error
   </td>
-
-  <td style="background-color:#ffcdd2">
-    Runtime error
-  </td>
 </tr>
 </table>
 
@@ -701,8 +675,8 @@
 
 <ul>
   <li>You must install a delegated certificate installer before the DPC can set
-  it. For both profile and device-owner apps targeting the N SDK, you should
-  install the delegated certificate installer before the device policy
+  it. For both profile and device-owner apps targeting Android 7.0 (API level 24),
+  you should install the delegated certificate installer before the device policy
   controller (DPC) calls
   <code>DevicePolicyManager.setCertInstallerPackage()</code>. If the installer
   is not already installed, the system throws an
@@ -749,12 +723,13 @@
   DER-encoded format under a .crt or .cer file extension.
   </li>
 
-  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed per user.
-  If a profile owner’s Device Policy Client (DPC) targets pre-N on an N device,
-  the user is still able to set fingerprint on the device, but work
-  applications cannot access device fingerprint. When the DPC targets N and
-  above, the user can set fingerprint specifically for work profile by going to
-  <strong>Settings &gt; Security &gt; Work profile security</strong>.
+  <li>Starting in Android 7.0, fingerprint enrollment and storage are managed
+  per user. If a profile owner’s Device Policy Client (DPC) targets API level
+  23 (or lower) on a device running Android 7.0 (API level 24), the user is
+  still able to set fingerprint on the device, but work applications cannot
+  access device fingerprint. When the DPC targets API level 24 and above, the user can set
+  fingerprint specifically for work profile by going to <strong>Settings &gt;
+  Security &gt; Work profile security</strong>.
   </li>
 
   <li>A new encryption status <code>ENCRYPTION_STATUS_ACTIVE_PER_USER</code> is
@@ -824,8 +799,9 @@
 </p>
 
 <p>
-Apps targeting N and above are not automatically killed on density changes;
-however, they may still respond poorly to configuration changes.
+  Apps targeting Android 7.0 (API level 24) and above are not automatically
+  killed on density changes; however, they may still respond poorly to
+  configuration changes.
 </p>
 </li>
 
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..8ef8bd6 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
 
@@ -44,7 +44,7 @@
         <li><a href="#vr">VR Support</a></li>
         <li><a href="#print_svc">Print Service Enhancements</a></li>
         <li><a href="#virtual_files">Virtual Files</a></li>
-        <li><a href="#framemetrics_api">FrameMetricsListener API</a></li>
+        <li><a href="#framemetrics_api">Frame Metrics API</a></li>
       </ol>
 </div>
 </div>
@@ -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>
 
 
@@ -430,9 +434,8 @@
 </p>
 
 <p>
-  For information about creating an app tile, see the documentation for
-  <code>android.service.quicksettings.Tile</code> in the downloadable <a href=
-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
+  For information about creating an app tile, see the reference documentation
+  for {@link android.service.quicksettings.Tile Tile}.
 </p>
 
 
@@ -461,9 +464,8 @@
 through any medium, such as a VOIP endpoint or forwarding phones.</p>
 
 <p>
-  For more information, see <code>android.provider.BlockedNumberContract</code>
-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
-  Reference</a>.
+  For more information, see the reference documentation for
+  {@link android.provider.BlockedNumberContract BlockedNumberContract}.
 </p>
 
 <h2 id="call_screening">Call Screening</h2>
@@ -482,9 +484,8 @@
 </ul>
 
 <p>
-  For more information, see <code>android.telecom.CallScreeningService</code>
-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API
-  Reference</a>.
+  For more information, see the reference documentation for
+  {@link android.telecom.CallScreeningService CallScreeningService}.
 </p>
 
 
@@ -776,8 +777,9 @@
 features such as face-tracking, eye-tracking, point scanning, and so on, to
 meet the needs of those users.</p>
 
-<p>For more information, see <code>android.accessibilityservice.GestureDescription</code>
-  in the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.</p>
+<p>For more information, see the reference documentation for
+{@link android.accessibilityservice.GestureDescription GestureDescription}.
+</p>
 
 
 <h2 id="direct_boot">Direct Boot</h2>
@@ -968,9 +970,8 @@
   from the system and from the app in focus. The system retrieves these
   shortcuts automatically from the app’s menu if the shortcuts exist. You can
   also provide your own fine-tuned shortcuts lists for the screen. You can do
-  this by overriding the new <code>Activity.onProvideKeyboardShortcuts()</code>
-  method, described in the downloadable <a href=
-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
+  this by overriding the {@link android.view.Window.Callback#onProvideKeyboardShortcuts
+  onProvideKeyboardShortcuts()} method.
 </p>
 
 <p class="note">
@@ -982,7 +983,8 @@
 
 <p>
   To trigger Keyboard Shortcuts Helper from anywhere in your app, call
-  {@code Activity.requestKeyboardShortcutsHelper()} for the relevant activity.
+  {@link android.app.Activity#requestShowKeyboardShortcuts requestShowKeyboardShortcuts()}
+  from the relevant activity.
 </p>
 
 <h2 id="custom_pointer_api">
@@ -1058,37 +1060,32 @@
 
 <ul>
   <li>You can set an icon from a resource ID by calling
-  <code>PrinterInfo.Builder.setResourceIconId()</code>
+  {@link android.print.PrinterInfo.Builder#setIconResourceId setIconResourceId()}.
   </li>
 
   <li>You can show an icon from the network by calling
-  <code>PrinterInfo.Builder.setHasCustomPrinterIcon()</code>, and setting a
-  callback for when the icon is requested using
-  <code>android.printservice.PrinterDiscoverySession.onRequestCustomPrinterIcon()</code>
+  {@link android.print.PrinterInfo.Builder#setHasCustomPrinterIcon setHasCustomPrinterIcon()},
+  and setting a callback for when the icon is requested using
+  {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon onRequestCustomPrinterIcon()}.
   </li>
 </ul>
 
 <p>
   In addition, you can provide a per-printer activity to display additional
-  information by calling <code>PrinterInfo.Builder.setInfoIntent()</code>.
+  information by calling {@link android.print.PrinterInfo.Builder#setInfoIntent setInfoIntent()}.
 </p>
 
 <p>
   You can indicate the progress and status of print jobs in the print job
   notification by calling
-  <code>android.printservice.PrintJob.setProgress()</code> and
-  <code>android.printservice.PrintJob.setStatus()</code>, respectively.
+  {@link android.printservice.PrintJob#setProgress setProgress()} and
+  {@link android.printservice.PrintJob#setStatus setStatus()}, respectively.
 </p>
 
-<p>
-  For more information about these methods, see the downloadable <a href=
-  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
-</p>
-
-<h2 id="framemetrics_api">FrameMetricsListener API</h2>
+<h2 id="framemetrics_api">Frame Metrics API</h2>
 
 <p>
-The FrameMetricsListener API allows an app to monitor its UI rendering
+The Frame Metrics API allows an app to monitor its UI rendering
 performance. The API provides this capability by exposing a streaming Pub/Sub API to transfer frame
 timing info for the app's current window. The data returned is
 equivalent to that which <code><a href="{@docRoot}tools/help/shell.html#shellcommands">adb shell</a>
@@ -1096,7 +1093,7 @@
 </p>
 
 <p>
-You can use FrameMetricsListener to measure interaction-level UI
+You can use the Frame Metrics API to measure interaction-level UI
 performance in production, without a USB connection. This API
 allows collection of data at a much higher granularity than does
 {@code adb shell dumpsys gfxinfo}. This higher granularity is possible because
@@ -1108,16 +1105,15 @@
 </p>
 
 <p>
-To monitor a window, implement the <code>FrameMetricsListener.onMetricsAvailable()</code>
-callback method and register it on that window. For more information, refer to
-the {@code FrameMetricsListener} class documentation in
-the downloadable <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
+To monitor a window, implement the
+{@link android.view.Window.OnFrameMetricsAvailableListener#onFrameMetricsAvailable OnFrameMetricsAvailableListener.onFrameMetricsAvailable()}
+callback method and register it on that window.
 </p>
 
 <p>
-The API provides a {@code FrameMetrics} object, which contains timing data that
-the rendering subsystem reports for various milestones in a frame lifecycle.
-The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
+The API provides a {@link android.view.FrameMetrics FrameMetrics} object, which
+contains timing data that the rendering subsystem reports for various milestones
+in a frame lifecycle. The supported metrics are: {@code UNKNOWN_DELAY_DURATION},
 {@code INPUT_HANDLING_DURATION}, {@code ANIMATION_DURATION},
 {@code LAYOUT_MEASURE_DURATION}, {@code DRAW_DURATION}, {@code SYNC_DURATION},
 {@code COMMAND_ISSUE_DURATION}, {@code SWAP_BUFFERS_DURATION},
diff --git a/docs/html/about/versions/nougat/index.jd b/docs/html/about/versions/nougat/index.jd
index aaf7e92..8661d77 100644
--- a/docs/html/about/versions/nougat/index.jd
+++ b/docs/html/about/versions/nougat/index.jd
@@ -1,79 +1,62 @@
-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
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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="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">
       <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>
           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
@@ -83,26 +66,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>
-        Report an issue
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        See release notes
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Join dev community
-      </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">Latest</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -114,7 +77,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 +84,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 +93,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/auto/index.jd b/docs/html/auto/index.jd
index e6fde38..3ebd87d 100644
--- a/docs/html/auto/index.jd
+++ b/docs/html/auto/index.jd
@@ -10,7 +10,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 .img-logo {
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index bd933f4..564dbf9 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -14,29 +14,36 @@
   <div class="wrap">
     <div class="cols dac-hero-content">
       <div class="col-1of2 col-push-1of2 dac-hero-figure">
-        <img class="dac-hero-image" src="/images/develop/hero_image_studio5_2x.png" srcset="/images/develop/hero_image_studio5.png 1x, /images/develop/hero_image_studio5_2x.png 2x">
+        <img class="dac-hero-image" style="padding-top:32px"
+          src="/images/develop/hero-layout-editor_2x.png"
+          srcset="/images/develop/hero-layout-editor_2x.png 2x,
+                  /images/develop/hero-layout-editor.png 1x">
       </div>
       <div class="col-1of2 col-pull-1of2" style="margin-bottom:40px">
         <h1 class="dac-hero-title">
             <a style="color:inherit" href="{@docRoot}studio/index.html">
-            Android Studio 2.1,<br>now available!</a></h1>
+            Android Studio 2.2</a></h1>
 
-<p class="dac-hero-description">Android Studio provides the fastest tools for
-building apps on every type of Android device.</p>
+<p class="dac-hero-description">There are 20+ new features in this release
+focused on helping you code faster and smarter. With Android Studio 2.2 you
+can:</p>
 
-<p class="dac-hero-description">The latest version, Android Studio 2.1, adds
-support for N Preview development on top of the faster Android Emulator and
-Instant Run feature from 2.0.</p>
+<ul class="dac-hero-description">
+  <li>Develop your app user interface faster with the new Layout Editor &amp;
+    Constraint Layout</li>
+  <li>Develop smarter with the APK analyzer &amp; expanded code analysis</li>
+  <li>Develop with the the latest Android 7.0 Nougat APIs &amp; features</li>
+</ul>
 
 <p style="margin-top:24px">
     <a class="dac-hero-cta" href="{@docRoot}studio/index.html">
       <span class="dac-sprite dac-auto-chevron"></span>
-      Get Android Studio
+      Get Android Studio 2.2
     </a>
   &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
-    <a class="dac-hero-cta" href="{@docRoot}studio/releases/index.html">
+    <a class="dac-hero-cta" href="{@docRoot}studio/features.html">
     <span class="dac-sprite dac-auto-chevron"></span>
-    See the release notes</a>
+    See more features</a>
 </p>
 
       </div>
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/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd
index 34c6cc5..be48491 100644
--- a/docs/html/distribute/essentials/quality/wear.jd
+++ b/docs/html/distribute/essentials/quality/wear.jd
@@ -42,6 +42,13 @@
   understand the basic implementation requirements for a Wear app.
 </p>
 
+<p>
+  This document helps you assess basic aspects of quality in your Wear app through a
+  compact set of functional and user interface quality criteria.
+   Make sure to check out the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
+  documentation to get ready for the next version of Android Wear.
+</p>
+
 <p class="caution">
   <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet
   specific requirements for usability. Only apps that meet the following quality criteria will
@@ -50,8 +57,8 @@
 </p>
 
 <p class="note">
- <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
- href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
+  <strong>Note:</strong> For information about how to publish your Wear apps in Google Play, see <a
+  href="{@docRoot}distribute/googleplay/wear.html">Distributing to Android Wear</a>.
 </p>
 
 <div class="headerLine">
@@ -67,6 +74,19 @@
   functional behavior.
 </p>
 
+<p class="caution">
+  <strong>Important:</strong> To learn about how Wear 2.0 platform changes may affect
+   your apps, see the <a href="https://developer.android.com/wear/preview/index.html">Wear 2.0 preview</a>
+   documentation.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
+  quality criteria that are not required for the corresponding Wear version.
+</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Functional criteria.
+</p>
 
 <table>
 <tr>
@@ -79,6 +99,12 @@
   <th>
     Description
   </th>
+  <th>
+    Wear 1.0
+  </th>
+  <th>
+    Wear 2.0
+  </th>
 </tr>
 
 <tr>
@@ -96,6 +122,12 @@
       (<a href="{@docRoot}training/building-wearables.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -107,6 +139,12 @@
       App has Wear functionality that is visible to the user.
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -118,6 +156,12 @@
       Wear functionality works as expected or as described in the app's Google Play Store listing.
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -135,6 +179,12 @@
       (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -152,6 +202,12 @@
       (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -164,6 +220,12 @@
       (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -176,6 +238,12 @@
       (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -193,6 +261,12 @@
       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -206,6 +280,12 @@
       (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -222,6 +302,12 @@
       (<a href="{@docRoot}training/wearables/watch-faces/index.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 </table>
@@ -245,8 +331,15 @@
 <p>
   These criteria ensure that your app follows critical design and interaction patterns to provide a
   consistent, intuitive, and enjoyable user experience on wearables.
+
+</p>
+<p clase="note">
+  <strong>Note:</strong> The symbol &#10008; is used in the table below to indicate
+  quality criteria that are not required for the corresponding Wear version.
 </p>
 
+<p class="table-caption"><strong>Table 2</strong>. Visual criteria.
+</p>
 <table>
 
 <tr>
@@ -259,6 +352,12 @@
   <th>
     Description
   </th>
+  <th>
+    Wear 1.0
+  </th>
+  <th>
+    Wear 2.0
+  </th>
 </tr>
 
 <tr>
@@ -277,6 +376,12 @@
       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -292,6 +397,13 @@
       (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
+
 </tr>
 
 <tr>
@@ -304,6 +416,12 @@
       (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -320,6 +438,12 @@
       (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -336,6 +460,12 @@
       (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -350,6 +480,12 @@
       (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -363,6 +499,12 @@
       (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 <tr>
@@ -375,6 +517,12 @@
       (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -387,6 +535,12 @@
       (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10008;
+  </td>
 </tr>
 
 <tr>
@@ -403,6 +557,12 @@
       (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>)
     </p>
   </td>
+  <td>
+    &#10004;
+  </td>
+  <td>
+    &#10004;
+  </td>
 </tr>
 
 
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 424983d..3d75758 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -9,16 +9,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <div class="dac-hero-carousel" data-carousel-query="collection:distribute/landing/carousel">
 </div>
 
@@ -28,18 +18,7 @@
   </a>
 </div>
 
-<section id="useOldTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
-  <h2 class="norule">Latest</h2>
-  <div class="resource-widget resource-flow-layout col-16"
-      data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
-      data-sortOrder="-timestamp"
-      data-cardSizes="6x6"
-      data-maxResults="3"
-      data-items-per-page="6"
-      data-initial-results="3"></div>
-</div></section>
-
-<section id="useUpdatedTemplates" style="display:none" class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
+<section class="dac-section dac-gray dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Latest</h2>
 
   <div class="dac-filter dac-filter-section" data-filter="#latest-resources">
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
index 1adc5ae..1745535 100644
--- a/docs/html/distribute/stories/index.jd
+++ b/docs/html/distribute/stories/index.jd
@@ -4,16 +4,6 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <p>Android developers, their apps, and their successes with Android and Google Play.</p>
 
 <section class="dac-section dac-small" id="latest-apps"><div class="wrap">
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
index 409dfdd..ba2bed7 100644
--- a/docs/html/distribute/tools/promote/brand.jd
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -34,30 +34,31 @@
     <ul>
     <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
     <li>Android should always be capitalized and is never plural or possessive.</li>
-    <li>"Android" cannot be used in names of applications or accessory products,
-    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
+    <li>"Android", or anything confusingly similar to "Android", cannot be used
+    in names of applications or accessory products, including phones, tablets, TVs,
+    speakers, headphones, watches, and other devices. Instead, use "for Android".
       <ul>
-        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
+        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Ndroid MediaPlayer"</li>
         <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
       </ul>
-      <p>If used with your logo, "for Android" should be no larger than 90% of your logo’s size.
-      First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
+      <p>If used with your logo, "for Android" should be no larger than 90% of your logo's size.
+      The first instance of this use should be followed by a TM symbol: "for Android&trade;".</p>
     </li>
-    <li>"Android TV", "Android Wear" and "Android Auto" may only be used to identify or market
+    <li>"Android TV", "Android Wear", and "Android Auto" may only be used to identify or market
       products or services with prior approval.  Use "for Android" or "with Android" for all
-      other Android-based products
+      other Android-based products.
       <ul>
         <li><span style="color:red">Incorrect</span>: "Android TV Streaming Stick",
           "Streaming Stick with Android TV"</li>
         <li><span style="color:green">Correct</span>: "Streaming Stick with Android"</li>
       </ul>
       <p>If used with your logo, "for Android" or "with Android" should be no larger than 90% of
-        your logo’s size. First instance of this use should be followed by a TM symbol,
+        your logo's size. The first instance of this use should be followed by a TM symbol:
         "for Android&trade;".</p>
     </li>
-    <li>Android may be used as a descriptor, as long as it is followed by a
-        proper generic term. (Think of "Android" as a term used in place of
-        "the Android platform.")
+    <li>Android may be used as a descriptor in text, as long as it is followed by a
+        proper generic term and is not the name of your product, app, or service.
+        Think of "Android" as a term used in place of "the Android platform."
       <ul>
         <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
         <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
@@ -100,7 +101,9 @@
 <h4 style="clear:right">Android logo</h4>
 
 <div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
-  <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
+  <img alt="" src="{@docRoot}images/brand/android_logo_no.png"
+    srcset="{@docRoot}images/brand/android_logo_no.png 1x,
+    {@docRoot}images/brand/android_logo_no_2x.png 2x">
 </div>
 
 <p>The Android logo may not be used.</p>
diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
index 7bc6f6c..65aa44a 100644
--- a/docs/html/distribute/users/build-buzz.jd
+++ b/docs/html/distribute/users/build-buzz.jd
@@ -28,9 +28,6 @@
     Link to Your Apps in Google Play
   </h2>
 
-
-</div>
-
 <p>
   After publishing your apps, you can take Android users directly to your
   app/games detail page on Google Play by <a href=
@@ -64,9 +61,6 @@
     Use the Google Play Badge
   </h2>
 
-
-</div>
-
 <div class="figure" style="margin:0 3em;">
   <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
 </div>
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index 292cfcc..ad09f1f 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -235,7 +235,7 @@
 
 <p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
 ","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
-<em>price</em>"
+<em>price</em>", "<em>pricing_template_id</em>"
 </p>
 
 <p>Descriptions and usage details are provided below.</p>
@@ -316,8 +316,9 @@
         <p>"true","<em>default_price_in_home_currency</em>"
       </li>
       <li>
-        <p>If <em>autofill</em> is set to <code>false</code>, you need to specify a <em>country</em>
-        and a <em>price</em> for each currency, and you must use the following syntax:</p>
+        <p>If <em>autofill</em> is set to <code>false</code>, you need to either specify the <em>pricing_template_id</em>
+        that is linked to the in-app product or specify a <em>country</em> and a <em>price</em> for each currency.
+        If you choose to specify countries and prices, you must use the following syntax:</p>
         <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
         <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
       </li>
@@ -335,11 +336,41 @@
   </dd>
   <dt>price</dt>
   <dd>
+    <p>
+    If you use this value, you shouldn't specify a value for the <em>pricing_template_id</em>.
+    </p>
+    <p>
     This is equivalent to the Price in the In-app Products UI. The price must be specified in
     micro-units. To convert a currency value to micro-units, you multiply the real value by
     1,000,000.
     For example, if you want to sell an in-app item for $1.99, you specify <code>1990000</code> in the
     <em>price</em> field.
+    </p>
+  </dd>
+  <dt>pricing_template_id</dt>
+  <dd>
+  <p>
+    If you use this value, you should set <em>autofill</em> to
+    <code>false</code> and leave the <em>price</em> column empty.
+  </p>
+  <p>
+    This value represents the ID of the pricing template that you've linked to
+    the in-app product. This ID appears under a pricing template's name
+    on the <strong>Pricing template</strong> page. If an in-app product isn't
+    linked to a pricing template, its <em>pricing_template_id</em> value is
+    empty.
+  </p>
+  <p>
+    If you import a CSV file and choose to overwrite the product list, you can
+    update the links between in-app products and pricing templates by changing
+    the value of an in-app product's <em>pricing_template_id</em>. Leave the
+    value empty to unlink an in-app product from all pricing templates.
+  </p>
+  <p>
+    <strong>Note: </strong>You can link up to 100 app prices or in-app product
+    prices with a particular pricing template. Therefore, don't specify the same
+    <em>pricing_template_id</em> value in more than 100 rows of your CSV file.
+  </p>
   </dd>
 </dl>
 
@@ -432,8 +463,11 @@
 
 <p>
   When creating a pricing template, you provide new pricing information that you
-  can apply to paid apps and in-app products. To add a pricing template, do the
-  following:
+  can apply to paid apps and in-app products. You can link the prices of up to
+  100 apps and in-app products to a single pricing template.
+</p>
+</p>
+  To add a pricing template, do the following:
 </p>
 
 <ol>
diff --git a/docs/html/google/play/filters.jd b/docs/html/google/play/filters.jd
index 50cc807..a73b17f 100644
--- a/docs/html/google/play/filters.jd
+++ b/docs/html/google/play/filters.jd
@@ -382,9 +382,12 @@
   suspended, users will not be able to reinstall or update it, even if it appears in their Downloads.</p> </td></tr>
   <tr>
   <td valign="top">Priced
-    Status</td> <td valign="top"><p>Not all users can see paid apps. To show paid apps, a device
-must have a SIM card and be running Android 1.1 or later, and it must be in a
-country (as determined by SIM carrier) in which paid apps are available.</p></td>
+    Status</td> <td valign="top"><p>Not all users can see paid apps. To show
+    paid apps, a device must be running Android 1.1 or later, and it must be in
+    a country where paid apps are available. If a device has a SIM card, the SIM
+    carrier determines whether paid apps are available. If a device doesn't have
+    a SIM card, the device's IP address is used to determine whether the device
+    is in a country where paid apps are available.</p></td>
 </tr> <tr>
   <td valign="top">Country Targeting</td> <td valign="top"> <p>When you upload your app to
     Google Play, you can select the countries in which to distribute your app
diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml
index 20ee483..f09fe77 100644
--- a/docs/html/guide/_book.yaml
+++ b/docs/html/guide/_book.yaml
@@ -396,14 +396,16 @@
     path: /guide/topics/data/data-storage.html
   - title: Data Backup
     path: /guide/topics/data/backup.html
+    section:
+    - title: Auto Backup
+      path: /guide/topics/data/autobackup.html
+    - title: Key/Value Backup
+      path: /guide/topics/data/keyvaluebackup.html
+    - title: Testing Backup and Restore
+      path: /guide/topics/data/testingbackup.html
   - title: App Install Location
     path: /guide/topics/data/install-location.html
 
-- title: Libraries
-  path: /topic/libraries/index.html
-  section:
-  - include: /topic/libraries/_book.yaml
-
 - title: Administration
   path: /guide/topics/admin/index.html
   section:
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index 9443924..e757288 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -624,8 +624,8 @@
 before making the activity vulnerable to destruction. The system passes this method
 a {@link android.os.Bundle} in which you can save
 state information about the activity as name-value pairs, using methods such as {@link
-android.os.BaseBundle#putString putString()} and {@link
-android.os.BaseBundle#putInt putInt()}. Then, if the system kills your application
+android.os.Bundle#putString putString()} and {@link
+android.os.Bundle#putInt putInt()}. Then, if the system kills your application
 process and the user navigates back to your activity, the system recreates the activity and passes
 the {@link android.os.Bundle} to both {@link android.app.Activity#onCreate onCreate()} and {@link
 android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Using either of these
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 9488f6e..47174d2 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>
 
@@ -2084,7 +2155,7 @@
 <p><b>Example intent:</b></p>
 <pre>
 public void openWifiSettings() {
-    Intent intent = new Intent(Intent.ACTION_WIFI_SETTINGS);
+    Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
     if (intent.resolveActivity(getPackageManager()) != null) {
         startActivity(intent);
     }
@@ -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/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 9257a76..8fe3f20 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -545,9 +545,16 @@
          <li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">
             <span class="en">Storage Options</span>
            </a></li>
-        <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
+        <li class="nav-section">
+          <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
             <span class="en">Data Backup</span>
-          </a></li>
+          </a></div>
+          <ul>
+            <li><a href="<?cs var:toroot ?>guide/topics/data/autobackup.html">Auto Backup</a></li>
+            <li><a href="<?cs var:toroot ?>guide/topics/data/keyvaluebackup.html">Key/Value Backup</a></li>
+            <li><a href="<?cs var:toroot ?>guide/topics/data/testingbackup.html">Testing Backup and Restore</a></li>
+          </ul>
+        </li>
         <li><a href="<?cs var:toroot ?>guide/topics/data/install-location.html">
             <span class="en">App Install Location</span>
           </a></li>
diff --git a/docs/html/guide/topics/connectivity/nfc/nfc.jd b/docs/html/guide/topics/connectivity/nfc/nfc.jd
index 520f520..881a75f 100644
--- a/docs/html/guide/topics/connectivity/nfc/nfc.jd
+++ b/docs/html/guide/topics/connectivity/nfc/nfc.jd
@@ -487,19 +487,22 @@
 intent and gets the NDEF messages from an intent extra.</p>
 
 <pre>
-public void onResume() {
-    super.onResume();
+&#64;Override
+protected void onNewIntent(Intent intent) {
+    super.onNewIntent(intent);
     ...
-    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
-        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
-        if (rawMsgs != null) {
-            msgs = new NdefMessage[rawMsgs.length];
-            for (int i = 0; i &lt; rawMsgs.length; i++) {
-                msgs[i] = (NdefMessage) rawMsgs[i];
+    if (intent != null &amp;&amp; NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
+        Parcelable[] rawMessages =
+            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
+        if (rawMessages != null) {
+            NdefMessage[] messages = new NdefMessage[rawMessages.length];
+            for (int i = 0; i < rawMessages.length; i++) {
+                messages[i] = (NdefMessage) rawMessages[i];
             }
+            // Process the messages array.
+            ...
         }
     }
-    //process the msgs array
 }
 </pre>
 
diff --git a/docs/html/guide/topics/data/autobackup.jd b/docs/html/guide/topics/data/autobackup.jd
new file mode 100644
index 0000000..3be09d7
--- /dev/null
+++ b/docs/html/guide/topics/data/autobackup.jd
@@ -0,0 +1,257 @@
+page.title=Auto Backup for Apps
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, autobackup
+page.image=images/cards/card-auto-backup_2x.png
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Files">Files that are backed up</a></li>
+    <li><a href="#BackupLocation">Backup location</a></li>
+    <li><a href="#BackupSchedule">Backup schedule</a></li>
+    <li><a href="#RestoreSchedule">Restore schedule</a></li>
+    <li><a href="#EnablingAutoBackup">Enabling and disabling Auto Backup</a></li>
+    <li><a href="#IncludingFiles">Including and excluding files</a><ul>
+      <li><a href="#XMLSyntax">XML config syntax</a></li>
+    </ul></li>
+    <li><a href="#ImplementingBackupAgent">Implementing BackupAgent</a></li>
+  </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.app.backup.BackupAgent}</li>
+    <li><a href="{@docRoot}reference/android/R.attr.html">R.attr</a></li>
+  </ol>
+
+</div>
+</div>
+
+Since Android 6.0 (API 23), Android has offered the <em>Auto Backup for Apps</em> feature as
+a way for developers to quickly add backup functionality to their apps. Auto
+Backup preserves app data by uploading it to the user’s Google Drive account.
+The amount of data is limited to 25MB per user of your app and there is no
+charge for storing backup data.
+
+<h2 id="Files">Files that are backed up</h2>
+<p>By default, Auto Backup includes files in most of the directories that are
+assigned to your app by the system:
+<ul>
+  <li>Shared preferences files.
+  <li>Files in the directory returned by {@link android.content.Context#getFilesDir()}.
+  <li>Files in the directory returned by {@link android.content.Context#getDatabasePath(String)},
+    which also includes files created with the
+    {@link android.database.sqlite.SQLiteOpenHelper} class.
+  <li>Files in directories created with {@link android.content.Context#getDir(String,int)}.
+  <li>Files on external storage in the directory returned by
+    {@link android.content.Context#getExternalFilesDir(String)}.</li></ul>
+
+<p>Auto Backup excludes files in directories returned by
+  {@link android.content.Context#getCacheDir()},
+  {@link android.content.Context#getCodeCacheDir()}, or
+  {@link android.content.Context#getNoBackupFilesDir()}. The files saved
+  in these locations are only needed temporarily, or are intentionally
+  excluded from backup operations.
+
+<p>You can configure your app to include and exclude particular files.
+For more information, see the <a href="#IncludingFiles">Include and exclude files</a>
+section.
+
+<h2 id="BackupLocation">Backup location</h2>
+<p>Backup data is stored in a private folder in the user's Google Drive account,
+limited to 25MB per app. The saved data does not count towards the user's
+personal Google Drive quota. Only the most recent backup is stored. When a
+backup is made, the previous backup (if one exists) is deleted.
+
+<p>Users can see a list of apps that have been backed up in the Google Drive app under
+<strong>Settings -> Auto Backup for apps -> Manage backup</strong>. The
+backup data cannot be read by the user or other applications on the device.
+
+<p>Backups from each device-setup-lifetime are stored in separate datasets
+as shown in the following examples:
+<ul>
+  <li>If the user owns two devices, then a backup dataset exists for each device.
+  <li>If the user factory resets a device and then sets up the device with the
+    same account, the backup is stored in a new dataset. Obsolete datasets are
+    automatically deleted after a period of inactivity.</li></ul>
+
+<p class="caution"><strong>Caution:</strong> Once the amount of data reaches
+25MB, the app is banned from sending data to the
+cloud, even if the amount of data later falls under the 25MB threshold. The ban
+affects only the offending device (not other devices that the user owns) and
+lasts for the entire device-setup-lifetime. For example, if the user removes and
+reinstalls the application, the ban is still in effect. The ban is lifted when
+the user performs factory reset on the device.
+
+<h2 id="BackupSchedule">Backup schedule</h2>
+<p>Backups occur automatically when all of the following conditions are met:
+<ul>
+  <li>The user has enabled backup on the device in <strong>Settings</strong> >
+    <strong>Backup &amp; Reset</strong>.
+  <li>At least 24 hours have elapsed since the last backup.
+  <li>The device is idle and charging.
+  <li>The device is connected to a Wi-Fi network. If the device is never connected
+    to a wifi network, then Auto Backup never occurs.</li></ul>
+
+<p>In practice, these conditions occur roughly every night. To conserve network
+bandwidth, upload takes place only if app data has changed.
+
+<p>During Auto Backup, the system shuts down the app to make sure it is no longer
+writing to the file system. By default, the backup system ignores apps that are
+running in the foreground because users would notice their apps being shut down.
+You can override the default behavior by setting the
+<a href="{@docRoot}reference/android/R.attr.html#backupInForeground">backupInForeground</a>
+attribute to true.
+
+<p>To simplify testing, Android includes tools that let you manually initiate
+a backup of your app. For more information, see
+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
+
+<h2 id="RestoreSchedule">Restore schedule</h2>
+<p>Data is restored whenever the app is installed, either from the Play store,
+during device setup (when the system installs previously installed apps), or
+from running adb install. The restore operation occurs after the APK is
+installed, but before the app is available to be launched by the user.
+
+<p>During the initial device setup wizard, the user is shown a list of available backup
+datasets and is asked which one to restore the data from. Whichever backup
+dataset is selected becomes the ancestral dataset for the device. The device can
+restore from either its own backups or the ancestral dataset. The device
+prioritize its own backup if backups from both sources are available. If the
+user didn't go through the device setup wizard, then the device can restore only from
+its own backups.
+
+<p>To simplify testing, Android includes tools that let you manually initiate
+a restore of your app. For more information, see
+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
+
+<h2 id="EnablingAutoBackup">Enabling and disabling backup</h2>
+<p>Apps that target Android 6.0 (API level 23) or higher automatically participate
+in Auto Backup. This is because the
+<a href="{@docRoot}reference/android/R.attr.html#allowBackup">android:allowBackup</a>
+attribute, which enables/disables backup, defaults to <code>true</code> if omitted.
+To avoid confusion, we recommend you explicitly set the attribute in the <code>&lt;application></code>
+element of your <code>AndroidManifest.xml</code>. For example:
+
+<pre class="prettyprint">&lt;application ...
+    android:allowBackup="true">
+&lt;/app></pre>
+
+<p>To disable Auto Backup, add either of the following attributes to the
+application element in your manifest file:
+
+<ul>
+  <li>set <code>android:allowBackup</code> to <code>false</code>. This completely disables data
+    backup. You may want to disable backups when your app can recreate its state
+    through some other mechanism or when your app deals with sensitive
+    information that should not be backed up.</li>
+  <li>set <code>android:allowBackup</code> to <code>true</code> and
+    <code>android:fullBackupOnly</code> to <code>false</code>. With these settings,
+    your app always participates in Key/Value Backup, even when running on devices that
+    support Auto Backup.</li></ul>
+
+<h2 id="IncludingFiles">Including and excluding files</h2>
+<p>By default, the system backs up almost all app data. For more information,
+see <a href="#Files">Files that are backed up</a>. This section shows you how to
+define custom XML rules to control what gets backed up.
+
+<ol>
+  <li>In <code>AndroidManifest.xml</code>, add the <a href="{@docRoot}reference/android/R.attr.html#fullBackupContent">android:fullBackupContent</a> attribute to the
+  <code>&lt;application></code> element. This attribute points to an XML file that contains backup
+  rules. For example:
+  <pre class="prettyprint">&lt;application ...
+    android:fullBackupContent="@xml/my_backup_rules">
+  &lt;/app></pre></li>
+  <li>Create an XML file called <code>my_backup_rules.xml</code> in the <code>res/xml/</code> directory. Inside the file, add rules with the <code>&lt;include></code> and <code>&lt;exclude></code> elements. The following sample backs up all shared preferences except <code>device.xml</code>:
+  <pre>&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;full-backup-content>
+    &lt;include domain="sharedpref" path="."/>
+    &lt;exclude domain="sharedpref" path="device.xml"/>
+&lt;/full-backup-content></pre></li>
+
+<h3 id="XMLSyntax">XML Config Syntax</h3>
+<p>The XML syntax for the configuration file is shown below:
+
+<pre class="prettyprint">&lt;full-backup-content>
+    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
+    path="string" />
+    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
+    path="string" />
+&lt;/full-backup-content></pre>
+
+<p>Inside the <code>&lt;full-backup-content></code> tag, you can define <code>&lt;include></code> and <code>&lt;exclude></code>
+elements:
+
+<ul>
+  <li><code>&lt;include></code> - Specifies a file or folder to backup. By default, Auto Backup
+includes almost all app files. If you specify an &lt;include> element, the system
+no longer includes any files by default and backs up <em>only the files
+specified</em>. To include multiple files, use multiple &lt;include> elements.
+  <p>note: Files in directories returned by <code>getCacheDir()</code>, <code>getCodeCacheDir()</code>, or
+<code>getNoBackupFilesDir()</code> are always excluded even if you try to include them.</li>
+
+  <li><code>&lt;exclude></code> - Specifies a file or folder to exclude during backup. Here are
+some files that are typically excluded from backup: <ul>
+    <li>Files that have device specific identifiers, either issued by a server or
+generated on the device. For example, <a href="https://developers.google.com/cloud-messaging/android/start">Google Cloud Messaging (GCM)</a> needs to
+generate a registration token every time a user installs your app on a new
+device. If the old registration token is restored, the app may behave
+unexpectedly.
+    <li>Account credentials or other sensitive information. Consider asking the
+user to reauthenticate the first time they launch a restored app rather than
+allowing for storage of such information in the backup.
+    <li>Files related to app debugging, such as <a href="{@docRoot}studio/run/index.html#instant-run">instant run files</a>. To exclude instant run files, add the rule <code>&lt;exclude
+domain="file" path="instant-run"/></code>
+    <li>Large files that cause the app to exceed the 25MB backup quota.</li> </ul>
+  </li> </ul>
+
+<p class="note"><strong>Note:</strong> If your configuration file specifies both elements, then the
+backup contains everything captured by the <code>&lt;include></code> elements minus the
+resources named in the <code>&lt;exclude></code> elements. In other words,
+<code>&lt;exclude></code> takes precedence.
+
+<p>Each element must include the following two attributes:
+<ul>
+  <li><code>domain</code> - specifies the location of resource. Valid values for this attribute
+include the following: <ul>
+    <li><code>root</code> - the directory on the filesystem where all private files belonging to
+this app are stored.
+    <li><code>file</code> - directories returned by {@link android.content.Context#getFilesDir()}.
+    <li><code>database</code> - directories returned by {@link android.content.Context#getDatabasePath(String) getDatabasePath()}.
+Databases created with {@link android.database.sqlite.SQLiteOpenHelper}
+are stored here.
+    <li><code>sharedpref</code> - the directory where {@link android.content.SharedPreferences}
+are stored.
+    <li><code>external</code> the directory returned by {@link android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}
+    <p>Note: You cannot backup files outside of these locations.</li></ul>
+  <li><code>path</code>: Specifies a file or folder to include in or exclude from backup. Note
+that: <ul>
+    <li>This attribute does not support wildcard or regex syntax.
+    <li>You can use <code>.</code> to reference the current directory, however, you cannot
+reference the parent directory <code>..</code> for security reasons.
+    <li>If you specify a directory, then the rule applies to all files in the
+directory and recursive sub-directories.</li></ul></li></ul>
+
+<h2 id="ImplementingBackupAgent">Implementing BackupAgent</h2>
+<p>Apps that implement Auto Backup do not need to implement {@link android.app.backup.BackupAgent}. However, you can optionally implement a custom {@link android.app.backup.BackupAgent}. Typically, there are two reasons for doing this:
+<ul>
+  <li>You want to receive notification of backup events such as,
+{@link android.app.backup.BackupAgent#onRestoreFinished()} or {@link android.app.backup.BackupAgent#onQuotaExceeded(long,long)}. These callback methods are executed
+even if the app is not running.
+<li>You can't easily express the set of files you want to backup with XML rules.
+In these very rare cases, you can implement a BackupAgent that overrides {@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput)} to
+store what you want. To retain the system's default implementation, call the
+corresponding method on the superclass with <code>super.onFullBackup()</code>.</li></ul>
+
+<p class="note"><strong>Note:</strong> Your <code>BackupAgent</code> must
+implement the abstract methods
+{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) onBackup()}
+and {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
+Those methods are used for Key/Value Backup. So if
+you are not using Key/Value Backup, implement those methods and leave them blank.
+
+<p>For more information, see
+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html#BackupAgent">Extending
+BackupAgent</a>.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 619c790..a688c6e 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -1,930 +1,34 @@
-page.title=Data Backup
+page.title=Backing up App Data to the Cloud
+page.tags=cloud,sync,backup
+
+startpage=true
+
 @jd:body
 
+<p>Users often invest significant time and effort creating data and setting
+preferences within apps. Preserving that data for users if they replace a broken
+device or upgrade to a new one is an important part of ensuring a great user
+experience. This section covers techniques for backing up data to the cloud so
+that users can restore their data.
 
-<div id="qv-wrapper">
-<div id="qv">
+<p>Android provides two ways for apps to backup their data to the cloud:
+<a href="{@docRoot}guide/topics/data/autobackup.html">Auto Backup for Apps</a> and
+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html">Key/Value Backup</a>.
+Auto Backup, which is available starting API 23, preserves app data by uploading
+it to the user’s Google Drive account. The Key/Value Backup feature (formerly
+known as the Backup API and the Android Backup Service) preserves app data by
+uploading it to the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
 
-  <h2>Quickview</h2>
-  <ul>
-    <li>Back up the user's data to the cloud in case the user loses it</li>
-    <li>If the user upgrades to a new Android-powered device, your app can restore the user's
-data onto the new device</li>
-    <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
-    <li>Requires API Level 8</li>
-  </ul>
+<p>Generally, we recommend Auto Backup because it requires no work to implement.
+Apps that target Android 6.0 (API level 23) or higher are automatically enabled
+for Auto Backup. The Auto Backup feature does have some limitations in terms of
+what data it can backup and it's availability on Android 6.0 and higher devices.
+Consider using the Key/Value Backup feature if you have more specific needs for
+backing up your app data. For more information, see <a href="{@docRoot}guide/topics/data/keyvaluebackup.html#Comparison">Comparison of Key/Value and Auto Backup</a></p>
 
-  <h2>In this document</h2>
-  <ol>
-    <li><a href="#Basics">The Basics</a></li>
-    <li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li>
-    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
-    <li><a href="#BackupAgent">Extending BackupAgent</a>
-      <ol>
-        <li><a href="#RequiredMethods">Required Methods</a></li>
-        <li><a href="#PerformingBackup">Performing backup</a></li>
-        <li><a href="#PerformingRestore">Performing restore</a></li>
-      </ol>
-    </li>
-    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
-      <ol>
-        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
-        <li><a href="#Files">Backing up Private Files</a></li>
-      </ol>
-    </li>
-    <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
-    <li><a href="#RequestingBackup">Requesting Backup</a></li>
-    <li><a href="#RequestingRestore">Requesting Restore</a></li>
-    <li><a href="#Testing">Testing Your Backup Agent</a></li>
-  </ol>
-
-  <h2>Key classes</h2>
-  <ol>
-    <li>{@link android.app.backup.BackupManager}</li>
-    <li>{@link android.app.backup.BackupAgent}</li>
-    <li>{@link android.app.backup.BackupAgentHelper}</li>
-  </ol>
-
-  <h2>See also</h2>
-  <ol>
-    <li><a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a></li>
-  </ol>
-
-</div>
-</div>
-
-<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
-application data to remote "cloud" storage, in order to provide a restore point for the
-application data and settings. If a user performs a factory reset or converts to a new
-Android-powered device, the system automatically restores your backup data when the application
-is re-installed. This way, your users don't need to reproduce their previous data or
-application settings. This process is completely transparent to the user and does not affect the
-functionality or user experience in your application.</p>
-
-<p>During a backup operation (which your application can request), Android's Backup Manager ({@link
-android.app.backup.BackupManager}) queries your application for backup data, then hands it to
-a backup transport, which then delivers the data to the cloud storage. During a
-restore operation, the Backup Manager retrieves the backup data from the backup transport and
-returns it to your application so your application can restore the data to the device. It's
-possible for your application to request a restore, but that shouldn't be necessary&mdash;Android
-automatically performs a restore operation when your application is installed and there exists
-backup data associated with the user. The primary scenario in which backup data is restored is when
-a user resets their device or upgrades to a new device and their previously installed
-applications are re-installed.</p>
-
-<p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for
-synchronizing application data with other clients or saving data that you'd like to access during
-the normal application lifecycle. You cannot read or write backup data on demand and cannot access
-it in any way other than through the APIs provided by the Backup Manager.</p>
-
-<p>The backup transport is the client-side component of Android's backup framework, which is
-customizable by
-the device manufacturer and service provider. The backup transport may differ from device to device
-and which backup transport is available on any given device is transparent to your application. The
-Backup Manager APIs isolate your application from the actual backup transport available on a given
-device&mdash;your application communicates with the Backup Manager through a fixed set of APIs,
-regardless of the underlying transport.</p>
-
-<p>Data backup is <em>not</em> guaranteed to be available on all Android-powered
-devices. However, your application is not adversely affected in the event
-that a device does not provide a backup transport. If you believe that users will benefit from data
-backup in your application, then you can implement it as described in this document, test it, then
-publish your application without any concern about which devices actually perform backup. When your
-application runs on a device that does not provide a backup transport, your application operates
-normally, but will not receive callbacks from the Backup Manager to backup data.</p>
-
-<p>Although you cannot know what the current transport is, you are always assured that your
-backup data cannot be read by other applications on the device. Only the Backup Manager and backup
-transport have access to the data you provide during a backup operation.</p>
-
-<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
-differ from device to device, Android makes no guarantees about the security of your data while
-using backup. You should always be cautious about using backup to store sensitive data, such as
-usernames and passwords.</p>
-
-
-<h2 id="Basics">The Basics</h2>
-
-<p>To backup your application data, you need to implement a backup agent. Your backup
-agent is called by the Backup Manager to provide the data you want to back up. It is also called
-to restore your backup data when the application is re-installed. The Backup Manager handles all
-your data transactions with the cloud storage (using the backup transport) and your backup agent
-handles all your data transactions on the device.</p>
-
-<p>To implement a backup agent, you must:</p>
-
-<ol>
-  <li>Declare your backup agent in your manifest file with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
-android:backupAgent}</a> attribute.</li>
-  <li>Register your application with a backup service. Google offers <a
-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup
-service for most Android-powered devices, which requires that you register your application in
-order for it to work. Any other backup services available might also require you to register
-in order to store your data on their servers.</li>
-  <li>Define a backup agent by either:</p>
-    <ol type="a">
-      <li><a href="#BackupAgent">Extending BackupAgent</a>
-        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
-which your application communicates with the Backup Manager. If you extend this class
-directly, you must override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to handle the backup and restore operations for your data.</p>
-        <p><em>Or</em></p>
-      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
-        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
-wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
-you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
-"helper" objects, which automatically backup and restore certain types of data, so that you do not
-need to implement {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}.</p>
-        <p>Android currently provides backup helpers that will backup and restore complete files
-from {@link android.content.SharedPreferences} and <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
-      </li>
-    </ol>
-  </li>
-</ol>
-
-
-
-<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
-
-<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
-it in your manifest with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
-android:backupAgent}</a> attribute in the <a
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code
-<application>}</a> tag.</p>
-
-<p>For example:</p>
-
-<pre>
-&lt;manifest ... &gt;
-    ...
-    &lt;application android:label="MyApplication"
-                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
-        &lt;activity ... &gt;
-            ...
-        &lt;/activity&gt;
-    &lt;/application&gt;
-&lt;/manifest&gt;
-</pre>
-
-<p>Another attribute you might want to use is <a
-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
-want to restore the application data regardless of the current application version compared to the
-version that produced the backup data. (The default value is "{@code false}".) See <a
-href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
-
-<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
-available only on devices running API Level 8 (Android 2.2) or greater, so you should also
-set your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
-attribute to "8".</p>
-
-
-
-
-<h2 id="BackupKey">Registering for Android Backup Service</h2>
-
-<p>Google provides a backup transport with <a
-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most
-Android-powered devices running Android 2.2 or greater.</p>
-
-<p>In order for your application to perform backup using Android Backup Service, you must
-register your application with the service to receive a Backup Service Key, then
-declare the Backup Service Key in your Android manifest.</p>
-
-<p>To get your Backup Service Key, <a
-href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>.
-When you register, you will be provided a Backup Service Key and the appropriate {@code
-<meta-data>} XML code for your Android manifest file, which you must include as a child of the
-{@code <application>} element. For example:</p>
-
-<pre>
-&lt;application android:label="MyApplication"
-             android:backupAgent="MyBackupAgent"&gt;
-    ...
-    &lt;meta-data android:name="com.google.android.backup.api_key"
-        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
-&lt;/application&gt;
-</pre>
-
-<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
-the <code>android:value</code> must be the Backup Service Key received from the Android Backup
-Service registration.</p>
-
-<p>If you have multiple applications, you must register each one, using the respective package
-name.</p>
-
-<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
-not guaranteed to be available
-on all Android-powered devices that support backup. Some devices might support backup
-using a different transport, some devices might not support backup at all, and there is no way for
-your application to know what transport is used on the device. However, if you implement backup for
-your application, you should always include a Backup Service Key for Android Backup Service so
-your application can perform backup when the device uses the Android Backup Service transport. If
-the device does not use Android Backup Service, then the {@code <meta-data>} element with the
-Backup Service Key is ignored.</p>
-
-
-
-
-<h2 id="BackupAgent">Extending BackupAgent</h2>
-
-<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
-directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
-advantage of the built-in helper classes that automatically backup and restore your files. However,
-you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
-<ul>
-  <li>Version your data format. For instance, if you anticipate the need to revise the
-format in which you write your application data, you can build a backup agent to cross-check your
-application version during a restore operation and perform any necessary compatibility work if the
-version on the device is different than that of the backup data. For more information, see <a
-href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
-  <li>Instead of backing up an entire file, you can specify the portions of data the should be
-backed up and how each portion is then restored to the device. (This can also help you manage
-different versions, because you read and write your data as unique entities, rather than
-complete files.)</li>
-  <li>Back up data in a database. If you have an SQLite database that you want to restore when
-the user re-installs your application, you need to build a custom {@link
-android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
-create your table and insert the data during a restore operation.</li>
-</ul>
-
-<p>If you don't need to perform any of the tasks above and want to back up complete files from
-{@link android.content.SharedPreferences} or <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
-should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
-
-
-
-<h3 id="RequiredMethods">Required Methods</h3>
-
-<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
-must implement the following callback methods:</p>
-
-<dl>
-  <dt>{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}</dt>
-    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
-backup</a>. In this method, you read your application data from the device and pass the data you
-want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
-backup</a>.</dd>
-
-  <dt>{@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}</dt>
-    <dd>The Backup Manager calls this method during a restore operation (you can <a
-href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
-the user re-installs your application). When it calls this method, the Backup Manager delivers your
-backup data, which you then restore to the device, as described below in <a
-href="#PerformingRestore">Performing restore</a>.</dd>
-</dl>
-
-
-
-<h3 id="PerformingBackup">Performing backup</h3>
-
-
-<p>When it's time to back up your application data, the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. This is where you must provide your application data to the Backup Manager so
-it can be saved to cloud storage.</p>
-
-<p>Only the Backup Manager can call your backup agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. Each time that your application data changes and you want to perform a backup,
-you must request a backup operation by calling {@link
-android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
-Backup</a> for more information). A backup request does not result in an immediate call to your
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
-backup for all applications that have requested a backup since the last backup was performed.</p>
-
-<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
-immediate backup operation from the Backup Manager with the <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
-
-<p>When the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method, it passes three parameters:</p>
-
-<dl>
-  <dt>{@code oldState}</dt>
-    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
-state provided by your application. This is not the backup data from cloud storage, but a
-local representation of the data that was backed up the last time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} was called (as defined by {@code newState}, below, or from {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}&mdash;more about this in the next section). Because {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} does not allow you to read existing backup data in
-the cloud storage, you can use this local representation to determine whether your data has changed
-since the last backup.</dd>
-  <dt>{@code data}</dt>
-    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
-data to the Backup Manager.</dd>
-  <dt>{@code newState}</dt>
-    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
-you must write a representation of the data that you delivered to {@code data} (a representation
-can be as simple as the last-modified timestamp for your file). This object is
-returned as {@code oldState} the next time the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
-will point to an empty file next time Backup Manager calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.</dd>
-</dl>
-
-<p>Using these parameters, you should implement your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method to do the following:</p>
-
-<ol>
-  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
-your current data. How you read data in {@code oldState} depends on how you originally wrote it to
-{@code newState} (see step 3). The easiest way to record the state of a file is with its
-last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
-oldState}:
-    <pre>
-// Get the oldState input stream
-FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
-DataInputStream in = new DataInputStream(instream);
-
-try {
-    // Get the last modified timestamp from the state file and data file
-    long stateModified = in.readLong();
-    long fileModified = mDataFile.lastModified();
-
-    if (stateModified != fileModified) {
-        // The file has been modified, so do a backup
-        // Or the time on the device changed, so be safe and do a backup
-    } else {
-        // Don't back up because the file hasn't changed
-        return;
-    }
-} catch (IOException e) {
-    // Unable to read state file... be safe and do a backup
-}
-</pre>
-    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
-  </li>
-  <li>If your data has changed, compared to {@code oldState}, write the current data to
-{@code data} to back it up to the cloud storage.
-    <p>You must write each chunk of data as an "entity" in the {@link
-android.app.backup.BackupDataOutput}. An entity is a flattened binary data
-record that is identified by a unique key string. Thus, the data set that you back up is
-conceptually a set of key-value pairs.</p>
-    <p>To add an entity to your backup data set, you must:</p>
-    <ol>
-      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
-writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
-size.</li>
-      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
-writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
-from the buffer (which should match the size passed to {@link
-android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
-    </ol>
-    <p>For example, the following code flattens some data into a byte stream and writes it into a
-single entity:</p>
-    <pre>
-// Create buffer stream and data output stream for our data
-ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
-DataOutputStream outWriter = new DataOutputStream(bufStream);
-// Write structured data
-outWriter.writeUTF(mPlayerName);
-outWriter.writeInt(mPlayerScore);
-// Send the data to the Backup Manager via the BackupDataOutput
-byte[] buffer = bufStream.toByteArray();
-int len = buffer.length;
-data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
-data.writeEntityData(buffer, len);
-</pre>
-    <p>Perform this for each piece of data that you want to back up. How you divide your data into
-entities is up to you (and you might use just one entity).</p>
-  </li>
-  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
-the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
-locally as a representation of the data that is currently backed up. It passes this back to you as
-{@code oldState} the next time it calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
-do not write the current data state to this file, then
-{@code oldState} will be empty during the next callback.
-    <p>The following example saves a representation of the current data into {@code newState} using
-the file's last-modified timestamp:</p>
-    <pre>
-FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
-DataOutputStream out = new DataOutputStream(outstream);
-
-long modified = mDataFile.lastModified();
-out.writeLong(modified);
-</pre>
-  </li>
-</ol>
-
-<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
-that you use synchronized statements while accessing the file so that your backup agent does not
-read the file while an Activity in your application is also writing the file.</p>
-
-
-
-
-<h3 id="PerformingRestore">Performing restore</h3>
-
-<p>When it's time to restore your application data, the Backup Manager calls your backup
-agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
-you can restore it onto the device.</p>
-
-<p>Only the Backup Manager can call {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, which happens automatically when the system installs your application and
-finds existing backup data. However, you can request a restore operation for
-your application by calling {@link
-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
-href="#RequestingRestore">Requesting restore</a> for more information).</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can also request a
-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-<p>When the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} method, it passes three parameters:</p>
-
-<dl>
-  <dt>{@code data}</dt>
-    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
-data.</dd>
-  <dt>{@code appVersionCode}</dt>
-    <dd>An integer representing the value of your application's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-manifest attribute, as it was when this data was backed up. You can use this to cross-check the
-current application version and determine if the data format is compatible. For more
-information about using this to handle different versions of restore data, see the section
-below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
-  <dt>{@code newState}</dt>
-    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
-you must write the final backup state that was provided with {@code data}. This object is
-returned as {@code oldState} the next time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is called. Recall that you must also write the same {@code newState} object in the
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is valid even the first time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is called after the device is restored.</dd>
-</dl>
-
-<p>In your implementation of {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
-{@code data} to iterate
-through all entities in the data set. For each entity found, do the following:</p>
-
-<ol>
-  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
-  <li>Compare the entity key to a list of known key values that you should have declared as static
-final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
-your known key strings, enter into a statement to extract the entity data and save it to the device:
-    <ol>
-      <li>Get the entity data size with {@link
-android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
-      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
-readEntityData()} and pass it the byte array, which is where the data will go, and specify the
-start offset and the size to read.</li>
-      <li>Your byte array is now full and you can read the data and write it to the device
-however you like.</li>
-    </ol>
-  </li>
-  <li>After you read and write your data back to the device, write the state of your data to the
-{@code newState} parameter the same as you do during {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.
-</ol>
-
-<p>For example, here's how you can restore the data backed up by the example in the previous
-section:</p>
-
-<pre>
-&#64;Override
-public void onRestore(BackupDataInput data, int appVersionCode,
-                      ParcelFileDescriptor newState) throws IOException {
-    // There should be only one entity, but the safest
-    // way to consume it is using a while loop
-    while (data.readNextHeader()) {
-        String key = data.getKey();
-        int dataSize = data.getDataSize();
-
-        // If the key is ours (for saving top score). Note this key was used when
-        // we wrote the backup entity header
-        if (TOPSCORE_BACKUP_KEY.equals(key)) {
-            // Create an input stream for the BackupDataInput
-            byte[] dataBuf = new byte[dataSize];
-            data.readEntityData(dataBuf, 0, dataSize);
-            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
-            DataInputStream in = new DataInputStream(baStream);
-
-            // Read the player name and score from the backup data
-            mPlayerName = in.readUTF();
-            mPlayerScore = in.readInt();
-
-            // Record the score on the device (to a file or something)
-            recordScore(mPlayerName, mPlayerScore);
-        } else {
-            // We don't know this entity key. Skip it. (Shouldn't happen.)
-            data.skipEntityData();
-        }
-    }
-
-    // Finally, write to the state blob (newState) that describes the restored data
-    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
-    DataOutputStream out = new DataOutputStream(outstream);
-    out.writeUTF(mPlayerName);
-    out.writeInt(mPlayerScore);
-}
-</pre>
-
-<p>In this example, the {@code appVersionCode} parameter passed to {@link
-android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
-it if you've chosen to perform backup when the user's version of the application has actually moved
-backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
-the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
-
-<div class="special">
-<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
-href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
-ExampleAgent}</a> class in the <a
-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
-application.</p>
-</div>
-
-
-
-
-
-
-<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
-
-<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
-to back up complete files (from either {@link android.content.SharedPreferences} or <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
-Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
-code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}.</p>
-
-<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
-use one or more backup helpers. A backup helper is a specialized
-component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
-restore operations for a particular type of data. The Android framework currently provides two
-different helpers:</p>
-<ul>
-  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
-android.content.SharedPreferences} files.</li>
-  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
-</ul>
-
-<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
-one helper is needed for each data type. That is, if you have multiple {@link
-android.content.SharedPreferences} files, then you need only one {@link
-android.app.backup.SharedPreferencesBackupHelper}.</p>
-
-<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
-the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
-<ol>
-  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
-specify the appropriate file(s) you want to backup.</li>
-  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
-to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
-</ol>
-
-<p>The following sections describe how to create a backup agent using each of the available
-helpers.</p>
-
-
-
-<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
-
-<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
-include the name of one or more {@link android.content.SharedPreferences} files.</p>
-
-<p>For example, to back up a {@link android.content.SharedPreferences} file named
-"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
-like this:</p>
-
-<pre>
-public class MyPrefsBackupAgent extends BackupAgentHelper {
-    // The name of the SharedPreferences file
-    static final String PREFS = "user_preferences";
-
-    // A key to uniquely identify the set of backup data
-    static final String PREFS_BACKUP_KEY = "prefs";
-
-    // Allocate a helper and add it to the backup agent
-    &#64;Override
-    public void onCreate() {
-        SharedPreferencesBackupHelper helper =
-                new SharedPreferencesBackupHelper(this, PREFS);
-        addHelper(PREFS_BACKUP_KEY, helper);
-    }
-}
-</pre>
-
-<p>That's it! That's your entire backup agent. The {@link
-android.app.backup.SharedPreferencesBackupHelper} includes all the code
-needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
-
-<p>When the Backup Manager calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
-backup and restore for your specified files.</p>
-
-<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
-you can safely read and write the shared preferences file from your backup agent and
-other activities.</p>
-
-
-
-<h3 id="Files">Backing up other files</h3>
-
-<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
-one or more files that are saved to your application's <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
-(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
-location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
-files).</p>
-
-<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
-android.app.backup.BackupAgentHelper} looks like this:</p>
-
-<pre>
-public class MyFileBackupAgent extends BackupAgentHelper {
-    // The name of the file
-    static final String TOP_SCORES = "scores";
-    static final String PLAYER_STATS = "stats";
-
-    // A key to uniquely identify the set of backup data
-    static final String FILES_BACKUP_KEY = "myfiles";
-
-    // Allocate a helper and add it to the backup agent
-    &#64;Override
-    public void onCreate() {
-        FileBackupHelper helper = new FileBackupHelper(this,
-                TOP_SCORES, PLAYER_STATS);
-        addHelper(FILES_BACKUP_KEY, helper);
-    }
-}
-</pre>
-
-<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
-restore files that are saved to your application's <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
-
-<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
-ensure that your backup agent does not read or write your files at the same time as your activities,
-you must use synchronized statements each time you perform a read or write. For example,
-in any Activity where you read and write the file, you need an object to use as the intrinsic
-lock for the synchronized statements:</p>
-
-<pre>
-// Object for intrinsic lock
-static final Object sDataLock = new Object();
-</pre>
-
-<p>Then create a synchronized statement with this lock each time you read or write the files. For
-example, here's a synchronized statement for writing the latest score in a game to a file:</p>
-
-<pre>
-try {
-    synchronized (MyActivity.sDataLock) {
-        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
-        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
-        raFile.writeInt(score);
-    }
-} catch (IOException e) {
-    Log.e(TAG, "Unable to write to file");
-}
-</pre>
-
-<p>You should synchronize your read statements with the same lock.</p>
-
-<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to synchronize the backup and restore operations with the same
-intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
-methods:</p>
-
-<pre>
-&#64;Override
-public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-          ParcelFileDescriptor newState) throws IOException {
-    // Hold the lock while the FileBackupHelper performs backup
-    synchronized (MyActivity.sDataLock) {
-        super.onBackup(oldState, data, newState);
-    }
-}
-
-&#64;Override
-public void onRestore(BackupDataInput data, int appVersionCode,
-        ParcelFileDescriptor newState) throws IOException {
-    // Hold the lock while the FileBackupHelper restores the file
-    synchronized (MyActivity.sDataLock) {
-        super.onRestore(data, appVersionCode, newState);
-    }
-}
-</pre>
-
-<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
-{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to synchronize read and write operations.</p>
-
-<div class="special">
-<p>For an example implementation of {@link
-android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
-{@code FileHelperExampleAgent} class in the <a
-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
-application.</p>
-</div>
-
-
-
-
-
-
-<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
-
-<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
-of your application, as defined by your manifest file's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-attribute. Before the Backup Manager calls your backup agent to restore your data, it
-looks at the <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
-android:versionCode}</a> of the installed application and compares it to the value
-recorded in the restore data set. If the version recorded in the restore data set is
-<em>newer</em> than the application version on the device, then the user has downgraded their
-application. In this case, the Backup Manager will abort the restore operation for your application
-and not call your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method, because the restore set is considered meaningless to an older version.</p>
-
-<p>You can override this behavior with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
-false}" to indicate whether you want to restore the application regardless of the restore set
-version. The default value is "{@code false}". If you define this to be "{@code true}" then the
-Backup Manager will ignore the <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-and call your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method in all cases. In doing so, you can manually check for the version difference in your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method and take any steps necessary to make the data compatible if the versions conflict.</p>
-
-<p>To help you handle different versions during a restore operation, the {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method passes you the version code included with the restore data set as the {@code appVersionCode}
-parameter. You can then query the current application's version code with the {@link
-android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
-
-<pre>
-PackageInfo info;
-try {
-    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
-    info = {@link android.content.ContextWrapper#getPackageManager
-getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
-getPackageInfo}(name,0);
-} catch (NameNotFoundException nnfe) {
-    info = null;
-}
-
-int version;
-if (info != null) {
-    version = info.versionCode;
-}
-</pre>
-
-<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
-to the {@code appVersionCode} passed into {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
-</p>
-
-<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
-<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
-application that supports backup does not properly account for variations in your data format during
-{@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
-then the data on the device could be saved in a format incompatible with the version currently
-installed on the device.</p>
-
-
-
-<h2 id="RequestingBackup">Requesting Backup</h2>
-
-<p>You can request a backup operation at any time by calling {@link
-android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
-like to backup your data using your backup agent. The Backup Manager then calls your backup
-agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method at an opportune time in the future. Typically, you should
-request a backup each time your data changes (such as when the user changes an application
-preference that you'd like to back up). If you call {@link
-android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
-Manager requests a backup from your agent, your agent still receives just one call to {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can request a
-backup and initiate an immediate backup operation with the <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-
-<h2 id="RequestingRestore">Requesting Restore</h2>
-
-<p>During the normal life of your application, you shouldn't need to request a restore operation.
-They system automatically checks for backup data and performs a restore when your application is
-installed. However, you can manually request a restore operation by calling {@link
-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
-which case, the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-implementation, passing the data from the current set of backup data.</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can request a
-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-
-<h2 id="Testing">Testing Your Backup Agent</h2>
-
-<p>Once you've implemented your backup agent, you can test the backup and restore functionality
-with the following procedure, using <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}</a>.</p>
-
-<ol>
-  <li>Install your application on a suitable Android system image
-    <ul>
-      <li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li>
-      <li>If using a device, the device must be running Android 2.2 or greater and have Google
-Play built in.</li>
-    </ul>
-  </li>
-  <li>Ensure that backup is enabled
-    <ul>
-      <li>If using the emulator, you can enable backup with the following command from your SDK
-{@code tools/} path:
-<pre class="no-pretty-print">adb shell bmgr enable true</pre>
-      </li>
-      <li>If using a device, open the system <b>Settings</b>, select
-      <b>Backup & reset</b>, then enable
-      <b>Back up my data</b> and <b>Automatic restore</b>.</li>
-    </ul>
-  </li>
-  <li>Open your application and initialize some data
-    <p>If you've properly implemented backup in your application, then it should request a
-backup each time the data changes. For example, each time the user changes some data, your app
-should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to
-the Backup Manager queue. For testing purposes, you can also make a request with the following
-{@code bmgr} command:</p>
-<pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre>
-  </li>
-  <li>Initiate a backup operation:
-<pre class="no-pretty-print">adb shell bmgr run</pre>
-    <p>This forces the Backup Manager to perform all backup requests that are in its
-queue.</p>
-  <li>Uninstall your application:
-<pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre>
-  </li>
-  <li>Re-install your application.</li>
-</ol>
-
-<p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p>
-
-
+<p class="note"><strong>Note:</strong> These data backup features are not designed for synchronizing app data with other clients or
+saving data that you'd like to access during the normal application lifecycle.
+You cannot read or write backup data on demand. For synchronizing app data, see
+<a href="{@docRoot}training/sync-adapters/index.html">Transferring
+Data Using Sync Adapters</a> or <a href="https://developers.google.com/drive/android/">Google Drive Android
+API</a>.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/images/backup-framework.png b/docs/html/guide/topics/data/images/backup-framework.png
new file mode 100644
index 0000000..2ba2e612
--- /dev/null
+++ b/docs/html/guide/topics/data/images/backup-framework.png
Binary files differ
diff --git a/docs/html/guide/topics/data/index.jd b/docs/html/guide/topics/data/index.jd
index 3872825..2365f18 100644
--- a/docs/html/guide/topics/data/index.jd
+++ b/docs/html/guide/topics/data/index.jd
@@ -5,21 +5,3 @@
 
 @jd:body
 
-<div class="landing-docs">
-
-
-  <div class="col-12">
-    <h3>Training</h3>
-
-    <a href="{@docRoot}training/backup/index.html">
-      <h4>Backing up App Data to the Cloud</h4>
-      <p>
-        This class covers techniques for backing up data to the cloud so that
-        users can restore their data when recovering from a data loss (such as a
-        factory reset) or installing your application on a new device.
-      </p>
-    </a>
-
-  </div>
-
-</div>
diff --git a/docs/html/guide/topics/data/keyvaluebackup.jd b/docs/html/guide/topics/data/keyvaluebackup.jd
new file mode 100644
index 0000000..c7c5e2f
--- /dev/null
+++ b/docs/html/guide/topics/data/keyvaluebackup.jd
@@ -0,0 +1,884 @@
+page.title=Key/Value Backup
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, kvbackup
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Comparison">Comparison to Auto Backup</a></li>
+    <li><a href="#ImplementingBackup">Implementing Key/Value Backup</a></li>
+
+    <li><a href="#BackupManifest">Declaring the backup agent in your manifest</a></li>
+    <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
+    <li><a href="#BackupAgent">Extending BackupAgent</a>
+      <ol>
+        <li><a href="#RequiredMethods">Required methods</a></li>
+        <li><a href="#PerformingBackup">Performing backup</a></li>
+        <li><a href="#PerformingRestore">Performing restore</a></li>
+      </ol>
+    </li>
+    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
+      <ol>
+        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
+        <li><a href="#Files">Backing up private files</a></li>
+      </ol>
+    </li>
+    <li><a href="#RestoreVersion">Checking the restore data version</a></li>
+    <li><a href="#RequestingBackup">Requesting backup</a></li>
+    <li><a href="#RequestingRestore">Requesting restore</a></li>
+    <li><a href="#Migrating">Migrating to Auto Backup</a></li>
+  </ol>
+
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.app.backup.BackupManager}</li>
+    <li>{@link android.app.backup.BackupAgent}</li>
+    <li>{@link android.app.backup.BackupAgentHelper}</li>
+  </ol>
+
+</div>
+</div>
+
+
+<p>Since Android 2.2 (API 8), Android has offered the <em>Key/Value Backup</em>
+feature as a way for developers to backup app data to the cloud. The Key/Value
+Backup feature (formerly known as the Backup API and the Android Backup Service)
+preserves app data by uploading it to
+<a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
+The amount of data is limited to 5MB per user of your app and there is
+no charge for storing backup data.
+
+<p class="note"><strong>Note:</strong> If your app implements Key/Value Backup
+and targets API 23 or higher, you should set
+<a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a>.
+This attribute indicates whether or not to use Auto Backup on devices where it is available.
+
+<h2 id="Comparison">Comparison to Auto Backup</h2>
+<p>Like Auto Backup, Key/Value Backups are restored automatically whenever the app
+is installed. The following table describes some of the key differences between Key/Value Backup and Auto Backup:
+
+<table>
+  <tr>
+   <th>Key/Value Backup</th>
+   <th>Auto Backup</th>
+  </tr>
+  <tr>
+   <td>Available in API 8, Android 2.2</td>
+   <td>Available in API 23, Android 6.0</td>
+  </tr>
+  <tr>
+   <td>Apps must implement a {@link android.app.backup.BackupAgent}. The backup agent defines what data to backup and how to
+restore data.</td>
+   <td>By default, Auto Backup includes almost all of the app's files. You can
+use XML to include and exclude files. Under the hood, Auto Backup relies on a
+backup agent that is built into the framework.</td>
+  </tr>
+  <tr>
+   <td>Apps must issue a request when there is data
+that is ready to be backed up. Requests
+from multiple apps are batched and executed every few hours.</td>
+   <td>Backups happen automatically roughly once a day.</td>
+  </tr>
+  <tr>
+   <td>Backup data can be transmitted via wifi or cellular data.</td>
+   <td>Backup data is tranmitted only via wifi. If the device is never connected to a
+wifi network, then Auto Backup never occurs.</td>
+  </tr>
+  <tr>
+   <td>Apps are not shut down during backup.</td>
+   <td>The system shuts down the app during backup.</td>
+  </tr>
+  <tr>
+   <td>Backup data is stored in <a href="{@docRoot}google/backup/index.html">Android Backup Service</a> limited to 5MB per app.</td>
+   <td>Backup data is stored in the user's Google Drive limited to 25MB per app.</td>
+  </tr>
+  <tr>
+   <td>Related API methods are not filed based:<ul>
+      <li>{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
+      <li>{@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()}</ul></td>
+   <td>Related API methods are filed based:<ul>
+<li>{@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput) onFullBackup()}
+<li>{@link android.app.backup.BackupAgent#onRestoreFile(ParcelFileDescriptor,long,File,int,long,long) onRestoreFile()}</ul></td>
+  </tr>
+</table>
+
+<h2 id="ImplementingBackup">Implementing Key/Value Backup</h2>
+<p>To backup your application data, you need to implement a backup agent. Your backup
+agent is called by the Backup Manager both during backup and restore.</p>
+
+<p>To implement a backup agent, you must:</p>
+
+<ol>
+  <li>Declare your backup agent in your manifest file with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute.</li>
+  <li>Register your application with <a href="{@docRoot}google/backup/index.html">Android
+   Backup Service</a></li>
+  <li>Define a backup agent by either:</p>
+    <ol type="a">
+      <li><a href="#BackupAgent">Extending BackupAgent</a>
+        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
+which your application communicates with the Backup Manager. If you extend this class
+directly, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to handle the backup and restore operations for your data.</p>
+        <p><em>Or</em></p>
+      <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
+        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
+wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
+you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
+"helper" objects, which automatically backup and restore certain types of data, so that you do not
+need to implement {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+        <p>Android currently provides backup helpers that will backup and restore complete files
+from {@link android.content.SharedPreferences} and <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
+      </li>
+    </ol>
+  </li>
+</ol>
+
+<h2 id="BackupManifest">Declaring the backup agent in your manifest</h2>
+
+<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
+it in your manifest with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute in the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+<application>}</a> tag.</p>
+
+<p>For example:</p>
+
+<pre>
+&lt;manifest ... &gt;
+    ...
+    &lt;application android:label="MyApplication"
+                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
+        &lt;activity ... &gt;
+            ...
+        &lt;/activity&gt;
+    &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>Another attribute you might want to use is <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
+want to restore the application data regardless of the current application version compared to the
+version that produced the backup data. (The default value is "{@code false}".) See <a
+href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
+
+<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
+available only on devices running API Level 8 (Android 2.2) or greater, so you should also
+set your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+attribute to "8".</p>
+
+
+
+
+<h2 id="BackupKey">Registering for Android Backup Service</h2>
+
+<p>Google provides a backup transport with <a
+href="{@docRoot}google/backup/index.html">Android Backup Service</a> for most
+Android-powered devices running Android 2.2 or greater.</p>
+
+<p>In order for your application to perform backup using Android Backup Service, you must
+register your application with the service to receive a Backup Service Key, then
+declare the Backup Service Key in your Android manifest.</p>
+
+<p>To get your Backup Service Key, <a
+href="{@docRoot}google/backup/signup.html">register for Android Backup Service</a>.
+When you register, you will be provided a Backup Service Key and the appropriate {@code
+<meta-data>} XML code for your Android manifest file, which you must include as a child of the
+{@code <application>} element. For example:</p>
+
+<pre>
+&lt;application android:label="MyApplication"
+             android:backupAgent="MyBackupAgent"&gt;
+    ...
+    &lt;meta-data android:name="com.google.android.backup.api_key"
+        android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /&gt;
+&lt;/application&gt;
+</pre>
+
+<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
+the <code>android:value</code> must be the Backup Service Key received from the Android Backup
+Service registration.</p>
+
+<p>If you have multiple applications, you must register each one, using the respective package
+name.</p>
+
+<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
+not guaranteed to be available
+on all Android-powered devices that support backup. Some devices might support backup
+using a different transport, some devices might not support backup at all, and there is no way for
+your application to know what transport is used on the device. However, if you implement backup for
+your application, you should always include a Backup Service Key for Android Backup Service so
+your application can perform backup when the device uses the Android Backup Service transport. If
+the device does not use Android Backup Service, then the {@code <meta-data>} element with the
+Backup Service Key is ignored.</p>
+
+
+
+
+<h2 id="BackupAgent">Extending BackupAgent</h2>
+
+<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
+directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
+advantage of the built-in helper classes that automatically backup and restore your files. However,
+you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
+<ul>
+  <li>Version your data format. For instance, if you anticipate the need to revise the
+format in which you write your application data, you can build a backup agent to cross-check your
+application version during a restore operation and perform any necessary compatibility work if the
+version on the device is different than that of the backup data. For more information, see <a
+href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
+  <li>Instead of backing up an entire file, you can specify the portions of data the should be
+backed up and how each portion is then restored to the device. (This can also help you manage
+different versions, because you read and write your data as unique entities, rather than
+complete files.)</li>
+  <li>Back up data in a database. If you have an SQLite database that you want to restore when
+the user re-installs your application, you need to build a custom {@link
+android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
+create your table and insert the data during a restore operation.</li>
+</ul>
+
+<p>If you don't need to perform any of the tasks above and want to back up complete files from
+{@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
+should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
+
+
+
+<h3 id="RequiredMethods">Required methods</h3>
+
+<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
+must implement the following callback methods:</p>
+
+<dl>
+  <dt>{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}</dt>
+    <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
+backup</a>. In this method, you read your application data from the device and pass the data you
+want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
+backup</a>.</dd>
+
+  <dt>{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}</dt>
+    <dd>The Backup Manager calls this method during a restore operation (you can <a
+href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
+the user re-installs your application). When it calls this method, the Backup Manager delivers your
+backup data, which you then restore to the device, as described below in <a
+href="#PerformingRestore">Performing restore</a>.</dd>
+</dl>
+
+
+
+<h3 id="PerformingBackup">Performing backup</h3>
+
+
+<p>When it's time to back up your application data, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. This is where you must provide your application data to the Backup Manager so
+it can be saved to cloud storage.</p>
+
+<p>Only the Backup Manager can call your backup agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Each time that your application data changes and you want to perform a backup,
+you must request a backup operation by calling {@link
+android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
+Backup</a> for more information). A backup request does not result in an immediate call to your
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
+backup for all applications that have requested a backup since the last backup was performed.</p>
+
+<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
+immediate backup operation from the Backup Manager with the <a
+href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method, it passes three parameters:</p>
+
+<dl>
+  <dt>{@code oldState}</dt>
+    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
+state provided by your application. This is not the backup data from cloud storage, but a
+local representation of the data that was backed up the last time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} was called (as defined by {@code newState}, below, or from {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}&mdash;more about this in the next section). Because {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} does not allow you to read existing backup data in
+the cloud storage, you can use this local representation to determine whether your data has changed
+since the last backup.</dd>
+  <dt>{@code data}</dt>
+    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
+data to the Backup Manager.</dd>
+  <dt>{@code newState}</dt>
+    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write a representation of the data that you delivered to {@code data} (a representation
+can be as simple as the last-modified timestamp for your file). This object is
+returned as {@code oldState} the next time the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
+will point to an empty file next time Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</dd>
+</dl>
+
+<p>Using these parameters, you should implement your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method to do the following:</p>
+
+<ol>
+  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
+your current data. How you read data in {@code oldState} depends on how you originally wrote it to
+{@code newState} (see step 3). The easiest way to record the state of a file is with its
+last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
+oldState}:
+    <pre>
+// Get the oldState input stream
+FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
+DataInputStream in = new DataInputStream(instream);
+
+try {
+    // Get the last modified timestamp from the state file and data file
+    long stateModified = in.readLong();
+    long fileModified = mDataFile.lastModified();
+
+    if (stateModified != fileModified) {
+        // The file has been modified, so do a backup
+        // Or the time on the device changed, so be safe and do a backup
+    } else {
+        // Don't back up because the file hasn't changed
+        return;
+    }
+} catch (IOException e) {
+    // Unable to read state file... be safe and do a backup
+}
+</pre>
+    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
+  </li>
+  <li>If your data has changed, compared to {@code oldState}, write the current data to
+{@code data} to back it up to the cloud storage.
+    <p>You must write each chunk of data as an "entity" in the {@link
+android.app.backup.BackupDataOutput}. An entity is a flattened binary data
+record that is identified by a unique key string. Thus, the data set that you back up is
+conceptually a set of key-value pairs.</p>
+    <p>To add an entity to your backup data set, you must:</p>
+    <ol>
+      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
+writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
+size.</li>
+      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
+writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
+from the buffer (which should match the size passed to {@link
+android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
+    </ol>
+    <p>For example, the following code flattens some data into a byte stream and writes it into a
+single entity:</p>
+    <pre>
+// Create buffer stream and data output stream for our data
+ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+DataOutputStream outWriter = new DataOutputStream(bufStream);
+// Write structured data
+outWriter.writeUTF(mPlayerName);
+outWriter.writeInt(mPlayerScore);
+// Send the data to the Backup Manager via the BackupDataOutput
+byte[] buffer = bufStream.toByteArray();
+int len = buffer.length;
+data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
+data.writeEntityData(buffer, len);
+</pre>
+    <p>Perform this for each piece of data that you want to back up. How you divide your data into
+entities is up to you (and you might use just one entity).</p>
+  </li>
+  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
+the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
+locally as a representation of the data that is currently backed up. It passes this back to you as
+{@code oldState} the next time it calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
+do not write the current data state to this file, then
+{@code oldState} will be empty during the next callback.
+    <p>The following example saves a representation of the current data into {@code newState} using
+the file's last-modified timestamp:</p>
+    <pre>
+FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+DataOutputStream out = new DataOutputStream(outstream);
+
+long modified = mDataFile.lastModified();
+out.writeLong(modified);
+</pre>
+  </li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
+that you use synchronized statements while accessing the file so that your backup agent does not
+read the file while an Activity in your application is also writing the file.</p>
+
+
+
+
+<h3 id="PerformingRestore">Performing restore</h3>
+
+<p>When it's time to restore your application data, the Backup Manager calls your backup
+agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
+you can restore it onto the device.</p>
+
+<p>Only the Backup Manager can call {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, which happens automatically when the system installs your application and
+finds existing backup data. However, you can request a restore operation for
+your application by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
+href="#RequestingRestore">Requesting restore</a> for more information).</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can also request a
+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method, it passes three parameters:</p>
+
+<dl>
+  <dt>{@code data}</dt>
+    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
+data.</dd>
+  <dt>{@code appVersionCode}</dt>
+    <dd>An integer representing the value of your application's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+manifest attribute, as it was when this data was backed up. You can use this to cross-check the
+current application version and determine if the data format is compatible. For more
+information about using this to handle different versions of restore data, see the section
+below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
+  <dt>{@code newState}</dt>
+    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write the final backup state that was provided with {@code data}. This object is
+returned as {@code oldState} the next time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called. Recall that you must also write the same {@code newState} object in the
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is valid even the first time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called after the device is restored.</dd>
+</dl>
+
+<p>In your implementation of {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
+{@code data} to iterate
+through all entities in the data set. For each entity found, do the following:</p>
+
+<ol>
+  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
+  <li>Compare the entity key to a list of known key values that you should have declared as static
+final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
+your known key strings, enter into a statement to extract the entity data and save it to the device:
+    <ol>
+      <li>Get the entity data size with {@link
+android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
+      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
+readEntityData()} and pass it the byte array, which is where the data will go, and specify the
+start offset and the size to read.</li>
+      <li>Your byte array is now full and you can read the data and write it to the device
+however you like.</li>
+    </ol>
+  </li>
+  <li>After you read and write your data back to the device, write the state of your data to the
+{@code newState} parameter the same as you do during {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.
+</ol>
+
+<p>For example, here's how you can restore the data backed up by the example in the previous
+section:</p>
+
+<pre>
+&#64;Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+                      ParcelFileDescriptor newState) throws IOException {
+    // There should be only one entity, but the safest
+    // way to consume it is using a while loop
+    while (data.readNextHeader()) {
+        String key = data.getKey();
+        int dataSize = data.getDataSize();
+
+        // If the key is ours (for saving top score). Note this key was used when
+        // we wrote the backup entity header
+        if (TOPSCORE_BACKUP_KEY.equals(key)) {
+            // Create an input stream for the BackupDataInput
+            byte[] dataBuf = new byte[dataSize];
+            data.readEntityData(dataBuf, 0, dataSize);
+            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+            DataInputStream in = new DataInputStream(baStream);
+
+            // Read the player name and score from the backup data
+            mPlayerName = in.readUTF();
+            mPlayerScore = in.readInt();
+
+            // Record the score on the device (to a file or something)
+            recordScore(mPlayerName, mPlayerScore);
+        } else {
+            // We don't know this entity key. Skip it. (Shouldn't happen.)
+            data.skipEntityData();
+        }
+    }
+
+    // Finally, write to the state blob (newState) that describes the restored data
+    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+    DataOutputStream out = new DataOutputStream(outstream);
+    out.writeUTF(mPlayerName);
+    out.writeInt(mPlayerScore);
+}
+</pre>
+
+<p>In this example, the {@code appVersionCode} parameter passed to {@link
+android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
+it if you've chosen to perform backup when the user's version of the application has actually moved
+backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
+the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
+
+<div class="special">
+<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
+href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
+ExampleAgent}</a> class in the <a
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
+
+<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
+to back up complete files (from either {@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
+Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
+code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+
+<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
+use one or more backup helpers. A backup helper is a specialized
+component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
+restore operations for a particular type of data. The Android framework currently provides two
+different helpers:</p>
+<ul>
+  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
+android.content.SharedPreferences} files.</li>
+  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
+</ul>
+
+<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
+one helper is needed for each data type. That is, if you have multiple {@link
+android.content.SharedPreferences} files, then you need only one {@link
+android.app.backup.SharedPreferencesBackupHelper}.</p>
+
+<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
+the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
+<ol>
+  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
+specify the appropriate file(s) you want to backup.</li>
+  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
+to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
+</ol>
+
+<p>The following sections describe how to create a backup agent using each of the available
+helpers.</p>
+
+
+
+<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
+
+<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
+include the name of one or more {@link android.content.SharedPreferences} files.</p>
+
+<p>For example, to back up a {@link android.content.SharedPreferences} file named
+"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
+like this:</p>
+
+<pre>
+public class MyPrefsBackupAgent extends BackupAgentHelper {
+    // The name of the SharedPreferences file
+    static final String PREFS = "user_preferences";
+
+    // A key to uniquely identify the set of backup data
+    static final String PREFS_BACKUP_KEY = "prefs";
+
+    // Allocate a helper and add it to the backup agent
+    &#64;Override
+    public void onCreate() {
+        SharedPreferencesBackupHelper helper =
+                new SharedPreferencesBackupHelper(this, PREFS);
+        addHelper(PREFS_BACKUP_KEY, helper);
+    }
+}
+</pre>
+
+<p>That's it! That's your entire backup agent. The {@link
+android.app.backup.SharedPreferencesBackupHelper} includes all the code
+needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
+
+<p>When the Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
+backup and restore for your specified files.</p>
+
+<p class="note"><strong>Note:</strong> The methods of {@link android.content.SharedPreferences}
+are threadsafe, so
+you can safely read and write the shared preferences file from your backup agent and
+other activities.</p>
+
+
+
+<h3 id="Files">Backing up other files</h3>
+
+<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
+one or more files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
+(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
+location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
+files).</p>
+
+<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
+android.app.backup.BackupAgentHelper} looks like this:</p>
+
+<pre>
+public class MyFileBackupAgent extends BackupAgentHelper {
+    // The name of the file
+    static final String TOP_SCORES = "scores";
+    static final String PLAYER_STATS = "stats";
+
+    // A key to uniquely identify the set of backup data
+    static final String FILES_BACKUP_KEY = "myfiles";
+
+    // Allocate a helper and add it to the backup agent
+    &#64;Override
+    public void onCreate() {
+        FileBackupHelper helper = new FileBackupHelper(this,
+                TOP_SCORES, PLAYER_STATS);
+        addHelper(FILES_BACKUP_KEY, helper);
+    }
+}
+</pre>
+
+<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
+restore files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
+
+<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
+ensure that your backup agent does not read or write your files at the same time as your activities,
+you must use synchronized statements each time you perform a read or write. For example,
+in any Activity where you read and write the file, you need an object to use as the intrinsic
+lock for the synchronized statements:</p>
+
+<pre>
+// Object for intrinsic lock
+static final Object sDataLock = new Object();
+</pre>
+
+<p>Then create a synchronized statement with this lock each time you read or write the files. For
+example, here's a synchronized statement for writing the latest score in a game to a file:</p>
+
+<pre>
+try {
+    synchronized (MyActivity.sDataLock) {
+        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
+        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
+        raFile.writeInt(score);
+    }
+} catch (IOException e) {
+    Log.e(TAG, "Unable to write to file");
+}
+</pre>
+
+<p>You should synchronize your read statements with the same lock.</p>
+
+<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize the backup and restore operations with the same
+intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
+methods:</p>
+
+<pre>
+&#64;Override
+public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+          ParcelFileDescriptor newState) throws IOException {
+    // Hold the lock while the FileBackupHelper performs backup
+    synchronized (MyActivity.sDataLock) {
+        super.onBackup(oldState, data, newState);
+    }
+}
+
+&#64;Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+        ParcelFileDescriptor newState) throws IOException {
+    // Hold the lock while the FileBackupHelper restores the file
+    synchronized (MyActivity.sDataLock) {
+        super.onRestore(data, appVersionCode, newState);
+    }
+}
+</pre>
+
+<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
+{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize read and write operations.</p>
+
+<div class="special">
+<p>For an example implementation of {@link
+android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
+{@code FileHelperExampleAgent} class in the <a
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="RestoreVersion">Checking the restore data version</h2>
+
+<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
+of your application, as defined by your manifest file's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+attribute. Before the Backup Manager calls your backup agent to restore your data, it
+looks at the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
+android:versionCode}</a> of the installed application and compares it to the value
+recorded in the restore data set. If the version recorded in the restore data set is
+<em>newer</em> than the application version on the device, then the user has downgraded their
+application. In this case, the Backup Manager will abort the restore operation for your application
+and not call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method, because the restore set is considered meaningless to an older version.</p>
+
+<p>You can override this behavior with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
+false}" to indicate whether you want to restore the application regardless of the restore set
+version. The default value is "{@code false}". If you define this to be "{@code true}" then the
+Backup Manager will ignore the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+and call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method in all cases. In doing so, you can manually check for the version difference in your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method and take any steps necessary to make the data compatible if the versions conflict.</p>
+
+<p>To help you handle different versions during a restore operation, the {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method passes you the version code included with the restore data set as the {@code appVersionCode}
+parameter. You can then query the current application's version code with the {@link
+android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
+
+<pre>
+PackageInfo info;
+try {
+    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
+    info = {@link android.content.ContextWrapper#getPackageManager
+getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
+getPackageInfo}(name,0);
+} catch (NameNotFoundException nnfe) {
+    info = null;
+}
+
+int version;
+if (info != null) {
+    version = info.versionCode;
+}
+</pre>
+
+<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
+to the {@code appVersionCode} passed into {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
+</p>
+
+<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
+<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
+application that supports backup does not properly account for variations in your data format during
+{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
+then the data on the device could be saved in a format incompatible with the version currently
+installed on the device.</p>
+
+
+
+<h2 id="RequestingBackup">Requesting backup</h2>
+
+<p>You can request a backup operation at any time by calling {@link
+android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
+like to backup your data using your backup agent. The Backup Manager then calls your backup
+agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method at an opportune time in the future. Typically, you should
+request a backup each time your data changes (such as when the user changes an application
+preference that you'd like to back up). If you call {@link
+android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
+Manager requests a backup from your agent, your agent still receives just one call to {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+backup and initiate an immediate backup operation with the <a
+href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+
+<h2 id="RequestingRestore">Requesting restore</h2>
+
+<p>During the normal life of your application, you shouldn't need to request a restore operation.
+They system automatically checks for backup data and performs a restore when your application is
+installed. However, you can manually request a restore operation by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
+which case, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+implementation, passing the data from the current set of backup data.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+
+<h2 id="Migrating">Migrating to Auto Backup</h2>
+<p>You can transition your app to full-data backups by setting <a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a> to <code>true</code> in the <code>&lt;application></code> element in the manifest file. When
+running on a device with Android 5.1 (API level 22) or lower, your app ignores
+this value in the manifest, and continues performing Key/Value Backups. When
+running on a device with Android 6.0 (API level 23) or higher, your app performs
+Auto Backup instead of Key/Value Backup.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/testingbackup.jd b/docs/html/guide/topics/data/testingbackup.jd
new file mode 100644
index 0000000..6ff5837
--- /dev/null
+++ b/docs/html/guide/topics/data/testingbackup.jd
@@ -0,0 +1,181 @@
+page.title=Testing Backup and Restore
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, restore, testing
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#HowBackupWorks">How backup works</a></li>
+    <li><a href="#Prerequisites">Prerequisites</a></li>
+    <li><a href="#Preparing">Preparing your device or emulator</a></li>
+    <li><a href="#TestingBackup">Testing backup</a></li>
+    <li><a href="#TestingRestore">Testing restore</a></li>
+    <li><a href="#Troubleshooting">Troubleshooting</a></li>
+  </ol>
+
+</div>
+</div>
+
+<p>This page shows you how to manually trigger Auto Backup, Key/Value Backup, and restore operations to
+ensure your app saves and restores data properly.
+
+<h2 id="HowBackupWorkso">How backup works</h2>
+<p>The section describes various pieces in the Android backup framework and how they
+interact with apps that support Auto Backup and Key/Value Backup. During the app
+development phase, most of the inner working of the framework were abstracted away, so you didn't need to know this information. However, during the
+testing phase, an understanding of these concepts is important.
+
+<p>The following diagram illustrates how data flows during backup and restore:
+
+<img src="images/backup-framework.png" alt="backup-framework">
+
+<p>The <em>Backup Manager Service</em> is an Android system
+service which orchestrates and initiates backup and restore operations. The service
+is accessible through the {@link android.app.backup.BackupManager}
+API. During a backup operation, the service queries your app for backup data,
+then hands it to the <em>backup transport</em>, which then archives the data.
+During a restore operation, the backup manager service retrieves the backup data
+from the backup transport and restores the data to the device.
+
+<p><em>Backup Transports</em> are Android components that are responsible
+for storing and retrieving backups. An Android device can have zero or more
+backup transports, but only one of those transports can be marked active. The
+available backup transports may differ from device to device (due to
+customizations by device manufacturers and service providers), but most Google
+Play enabled devices ship with the following transports:
+</p><ul>
+<li><strong>Google GMS Transport</strong>(default) - the active backup
+transport on most devices, part of <a href="https://www.android.com/gms/">Google Mobile Services</a>. This documentation assumes that users are using the
+Google GMS transport. This transport stores Auto Backup data in a private folder in the
+user's Google Drive account. Key/Value Backup data is stored in the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
+<li><strong>Local Transport</strong> - stores backup data locally on the device.
+This transport is typically used for development/debugging purposes and is not
+useful in the real world.</li></ul>
+
+<p>If a device does not have any backup transports, then the data cannot be
+backed up. Your app is not adversely affected.
+
+<p class="caution"><strong>Caution:</strong> Because the backup transport
+can differ from device to device, Android cannot guarantee the security
+of your data while using backup. Be cautious about using backup to store
+sensitive data, such as usernames and passwords.
+
+<h2 id="Prerequisites">Prerequisites</h2>
+<p>You need to know a bit about the following tools:
+
+<ul>
+  <li><a href="{@docRoot}studio/command-line/adb.html">adb</a>
+- to run commands on the device or emulator
+  <li><a href="{@docRoot}studio/command-line/bmgr.html">bmgr</a> - to
+perform various backup and restore operations
+  <li><a href="{@docRoot}studio/command-line/logcat.html">logcat</a>
+- to see the output of backup and restore operations.</li></ul>
+
+<h2 id="Preparing">Preparing your device or
+emulator</h2>
+<p>Prepare your device or emulator for backup testing by working through the
+following checklist:
+<ul>
+  <li>For Auto Backup, check that you are using a device or emulator running
+Android 6.0 (API level 23) or higher.</li>
+  <li>For Key/Value Backup, check that you are using a device or emulator running
+Android 2.2 (API level 8) or higher.</li>
+  <li>Check that backup and restore is enabled on the device or emulator. There
+are two ways to check: <ul>
+    <li>On the device, go to <strong>Settings -> Backup &amp; Restore</strong>.
+    <li>From adb shell, run <code>bmgr enable</code></li></ul>
+    <p>On physical devices, backup and restore is typically enabled during the
+initial setup wizard. Emulators do not run the setup wizard, so don't forget to
+enable backup and specify a backup account in device settings.
+  <li>Make sure the GMS Backup Transport is available and active by running the
+command from adb shell:
+  <pre class="prettyprint">$ bmgr list transports</pre>
+  <p>Then, check the console for the following output:
+  <pre class="prettyprint">android/com.android.internal.backup.LocalTransport
+* com.google.android.gms/.backup.BackupTransportService</pre>
+  <p>Physical devices without Google Play and emulators without Google APIs
+might not include the GMS Backup Transport. This article assumes you are using
+the GMS Backup Transport. You can test backup and restore with other backup
+transports, but the procedure and output can differ.
+</ul>
+
+<h2 id="TestingBackup">Testing backup</h2>
+<p>To initiate a backup of your app, run the following command:
+
+<pre class="prettyprint">$ bmgr backupnow &lt;PACKAGE></pre>
+
+<p>The <code>backupnow</code> command runs either a Key/Value Backup or Auto Backup depending on
+the package's manifest declarations. Check logcat to see the output of the
+backup procedure. For example:
+
+<pre class="prettyprint">D/BackupManagerService: fullTransportBackup()
+I/GmsBackupTransport: Attempt to do full backup on &lt;PACKAGE>
+
+---- or ----
+
+V/BackupManagerService: Scheduling immediate backup pass
+D/PerformBackupTask: starting key/value Backup of BackupRequest{pkg=&lt;PACKAGE>}
+</pre>
+
+<p>If the <code>backupnow</code> command is not available on your device, you need to run one
+of the following commands:
+<ul>
+  <li>For Auto Backups, run: <code>bmgr fullbackup &lt;PACKAGE></code>
+  <li>For Key/Value Backups, schedule and run your backup with the following
+commands:
+  <pre class="prettyprint">$ bmgr backup &lt;PACKAGE>
+$ bmgr run</pre>
+  <p><code>bmgr backup</code> adds your app to the Backup Manager's queue. <code>bmgr run</code> initiates the
+backup operation, which forces the Backup Manager to perform all backup requests
+that are in its queue.
+  </li></ul>
+
+<h2 id="TestingRestore">Testing restore</h2>
+<p>To manually initiate a restore, run the following command:
+
+<pre class="prettyprint">$ bmgr restore &lt;PACKAGE></pre>
+
+<p>Warning: This action stops your app and wipes its data before performing the
+restore operation.
+
+<p>Then, check logcat to see the output of the restore procedure. For example:
+
+<pre class="prettyprint">V/BackupManagerService: beginRestoreSession: pkg=&lt;PACKAGE> transport=null
+V/RestoreSession: restorePackage pkg=&lt;PACKAGE> token=368abb4465c5c683
+...
+I/BackupManagerService: Restore complete.
+</pre>
+
+<p>You also can test automatic restore for your app by uninstalling and
+reinstalling your app either with <code>adb</code> or through the Google
+Play Store app.
+
+<h2 id="Troubleshooting">Troubleshooting</h2>
+<p><strong>Exceeded Quota</strong>
+
+<p>If you see the the following messages in logcat:
+
+<pre class="prettyprint">I/PFTBT: Transport rejected backup of &lt;PACKAGE>, skipping
+
+--- or ---
+
+I/PFTBT: Transport quota exceeded for package: &lt;PACKAGE>
+</pre>
+
+<p>Your app has exceeded the quota and has been banned from backing up
+data on this device. To lift the ban, either factory reset your device or change
+the backup account.
+
+<p><strong>Full Backup Not Possible</strong>
+
+<p>If you see the the following message in logcat:
+
+<pre class="prettyprint">I/BackupManagerService: Full backup not currently possible -- key/value backup not yet run?
+</pre>
+
+<p>The fullbackup operation failed because no Key/Value Backup operation has yet
+occurred on the device. Trigger a Key/Value Backup with the command <code>bmgr
+run </code>and then try again.
\ No newline at end of file
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index 9cae53c..d7dd038 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -21,6 +21,7 @@
     </li>
     <li><a href="#shape-drawable">Shape Drawable</a></li>
     <li><a href="#nine-patch">Nine-patch</a></li>
+    <li><a href="#vector-drawable">Vector Drawables</a></li>
   </ol>
 
   <h2>See also</h2>
@@ -428,58 +429,66 @@
          of the object it's attached to.
          -->
 
-         <h2 id="nine-patch">Nine-patch</h2>
+<h2 id="nine-patch">Nine-patch</h2>
 
-         <p>A {@link android.graphics.drawable.NinePatchDrawable} graphic is a stretchable bitmap
-image,           which Android
-           will automatically resize to accommodate the contents of the View in which you have
-placed it as the           background.
-           An example use of a NinePatch is the backgrounds used by standard Android buttons &mdash;
-           buttons must stretch to accommodate strings of various lengths. A NinePatch drawable is a
-standard           PNG
-           image that includes an extra 1-pixel-wide border. It must be saved with the extension
-           <code>.9.png</code>,
-           and saved into the <code>res/drawable/</code> directory of your project.
-         </p>
-         <p>
-           The border is used to define the stretchable and static areas of
-           the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide
-           black line(s) in the left and top part of the border (the other border pixels should
-           be fully transparent or white). You can have as many stretchable sections as you want:
-           their relative size stays the same, so the largest sections always remain the largest.
-         </p>
-         <p>
-           You can also define an optional drawable section of the image (effectively,
-           the padding lines) by drawing a line on the right and bottom lines.
-           If a View object sets the NinePatch as its background and then specifies the
-           View's text, it will stretch itself so that all the text fits inside only
-           the area designated by the right and bottom lines (if included). If the
-           padding lines are not included, Android uses the left and top lines to
-           define this drawable area.
-         </p>
-         <p>To clarify the difference between the different lines, the left and top lines define
-           which pixels of the image are allowed to be replicated in order to stretch the image.
-           The bottom and right lines define the relative area within the image that the contents
-           of the View are allowed to lie within.</p>
-         <p>
-           Here is a sample NinePatch file used to define a button:
-         </p>
-         <img src="{@docRoot}images/ninepatch_raw.png" alt="" />
-
-         <p>This NinePatch defines one stretchable area with the left and top lines
-           and the drawable area with the bottom and right lines. In the top image, the dotted grey
-           lines identify the regions of the image that will be replicated in order to stretch the
-image. The           pink
-           rectangle in the bottom image identifies the region in which the contents of the View are
-allowed.
-           If the contents don't fit in this region, then the image will be stretched so that they
-do.
+<p>
+  A {@link android.graphics.drawable.NinePatchDrawable} graphic is a
+  stretchable bitmap image, which Android will automatically resize to
+  accommodate the contents of the View in which you have placed it as the
+  background. An example use of a NinePatch is the backgrounds used by
+  standard Android buttons — buttons must stretch to accommodate strings of
+  various lengths. A NinePatch drawable is a standard PNG image that includes
+  an extra 1-pixel-wide border. It must be saved with the extension
+  <code>.9.png</code>, and saved into the <code>res/drawable/</code> directory
+  of your project.
 </p>
 
-<p>The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool offers
-   an extremely handy way to create your NinePatch images, using a WYSIWYG graphics editor. It
-even raises warnings if the region you've defined for the stretchable area is at risk of
-producing drawing artifacts as a result of the pixel replication.
+<p>
+  The border is used to define the stretchable and static areas of the image.
+  You indicate a stretchable section by drawing one (or more) 1-pixel-wide
+  black line(s) in the left and top part of the border (the other border
+  pixels should be fully transparent or white). You can have as many
+  stretchable sections as you want: their relative size stays the same, so the
+  largest sections always remain the largest.
+</p>
+
+<p>
+  You can also define an optional drawable section of the image (effectively,
+  the padding lines) by drawing a line on the right and bottom lines. If a
+  View object sets the NinePatch as its background and then specifies the
+  View's text, it will stretch itself so that all the text fits inside only
+  the area designated by the right and bottom lines (if included). If the
+  padding lines are not included, Android uses the left and top lines to
+  define this drawable area.
+</p>
+
+<p>
+  To clarify the difference between the different lines, the left and top
+  lines define which pixels of the image are allowed to be replicated in order
+  to stretch the image. The bottom and right lines define the relative area
+  within the image that the contents of the View are allowed to lie within.
+</p>
+
+<p>
+  Here is a sample NinePatch file used to define a button:
+</p>
+<img src="{@docRoot}images/ninepatch_raw.png" alt="">
+<p>
+  This NinePatch defines one stretchable area with the left and top lines and
+  the drawable area with the bottom and right lines. In the top image, the
+  dotted grey lines identify the regions of the image that will be replicated
+  in order to stretch the image. The pink rectangle in the bottom image
+  identifies the region in which the contents of the View are allowed. If the
+  contents don't fit in this region, then the image will be stretched so that
+  they do.
+</p>
+
+<p>
+  The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool
+  offers an extremely handy way to create your NinePatch images, using a
+  WYSIWYG graphics editor. It even raises warnings if the region you've
+  defined for the stretchable area is at risk of producing drawing artifacts
+  as a result of the pixel replication.
 </p>
 
 <h3>Example XML</h3>
@@ -516,3 +525,265 @@
 </p>
 
 <img src="{@docRoot}images/ninepatch_examples.png" alt=""/>
+
+<h2 id="vector-drawable">
+  Vector Drawables
+</h2>
+
+<p>
+  A {@link android.graphics.drawable.VectorDrawable} graphic replaces multiple
+  PNG assets with a single vector graphic. The vector graphic is defined in an
+  XML file as a set of points, lines, and curves along with its associated
+  color information.
+</p>
+
+<p>
+  The major advantage of using a vector graphic is image scalability. Using
+  vector graphics resizes the same file for different screen densities without
+  loss of image quality. This results in smaller APK files and less developer
+  maintenance. You can also use vector images for animation by using multiple
+  XML files instead of multiple images for each display resolution.
+</p>
+
+<p>
+  Let's go through an example to understand the benefits. An image of size 100
+  x 100 dp may render good quality on a smaller display resolution. On larger
+  devices, the app might want to use a 400 x 400 dp version of the image.
+  Normally, developers create multiple versions of an asset to cater to
+  different screen densities. This approach consumes more development efforts,
+  and results in a larger APK, which takes more space on the device.
+</p>
+
+<p>
+  As of Android 5.0 (API level 21), there are two classes that support vector
+  graphics as a drawable resource: {@link
+  android.graphics.drawable.VectorDrawable} and {@link
+  android.graphics.drawable.AnimatedVectorDrawable}. For more information
+  about using the VectorDrawable and the AnimatedVectorDrawable classes, read
+  the <a href="#vector-drawable-class">About VectorDrawable class</a> and
+  <a href="#animated-vector-drawable-class">About AnimatedVectorDrawable
+  class</a> sections.
+</p>
+
+<h3 id="vector-drawable-class">About VectorDrawable class</h3>
+<p>
+  {@link android.graphics.drawable.VectorDrawable} defines a static drawable
+  object. Similar to the SVG format, each vector graphic is defined as a tree
+  hierachy, which is made up of <code>path</code> and <code>group</code> objects.
+  Each <code>path</code> contains the geometry of the object's outline and
+  <code>group</code> contains details for transformation. All paths are drawn
+  in the same order as they appear in the XML file.
+</p>
+
+<img src="{@docRoot}images/guide/topics/graphics/vectorpath.png" alt=""/>
+<p class="img-caption">
+  <strong>Figure 1.</strong> Sample hierarchy of a vector drawable asset
+</p>
+
+
+<p>
+  The <a href="{@docRoot}studio/write/vector-asset-studio.html">Vector Asset
+  Studio</a> tool offers a simple way to add a vector graphic to the project
+  as an XML file.
+</p>
+
+<h4>
+  Example XML
+</h4>
+
+<p>
+  Here is a sample <code>VectorDrawable</code> XML file that renders an image
+  of a battery in the charging mode.
+</p>
+
+<pre>
+&lt;!-- res/drawable/battery_charging.xml --&gt;
+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
+    &lt;!-- intrinsic size of the drawable --&gt;
+    android:height="24dp"
+    android:width="24dp"
+    &lt;!-- size of the virtual canvas --&gt;
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"&gt;
+   &lt;group
+         android:name="rotationGroup"
+         android:pivotX="10.0"
+         android:pivotY="10.0"
+         android:rotation="15.0" &gt;
+      &lt;path
+        android:name="vect"
+        android:fillColor="#FF000000"
+        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z"
+        android:fillAlpha=".3"/&gt;
+      &lt;path
+        android:name="draw"
+        android:fillColor="#FF000000"
+        android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z"/&gt;
+   &lt;/group&gt;
+&lt;/vector&gt;
+</pre>
+
+<p>This XML renders the following image:
+</p>
+
+<img src=
+"{@docRoot}images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png"
+alt=""/>
+
+<h3 id="animated-vector-drawable-class">
+  About AnimatedVectorDrawable class
+</h3>
+
+<p>
+  {@link android.graphics.drawable.AnimatedVectorDrawable
+  AnimatedVectorDrawable} adds animation to the properties of a vector
+  graphic. You can define an animated vector graphic as three separate
+  resource files or as a single XML file defining the entire drawable. Let's
+  look at both the approaches for better understanding: <a href=
+  "#multiple-files">Multiple XML files</a> and <a href="#single-file">Single
+  XML file</a>.
+</p>
+
+<h4 id="multiple-files">
+  Multiple XML files
+</h4>
+<p>
+  By using this approach, you can define three separate XML files:
+
+<ul>
+  <li>A {@link android.graphics.drawable.VectorDrawable} XML file.
+  </li>
+
+  <li>
+  An {@link android.graphics.drawable.AnimatedVectorDrawable} XML file that
+defines the target {@link android.graphics.drawable.VectorDrawable}, the
+target paths and groups to animate, the properties, and the animations defined
+as {@link android.animation.ObjectAnimator ObjectAnimator} objects or {@link
+android.animation.AnimatorSet AnimatorSet} objects.
+  </li>
+
+  <li>An animator XML file.
+  </li>
+</ul>
+</p>
+
+<h5>
+  Example of multiple XML files
+</h5>
+<p>
+  The following XML files demonstrate the animation of a vector graphic.
+
+<ul>
+  <li>VectorDrawable's XML file: <code>vd.xml</code>
+  </li>
+
+  <li style="list-style: none; display: inline">
+<pre>
+&lt;vector xmlns:android="http://schemas.android.com/apk/res/android"
+   android:height="64dp"
+   android:width="64dp"
+   android:viewportHeight="600"
+   android:viewportWidth="600" &gt;
+   &lt;group
+      android:name="rotationGroup"
+      android:pivotX="300.0"
+      android:pivotY="300.0"
+      android:rotation="45.0" &gt;
+      &lt;path
+         android:name="vectorPath"
+         android:fillColor="#000000"
+         android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /&gt;
+   &lt;/group&gt;
+&lt;/vector&gt;
+</pre>
+  </li>
+
+  <li>AnimatedVectorDrawable's XML file: <code>avd.xml</code>
+  </li>
+
+  <li style="list-style: none; display: inline">
+<pre>
+&lt;animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+   android:drawable="@drawable/vd" &gt;
+     &lt;target
+         android:name="rotationGroup"
+         android:animation="@anim/rotation" /&gt;
+     &lt;target
+         android:name="vectorPath"
+         android:animation="@anim/path_morph" /&gt;
+&lt;/animated-vector&gt;
+</pre>
+  </li>
+
+  <li>Animator XML files that are used in the AnimatedVectorDrawable's XML
+  file: <code>rotation.xml</code> and <code>path_morph.xml</code>
+  </li>
+
+  <li style="list-style: none; display: inline">
+<pre>
+&lt;objectAnimator
+   android:duration="6000"
+   android:propertyName="rotation"
+   android:valueFrom="0"
+   android:valueTo="360" /&gt;
+</pre>
+
+<pre>
+&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+   &lt;objectAnimator
+      android:duration="3000"
+      android:propertyName="pathData"
+      android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
+      android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
+      android:valueType="pathType"/&gt;
+&lt;/set&gt;
+</pre>
+  </li>
+</ul>
+</p>
+<h4 id="single-file">
+  Single XML file
+</h4>
+
+<p>
+  By using this approach, you can merge the related XML files into a single
+  XML file through the XML Bundle Format. At the time of building the app, the
+  <code>aapt</code> tag creates separate resources and references them in the
+  animated vector. This approach requires Build Tools 24 or higher, and the
+  output is backward compatible.
+</p>
+
+<h5>
+  Example of a single XML file
+</h5>
+<pre>
+&lt;animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"&gt;
+    &lt;aapt:attr name="android:drawable"&gt;
+        &lt;vector
+            android:width="24dp"
+            android:height="24dp"
+            android:viewportWidth="24"
+            android:viewportHeight="24"&gt;
+            &lt;path
+                android:name="root"
+                android:strokeWidth="2"
+                android:strokeLineCap="square"
+                android:strokeColor="?android:colorControlNormal"
+                android:pathData="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" /&gt;
+        &lt;/vector&gt;
+    &lt;/aapt:attr&gt;
+    &lt;target android:name="root"&gt;
+        &lt;aapt:attr name="android:animation"&gt;
+            &lt;objectAnimator
+                android:propertyName="pathData"
+                android:valueFrom="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7"
+                android:valueTo="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4"
+                android:duration="300"
+                android:interpolator="@android:interpolator/fast_out_slow_in"
+                android:valueType="pathType" /&gt;
+        &lt;/aapt:attr&gt;
+    &lt;/target&gt;
+&lt;/animated-vector&gt;
+</pre>
\ No newline at end of file
diff --git a/docs/html/guide/topics/location/strategies.jd b/docs/html/guide/topics/location/strategies.jd
index 2dfed2c..548ed9c 100755
--- a/docs/html/guide/topics/location/strategies.jd
+++ b/docs/html/guide/topics/location/strategies.jd
@@ -133,36 +133,69 @@
 both to zero requests location notifications as frequently as possible. The last parameter is your
 {@link android.location.LocationListener}, which receives callbacks for location updates.</p>
 
-<p>To request location updates from the GPS provider,
-substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
-location updates from both the GPS and the Network Location Provider by calling {@link
-android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
-for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
+<p>To request location updates from the GPS provider, use {@link
+android.location.LocationManager#GPS_PROVIDER} instead of {@link
+android.location.LocationManager#NETWORK_PROVIDER}. You can also request
+location updates from both the GPS and the Network Location Provider by calling
+{@link android.location.LocationManager#requestLocationUpdates
+requestLocationUpdates()} twice&mdash;once for {@link
+android.location.LocationManager#NETWORK_PROVIDER} and once for {@link
+android.location.LocationManager#GPS_PROVIDER}.</p>
 
 
 <h3 id="Permission">Requesting User Permissions</h3>
 
-<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
-<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
-ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
-manifest file. For example:</p>
+<p>
+  In order to receive location updates from {@link
+  android.location.LocationManager#NETWORK_PROVIDER} or {@link
+  android.location.LocationManager#GPS_PROVIDER}, you must request the user's
+  permission by declaring either the {@code ACCESS_COARSE_LOCATION} or {@code
+  ACCESS_FINE_LOCATION} permission, respectively, in your Android manifest file.
+  Without these permissions, your application will fail at runtime when
+  requesting location updates.
+</p>
 
+<p>
+  If you are using both {@link
+  android.location.LocationManager#NETWORK_PROVIDER} and {@link
+  android.location.LocationManager#GPS_PROVIDER}, then you need to request only
+  the {@code ACCESS_FINE_LOCATION} permission, because it includes permission
+  for both providers. Permission for {@code ACCESS_COARSE_LOCATION} allows
+  access only to {@link android.location.LocationManager#NETWORK_PROVIDER}.
+</p>
+
+<p id="location-feature-caution" class="caution">
+  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
+  higher, you <em>must</em> declare that your app uses the
+  <code>android.hardware.location.network</code> or
+  <code>android.hardware.location.gps</code> hardware feature in the manifest
+  file, depending on whether your app receives location updates from {@link
+  android.location.LocationManager#NETWORK_PROVIDER} or from {@link
+  android.location.LocationManager#GPS_PROVIDER}. If your app receives location
+  information from either of these location provider sources, you need to
+  declare that the app uses these hardware features in your app manifest.
+  On devices running verions prior to Android 5.0 (API 21), requesting the
+  {@code ACCESS_FINE_LOCATION} or {@code ACCESS_COARSE_LOCATION} permission
+  includes an implied request for location hardware features. However,
+  requesting those permissions <em>does not</em> automatically request location
+  hardware features on Android 5.0 (API level 21) and higher.
+</p>
+
+<p>
+   The following code sample demonstrates how to declare the permission and
+   hardware feature in the manifest file of an app that reads data from the
+   device's GPS:
+</p>
 <pre>
 &lt;manifest ... &gt;
     &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
     ...
+    &lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
+    &lt;uses-feature android:name="android.hardware.location.gps" /&gt;
+    ...
 &lt;/manifest&gt;
 </pre>
 
-<p>Without these permissions, your application will fail at runtime when requesting
-location updates.</p>
-
-<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
-<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
-permission, because it includes permission for both providers. (Permission for {@code
-ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
-
-
 <h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
 
   <p>Location-based applications are now commonplace, but due to the less than optimal
@@ -404,9 +437,10 @@
 the Android emulator. There are three different ways to send your application mock location
 data: using Android Studio, DDMS, or the "geo" command in the emulator console.</p>
 
-<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
-data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
-data to work.</p>
+<p class="note"><strong>Note:</strong> Providing mock location data is injected
+as GPS location data, so you must request location updates from {@link
+android.location.LocationManager#GPS_PROVIDER} in order for mock location data
+to work.</p>
 
 <h3 id="MockAVD">Using Android Studio</h3>
 
diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
index 945b116..2d1bdfe 100644
--- a/docs/html/guide/topics/manifest/meta-data-element.jd
+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
@@ -60,7 +60,7 @@
 <dt><a name="rsrc"></a>{@code android:resource}</dt>
 <dd>A reference to a resource.  The ID of the resource is the value assigned
 to the item.  The ID can be retrieved from the meta-data Bundle by the
-{@link android.os.BaseBundle#getInt Bundle.getInt()} method.</dd>
+{@link android.os.Bundle#getInt Bundle.getInt()} method.</dd>
 
 <dt><a name="val"></a>{@code android:value}</dt>
 <dd>The value assigned to the item.  The data types that can be assigned as values and the Bundle methods that  components use to retrieve those values are listed in the following table:
@@ -72,17 +72,17 @@
 </tr><tr>
   <td>String value, using double backslashes ({@code \\}) to escape characters
       &mdash; such as "{@code \\n}" and "{@code \\uxxxxx}" for a Unicode character.</td>
-  <td>{@link android.os.BaseBundle#getString(String) getString()}</td>
+  <td>{@link android.os.Bundle#getString(String) getString()}</td>
 </tr><tr>
   <td>Integer value, such as "{@code 100}"</td>
-  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
+  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
 </tr><tr>
   <td>Boolean value, either "{@code true}" or "{@code false}"</td>
-  <td>{@link android.os.BaseBundle#getBoolean(String) getBoolean()}</td>
+  <td>{@link android.os.Bundle#getBoolean(String) getBoolean()}</td>
 </tr><tr>
   <td>Color value, in the form "{@code #rgb}", "{@code #argb}",
       "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
-  <td>{@link android.os.BaseBundle#getInt(String) getInt()}</td>
+  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
 </tr><tr>
   <td>Float value, such as "{@code 1.23}"</td>
   <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index 1947849..0e729c3 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -215,17 +215,15 @@
 </p></dd>
 
 <dt><a name="multi"></a>{@code android:multiprocess}</dt>
-<dd>Whether or not an instance of the content provider can be created in
-every client process &mdash; "{@code true}" if instances can run in multiple
-processes, and "{@code false}" if not.  The default value is "{@code false}".
+<dd>If the app runs in multiple processes, this attribute determines whether
+multiple instances of the content provder are created. If <code>true</code>,
+each of the app's processes has its own content provider object. If
+<code>false</code>, the app's processes share only one content provider object.
+The default value is <code>false</code>.
 
-<p>
-Normally, a content provider is instantiated in the process of the
-application that defined it.  However, if this flag is set to "{@code true}",
-the system can create an instance in every process where there's a client
-that wants to interact with it, thus avoiding the overhead of interprocess
-communication.
-</p></dd>
+<p>Setting this flag to <code>true</code> may improve performance by reducing
+the overhead of interprocess communication, but it also increases the memory
+footprint of each process.</p></dd>
 
 <dt><a name="nm"></a>{@code android:name}</dt>
 <dd>The name of the class that implements the content provider, a subclass of
diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
index 800ee8a..c866047 100644
--- a/docs/html/guide/topics/manifest/receiver-element.jd
+++ b/docs/html/guide/topics/manifest/receiver-element.jd
@@ -33,8 +33,18 @@
 declare it in the manifest file with this element.  The other is to create
 the receiver dynamically in code and register it with the <code>{@link
 android.content.Context#registerReceiver Context.registerReceiver()}</code>
-method.  See the {@link android.content.BroadcastReceiver} class description
-for more on dynamically created receivers.
+method. For more information about how to dynamically create receivers, see the
+{@link android.content.BroadcastReceiver} class description.
+</p>
+
+<p class="warning">
+    <strong>Warning:</strong> Limit how many broadcast
+    receivers you set in your app. Having too many broadcast receivers can
+    affect your app's performance and the battery life of users' devices.
+    For more information about APIs you can use instead of the
+    {@link android.content.BroadcastReceiver} class for scheduling background
+    work, see
+    <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
 </p></dd>
 
 <dt>attributes:</dt>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 9b32244..843fe1c 100755
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -512,10 +512,11 @@
 
 <li>Next, locate the <code>aapt</code> tool, if it is not already in your PATH.
 If you are using SDK Tools r8 or higher, you can find <code>aapt</code> in the
-<code>&lt;<em>SDK</em>&gt;/platform-tools/</code> directory.
+<code>&lt;<em>SDK</em>&gt;/build-tools/&lt;<em>tools version number</em>&gt;</code>
+directory.
 <p class="note"><strong>Note:</strong> You must use the version of
-<code>aapt</code> that is provided for the latest Platform-Tools component available. If
-you do not have the latest Platform-Tools component, download it using the <a
+<code>aapt</code> that is provided for the latest Build-Tools component available. If
+you do not have the latest Build-Tools component, download it using the <a
 href="{@docRoot}studio/intro/update.html">Android SDK Manager</a>.
 </p></li>
 <li>Run <code>aapt</code> using this syntax: </li>
@@ -1666,6 +1667,15 @@
 
 <pre>&lt;uses-feature android:name="android.hardware.camera" android:required="false" /&gt;</pre>
 
+<p class="caution">
+  <strong>Caution:</strong> If your app targets Android 5.0 (API level 21) or
+  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
+  <code>ACCESS_FINE_LOCATION</code> permission in order to receive location
+  updates from the network or a GPS, respectively, you must also explicitly
+  declare that your app uses the <code>android.hardware.location.network</code>
+  or <code>android.hardware.location.gps</code> hardware features.
+</p>
+
 <p class="table-caption" id="permissions-features">
   <strong>Table 2. </strong>Device permissions that imply device hardware use.
 </p>
@@ -1717,14 +1727,29 @@
 </tr>
 <tr>
   <td><code>ACCESS_COARSE_LOCATION</code></td>
-  <td><code>android.hardware.location.network</code> <em>and</em>
-<br><code>android.hardware.location</code></td>
+  <td>
+    <p>
+      <code>android.hardware.location</code>
+    </p>
+    <p>
+      <code>android.hardware.location.network</code>
+      (Only when target API level is 20 or lower.)
+    </p>
+  </td>
 <!--  <td></td> -->
 </tr>
 <tr>
   <td><code>ACCESS_FINE_LOCATION</code></td>
-  <td><code>android.hardware.location.gps</code> <em>and</em>
-<br><code>android.hardware.location</code></td>
+  <td>
+    <p>
+      <code>android.hardware.location</code>
+    </p>
+    <p>
+      <code>android.hardware.location.gps</code>
+      (Only when target API level is 20 or lower.)
+    </p>
+  </td>
+
 <!--  <td></td> -->
 </tr>
 
diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
index c806c88..383b6c1 100644
--- a/docs/html/guide/topics/media/camera.jd
+++ b/docs/html/guide/topics/media/camera.jd
@@ -9,12 +9,7 @@
     <li><a href="#considerations">Considerations</a></li>
     <li><a href="#basics">The Basics</a>
     <li><a href="#manifest">Manifest Declarations</a></li>
-    <li><a href="#intents">Using Existing Camera Apps</a>
-      <ol>
-        <li><a href="#intent-image">Image capture intent</a></li>
-        <li><a href="#intent-video">Video capture intent</a></li>
-        <li><a href="#intent-receive">Receiving camera intent result</a></li>
-      </ol>
+    <li><a href="#camera-apps">Using Existing Camera Apps</a>
     <li><a href="#custom-camera">Building a Camera App</a>
       <ol>
         <li><a href="#detect-camera">Detecting camera hardware</a></li>
@@ -72,7 +67,7 @@
   <li><strong>Quick Picture or Customized Camera</strong> - How will your application use the
 camera? Are you just interested in snapping a quick picture or video clip, or will your application
 provide a new way to use cameras? For a getting a quick snap or clip, consider
-<a href="#intents">Using Existing Camera Apps</a>. For developing a customized camera feature, check
+<a href="#camera-apps">Using Existing Camera Apps</a>. For developing a customized camera feature, check
 out the <a href="#custom-camera">Building a Camera App</a> section.</li>
 
   <li><strong>Storage</strong> - Are the images or videos your application generates intended to be
@@ -122,8 +117,9 @@
 <pre>
 &lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; /&gt;
 </pre>
-  <p class="note"><strong>Note:</strong> If you are using the camera <a href="#intents">via an
-intent</a>, your application does not need to request this permission.</p>
+  <p class="note"><strong>Note:</strong> If you are using the camera <a href="#camera-apps">by
+invoking an existing camera app</a>,
+your application does not need to request this permission.</p>
   </li>
   <li><strong>Camera Features</strong> - Your application must also declare use of camera features,
 for example:
@@ -158,10 +154,16 @@
 &lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
 </pre>
   </li>
-  <li><strong>Location Permission</strong> - If your application tags images with GPS location
-information, you must request location permission:
+  <li>
+    <p><strong>Location Permission</strong> - If your application tags images
+    with GPS location information, you must request the {@code ACCESS_FINE_LOCATION}
+    permission. Note that, if your app targets Android 5.0 (API level 21) or
+    higher, you also need to declare that your app uses the device's GPS:</p>
 <pre>
 &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
+...
+&lt;!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&gt;
+&lt;uses-feature android:name="android.hardware.location.gps" /&gt;
 </pre>
 <p>For more information about getting user location, see
 <a href="{@docRoot}guide/topics/location/strategies.html">Location Strategies</a>.</p>
@@ -169,193 +171,17 @@
 </ul>
 
 
-<h2 id="intents">Using Existing Camera Apps</h2>
+<h2 id="camera-apps">Using Existing Camera Apps</h2>
 <p>A quick way to enable taking pictures or videos in your application without a lot of extra code
-is to use an {@link android.content.Intent} to invoke an existing Android camera application. A
-camera intent makes a request to capture a picture or video clip through an existing camera app and
-then returns control back to your application. This section shows you how to capture an image or
-video using this technique.</p>
-
-<p>The procedure for invoking a camera intent follows these general steps:</p>
-
-<ol>
-  <li><strong>Compose a Camera Intent</strong> - Create an {@link android.content.Intent} that
-requests an image or video, using one of these intent types:
-    <ul>
-      <li>{@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE MediaStore.ACTION_IMAGE_CAPTURE} -
-Intent action type for requesting an image from an existing camera application.</li>
-      <li>{@link android.provider.MediaStore#ACTION_VIDEO_CAPTURE MediaStore.ACTION_VIDEO_CAPTURE} -
-Intent action type for requesting a video from an existing camera application. </li>
-    </ul>
-  </li>
-  <li><strong>Start the Camera Intent</strong> - Use the {@link
-android.app.Activity#startActivityForResult(android.content.Intent, int) startActivityForResult()}
-method to execute the camera intent. After you start the intent, the Camera application user
-interface appears on the device screen and the user can take a picture or video.</li>
-  <li><strong>Receive the Intent Result</strong> - Set up an {@link
-android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()} method
-in your application to receive the callback and data from the camera intent. When the user
-finishes taking a picture or video (or cancels the operation), the system calls this method.</li>
-</ol>
-
-
-<h3 id="intent-image">Image capture intent</h3>
-<p>Capturing images using a camera intent is quick way to enable your application to take pictures
-with minimal coding. An image capture intent can include the following extra information:</p>
-
-<ul>
-  <li>{@link android.provider.MediaStore#EXTRA_OUTPUT MediaStore.EXTRA_OUTPUT} - This setting
-requires a {@link android.net.Uri} object specifying a path and file name where you'd like to
-save the picture. This setting is optional but strongly recommended. If you do not specify this
-value, the camera application saves the requested picture in the default location with a default
-name, specified in the returned intent's {@link android.content.Intent#getData() Intent.getData()}
-field.</li>
-</ul>
-
-<p>The following example demonstrates how to construct a image capture intent and execute it.
-The {@code getOutputMediaFileUri()} method in this example refers to the sample code shown in <a
-href= "#saving-media">Saving Media Files</a>.</p>
-
-<pre>
-private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
-private Uri fileUri;
-
-&#64;Override
-public void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.main);
-
-    // create Intent to take a picture and return control to the calling application
-    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-
-    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
-    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
-
-    // start the image capture Intent
-    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
-}
-</pre>
-
-<p>When the {@link android.app.Activity#startActivityForResult(android.content.Intent, int)
-startActivityForResult()} method is executed, users see a camera application interface.
-After the user finishes taking a picture (or cancels the operation), the user interface returns to
-your application, and you must intercept the {@link
-android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()}
-method to receive the result of the intent and continue your application execution. For information
-on how to receive the completed intent, see <a href="#intent-receive">Receiving camera intent
-result</a>.</p>
-
-
-<h3 id="intent-video">Video capture intent</h3>
-<p>Capturing video using a camera intent is a quick way to enable your application to take videos
-with minimal coding. A video capture intent can include the following extra information:</p>
-
-<ul>
-  <li>{@link android.provider.MediaStore#EXTRA_OUTPUT MediaStore.EXTRA_OUTPUT} - This setting
-requires a {@link android.net.Uri} specifying a path and file name where you'd like to save the
-video. This setting is optional but strongly recommended. If you do not specify this value, the
-Camera application saves the requested video in the default location with a default name, specified
-in the returned intent's {@link android.content.Intent#getData() Intent.getData()} field.</li>
-  <li>{@link android.provider.MediaStore#EXTRA_VIDEO_QUALITY MediaStore.EXTRA_VIDEO_QUALITY} -
-This value can be 0 for lowest quality and smallest file size or 1 for highest quality and
-larger file size.</li>
-  <li>{@link android.provider.MediaStore#EXTRA_DURATION_LIMIT MediaStore.EXTRA_DURATION_LIMIT} -
-Set this value to limit the length, in seconds, of the video being captured.</li>
-  <li>{@link android.provider.MediaStore#EXTRA_SIZE_LIMIT MediaStore.EXTRA_SIZE_LIMIT} -
-Set this value to limit the file size, in bytes, of the video being captured.
-</li>
-</ul>
-
-<p>The following example demonstrates how to construct a video capture intent and execute it.
-The {@code getOutputMediaFileUri()} method in this example refers to the sample code shown in <a
-href= "#saving-media">Saving Media Files</a>.</p>
-
-<pre>
-private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
-private Uri fileUri;
-
-&#64;Override
-public void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.main);
-
-    //create new Intent
-    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
-
-    fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);  // create a file to save the video
-    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);  // set the image file name
-
-    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
-
-    // start the Video Capture Intent
-    startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
-}
-</pre>
-
-<p>When the {@link
-android.app.Activity#startActivityForResult(android.content.Intent, int)
-startActivityForResult()} method is executed, users see a modified camera application interface.
-After the user finishes taking a video (or cancels the operation), the user interface
-returns to your application, and you must intercept the {@link
-android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()}
-method to receive the result of the intent and continue your application execution. For information
-on how to receive the completed intent, see the next section.</p>
-
-<h3 id="intent-receive">Receiving camera intent result</h3>
-<p>Once you have constructed and executed an image or video camera intent, your application must be
-configured to receive the result of the intent. This section shows you how to intercept the callback
-from a camera intent so your application can do further processing of the captured image or
-video.</p>
-
-<p>In order to receive the result of an intent, you must override the {@link
-android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()} in the
-activity that started the intent. The following example demonstrates how to override {@link
-android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()} to
-capture the result of the <a href="#intent-image">image camera intent</a> or <a
-href="#intent-video">video camera intent</a> examples shown in the previous sections.</p>
-
-<pre>
-private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
-private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200;
-
-&#64;Override
-protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-    if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
-        if (resultCode == RESULT_OK) {
-            // Image captured and saved to fileUri specified in the Intent
-            Toast.makeText(this, "Image saved to:\n" +
-                     data.getData(), Toast.LENGTH_LONG).show();
-        } else if (resultCode == RESULT_CANCELED) {
-            // User cancelled the image capture
-        } else {
-            // Image capture failed, advise user
-        }
-    }
-
-    if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
-        if (resultCode == RESULT_OK) {
-            // Video captured and saved to fileUri specified in the Intent
-            Toast.makeText(this, "Video saved to:\n" +
-                     data.getData(), Toast.LENGTH_LONG).show();
-        } else if (resultCode == RESULT_CANCELED) {
-            // User cancelled the video capture
-        } else {
-            // Video capture failed, advise user
-        }
-    }
-}
-</pre>
-
-<p>Once your activity receives a successful result, the captured image or video is available in the
-specified location for your application to access.</p>
-
-
+is to use an {@link android.content.Intent} to invoke an existing Android camera application.
+The details are described in the training lessons
+<a href="{@docRoot}training/camera/photobasics.html">Taking Photos Simply</a> and
+<a href="{@docRoot}training/camera/videobasics.html">Recording Videos Simply</a>.</p>
 
 <h2 id="custom-camera">Building a Camera App</h2>
 <p>Some developers may require a camera user interface that is customized to the look of their
-application or provides special features. Creating a customized camera activity requires more
-code than <a href="#intents">using an intent</a>, but it can provide a more compelling experience
-for your users.</p>
+application or provides special features. Writing your own picture-taking code
+can provide a more compelling experience for your users.</p>
 
 <p><strong> Note: The following guide is for the older, deprecated {@link android.hardware.Camera}
 API. For new or advanced camera applications, the newer {@link android.hardware.camera2} API is
@@ -419,7 +245,7 @@
 <h3 id="access-camera">Accessing cameras</h3>
 <p>If you have determined that the device on which your application is running has a camera, you
 must request to access it by getting an instance of {@link android.hardware.Camera} (unless you
-are using an <a href="#intents">intent to access the camera</a>). </p>
+are using an <a href="camera-apps">intent to access the camera</a>). </p>
 
 <p>To access the primary camera, use the {@link android.hardware.Camera#open() Camera.open()} method
 and be sure to catch any exceptions, as shown in the code below:</p>
diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
index 01a1bfc..485f3c1 100644
--- a/docs/html/guide/topics/providers/calendar-provider.jd
+++ b/docs/html/guide/topics/providers/calendar-provider.jd
@@ -278,9 +278,9 @@
 
 <div class="sidebox-wrapper"> <div class="sidebox"> <h3>Why must you include
 ACCOUNT_TYPE?</h3> <p>If you query on a {@link
-android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME
+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
 Calendars.ACCOUNT_NAME}, you must also include
-{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
 in the selection. That is because a given account is
 only considered unique given both its <code>ACCOUNT_NAME</code> and its
 <code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> is the string corresponding to the
diff --git a/docs/html/guide/topics/providers/contacts-provider.jd b/docs/html/guide/topics/providers/contacts-provider.jd
index ac855aa..2b14558 100644
--- a/docs/html/guide/topics/providers/contacts-provider.jd
+++ b/docs/html/guide/topics/providers/contacts-provider.jd
@@ -329,13 +329,13 @@
 </p>
 <dl>
     <dt>
-        {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}
+        {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID}
     </dt>
     <dd>
         The value of the <code>_ID</code> column of the raw contact for this data.
     </dd>
     <dt>
-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE}
+        {@link android.provider.ContactsContract.Data#MIMETYPE}
     </dt>
     <dd>
         The type of data stored in this row, expressed as a custom MIME type. The Contacts Provider
@@ -2351,7 +2351,7 @@
     {@link android.provider.ContactsContract.Data} table, selecting on the raw contact's
     {@link android.provider.BaseColumns#_ID}, the
     {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE
-    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}
+    Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.Data#IS_PRIMARY}
     column to find the raw contact's primary photo row.
 </p>
 <p>
diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
index ec6909c..59dc108 100755
--- a/docs/html/guide/topics/providers/content-provider-creating.jd
+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
@@ -460,7 +460,7 @@
                  * present. Get the last path segment from the URI; this is the _ID value.
                  * Then, append the value to the WHERE clause for the query
                  */
-                selection = selection + "_ID = " uri.getLastPathSegment();
+                selection = selection + "_ID = " + uri.getLastPathSegment();
                 break;
 
             default:
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/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index aae0cba..4587ae4 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -1270,7 +1270,7 @@
 progressively reveal the image:</p>
 <pre>
 ImageView imageview = (ImageView) findViewById(R.id.image);
-ClipDrawable drawable = (ClipDrawable) imageview.getDrawable();
+ClipDrawable drawable = (ClipDrawable) imageview.getBackground();
 drawable.setLevel(drawable.getLevel() + 1000);
 </pre>
 
diff --git a/docs/html/guide/topics/resources/multilingual-support.jd b/docs/html/guide/topics/resources/multilingual-support.jd
index 8d8484b..28699fe 100644
--- a/docs/html/guide/topics/resources/multilingual-support.jd
+++ b/docs/html/guide/topics/resources/multilingual-support.jd
@@ -88,15 +88,17 @@
 
 <h2 id="postN">Improvements to Resource-Resolution Strategy</h2>
 <p>Android 7.0 (API level 24) brings more robust resource resolution, and
- finds better fallbacks automatically. However, to speed up resolution and
- improve
+ finds better fallbacks automatically.
+ However, to speed up resolution and improve
  maintainability, you should store resources in the most common parent dialect.
- For example, if you were storing Spanish resources in the {@code es-US}
- directory
- before, move them into the {@code es-419} directory, which contains Latin
- American Spanish.
- Similarly, if you have resource strings in a folder named {@code en-GB}, rename
- the folder to {@code en-001} (international English), because the most common
+ For example, if you were storing Spanish resources
+ in the {@code values-es-rUS} directory
+ before, move them into the {@code values-b+es+419} directory,
+ which contains Latin American Spanish.
+ Similarly, if you have resource strings in a
+ directory named {@code values-en-rGB}, rename
+ the directory to {@code values-b+en+001} (International
+ English), because the most common
  parent for <code>en-GB</code> strings is {@code en-001}.
  The following examples explain why these practices improve performance and
 reliability of resource resolution.</p>
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index 8278ab1..4d6b400 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -699,7 +699,7 @@
     inflater.inflate(R.menu.options_menu, menu);
 
     // Get the SearchView and set the searchable configuration
-    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService(java.lang.String) getSystemService()}(Context.SEARCH_SERVICE);
+    SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
     SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
     // Assumes current activity is the searchable activity
     searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
index c415762..ab8c792 100644
--- a/docs/html/guide/topics/ui/accessibility/apps.jd
+++ b/docs/html/guide/topics/ui/accessibility/apps.jd
@@ -298,7 +298,7 @@
 dispatchPopulateAccessibilityEvent()} method for each child of this view. In order to support
 accessibility services on revisions of Android <em>prior</em> to 4.0 (API Level 14) you
 <em>must</em> override this method and populate {@link
-android.view.accessibility.AccessibilityRecord#getText} with descriptive text for your custom
+android.view.accessibility.AccessibilityEvent#getText} with descriptive text for your custom
 view, which is spoken by accessibility services, such as TalkBack.</dd>
 
   <dt>{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()}</dt>
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index d08022e..dbc69ef 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -79,22 +79,15 @@
 as shown in the following sample:</p>
 
 <pre>
-&lt;manifest&gt;
-  ...
-  &lt;uses-permission ... /&gt;
-  ...
   &lt;application&gt;
-    ...
     &lt;service android:name=&quot;.MyAccessibilityService&quot;
-        android:label=&quot;@string/accessibility_service_label&quot;
-        android:permission=&quot;android.permission.BIND_ACCESSIBILITY_SERVICE&quot&gt;
+        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+        android:label=&quot;@string/accessibility_service_label&quot;&gt;
       &lt;intent-filter&gt;
         &lt;action android:name=&quot;android.accessibilityservice.AccessibilityService&quot; /&gt;
       &lt;/intent-filter&gt;
     &lt;/service&gt;
-    &lt;uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /&gt;
   &lt;/application&gt;
-&lt;/manifest&gt;
 </pre>
 
 <p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
@@ -205,7 +198,7 @@
 while it is running ({@link android.accessibilityservice.AccessibilityService#onAccessibilityEvent
 onAccessibilityEvent()},
 {@link android.accessibilityservice.AccessibilityService#onInterrupt onInterrupt()}) to when it is
-shut down ({@link android.app.Service#onUnbind onUnbind()}).</p>
+shut down ({@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()}).</p>
 
 <ul>
   <li>{@link android.accessibilityservice.AccessibilityService#onServiceConnected
@@ -231,7 +224,7 @@
 providing, usually in response to a user action such as moving focus to a different control. This
 method may be called many times over the lifecycle of your service.</li>
 
-  <li>{@link android.app.Service#onUnbind onUnbind()} - (optional)
+  <li>{@link android.accessibilityservice.AccessibilityService#onUnbind onUnbind()} - (optional)
 This method is called when the system is about to shutdown the accessibility service. Use this
 method to do any one-time shutdown procedures, including de-allocating user feedback system
 services, such as the audio manager or device vibrator.</li>
@@ -283,7 +276,7 @@
 to the {@link android.view.accessibility.AccessibilityEvent} passed to you by the system. This level
 of detail provides more context for the event that triggered your accessibility service.</li>
 
-  <li>{@link android.view.accessibility.AccessibilityRecord#getSource
+  <li>{@link android.view.accessibility.AccessibilityEvent#getSource
 AccessibilityEvent.getSource()} - This method returns an {@link
 android.view.accessibility.AccessibilityNodeInfo} object. This object allows you to request view
 layout hierarchy (parents and children) of the component that originated the accessibility event.
@@ -296,10 +289,10 @@
 level of access through the accessibility <a href="#service-config">service configuration XML</a>
 file, by including the {@code canRetrieveWindowContent} attribute and setting it to {@code true}. If
 you do not include this setting in your service configuration xml file, calls to {@link
-android.view.accessibility.AccessibilityRecord#getSource getSource()} fail.</p>
+android.view.accessibility.AccessibilityEvent#getSource getSource()} fail.</p>
 
 <p class="note"><strong>Note:</strong> In Android 4.1 (API Level 16) and higher, the
-{@link android.view.accessibility.AccessibilityRecord#getSource getSource()} method,
+{@link android.view.accessibility.AccessibilityEvent#getSource getSource()} method,
 as well as {@link android.view.accessibility.AccessibilityNodeInfo#getChild
 AccessibilityNodeInfo.getChild()} and
 {@link android.view.accessibility.AccessibilityNodeInfo#getParent getParent()}, return only
@@ -372,7 +365,7 @@
   <a href="#service-config">service configuration file</a>. When events are received by your
   service, it can then retrieve the
   {@link android.view.accessibility.AccessibilityNodeInfo} object from the event using
-  {@link android.view.accessibility.AccessibilityRecord#getSource getSource()}.
+  {@link android.view.accessibility.AccessibilityEvent#getSource getSource()}.
   With the {@link android.view.accessibility.AccessibilityNodeInfo} object, your service can then
   explore the view hierarchy to determine what action to take and then act for the user using
   {@link android.view.accessibility.AccessibilityNodeInfo#performAction performAction()}.</p>
diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
index e0549ec..181647c 100644
--- a/docs/html/guide/topics/ui/controls/togglebutton.jd
+++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
@@ -14,6 +14,7 @@
   <ol>
     <li>{@link android.widget.ToggleButton}</li>
     <li>{@link android.widget.Switch}</li>
+    <li>{@link android.support.v7.widget.SwitchCompat}</li>
     <li>{@link android.widget.CompoundButton}</li>
   </ol>
 </div>
@@ -21,9 +22,12 @@
 
 <p>A toggle button allows the user to change a setting between two states.</p>
 
-<p>You can add a basic toggle button to your layout with the {@link android.widget.ToggleButton}
-object. Android 4.0 (API level 14) introduces another kind of toggle button called a switch that
-provides a slider control, which you can add with a {@link android.widget.Switch} object.</p>
+<p>You can add a basic toggle button to your layout with the
+{@link android.widget.ToggleButton} object. Android 4.0 (API level 14)
+introduces another kind of toggle button called a switch that provides a slider
+control, which you can add with a {@link android.widget.Switch} object.
+{@link android.support.v7.widget.SwitchCompat} is a version of the Switch
+widget which runs on devices back to API 7.</p>
 
 <p>
   If you need to change a button's state yourself, you can use the {@link
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index ecdcfdc..bf0db57 100755
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -423,7 +423,7 @@
   <li>The string array</li>
 </ul>
 <p>Then simply call
-{@link android.widget.AdapterView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
+{@link android.widget.ListView#setAdapter setAdapter()} on your {@link android.widget.ListView}:</p>
 <pre>
 ListView listView = (ListView) findViewById(R.id.listview);
 listView.setAdapter(adapter);
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 52cd1a0..7ab4ca5 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -643,7 +643,7 @@
 or other {@link android.app.Dialog} objects to build the dialog in this case. If
 you want the {@link android.support.v4.app.DialogFragment} to be
 embeddable, you must define the dialog's UI in a layout, then load the layout in the
-{@link android.support.v4.app.Fragment#onCreateView
+{@link android.support.v4.app.DialogFragment#onCreateView
 onCreateView()} callback.</p>
 
 <p>Here's an example {@link android.support.v4.app.DialogFragment} that can appear as either a
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index 8871c87..d6e07a5 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -152,7 +152,7 @@
     drag event listeners or callback methods of each View in the layout. The listeners or callback
     methods can use the metadata to decide if they want to accept the data when it is dropped.
     If the user drops the data over a View object, and that View object's listener or callback
-    method has previously told the system that it wants to accept the drop, then the system sends
+    method has previously told the system that it wants to accept the data, then the system sends
     the data to the listener or callback method in a drag event.
 </p>
 <p>
@@ -226,7 +226,8 @@
     </dt>
     <dd>
         The user releases the drag shadow within the bounding box of a View that can accept the
-        data. The system sends the View object's listener a drag event with action type
+        data, but not within its descendant view that can accept the data. The system sends the View
+        object's listener a drag event with action type
         {@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was
         passed to the system in the call to
         {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
@@ -317,6 +318,10 @@
             application calls
 {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and
             gets a drag shadow.
+            <p>
+                If the listener wants to continue receiving drag events for this operation, it must
+                return boolean <code>true</code> to the system.
+            </p>
         </td>
     </tr>
     <tr>
@@ -324,9 +329,7 @@
         <td>
             A View object's drag event listener receives this event action type when the drag shadow
             has just entered the bounding box of the View. This is the first event action type the
-            listener receives when the drag shadow enters the bounding box. If the listener wants to
-            continue receiving drag events for this operation, it must return boolean
-            <code>true</code> to the system.
+            listener receives when the drag shadow enters the bounding box.
         </td>
     </tr>
     <tr>
@@ -334,7 +337,8 @@
         <td>
             A View object's drag event listener receives this event action type after it receives a
             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event while the drag shadow is
-            still within the bounding box of the View.
+            still within the bounding box of the View and not within a descendant view that can
+            accept the data.
         </td>
     </tr>
     <tr>
@@ -343,7 +347,8 @@
             A View object's drag event listener receives this event action type after it receives a
             {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one
             {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved
-            the drag shadow outside the bounding box of the View.
+            the drag shadow outside the bounding box of the View or into a descendant view that can
+            accept the data.
         </td>
     </tr>
     <tr>
@@ -395,7 +400,7 @@
         <td style="text-align: center;">X</td>
         <td style="text-align: center;">X</td>
         <td style="text-align: center;">X</td>
-        <td style="text-align: center;">&nbsp;</td>
+        <td style="text-align: center;">X</td>
         <td style="text-align: center;">&nbsp;</td>
         <td style="text-align: center;">&nbsp;</td>
     </tr>
@@ -403,8 +408,8 @@
         <td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td>
         <td style="text-align: center;">X</td>
         <td style="text-align: center;">X</td>
-        <td style="text-align: center;">X</td>
-        <td style="text-align: center;">X</td>
+        <td style="text-align: center;">&nbsp;</td>
+        <td style="text-align: center;">&nbsp;</td>
         <td style="text-align: center;">&nbsp;</td>
         <td style="text-align: center;">&nbsp;</td>
     </tr>
@@ -437,7 +442,7 @@
     </tr>
     <tr>
         <td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td>
-        <td style="text-align: center;">X</td>
+        <td style="text-align: center;">&nbsp;</td>
         <td style="text-align: center;">X</td>
         <td style="text-align: center;">&nbsp;</td>
         <td style="text-align: center;">&nbsp;</td>
@@ -711,8 +716,7 @@
         If the listener can accept a drop, it should return <code>true</code>. This tells
         the system to continue to send drag events to the listener.
         If it can't accept a drop, it should return <code>false</code>, and the system
-        will stop sending drag events until it sends out
-        {@link android.view.DragEvent#ACTION_DRAG_ENDED}.
+        will stop sending drag events for the current drag operation.
     </li>
 </ol>
 <p>
@@ -754,7 +758,8 @@
     <li>
         {@link android.view.DragEvent#ACTION_DRAG_EXITED}:  This event is sent to a listener that
         previously received {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, after
-        the drag shadow is no longer within the bounding box of the listener's View.
+        the drag shadow is no longer within the bounding box of the listener's View or it's within
+        the bounding box of a descendant view that can accept the data.
     </li>
 </ul>
 <p>
diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
index 4ed6ff5..13467ae 100644
--- a/docs/html/guide/topics/ui/layout/gridview.jd
+++ b/docs/html/guide/topics/ui/layout/gridview.jd
@@ -81,7 +81,7 @@
   <p>After the {@code main.xml} layout is set for the content view, the
 {@link android.widget.GridView} is captured from the layout with {@link
 android.app.Activity#findViewById(int)}. The {@link
-android.widget.AdapterView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
+android.widget.GridView#setAdapter(T) setAdapter()} method then sets a custom adapter ({@code
 ImageAdapter}) as the source for all items to be displayed in the grid. The {@code ImageAdapter} is
 created in the next step.</p>
 <p>To do something when an item in the grid is clicked, the {@link
@@ -170,7 +170,7 @@
 image is resized and cropped to fit in these dimensions, as appropriate.</li>
   <li>{@link android.widget.ImageView#setScaleType(ImageView.ScaleType)} declares that images should
 be cropped toward the center (if necessary).</li>
-  <li>{@link android.view.View#setPadding(int,int,int,int)} defines the padding for all
+  <li>{@link android.widget.ImageView#setPadding(int,int,int,int)} defines the padding for all
 sides. (Note that, if the images have different aspect-ratios, then less
 padding will cause more cropping of the image if it does not match
 the dimensions given to the ImageView.)</li>
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 38f6e21..3325c0e 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -682,7 +682,7 @@
 </pre>
 
 <p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
-android.view.ActionMode.Callback#onCreateActionMode onCreateActionMode()}
+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
 method and displays the contextual action bar with the specified actions. While the contextual
 action bar is visible, users can select additional items.</p>
 
diff --git a/docs/html/guide/topics/ui/multi-window.jd b/docs/html/guide/topics/ui/multi-window.jd
index 704391f..bab582d 100644
--- a/docs/html/guide/topics/ui/multi-window.jd
+++ b/docs/html/guide/topics/ui/multi-window.jd
@@ -169,7 +169,7 @@
   A root activity's attribute settings apply to all activities
   within its task stack. For example, if the root activity has
   <code>android:resizeableActivity</code> set to true, then all activities
-  in the task stack are resizeable.
+  in the task stack are resizable.
 </p>
 
 <p class="note">
@@ -215,7 +215,7 @@
   Set this attribute in your manifest's <a href=
   "{@docRoot}guide/topics/manifest/activity-element"><code>&lt;activity&gt;</code></a>
   node to indicate whether the activity supports <a href=
-  "{@docRoot}training/tv/playback/picture-in-picture.jd">Picture-in-Picture</a>
+  "{@docRoot}training/tv/playback/picture-in-picture.html">Picture-in-Picture</a>
   display. This attribute is ignored if <code>android:resizeableActivity</code>
   is false.
 </p>
@@ -599,7 +599,7 @@
 
 <p>
   If you disabled multi-window support by setting
-  <code>android:resizableActivity="false"</code>, you should launch your app on
+  <code>android:resizeableActivity="false"</code>, you should launch your app on
   a device running Android 7.0 or higher and attempt to put the app in
   freeform and split-screen modes. Verify that when you do so, the app remains
   in full-screen mode.
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/brand/android_logo_no.png b/docs/html/images/brand/android_logo_no.png
index 8de22d8..946bc49 100644
--- a/docs/html/images/brand/android_logo_no.png
+++ b/docs/html/images/brand/android_logo_no.png
Binary files differ
diff --git a/docs/html/images/brand/android_logo_no_2x.png b/docs/html/images/brand/android_logo_no_2x.png
new file mode 100644
index 0000000..8434c79
--- /dev/null
+++ b/docs/html/images/brand/android_logo_no_2x.png
Binary files differ
diff --git a/docs/html/images/develop/hero-layout-editor.png b/docs/html/images/develop/hero-layout-editor.png
new file mode 100644
index 0000000..195150e
--- /dev/null
+++ b/docs/html/images/develop/hero-layout-editor.png
Binary files differ
diff --git a/docs/html/images/develop/hero-layout-editor_2x.png b/docs/html/images/develop/hero-layout-editor_2x.png
new file mode 100644
index 0000000..60c3d24
--- /dev/null
+++ b/docs/html/images/develop/hero-layout-editor_2x.png
Binary files differ
diff --git a/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png
new file mode 100644
index 0000000..44a4e86
--- /dev/null
+++ b/docs/html/images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png
Binary files differ
diff --git a/docs/html/images/guide/topics/graphics/vectorpath.png b/docs/html/images/guide/topics/graphics/vectorpath.png
new file mode 100644
index 0000000..592bab67
--- /dev/null
+++ b/docs/html/images/guide/topics/graphics/vectorpath.png
Binary files differ
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/images/tools/sdk-manager-support-libs.png b/docs/html/images/tools/sdk-manager-support-libs.png
deleted file mode 100644
index cb4cea5..0000000
--- a/docs/html/images/tools/sdk-manager-support-libs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/tools/studio-sdk-manager-packages.png b/docs/html/images/tools/studio-sdk-manager-packages.png
deleted file mode 100644
index 79ea912..0000000
--- a/docs/html/images/tools/studio-sdk-manager-packages.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/training/ctl-config.png b/docs/html/images/training/ctl-config.png
index 82f63c8..3a4f738 100644
--- a/docs/html/images/training/ctl-config.png
+++ b/docs/html/images/training/ctl-config.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png
new file mode 100644
index 0000000..5839a50
--- /dev/null
+++ b/docs/html/images/training/tv/playback/onboarding-fragment-diagram.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/onboarding-fragment.png b/docs/html/images/training/tv/playback/onboarding-fragment.png
new file mode 100644
index 0000000..5b7da55
--- /dev/null
+++ b/docs/html/images/training/tv/playback/onboarding-fragment.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/onboarding-fragment_2x.png b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png
new file mode 100644
index 0000000..0034be4
--- /dev/null
+++ b/docs/html/images/training/tv/playback/onboarding-fragment_2x.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index b1248af..78fc848 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -6,50 +6,36 @@
 
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</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>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,27 +63,44 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
-      <i class="dac-sprite dac-arrow-down-gray"></i>
+
+<section class="dac-expand dac-hero" style="background-color:#FFF0B4;">
+  <div class="wrap" style="max-width:1000px;margin-top:0;overflow:auto">
+    <div class="col-7of16 col-push-8of16 dac-hero-figure">
+      <a href="/studio/index.html">
+        <img class="dac-hero-image" style="padding-top:24px"
+          src="/studio/images/hero_image_studio_2-2_2x.png">
+      </a>
+    </div>
+    <div class="col-7of16 col-pull-6of16">
+        <h1 class="dac-hero-title" style="color:#004d40">Android Studio 2.2</h1>
+
+<p class="dac-hero-description" style="color:#004d40">Packed with 20+ new
+features, Android Studio 2.2 focuses on speed, smarts, and Android platform
+support.</p>
+
+<p class="dac-hero-description" style="color:#004d40">Develop faster with
+features such as the new Layout Editor, and develop smarter with the new APK
+analyzer, expanded code analysis and more.</p>
+
+<p class="dac-hero-description" style="color:#004d40">Plus, this update
+includes support for all the latest developer features in Android 7.0 Nougat,
+with an updated emulator to test them all out.</p>
+
+<p style="margin-top:24px">
+   <a class="dac-hero-cta" href="/studio/index.html" style="color:#004d40">
+      <span class="dac-sprite dac-auto-chevron"></span>
+      Get Android Studio 2.2
     </a>
-    <div class="actions">
-      <div><a href="{@docRoot}studio/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Get Android Studio
-      </a></div>
-      <div><a href="{@docRoot}samples/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Browse Samples
-      </a></div>
-      <div><a href="{@docRoot}distribute/stories/index.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Watch Stories
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
+  &nbsp;&nbsp;&nbsp;&nbsp;<wbr>
+   <a class="dac-hero-cta" href="/studio/features.html" style="color:#004d40">
+    <span class="dac-sprite dac-auto-chevron"></span>
+    See more features</a>
+</p>
+    </div>
+  </div>
+</section>
+
 
 <section class="dac-section dac-light" id="build-apps"><div class="wrap">
   <h1 class="dac-section-title">Build Beautiful Apps</h1>
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
deleted file mode 100644
index 3ceddf2..0000000
--- a/docs/html/jd_collections.js
+++ /dev/null
@@ -1,1935 +0,0 @@
-/*
- * THIS FILE IS DEPRECATED.
- *
- * Please add and edit resource collections in jd_extras_<lang>.js
- * where lang matches the language code appropriate for the resource.
- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
- *
- */
-var RESOURCE_COLLECTIONS = {
-  "index/carousel": {
-    "title": "",
-    "resources": [
-      "about/versions/lollipop.html"
-    ]
-  },
-  "index/primary": {
-    "title": "",
-    "resources": [
-      "training/building-wearables.html",
-      "training/material/index.html",
-      "studio/index.html"
-    ]
-  },
-  "index/secondary/carousel": {
-    "title": "",
-    "resources": [
-      "http://www.youtube.com/watch?v=9m6MoBM-sFI",
-      "http://www.youtube.com/watch?v=Pms0pcyPbAM",
-      "http://www.youtube.com/watch?v=e7t3svG9PTk",
-      "http://www.youtube.com/watch?v=J3IvOfvH1ys"
-    ]
-  },
-  "index/multiscreen": {
-    "title": "",
-    "resources": [
-      "wear/index.html",
-      "tv/index.html",
-      "auto/index.html"
-    ]
-  },
-  "index/primary/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/resources.html",
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-  "design/landing/latest": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=p4gmvHyuZzw",
-      "https://www.youtube.com/watch?v=YaG_ljfzeUw",
-      "https://www.youtube.com/watch?v=XOcCOBe8PTc"
-    ]
-  },
-  "design/landing/materialdesign": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/design/spec/animation/",
-      "https://www.google.com/design/spec/style/",
-      "https://www.google.com/design/spec/layout/",
-      "https://www.google.com/design/spec/components/",
-      "https://www.google.com/design/spec/patterns/",
-      "https://www.google.com/design/spec/usability/"
-    ]
-  },
-  "design/landing/pureandroid": {
-    "title": "",
-    "resources": [
-      "design/get-started/creative-vision.html",
-      "design/material/index.html",
-      "training/material/index.html",
-      "design/patterns/pure-android.html",
-      "design/patterns/new.html",
-      "design/devices.html"
-    ]
-  },
-  "design/landing/resources": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/design/spec/resources/color-palettes.html",
-      "https://www.google.com/design/spec/resources/layout-templates.html",
-      "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
-      "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
-      "https://www.google.com/design/icons/index.html",
-      "design/downloads/index.html#Wear"
-    ]
-  },
-  "develop/landing/mainlinks": {
-    "title": "",
-    "resources": [
-      "tools/studio/index.html",
-      "samples/new/index.html",
-      "tools/projects/templates.html"
-    ]
-  },
-  "develop/landing/latest": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2015/04/new-android-code-samples.html",
-      "https://android-developers.blogspot.com/2015/04/android-support-library-221.html",
-      "https://android-developers.blogspot.com/2015/03/a-new-reference-app-for-multi-device.html"
-    ]
-  },
-  "develop/landing/devpatterns": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=kmUGLURRPkI",
-      "https://www.youtube.com/watch?v=HGElAW224dE",
-      "https://www.youtube.com/watch?v=zQekzaAgIlQ"
-    ]
-  },
-  "develop/landing/performance": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=fEEulSk1kNY",
-      "https://www.youtube.com/watch?v=-3ry8PxcJJA",
-      "https://www.youtube.com/watch?v=_kKTGK-Cb_4"
-    ]
-  },
-  "develop/landing/buildwithgoogle": {
-    "title": "",
-    "resources": [
-    ]
-  },
-  "develop/landing/ubicomp": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
-      "https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
-      "https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM"
-    ]
-  },
-  "develop/landing/tools": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-      "https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX"
-    ]
-  },
-  "preview/landing/resources": {
-    "title": "",
-    "resources": [
-      "preview/overview.html",
-      "preview/api-overview.html",
-      "preview/behavior-changes.html",
-      "preview/setup-sdk.html",
-      "preview/samples.html",
-      "preview/support.html"
-    ]
-  },
-  "preview/landing/more": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=CsulIu3UaUM",
-      "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/picture-in-picture.html",
-      "preview/features/tv-recording-api.html"
-    ]
-  },
-  "wear/preview/landing": {
-    "title": "",
-    "resources": [
-      "wear/preview/api-overview.html",
-      "wear/preview/downloads.html",
-      "wear/preview/start.html"
-    ]
-  },
-  "wear/preview/landing/resources": {
-    "title": "",
-    "resources": [
-      "wear/preview/features/complications.html",
-      "wear/preview/features/notifications.html",
-      "wear/preview/features/ui-nav-actions.html"
-    ]
-  },
-  "google/landing/services": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/analytics/devguides/collection/android/",
-      "https://developers.google.com/maps/documentation/android/",
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/mobile-ads-sdk/download",
-      "https://developers.google.com/cloud-messaging/gcm",
-      "https://developers.google.com/app-indexing/"
-    ]
-  },
-  "google/landing/videos": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-      "https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf"
-    ]
-  },
-  "google/landing/googleplay": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html",
-      "google/play/developer-api.html"
-    ]
-  },
-  "develop/landing/courses": {
-    "title": "",
-    "resources": [
-      "https://www.udacity.com/course/ud849",
-      "https://www.udacity.com/course/ud853",
-      "https://www.udacity.com/course/ud825",
-      "https://www.udacity.com/android",
-      "https://www.udacity.com/course/ud855",
-      "https://www.udacity.com/course/ud875A",
-      "https://www.udacity.com/course/ud875B",
-      "https://www.udacity.com/course/ud875C",
-      "https://www.udacity.com/course/ud876--1",
-      "https://www.udacity.com/course/ud876--2",
-      "https://www.udacity.com/course/ud876--3",
-      "https://www.udacity.com/course/ud876--4",
-      "https://www.udacity.com/course/ud876--5",
-      "https://www.udacity.com/course/ud862",
-      "https://www.udacity.com/course/ud837",
-      "https://www.udacity.com/course/ud867"
-    ]
-  },
-  "distribute/landing/carousel": {
-    "title": "",
-    "resources": [
-    "distribute/googleplay/guide.html",
-    "https://www.youtube.com/watch?v=JrR6o5tYMWQ",
-    "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "https://www.youtube.com/watch?v=yJisuP94lHU",
-    ]
-  },
-  "distribute/landing/googleplay": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/about.html",
-      "distribute/googleplay/developer-console.html",
-      "distribute/googleplay/index.html#opportunities"
-    ]
-  },
-  "distribute/landing/more": {
-    "title": "",
-    "resources": [
-      "distribute/users/promote-with-ads.html",
-      "distribute/monetize/ads.html",
-      "distribute/analyze/index.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/easy-signin.html",
-      "https://cloud.google.com/docs/"
-    ]
-  },
-  "distribute/edu/videos/stories": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=Idu7VcTTXfk",
-      "https://www.youtube.com/watch?v=iokH4SAIfRw"
-    ]
-  },
-  "distribute/edu/videos/bestpractices": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=iulXz8QTD1g",
-      "https://www.youtube.com/watch?v=IKhU180eJMo",
-      "https://www.youtube.com/watch?v=_AZ6UcPz-_g",
-      "https://www.youtube.com/watch?v=Eh2adsAyTKc"
-    ]
-  },
-  "distribute/edu/videos/experience": {
-    "title": "",
-    "resources": [
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-/*  "launch/static": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=1RIz-cmTQB4",
-      "https://www.youtube.com/watch?v=MVBMWDzyHAI",
-      "https://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/users/build-buzz.html",
-      "distribute/monetize/premium.html",
-      "distribute/monetize/freemium.html",
-      "distribute/monetize/ads.html",
-      "distribute/essentials/best-practices/apps.html",
-      "distribute/essentials/best-practices/games.html",
-      "distribute/users/know-your-user.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  }, */
-  "launch/static/ja": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=xelYnWcYkuE",
-      "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
-      "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
-      "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
-      "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
-      "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
-      "intl/ja/distribute/googleplay/guide.html",
-      "intl/ja/distribute/essentials/quality/core.html",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
-      "intl/ja/support.html",
-      "intl/ja/distribute/essentials/quality/wear.html",
-      "intl/ja/training/tv/start/index.html",
-      "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
-      "intl/ja/distribute/monetize/ads.html"
-    ]
-  },
-  "launch/static/ko": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
-      "https://www.youtube.com/watch?v=83FpwuschCQ",
-      "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
-      "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
-      "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
-      "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
-      "intl/ko/distribute/googleplay/guide.html",
-      "intl/ko/distribute/essentials/quality/core.html",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
-      "intl/ko/support.html",
-      "intl/ko/distribute/essentials/quality/wear.html",
-      "intl/ko/tv/index.html",
-      "intl/ko/google/play-services/games.html",
-      "intl/ko/distribute/monetize/ads.html"
-    ]
-  },
-  "distribute/gp/gplanding": {
-    "resources": [
-      "distribute/googleplay/about.html",
-      "distribute/googleplay/start.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  },
-  "distribute/gp/gpfelanding": {
-    "resources": [
-      "distribute/googleplay/wear.html",
-      "distribute/googleplay/tv.html",
-      "distribute/googleplay/auto.html",
-      "distribute/googleplay/families/about.html",
-      "distribute/googleplay/work/about.html",
-      "distribute/googleplay/edu/about.html",
-      "distribute/googleplay/cast.html",
-      "distribute/googleplay/cardboard.html",
-      "distribute/googleplay/guide.html"
-    ]
-  },
-  "distribute/googleplay/gpfw": {
-    "resources": [
-      "https://www.android.com/work/",
-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "work/index.html"
-    ]
-  },
-  "distribute/essentials": {
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/wear.html",
-      "distribute/essentials/quality/auto.html",
-      "distribute/essentials/quality/billions.html"
-    ]
-  },
-  "distribute/essentials/zhcn": {
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/wear.html",
-      "https://developers.google.com/edu/guidelines",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/users": {
-    "title": "",
-    "resources": [
-      "distribute/users/your-listing.html",
-      "distribute/users/promote-with-ads.html",
-      "distribute/googleplay/index.html#opportunities",
-      "distribute/analyze/improve-roi.html",
-      "distribute/users/expand-to-new-markets.html",
-      "distribute/analyze/index.html",
-      "distribute/users/app-invites.html",
-      "distribute/users/ota-installs.html",
-      "distribute/users/youtube.html",
-      "distribute/users/house-ads.html",
-      "distribute/users/experiments.html",
-      "distribute/users/user-acquisition.html",
-      "distribute/users/banners.html",
-      "distribute/users/beta.html"
-    ]
-  },
-  "distribute/engagelanding": {
-    "resources": [
-      "distribute/engage/intents.html",
-      "distribute/engage/widgets.html",
-      "distribute/engage/translate.html",
-      "distribute/engage/notifications.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/ads.html",
-      "distribute/engage/game-services.html",
-      "distribute/engage/easy-signin.html",
-      "distribute/analyze/build-better-apps.html",
-      "distribute/engage/gcm.html",
-      "distribute/engage/beta.html",
-      "distribute/engage/nearby.html"
-    ]
-  },
-  "distribute/monetize": {
-    "resources": [
-      "distribute/monetize/premium.html",
-      "distribute/monetize/freemium.html",
-      "distribute/monetize/subscriptions.html",
-      "distribute/monetize/ads.html",
-      "distribute/monetize/ecommerce.html",
-      "distribute/monetize/payments.html",
-      "distribute/monetize/conversions.html",
-      "distribute/analyze/understand-user-value.html",
-    ]
-  },
-  "distribute/analyzelanding": {
-    "resources": [
-      "distribute/analyze/start.html",
-      "distribute/analyze/measure.html",
-      "distribute/analyze/understand-user-value.html",
-      "distribute/analyze/improve-roi.html",
-      "distribute/analyze/build-better-apps.html",
-      "distribute/analyze/google-services.html"
-    ]
-  },
-  "distribute/analyzestart": {
-    "resources": [
-      "https://analyticsacademy.withgoogle.com/course04",
-      "google/play-services/index.html",
-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-      "https://developers.google.com/analytics/devguides/collection/android/",
-      "https://www.google.com/tagmanager/",
-      "https://github.com/googleanalytics/google-analytics-plugin-for-unity"
-    ]
-  },
-  "distribute/analyzemeasure": {
-    "resources": [
-
-      "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-      "https://support.google.com/analytics/answer/1032415",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/events",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/user-id"
-    ]
-  },
-  "distribute/analyzeunderstand": {
-    "resources": [
-      "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
-      "https://support.google.com/analytics/answer/3123906",
-      "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-      "https://support.google.com/analytics/answer/1032415",
-    ]
-  },
-  "distribute/analyzeimprove": {
-    "resources": [
-
-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
-      "https://support.google.com/analytics/answer/2956981",
-      "https://support.google.com/analytics/answer/1033961",
-      "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
-      "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link"
-    ]
-  },
-  "distribute/analyzebuild": {
-    "resources": [
-      "https://support.google.com/tagmanager/answer/6003007",
-      "https://support.google.com/analytics/answer/2785577",
-      "https://support.google.com/analytics/answer/1151300"
-    ]
-  },
-  "distribute/analyzeact": {
-    "resources": [
-      "https://support.google.com/analytics/answer/2611268",
-      "https://support.google.com/analytics/answer/1033961",
-      "https://support.google.com/admob/answer/3508177",
-      "https://support.google.com/analytics/answer/2956981",
-      "https://support.google.com/tagmanager/answer/6003007"
-    ]
-  },
-  "distribute/essentials/guidelines": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/quality/wear.html",
-      "distribute/essentials/quality/tv.html",
-      "distribute/essentials/quality/auto.html",
-      "distribute/essentials/quality/billions.html"
-    ]
-  },
-  "distribute/essentials/tools": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/googleplay/android-developer",
-      "distribute/tools/promote/brand.html",
-      "distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/tools/checklists": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/localization-checklist.html"
-    ]
-  },
-  "distribute/tools/checklists/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-  "distribute/tools/promote": {
-    "resources": [
-      "distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/tools/promote/zhcn": {
-    "resources": [
-      "intl/zh-cn/distribute/tools/promote/device-art.html",
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/tools/support": {
-    "title": "Google Play",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer",
-      "https://support.google.com/googleplay/android-developer/answer/4430948",
-      "support.html"
-    ]
-  },
-  "distribute/tools/support/zhcn": {
-    "title": "Google Play",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-      "support.html"
-    ]
-  },
-  "distribute/tools/news": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/",
-      "https://plus.google.com/+AndroidDevelopers/"
-    ]
-  },
-  "distribute/tools/more": {
-    "title": "Google Play",
-    "resources": [
-      "distribute/tools/promote/brand.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/tools/more/zhcn": {
-    "title": "Google Play",
-    "resources": [
-      "intl/zh-cn/distribute/tools/promote/brand.html",
-      "distribute/tools/open-distribution.html",
-      "about/dashboards/index.html"
-    ]
-  },
-  "distribute/googleplay": {
-    "title": "Google Play",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "distribute/essentials/best-practices/apps.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/essentials/best-practices/games.html",
-    ]
-  },
-  "distribute/googleplay/gettingstarted": {
-    "title": "Get Started",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://support.google.com/googleplay/android-developer/answer/113468",
-      "https://support.google.com/googleplay/android-developer/answer/138294",
-      "https://support.google.com/googleplay/android-developer"
-    ]
-  },
-  "distribute/googleplay/developerconsole/related": {
-    "title": "Developer Console",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/googleplay/beta": {
-    "title": "Alpha and Beta Testing",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/3131213",
-      "https://support.google.com/googleplay/android-developer/answer/3131213#games",
-      "distribute/googleplay/experiments.html"
-    ]
-  },
-  "distribute/googleplay/experiments/successes": {
-    "title": "Store Listing Experiment successes",
-    "resources": [
-    ]
-  },
-  "distribute/googleplay/experiments/related": {
-    "title": "Store Listing Experiments",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/6227309",
-      "https://www.youtube.com/watch?v=B6ydLpkhq04",
-      "https://support.google.com/tagmanager/answer/6003007"
-    ]
-  },
-  "distribute/googleplay/banners/related": {
-    "title": "App Install Banners",
-    "resources": [
-      "https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native"
-    ]
-  },
-  "distribute/googleplay/useracquisition/related": {
-    "title": "User Acquisition",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/6263332"
-    ]
-  },
-  "distribute/googleplay/cast": {
-    "title": "Google Cast",
-    "resources": [
-      "https://developers.google.com/cast/docs/ux_guidelines",
-      "https://developers.google.com/cast/docs/android_sender",
-      "https://www.github.com/googlecast"
-    ]
-  },
-  "distribute/googleplay/cardboard": {
-    "title": "Google Cast",
-    "resources": [
-      "https://www.google.com/get/cardboard/get-cardboard/",
-      "https://developers.google.com/cardboard/android/download",
-      "https://www.google.com/design/spec-vr"
-    ]
-  },
-  "distribute/googleplay/gpfe/highlight": {
-    "title": "About Google Play for Education",
-    "resources": [
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/googleplay/gpfe/dev/about": {
-    "title": "About Google Play for Education / Developers",
-    "resources": [
-      "distribute/googleplay/edu/start.html",
-      "https://developers.google.com/edu/guidelines",
-      "https://developers.google.com/edu/faq",
-      "distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/",
-      "https://www.google.com/edu/tablets/#tablets-family"
-    ]
-  },
-  "distribute/googleplay/gpfe/dev": {
-    "title": "About Google Play for Education / Developers",
-    "resources": [
-      "distribute/googleplay/edu/about.html",
-      "https://developers.google.com/edu/guidelines",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/googleplay/developer-console.html",
-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-    ]
-  },
-  "distribute/googleplay/aboutgpfe/educators/about": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://www.youtube.com/watch?v=haEmsMo0f3w"
-    ]
-  },
-  "distribute/googleplay/aboutgpfe/educators": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/googleplay/gettingstartedgpfe/educators": {
-    "title": "About Google Play for Education / Educators",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "https://youtu.be/vzvpcEffvaE"
-    ]
-  },
-  "distribute/essentials/eduessentials/developers": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "distribute/googleplay/edu/start.html",
-      "https://developers.google.com/edu/faq"
-    ]
-  },
-  "distribute/essentials/eduessentials/educators": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "distribute/essentials/quality/tablets.html",
-    ]
-  },
-  "distribute/essentials/optimizing": {
-    "title": "Optimizing Your App",
-    "resources": [
-      "design/index.html",
-      "training/articles/perf-anr.html",
-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
-     ]
-  },
-  "distribute/users/appinvites": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/app-invites/",
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/app-indexing/"
-    ]
-  },
-  "distribute/users/knowyouruser": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/optimizing-your-app.html",
-      "http://www.youtube.com/watch?v=RRelFvc6Czo",
-      "distribute/stories/games/rvappstudios-zombie.html"
-    ]
-  },
-  "distribute/users/promotewithads": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/6032059",
-      "https://support.google.com/adwords/answer/6032073",
-      "https://support.google.com/adwords/answer/6167164",
-      "https://support.google.com/adwords/answer/6167162"
-    ]
-  },
-  "distribute/users/nearby": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/nearby/",
-      "https://www.youtube.com/watch?v=hultDpBS22s",
-      "https://developers.google.com/beacons"
-    ]
-  },
-  "distribute/users/buildbuzz": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/promote/device-art.html",
-      "https://plus.google.com/+GooglePlay"
-    ]
-  },
-  "distribute/users/createagreatlisting": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "distribute/tools/launch-checklist.html",
-      "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
-      "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
-      "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
-    ]
-  },
-  "distribute/users/buildcommunity": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://support.google.com/groups/answer/46601",
-      "https://support.google.com/plus/topic/2888488",
-      "https://www.youtube.com/yt/dev/"
-    ]
-  },
-  "distribute/users/appindexing": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/app-indexing/",
-      "https://developers.google.com/app-indexing/webmasters/details",
-      "distribute/engage/deep-linking.html",
-      "training/app-indexing/index.html"
-    ]
-  },
-  "distribute/users/otas": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/identity/sign-in/android/",
-      "https://developers.google.com/+/features/play-installs",
-      "https://developers.google.com/+/features/analytics"
-    ]
-  },
-  "distribute/users/houseads": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/admob/topic/2784623",
-      "https://developers.google.com/mobile-ads-sdk/download",
-      "https://support.google.com/googleplay/android-developer/topic/2985714",
-      "https://analyticsacademy.withgoogle.com/mobile-app",
-      "https://support.google.com/analytics/answer/2611404",
-      "https://support.google.com/admob/answer/3111064"
-    ]
-  },
-  "distribute/users/youtube": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/youtube/answer/6140493",
-      "https://support.google.com/youtube/answer/2797387"
-    ]
-  },
-  "distribute/toolsreference/bestpractices/apps": {
-    "title": "",
-    "resources": [
-      "distribute/googleplay/developer-console.html",
-      "https://android-developers.blogspot.com/"
-    ]
-  },
-  "distribute/toolsreference/bestpractices/games": {
-    "title": "",
-    "resources": [
-      "google/play-services/games.html",
-      "https://android-developers.blogspot.com/",
-      "distribute/googleplay/developer-console.html",
-      "https://www.youtube.com/watch?v=1RIz-cmTQB4"
-    ]
-  },
-  "distribute/essentials/corequalityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/index.html",
-      "design/patterns/navigation.html",
-      "design/patterns/actionbar.html",
-      "design/style/iconography.html"
-    ]
-  },
-  "distribute/essentials/corequalityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
-      "guide/components/tasks-and-back-stack.html",
-      "training/basics/activity-lifecycle/recreating.html"
-    ]
-  },
-  "distribute/essentials/tvqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/tv/index.html",
-      "training/tv/start/index.html"
-    ]
-  },
-  "distribute/essentials/tvqualityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "training/tv/start/hardware.html",
-      "training/tv/games/index.html"
-    ]
-  },
-  "distribute/essentials/wearqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "design/wear/index.html",
-      "training/building-wearables.html",
-      "training/wearables/ui/index.html"
-    ]
-  },
-  "distribute/essentials/wearqualityguidelines/functionality": {
-    "title": "",
-    "resources": [
-      "training/wearables/notifications/index.html",
-      "training/wearables/apps/index.html",
-      "training/wearables/notifications/voice-input.html"
-    ]
-  },
-    "distribute/essentials/autoqualityguidelines/visualdesign": {
-    "title": "",
-    "resources": [
-      "training/auto/messaging/index.html",
-      "training/auto/start/index.html"
-    ]
-  },
-  "distribute/essentials/core/performance": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
-      "training/articles/perf-anr.html",
-      "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
-    ]
-  },
-  "distribute/essentials/core/play": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "https://play.google.com/about/developer-content-policy.html?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
-    ]
-  },
-  "distribute/essentials/core/play/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/optimize": {
-    "title": "",
-    "resources": [
-      "design/style/metrics-grids.html",
-      "design/style/devices-displays.html",
-      "guide/practices/screens_support.html",
-      //"guide/practices/screens_support.html#ConfigurationExamples",
-    ]
-  },
-  "distribute/essentials/tabletguidelines/extrascreen": {
-    "title": "",
-    "resources": [
-      "design/patterns/multi-pane-layouts.html",
-      "training/design-navigation/multiple-sizes.html",
-      "training/multiscreen/index.html",
-    ]
-  },
-  "distribute/essentials/tabletguidelines/assets": {
-    "title": "",
-    "resources": [
-      "design/style/iconography.html",
-      "guide/topics/resources/providing-resources.html",
-      "guide/practices/screens_support.html",
-      "training/basics/supporting-devices/screens.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/fonts": {
-    "title": "",
-    "resources": [
-      "design/style/metrics-grids.html",
-      "design/style/typography.html",
-      "guide/practices/screens_support.html",
-      "training/multiscreen/screendensities.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/widgets": {
-    "title": "",
-    "resources": [
-      "guide/topics/appwidgets/index.html#MetaData",
-      "guide/topics/appwidgets/index.html",
-      "design/patterns/widgets.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/versions": {
-    "title": "",
-    "resources": [
-      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
-      "guide/topics/manifest/uses-sdk-element.html",
-      "training/basics/supporting-devices/platforms.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/hardware": {
-    "title": "",
-    "resources": [
-      "guide/topics/manifest/uses-feature-element.html",
-      "guide/topics/manifest/uses-feature-element.html#testing"
-    ]
-  },
- "distribute/essentials/tabletguidelines/tabletscreens": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
-      "guide/practices/screens_support.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/showcase": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-      "https://play.google.com/apps/publish/",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/showcase/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "https://play.google.com/apps/publish/?hl=zh-Hans",
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines/googleplay": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "google/play/filters.html"
-    ]
-  },
- "distribute/essentials/billionsquality/connectivity": {
-    "title": "",
-    "resources": [
-      "training/basics/network-ops/managing.html",
-      "training/monitoring-device-state/connectivity-monitoring.html",
-      "guide/topics/providers/content-providers.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/capability": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html",
-      "training/multiscreen/screendensities.html",
-      "training/articles/memory.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/cost": {
-    "title": "",
-    "resources": [
-      "https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
-      "training/basics/network-ops/managing.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/consumption": {
-    "title": "",
-    "resources": [
-      "training/efficient-downloads/efficient-network-access.html",
-      "training/monitoring-device-state/index.html"
-    ]
-  },
-  "distribute/essentials/billionsquality/content": {
-    "title": "",
-    "resources": [
-      "training/material/animations.html#Touch",
-      "training/articles/perf-anr.html",
-      "training/improving-layouts/index.html"
-    ]
-  },
-  "distribute/essentials/tabletguidelines": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "https://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/getusers/notifications": {
-    "title": "",
-    "resources": [
-      "distribute/engage/gcm.html",
-      "https://play.google.com/about/developer-content-policy.html"
-    ]
-  },
-  "distribute/engage/analytics": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/analytics/mobile/",
-      "https://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
-      "https://developers.google.com/analytics/devguides/collection/android/"
-    ]
-  },
-  "distribute/engage/widgets": {
-    "title": "",
-    "resources": [
-      "design/patterns/widgets.html",
-      "guide/topics/appwidgets/index.html"
-    ]
-  },
-  "distribute/engage/translate": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/l10n/answer/6359997"
-    ]
-  },
-  "distribute/engage/reengage": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/6032073",
-      "distribute/engage/deep-linking.html",
-      "https://support.google.com/adwords/answer/6167162",
-      "distribute/users/promote-with-ads.html"
-    ]
-  },
-  "distribute/engage/appindexing": {
-    "title": "",
-    "resources": [
-      "distribute/engage/intents.html",
-      "distribute/engage/deep-linking.html",
-      "training/app-indexing/index.html"
-    ]
-  },
-  "distribute/engage/intents": {
-    "title": "",
-    "resources": [
-      "guide/components/intents-filters.html",
-      "distribute/engage/deep-linking.html",
-      "distribute/engage/ads.html"
-    ]
-  },
-  "distribute/getusers/expandnewmarkets": {
-    "title": "",
-    "resources": [
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/googleplay/android-developer/table/3541286",
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html",
-      "https://www.youtube.com/watch?v=SkHHPf3EdzE"
-    ]
-  },
-  "distribute/engage/gcm": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/cloud-messaging/gcm",
-      "https://developers.google.com/cloud-messaging/android/client",
-    ]
-  },
-  "distribute/engage/gamesservices/related": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/games/services/",
-      "distribute/analyze/start.html",
-      "distribute/googleplay/cardboard.html",
-      "https://www.google.com/admob/"
-    ]
-  },
-  "distribute/engage/gplus": {
-    "title": "",
-    "resources": [
-      "distribute/users/ota-installs.html",
-      "https://developers.google.com/identity/sign-in/android/people",
-      "https://developers.google.com/+/mobile/android/"
-    ]
-  },
-  "distribute/engage/community": {
-    "title": "",
-    "resources": [
-      "distribute/users/build-community.html",
-      "distribute/engage/video.html"
-    ]
-  },
-  "distribute/engage/deeplinks": {
-    "title": "",
-    "resources": [
-      "distribute/engage/easy-signin.html",
-      "https://developers.google.com/app-indexing/",
-      "https://developers.google.com/+/mobile/android/share/interactive-post"
-    ]
-  },
-  "distribute/engage/appupdates": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/optimizing-your-app.html",
-      "distribute/tools/launch-checklist.html",
-      "distribute/googleplay/developer-console.html"
-    ]
-  },
-  "distribute/engage/video/more": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/yt/dev/",
-      "distribute/essentials/best-practices/games.html",
-      "https://www.youtube.com/watch?v=RRelFvc6Czo"
-    ]
-  },
-  "distribute/engage/community": {
-    "title": "",
-    "resources": [
-      "distribute/users/build-community.html",
-      "distribute/engage/video.html"
-    ]
-  },
-  "distribute/engage/kiwi": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=WWArLD6nqrk"
-    ]
-  },
-  "distribute/toolsreference/gpfefaq": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/edu/tablets/",
-      "distribute/googleplay/edu/start.html",
-      "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/identifylocales": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/identifylocales/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
-    ]
-  },
-  "distribute/tools/loc/designforloc": {
-    "title": "",
-    "resources": [
-      "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
-      "guide/topics/resources/string-resource.html#Plurals",
-      "guide/topics/resources/string-resource.html",
-      "reference/java/util/Locale.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/managestrings": {
-    "title": "",
-    "resources": [
-      "guide/topics/resources/string-resource.html",
-      "design/style/writing.html",
-      "https://en.wikipedia.org/wiki/XLIFF"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/managestrings/zhcn": {
-    "title": "",
-    "resources": [
-      "guide/topics/resources/string-resource.html",
-      "intl/zh-cn/design/style/writing.html",
-      "https://en.wikipedia.org/wiki/XLIFF"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/preplaunch": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/preplaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/device-art.html"
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/supportlaunch": {
-    "title": "",
-    "resources": [
-      "distribute/tools/launch-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/localizationchecklist/supportlaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/understanding": {
-    "title": "",
-    "resources": [
-      "tools/publishing/publishing_overview.html",
-      "tools/publishing/preparing.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/policies": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/4430948",
-      "https://support.google.com/googleplay/android-developer/topic/2364761",
-      "https://support.google.com/googleplay/android-developer"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/quality": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/guidelines"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/rating": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/188189",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/country": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/size": {
-    "title": "",
-    "resources": [
-      "google/play/expansion-files.html",
-      "tools/help/proguard.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/platform": {
-    "title": "",
-    "resources": [
-      "guide/practices/screens_support.html",
-      "about/dashboards/index.html",
-      "guide/topics/manifest/uses-sdk-element.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/price": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/table/3541286",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/purchasemethod": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/setprice": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1169947",
-      "https://support.google.com/googleplay/android-developer/answer/138412",
-      "https://support.google.com/googleplay/android-developer/answer/112622",
-      "https://support.google.com/googleplay/android-developer/answer/138000"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/localization": {
-    "title": "",
-    "resources": [
-      "distribute/tools/localization-checklist.html",
-      "https://support.google.com/l10n/answer/6359997"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/graphics": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/productdetails": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113475",
-      "https://support.google.com/googleplay/android-developer/answer/1078870"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/badges": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/finalchecks": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/113476",
-      "support.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/afterlaunch": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113477",
-      "https://support.google.com/googleplay/android-developer/answer/1153479",
-      "https://support.google.com/payments/answer/2741495",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/understanding/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/tools/publishing/publishing_overview.html",
-      "intl/zh-cn/tools/publishing/preparing.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/policies/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/quality/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "https://developers.google.com/edu/guidelines?hl=zh-Hans"
-    ]
-  },
-
-  "distribute/toolsreference/launchchecklist/rating/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/country/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/size/zhcn": {
-    "title": "",
-    "resources": [
-      "google/play/expansion-files.html",
-      "intl/zh-cn/tools/help/proguard.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/price/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/purchasemethod/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/google/play/billing/index.html",
-      "google/play/billing/billing_subscriptions.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/setprice/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans"
-    ]
-  },
-  "distribute/stories/localization": {
-    "title": "",
-    "resources": [
-      "distribute/stories/games/rvappstudios-zombie.html",
-      "distribute/stories/games/g4a-indian-rummy.html",
-      "distribute/stories/apps/sayhi.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/localization/zhcn": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/tools/localization-checklist.html",
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/graphics/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-      "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/productdetails/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/badges/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "intl/zh-cn/distribute/tools/promote/linking.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/finalchecks/zhcn": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/developer-content-policy.html",
-      "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
-      "support.html"
-    ]
-  },
-  "distribute/toolsreference/launchchecklist/afterlaunch/zhcn": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
-      "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
-      "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
-      "distribute/essentials/optimizing-your-app.html"
-    ]
-  },
-  "distribute/monetize/premium": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/freemium": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/subscriptions": {
-    "title": "",
-    "resources": [
-      "google/play/billing/billing_subscriptions.html",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/ecommerce": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/wallet/instant-buy/",
-      "https://support.google.com/googleplay/android-developer/answer/4407611"
-    ]
-  },
-  "distribute/monetize/advertising": {
-    "title": "",
-    "resources": [
-      "https://www.google.com/ads/admob/#subid=us-en-et-dac",
-      "https://www.google.com/doubleclick/publishers/small-business/index.html",
-      "https://support.google.com/googleplay/android-developer/topic/2985714",
-      "training/monetization/ads-and-ux.html"
-    ]
-  },
-  "distribute/monetize/admob": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/admob/topic/2784623",
-      "https://admob.blogspot.com/",
-      "https://analyticsacademy.withgoogle.com/mobile-app",
-      "https://www.udacity.com/courses/ud876-3"
-    ]
-  },
-  "distribute/monetize/paymentmethods": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/about/giftcards/",
-      "https://support.google.com/googleplay/answer/2651410"
-    ]
-  },
-  "distribute/monetize/conversions": {
-    "title": "",
-    "resources": [
-      "https://support.google.com/adwords/answer/2471188",
-      "https://developers.google.com/app-conversion-tracking/",
-      "https://support.google.com/analytics/answer/2611404",
-      "https://support.google.com/adwords/answer/1704341"
-    ]
-  },
-  "autolanding": {
-    "title": "",
-    "resources": [
-      "auto/index.html",
-      "design/auto/index.html",
-      "training/auto/index.html"
-    ]
-  },
-  "tvlanding": {
-    "title": "",
-    "resources": [
-      "tv/index.html",
-      "design/tv/index.html",
-      "training/tv/index.html"
-    ]
-  },
-  "wearlanding": {
-    "title": "",
-    "resources": [
-      "design/wear/index.html",
-      "training/building-wearables.html",
-      "training/wearables/ui/index.html"
-    ]
-  },
-  "design/auto/auto_ui_guidelines": {
-    "title": "",
-    "resources": [
-      "shareables/auto/AndroidAuto-audio-apps.pdf",
-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
-      "shareables/auto/AndroidAuto-custom-colors.pdf"
-    ]
-  },
-  "training/auto/overview": {
-    "title": "",
-    "resources": [
-      "training/auto/start/index.html",
-      "design/auto/index.html",
-      "shareables/auto/AndroidAuto-custom-colors.pdf"
-    ]
-  },
-  "training/auto/messaging": {
-    "title": "",
-    "resources": [
-      "training/auto/messaging/index.html",
-      "shareables/auto/AndroidAuto-messaging-apps.pdf",
-      "samples/MessagingService/index.html"
-    ]
-  },
-  "training/auto/media": {
-    "title": "",
-    "resources": [
-      "training/auto/audio/index.html",
-      "shareables/auto/AndroidAuto-audio-apps.pdf",
-      "samples/MediaBrowserService/index.html"
-    ]
-  },
-  "training/auto/distribute": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/auto.html",
-      "distribute/googleplay/auto.html"
-    ]
-  },
-  "training/testing/overview": {
-    "title": "",
-    "resources": [
-      "training/testing/start/index.html",
-      "tools/testing/testing_android.html",
-      "https://www.youtube.com/watch?v=vdasFFfXKOY"
-    ]
-  },
-  "training/testing/tools": {
-    "title": "",
-    "resources": [
-      "tools/testing-support-library/index.html",
-      "tools/help/monkey.html",
-      "tools/help/monkeyrunner_concepts.html",
-      "tools/testing/testing_otheride.html",
-      "https://source.android.com/devices/tech/debug/dumpsys.html"
-    ]
-  },
-  "training/testing/techniques": {
-    "title": "",
-    "resources": [
-      "training/testing/ui-testing/index.html",
-      "training/testing/unit-testing/index.html",
-      "training/testing/performance.html"
-    ]
-  },
-  "training/testing/resources": {
-    "title": "",
-    "resources": [
-      "https://github.com/googlesamples/android-testing",
-      "https://www.youtube.com/watch?v=2I6fuD20qlY",
-      "https://codelabs.developers.google.com/codelabs/android-testing/index.html",
-      "https://github.com/googlesamples/android-testing-templates",
-      "https://google.github.io/android-testing-support-library"
-    ]
-  },
-  "distribute/stories/games": {
-    "title": "",
-    "resources": [
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
-      "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
-    ]
-  },
-  "overview/zhcn/1": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/distribute/essentials/quality/core.html",
-      "intl/zh-cn/distribute/essentials/quality/tablets.html",
-      "intl/zh-cn/distribute/tools/launch-checklist.html",
-      "intl/zh-cn/tools/publishing/publishing_overview.html",
-      "intl/zh-cn/distribute/tools/localization-checklist.html"
-    ]
-  },
-    "overview/zhcn/2": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/google/play/billing/index.html",
-      "intl/zh-cn/google/play/billing/api.html",
-      "intl/zh-cn/google/play/billing/billing_admin.html",
-      "intl/zh-cn/google/play/billing/billing_testing.html",
-      "intl/zh-cn/google/play/billing/billing_best_practices.html"
-    ]
-  },
-  "overview/zhcn/3": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-
-      "intl/zh-cn/distribute/tools/promote/device-art.html",
-      "intl/zh-cn/distribute/tools/promote/linking.html",
-      "intl/zh-cn/distribute/tools/promote/brand.html",
-      "intl/zh-cn/tools/help/proguard.html"
-    ]
-  },
-  "overview/zhcn/4": {
-    "title": "",
-    "resources": [
-      "intl/zh-cn/design/style/writing.html",
-      "intl/zh-cn/training/basics/fragments/fragment-ui.html",
-      "intl/zh-cn/training/multiscreen/index.html",
-      "intl/zh-cn/training/monitoring-device-state/index.html"
-    ]
-  },
-  "overview/carousel/zhcn": {
-    "title": "",
-    "resources": [
-      "https://www.youtube.com/watch?v=vGV7FHGzpFU",
-      "https://www.youtube.com/watch?v=aqc3ZOTzpdk",
-      "https://www.youtube.com/watch?v=jaNrJ8uyLSc"
-    ]
-  },
-  "overview/1": {
-    "title": "",
-    "resources": [
-      "distribute/essentials/quality/core.html",
-      "distribute/essentials/quality/tablets.html",
-      "distribute/tools/launch-checklist.html",
-      "tools/publishing/publishing_overview.html",
-      "distribute/tools/localization-checklist.html"
-    ]
-  },
-    "overview/2": {
-    "title": "",
-    "resources": [
-      "google/play/billing/index.html",
-      "google/play/billing/api.html",
-      "google/play/billing/billing_admin.html",
-      "google/play/billing/billing_testing.html",
-      "google/play/billing/billing_best_practices.html"
-    ]
-  },
-  "overview/3": {
-    "title": "",
-    "resources": [
-      "https://play.google.com/intl/en_us/badges/",
-      "distribute/tools/promote/device-art.html",
-      "distribute/tools/promote/linking.html",
-      "distribute/tools/promote/brand.html",
-      "tools/help/proguard.html"
-    ]
-  },
-  "overview/4": {
-    "title": "",
-    "resources": [
-      "design/style/writing.html",
-      "training/basics/fragments/fragment-ui.html",
-      "training/multiscreen/index.html",
-      "training/monitoring-device-state/index.html"
-    ]
-  },
-"tools/help/log": {
-    "title": "",
-    "resources": [
-       "tools/help/am-logcat.html"
-    ]
-  },
-"tools/help/monitor": {
-    "title": "",
-    "resources": [
-       "tools/help/am-memory.html",
-       "tools/help/am-cpu.html",
-       "tools/help/am-gpu.html",
-       "tools/help/am-network.html"
-    ]
-  },
- "tools/help/data": {
-    "title": "",
-    "resources": [
-       "tools/help/am-hprof.html",
-       "tools/help/am-allocation.html",
-       "tools/help/am-methodtrace.html",
-       "tools/help/am-sysinfo.html"
-    ]
-  },
-  "tools/help/shot": {
-    "title": "",
-    "resources": [
-       "tools/help/am-screenshot.html",
-       "tools/help/am-video.html"
-    ]
-  },
-  "tools/performance/rendering": {
-    "title": "",
-    "resources": [
-       "tools/performance/debug-gpu-overdraw/index.html",
-       "tools/performance/profile-gpu-rendering/index.html",
-       "tools/performance/hierarchy-viewer/setup.html",
-       "tools/performance/hierarchy-viewer/index.html",
-       "tools/performance/hierarchy-viewer/profiling.html"
-    ]
-  },
-  "tools/performance/memory": {
-    "title": "",
-    "resources": [
-       "tools/performance/memory-monitor/index.html",
-       "tools/performance/heap-viewer/index.html",
-       "tools/performance/allocation-tracker/index.html",
-       "tools/performance/comparison.html"
-    ]
-  },
-  "tools/performance/cpu": {
-    "title": "",
-    "resources": [
-       "tools/performance/traceview/index.html",
-       "tools/performance/systrace/index.html"
-    ]
-  },
-  "tools/performance/battery": {
-    "title": "",
-    "resources": [
-       "tools/performance/batterystats-battery-historian/index.html",
-       "tools/performance/batterystats-battery-historian/charts.html"
-    ]
-  },
-  "marshmallow/landing/resources": {
-    "title": "",
-    "resources": [
-       "about/versions/marshmallow/android-6.0-changes.html",
-       "about/versions/marshmallow/android-6.0.html",
-       "about/versions/marshmallow/samples.html"
-    ]
-  },
-  "marshmallow/landing/videos": {
-    "title": "",
-    "resources": [
-       "https://youtu.be/U9tw5ypqEN0",
-       "https://youtu.be/N72ksDKrX6c",
-       "https://youtu.be/iZqDdvhTZj0",
-       "https://www.youtube.com/watch?v=vcSj8ln-BlE",
-       "https://youtu.be/LQoohRwojmw",
-       "https://www.youtube.com/watch?v=VOn7VrTRlA4",
-       "https://youtu.be/5sCQjeGoE7M",
-       "https://www.youtube.com/watch?v=C8lUdPVSzDk",
-       "https://www.youtube.com/watch?v=HXacyy0HSW0",
-       "https://www.youtube.com/watch?v=OW1A4XFRuyc",
-       "https://www.youtube.com/watch?v=j3QC6hcpy90",
-       "https://www.youtube.com/watch?v=f17qe9vZ8RM",
-       "https://www.youtube.com/watch?v=ndBdf1_oOGA"
-    ]
-  },
-  "marshmallow/landing/more": {
-    "title": "",
-    "resources": [
-      "training/permissions/requesting.html",
-      "training/backup/autosyncapi.html",
-      "training/monitoring-device-state/doze-standby.html",
-      "training/app-links/index.html",
-      "training/articles/assistant.html",
-      "training/testing/performance.html",
-      "https://developers.google.com/android/nexus/images"
-    ]
-  },
-  "tools/landing/resources": {
-    "title": "",
-    "resources": [
-    "tools/studio/index.html",
-    "tools/studio/studio-features.html",
-    "studio/intro/index.html",
-    ]
-  },
-  "tools/landing/latest": {
-    "title": "",
-    "resources": [
-    "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
-    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
-    "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
-    ]
-  },
-  "work/landing/primary": {
-    "title": "",
-    "resources": [
-      "work/overview.html",
-      "work/guide.html",
-      "https://www.google.com/work/android/developers/applyDevHub/",
-      "work/managed-configurations.html",
-      "work/cosu.html",
-      "work/managed-profiles.html"
-    ]
-  },
-  "work/landing/resources": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/android/work/",
-      "https://www.google.com/work/android/",
-      "https://developers.google.com/android/work/build-dpc",
-      "https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "https://www.youtube.com/watch?v=Za0OQo8DRM4",
-      "https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX"
-    ]
-  },
-  "work/apps": {
-    "title": "",
-    "resources": [
-      "work/managed-profiles.html",
-      "work/managed-configurations.html",
-      "work/cosu.html",
-      "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-      "samples/AppRestrictionSchema/index.html",
-      "samples/AppRestrictionEnforcer/index.html"
-    ]
-  },
-  "work/admin": {
-    "title": "",
-    "resources": [
-      "https://developers.google.com/android/work/build-dpc",
-      "samples/BasicManagedProfile/index.html",
-      "https://www.youtube.com/watch?v=j3QC6hcpy90"
-    ]
-  }
-};
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
deleted file mode 100644
index 44ccafa..0000000
--- a/docs/html/jd_extras.js
+++ /dev/null
@@ -1,4120 +0,0 @@
-/*
- * THIS FILE IS DEPRECATED.
- *
- * Please add and edit resource collections in jd_extras_<lang>.js
- * where lang matches the language code appropriate for the resource.
- * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016.
- *
- */
-DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
- /* TODO Remove standard resources from here, such as below
- */
-  {
-    "title":"Writing More Code by Writing Less Code with Android Studio Live Templates",
-    "titleFriendly":"",
-    "summary":"Unless you’re getting paid by the keystroke, no one wants to write repetitive boilerplate code.",
-    "url":"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
-    "group":"",
-    "keywords": [],
-    "tags": ['studio'],
-    "image":"https://cdn-images-1.medium.com/max/800/1*JkrYXGs1AxZAbK0sCLrJAQ.gif",
-    "type":"medium"
-  },
-  {
-    "title":"How Often Should You Update Android Studio?",
-    "titleFriendly":"",
-    "summary":"One of the beauties of Android Studio is how quickly is evolves and improves.",
-    "url":"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
-    "group":"",
-    "keywords": [],
-    "tags": ['studio'],
-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
-    "type":"medium"
-  },
-  {
-    "title":"SmallerAPK, Part 6: Image optimization, Zopfli & WebP",
-    "category":"",
-    "summary":"Series of posts on minimizing your APK size.",
-    "url":"https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
-    "type":"medium"
-  },
-  {
-    "title":"Measure your app’s user acquisition channels",
-    "titleFriendly":"",
-    "summary":"Get details on how to use the Developer Console User Acquisitions reports to discover where your users come from.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/6263332",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Set up native app install banners in Chrome",
-    "titleFriendly":"",
-    "summary":"Get the details you need to add your native app or game to your site’s web app manifest file.",
-    "url":"https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android#native",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Optimize your store listing pages with experiments",
-    "titleFriendly":"",
-    "summary":"You can run experiments to find the most effective graphics and localized text for your app.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/6227309",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Content Experiments for Mobile Apps",
-    "titleFriendly":"",
-    "summary":"Google Analytics Content Experiments allows you to test multiple variations of a given web page.",
-    "url":"https://support.google.com/tagmanager/answer/6003007",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Store Listing Experiments for Google Play",
-    "titleFriendly":"",
-    "summary":"Learn how to use Google Play’s new store listing optimization feature to get more installs of your app.",
-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Use alpha/beta testing & staged rollouts",
-    "titleFriendly":"",
-    "summary":"Using the Google Play Developer Console, you can choose groups of users to test different versions of your app.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/3131213",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Quizlet Developer Story",
-    "titleFriendly":"",
-    "summary":"Quizlet is an extremely popular online learning tool for students. See how they optimized for the classroom with Android and the power of Google Play for Education.",
-    "url":"https://www.youtube.com/watch?v=Idu7VcTTXfk",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/Idu7VcTTXfk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"What's New in GPFE",
-    "titleFriendly":"",
-    "summary":"Learn about the vision and philosophy behind Google Play for Education",
-    "url":"https://www.youtube.com/watch?v=IKhU180eJMo",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/IKhU180eJMo/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Get started with Google Cast",
-    "titleFriendly":"",
-    "summary":"Build multi-screen experiences, let the user send video and audio content to TVs and speakers.",
-    "url":"https://developers.google.com/cast/docs/ux_guidelines",
-    "group":"",
-    "keywords": ["cast", "chromecast", "video", "audio"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Guide"
-  },
-  {
-    "title":"Android Sender Applications",
-    "titleFriendly":"",
-    "summary":"Get an overview of how your Android app can act as a Google Cast sender app.",
-    "url":"https://developers.google.com/cast/docs/android_sender",
-    "group":"",
-    "keywords": ["cast", "sender"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Guide"
-  },
-  {
-    "title":"Cast sample apps",
-    "titleFriendly":"",
-    "summary":"Get example Google Cast applications for both senders and receivers.",
-    "url":"https://www.github.com/googlecast",
-    "group":"",
-    "keywords": ["cast", "samples"],
-    "tags": [],
-    "image":"images/cards/card-cast_2x.jpg",
-    "type":"Samples"
-  },
-  {
-    "title":"Get Cardboard",
-    "titleFriendly":"",
-    "summary":"Get your own Cardboard, today. Buy one from a manufacturer or build your own, and start developing.",
-    "url":"https://www.google.com/get/cardboard/get-cardboard/",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Guide"
-  },
-    {
-    "title":"Download the Cardboard SDK",
-    "titleFriendly":"",
-    "summary":"Grab the Cardboard libraries from GitHub and start creating VR apps in your favorite development environment.",
-    "url":"https://developers.google.com/cardboard/android/download",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"Cardboard design guidelines",
-    "titleFriendly":"",
-    "summary":"Focus on overall usability and avoiding common VR pitfalls while creating an immersive experience of your own.",
-    "url":"https://www.google.com/design/spec-vr",
-    "group":"",
-    "keywords": ["carboard","vr"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type":"Design"
-  },
-  {
-    "title":"Maps",
-    "titleFriendly":"",
-    "summary":"Give users the map that more than a billion people use every month.",
-    "url":"https://developers.google.com/maps/documentation/android/",
-    "group":"",
-    "keywords": ["maps"],
-    "tags": [],
-    "image":"images/google/gps-maps.png",
-    "type":"Guide"
-  },
-    {
-    "title":"Places API",
-    "titleFriendly":"",
-    "summary":"give your users contextual information about where they are, when they’re there.",
-    "url":"https://developers.google.com/places/android/",
-    "group":"",
-    "keywords": ["places","location", "context"],
-    "tags": [],
-    "image":"images/cards/card-places_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"GCM Client for Android",
-    "titleFriendly":"",
-    "summary":"Send push notifications and pubsub from your server to Android devices around the world.",
-    "url":"https://developers.google.com/cloud-messaging/android/client",
-    "group":"",
-    "keywords": ["push","gcm"],
-    "tags": [],
-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"Google Cloud Messaging",
-    "titleFriendly":"",
-    "summary":"Learn about GCM and the kinds of services you can offer to users through push notifications",
-    "url":"https://developers.google.com/cloud-messaging/gcm",
-    "group":"",
-    "keywords": ["push","gcm"],
-    "tags": [],
-    "image":"images/cards/card-google-cloud-messaging_16-9_2x.png",
-    "type":"Guide"
-  },
-  {
-    "title":"ClassDojo Developer Story",
-    "titleFriendly":"",
-    "summary":"ClassDojo is a classroom tool that helps teachers improve behavior in their classrooms quickly and easily. See how they optimized for the classroom with Android and the power of Google Play for Education.",
-    "url":"https://www.youtube.com/watch?v=iokH4SAIfRw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/iokH4SAIfRw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Plan for Success",
-    "titleFriendly":"",
-    "summary":"5 tips from developers on creating great EDU apps.",
-    "url":"https://www.youtube.com/watch?v=Eh2adsAyTKc",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/Eh2adsAyTKc/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Optimizing Apps for Education",
-    "titleFriendly":"",
-    "summary":"Learn how to optimize your app for teachers and students.",
-    "url":"https://www.youtube.com/watch?v=_AZ6UcPz-_g",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/_AZ6UcPz-_g/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Ideas and Tools for Building Innovative Education Apps",
-    "titleFriendly":"",
-    "summary":"Are you hungry to build an awesome app for education but don't quite know where to start? Come hear about apps that teachers want, and the APIs you're going to need to build them! In particular, we'll talk about app ideas that combine APIs for Google Drive, Google Login, Android Single Task Mode and more to build transformative Educational apps that will delight educators and kids in and out of the classroom.",
-    "url":"https://www.youtube.com/watch?v=iulXz8QTD1g",
-    "group":"",
-    "keywords": [],
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "image":"https://i1.ytimg.com/vi/iulXz8QTD1g/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Intro To Material Design",
-    "titleFriendly":"",
-    "summary":"These days, UI designers need to be thinking about phones, tablets, laptops, TVs, smartwatches, and beyond. In this DesignByte we talk about how Google designers have been working on making cross-platform and multi-screen design easier. We wanted to build a design system that felt at home on every screen, from the smallest watch to the largest TV.",
-    "url":"https://www.youtube.com/watch?v=p4gmvHyuZzw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/p4gmvHyuZzw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Paper and Ink: The Materials that Matter",
-    "titleFriendly":"",
-    "summary":"Join Rich Fulcher to learn about the materials of material design. See how virtual paper and ink form the foundation of your tactile user interface and master the rules that govern their behaviour.",
-    "url":"https://www.youtube.com/watch?v=YaG_ljfzeUw",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/YaG_ljfzeUw/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"DesignBytes: Material Design in the Google I/O App",
-    "titleFriendly":"",
-    "summary":"Roman Nurik shares details on the design process for the Google I/O 2014 app. To check out the app's source code, visit github.com/google/iosched.",
-    "url":"https://www.youtube.com/watch?v=XOcCOBe8PTc",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/XOcCOBe8PTc/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Toolbars for a flexible Action Bar & more",
-    "titleFriendly":"",
-    "summary":"Toolbars are a flexible View you can add to your Android app which provides many of the same APIs as the system provided Action Bar, but can also do so much more such as reacting to scrolling or being integrated directly into your layouts.",
-    "url":"https://www.youtube.com/watch?v=kmUGLURRPkI",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/kmUGLURRPkI/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Protecting Implicit Intents with Runtime Checks",
-    "titleFriendly":"",
-    "summary":"Make sure you protect your implicit intents with a simple runtime check.",
-    "url":"https://www.youtube.com/watch?v=HGElAW224dE",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/HGElAW224dE/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Tabs and ViewPager",
-    "titleFriendly":"",
-    "summary":"Showing multiple screens or pages of content is easy with the help of ViewPager and a PagerAdapter. Combining that with tabs make for an effective top level navigation strategy for your app or for moving between content at the same level of hierarchy within your app.",
-    "url":"https://www.youtube.com/watch?v=zQekzaAgIlQ",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/zQekzaAgIlQ/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Battery Drain and Networking",
-    "titleFriendly":"",
-    "summary":"Let’s take a moment to make something insanely clear: As far as battery is concerned, NETWORKING is the biggest, baddest, dirtiest offender there is. And optimizing performance here isn’t easy. Since the chip isn’t always awake and draining power, means you can optimize how it wakes up, sends traffic, and saves battery.",
-    "url":"https://www.youtube.com/watch?v=fEEulSk1kNY",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/fEEulSk1kNY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Batching Background Work Until Later",
-    "titleFriendly":"",
-    "summary":"Yes, your app is special. But when it comes to battery use, sometimes it’s better to be part of the crowd. Why not spread the battery blame around a bit? Ian Ni-Lewis shows you how ridiculously easy it is to go from battery hog to team player in this video.",
-    "url":"https://www.youtube.com/watch?v=-3ry8PxcJJA",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/-3ry8PxcJJA/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"The Performance Lifecycle",
-    "titleFriendly":"",
-    "summary":"Performance problems surface in your application at the least-wanted times (like right before you’re about to ship your first build). But don’t freak out: There’s a simple process that you can follow to help get your performance back under control.",
-    "url":"https://www.youtube.com/watch?v=_kKTGK-Cb_4",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/_kKTGK-Cb_4/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android Studio",
-    "titleFriendly":"",
-    "summary":"Learn why you should migrate your projects to Android Studio now and how it can help you be more productive as a developer. Rich layout editor, handy suggestions and fixes, new Android project view - these are just some of the things you can expect from the IDE, which is built on the successful IntelliJ IDEA.",
-    "url":"https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["studio", "tools"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/K2dodTXARqc/maxresdefault.jpg",
-    "type":"video"
-  },
-
-  {
-    "title":"Google Play Services 7.5",
-    "titleFriendly":"",
-    "summary":"This update brings App Invites, topics to GCM, GCMNetworkManager, Cast Remote Display API, Smart Lock for Passwords, Maps API for Android Wear, Google Fit extensions and more.",
-    "url":"https://www.youtube.com/watch?v=M3Udfu6qidk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/M3Udfu6qidk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Google Play Services 7.3",
-    "titleFriendly":"",
-    "summary":"This update brings the ability to connect multiple wearables simultaneously to a single phone. There are also some great new updates to Google Fit, including nutrition types, and to Location.",
-    "url":"https://www.youtube.com/watch?v=FOn64iqlphk&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/FOn64iqlphk/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Google Play Services 6.5",
-    "titleFriendly":"",
-    "summary":"Google Play services 6.5 includes new features in Google Maps, Google Drive and Google Wallet as well as the recently launched Google Fit API. ",
-    "url":"https://www.youtube.com/watch?v=fvtMtfCuEpw&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/fvtMtfCuEpw/maxresdefault.jpg",
-    "type":"video"
-  },
-    {
-    "title":"Google Play Services 7.0",
-    "titleFriendly":"",
-    "summary":"Google Play services 7.0 is here! we've added the Places API, made enhancements to Location and Google Fit, and you can also remote control your Android TV through the new Nearby Connections API.",
-    "url":"https://www.youtube.com/watch?v=F0Kh_RnSM0w&list=PLWz5rJ2EKKc9Qk1_iCZNbBp6adYnJf9Vf",
-    "group":"",
-    "keywords": ["google play services"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/F0Kh_RnSM0w/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Running a Successful Games Business with Google",
-    "titleFriendly":"",
-    "summary":"Sure, we all want to make the next great gaming masterpiece. But we also want to feed our families and/or dogs. Join Bob Meese from the Google Play team as he gives you some key pointers on how to make sure you're best taking advantage of Google Play and running a successful games business.",
-    "url":"https://www.youtube.com/watch?v=tDmnGNkTtlE",
-    "group":"",
-    "keywords": [],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/tDmnGNkTtlE/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android TV",
-    "titleFriendly":"",
-    "summary":"Android TV brings the Android platform to the living room with rich content and entertaining app experiences. In this video, Timothy introduces the design philosophy and developer components that make building TV experiences easier than ever before.",
-    "url":"https://www.youtube.com/watch?v=6K_jxccHv5M&index=1&list=PLOU2XLYxmsILFBfx66ens76VMLMEPJAB0",
-    "group":"",
-    "keywords": ["tv"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/6K_jxccHv5M/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Introduction to Android Auto",
-    "titleFriendly":"",
-    "summary":"Android Auto brings the Android platform to the car in a way that's optimized for the driving experience. It's the same platform you already use for phones, tablets, televisions, wearables, and more. ",
-    "url":"https://www.youtube.com/watch?v=ctiaVxgclsg&list=PLWz5rJ2EKKc9BdE_PSLNIGjXXr3h_orXM",
-    "group":"",
-    "keywords": ["auto"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/ctiaVxgclsg/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Debugging and testing in Android Studio",
-    "titleFriendly":"",
-    "summary":"This video introduces the state of unit testing support in Studio and Google’s new Android Testing Support Library for functional UI testing and running instrumented tests on a device.",
-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"Android Testing (Android Dev Summit 2015)",
-    "titleFriendly":"",
-    "summary":"Overview of the testing tools and frameworks provided by Google and how they can help you to iterate more quickly and maintain a more healthy codebase.",
-    "url":"https://www.youtube.com/watch?v=vdasFFfXKOY",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"https://i1.ytimg.com/vi/vdasFFfXKOY/maxresdefault.jpg",
-    "type":"video"
-  },
-  {
-    "title":"dumpsys",
-    "titleFriendly":"",
-    "summary":"A tool that runs on the device and provides information about the status of system services.",
-    "url":"https://source.android.com/devices/tech/debug/dumpsys.html",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"",
-    "type":"google"
-  },
-  {
-    "title":"Android Testing Samples",
-    "titleFriendly":"",
-    "summary":"A collection of samples demonstrating different frameworks and techniques for automated testing.",
-    "url":"https://github.com/googlesamples/android-testing",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-  {
-    "title":"Android Testing Templates",
-    "titleFriendly":"",
-    "summary":"A collection of Google's Android testing tools and frameworks, all integrated in a single application project.",
-    "url":"https://github.com/googlesamples/android-testing-templates",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-   {
-    "title":"Android Testing Support Library (GitHub)",
-    "titleFriendly":"",
-    "summary":"A resource page on GitHub for the Android Testing Support Library.",
-    "url":"https://google.github.io/android-testing-support-library",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"Samples"
-  },
-  {
-    "title":"Android Testing Codelab",
-    "titleFriendly":"",
-    "summary":"This codelab shows how to build an Android app from the ground up in Android Studio, using a Model View Presenter architecture, Unit Tests and Instrumentation Tests.",
-    "url":"https://codelabs.developers.google.com/codelabs/android-testing/index.html",
-    "group":"",
-    "keywords": ["testing"],
-    "tags": [
-    ],
-    "image":"images/testing/testing-icon.png",
-    "type":"google"
-  },
-  {
-    "title":"Developer Registration",
-    "titleFriendly":"",
-    "summary":"Additional information about the registration process.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title": "Google Play Distribution and Seller Countries",
-    "titleFriendly":"",
-    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title": "支持向Google Play用户发布应用的地区",
-    "lang": "zh-cn",
-    "titleFriendly":"",
-    "summary": "支持向Google Play用户发布应用的国家/地区。",
-    "url":"https://support.google.com/googleplay/android-developer/answer/138294?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Content Policies",
-    "titleFriendly":"",
-    "summary":"Details on policies relating to your developer account and app distribution is governed.",
-    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
-    "group":"",
-    "keywords": [],
-    "tags": ["#developersupport"],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Badge Generator",
-    "titleFriendly":"",
-    "summary":"Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.",
-    "url":"https://play.google.com/intl/en_us/badges/",
-    "group":"",
-    "keywords": [],
-    "tags": ["#developersupport"],
-    "image":"images/gp-badges-set.png",
-    "type":"google"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["#developersupport #termsandpolicies"],
-    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
-    "timestamp": 1194884220000,
-    "image": 'images/play_dev.jpg',
-    "title": "Google Play Terms and Policies",
-    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "title":"Google Play Policy Center",
-    "titleFriendly":"",
-    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
-    "type":"google"
-  },
-  {
-    "title":"Google Play应用政策中心",
-    "titleFriendly":"",
-    "summary":"一个方便你了解Google Play政策和指南的中心资源。",
-    "url":"https://support.google.com/googleplay/android-developer/answer/4430948?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
-    "type":"google"
-  },
-  {
-    "title":"Developer Help Center",
-    "titleFriendly":"",
-    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
-    "url":"https://support.google.com/googleplay/android-developer",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/google-play_2x.png",
-    "type":"google"
-  },
-  {
-    "title":"开发者帮助中心",
-    "titleFriendly":"",
-    "summary":"完整资料帮助开发者新手入手,发布,故障排除,等等",
-    "url":"https://support.google.com/googleplay/android-developer?hl=zh-Hans",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/play_dev.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Google for Education",
-    "titleFriendly":"",
-    "summary":"Find out more about how Google can support your work with apps and tablets.",
-    "url":"https://www.google.com/edu/tablets/",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"distribute/images/gp-edu-apps-image.jpg",
-    "type":"google"
-  },
-  {
-    "title":"Keeping Your App Responsive",
-    "titleFriendly":"",
-    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
-    "url":"training/articles/perf-anr.html",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"",
-    "type":"google"
-  },
-  {
-    "title":"Google Play Game Services",
-    "titleFriendly":"",
-    "summary":"Make your games social with Google Play game services. Add achievements, leaderboards, real-time multiplayer, and other popular features using the Google Play game services SDK.",
-    "url":"https://developers.google.com/games/services/",
-    "group":"",
-    "keywords": ["games","play games"],
-    "tags": [],
-    "image":"images/google/gps-play_games_logo.png",
-    "type":"google"
-  },
-  {
-    "title":"Get Started with Analytics",
-    "titleFriendly":"",
-    "summary":"Get advanced insight into how players discover and play your games.",
-    "url":"distribute/analyze/start.html",
-    "group":"",
-    "keywords": ["analytics"],
-    "tags": [],
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "type": "distribute"
-  },
-  {
-    "title":"Build VR with Google Cardboard",
-    "titleFriendly":"",
-    "summary":"Turn any phone into a virtual reality headset with a Cardboard viewer and experiment with adding virtual reality to your games with the Cardboard SDK.",
-    "url":"distribute/googleplay/cardboard.html",
-    "group":"",
-    "keywords": ["cardboard"],
-    "tags": [],
-    "image":"images/cards/card-cardboard_2x.png",
-    "type": "distribute"
-  },
-  {
-    "title":"Monetize your apps intelligently",
-    "titleFriendly":"",
-    "summary":"Generate revenue from your free games with ads tailored to match your game's look and feel.",
-    "url":"https://www.google.com/admob/",
-    "group":"",
-    "keywords": ["AdMob"],
-    "tags": [],
-    "image":"images/cards/admob-analytics_2x.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "versions", "blog", "googleplay"
-    ],
-    "url": "https://android-developers.blogspot.com/",
-    "timestamp": 1004884220000,
-    "image": "images/blog.jpg",
-    "title": "Android Developers Blog",
-    "summary": "Follow the latest news on Android design, development, and distribution.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Making Android Apps that Play Nice",
-    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Multithreading for Performance",
-    "summary": "Ways to improve performance through multi-threading.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-content-policy.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Developer Program Policies",
-    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
-    "keywords": [],
-    "type": "google",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Rating your application content for Google Play",
-    "summary": "How to choose the appropriate content ratings level for your apps.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["devices", "nexus", "testing"],
-    "url": "https://developers.google.com/android/nexus/images",
-    "timestamp": 1194884220000,
-    "image": "images/cards/card-download_16-9_2x.png",
-    "title": "Factory Images for Nexus Devices",
-    "summary": "System image files for Android 6.0 and other Android releases.",
-    "keywords": ["nexus, downloads"],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/188189?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "针对Google Play为你的应用内容分级",
-    "summary": "如何为你的应用内容分级。",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Featured Image Guidelines",
-    "summary": "How to create attractive, effective Featured Images for your apps.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-{
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Supporting your users",
-    "summary": "Options for supporting users.",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-{
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113477?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "为用户提供支持",
-    "summary": "为用户提供支持的各种选择。",
-    "keywords": [],
-    "type": "support",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/practices/screens_support.html#ConfigurationExamples",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Configuration examples",
-    "summary": "How to declare layouts and other resources for specific screen sizes.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/design-navigation/multiple-sizes.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Planning for Multiple Touchscreen Sizes",
-    "summary": "",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/multiscreen/index.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Designing for Multiple Screens",
-    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/providing-resources.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Providing Resources",
-    "summary": "Layouts and drawable resources for specific ranges of device screens.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/basics/supporting-devices/screens.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Supporting Different Screens",
-    "summary": "Optimizing the user experience for different screen sizes and densities.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/appwidgets/index.html#MetaData",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Adding the AppWidgetProviderInfo Metadata",
-    "summary": "How to set the height and width dimensions of a widget.",
-    "keywords": [],
-    "type": "design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Android API Levels",
-    "summary": "Introduction to API levels and how they relate to compatibility.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Declaring screen size support",
-    "summary": "How to declare support for screen sizes in your app\'s manifest.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "training/material/animations.html#Touch",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Customize Touch Feedback",
-    "summary": "Provide visual confirmation when users interact with your UI.",
-    "keywords": [],
-    "type": "develop",
-    "category": "guide"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/manifest/uses-feature-element.html#testing",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Checking for hardware feature requirements",
-    "summary": "Determining an app’s hardware and software requirements.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/apps/publish/",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Google Play Developer Console",
-    "summary": "The tools console for publishing your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/apps/publish/?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Google Play 开发者控制台",
-    "summary": "发布应用的开发者控制台",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://youtu.be/SkHHPf3EdzE",
-    "timestamp": 1194884220000,
-    "image": "https://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
-    "title": "Level Up Your Android Game",
-    "summary": "Learn how to take your game to the next level on Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Sharing interactive posts to Google+ from your Android app",
-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
-    "keywords": ["Interactive", "Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-distribution-agreement.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Developer Distribution Agreement",
-    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Inappropriate content in comments and applications",
-    "summary": "More details on what content is appropriate.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/legal/troubleshooter/1114905",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Removing content from Google",
-    "summary": "Find how how to request the removal of content that infringes on your trademark.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://play.google.com/about/developer-distribution-agreement-addendum.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play for Education Addendum",
-    "summary": "Review the education-specific requirements.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
-    "timestamp": null,
-    "image": null,
-    "title": "Native RTL Support in Android 4.2",
-    "summary": "Blog post that explains how to support RTL in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/string-resource.html#Plurals",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Quantity Strings (Plurals)",
-    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "reference/java/util/Locale.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Locale",
-    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-    {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/string-resource.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "String Resources",
-    "summary": "Explains how to use string resources in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "distribute/tools/localization-checklist.html#strings",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Manage strings for localization",
-    "summary": "Guidance on having your strings translation ready.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/publishing/publishing_overview.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "General Publishing Overview",
-    "summary": "Start here for an overview of publishing options for Android apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/publishing/preparing.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Preparing for Release",
-    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "distribute/googleplay/policies/index.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Policies and Guidelines",
-    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Policy and Best Practices",
-    "summary": "Help Center document describing various content policies and processes.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2364761?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "政策和最佳做法",
-    "summary": "内容政策和流程",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "google/play/expansion-files.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "APK Expansion Files",
-    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "tools/help/proguard.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "ProGuard",
-    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "title":"Dashboards",
-    "titleFriendly":"",
-    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
-    "url":"about/dashboards/index.html",
-    "group":"",
-    "keywords": ["android","dashboard","platforms","versions"],
-    "tags": ["#ecosystem","#versions","#whatsnew"],
-    "image":"https://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
-    "lang":"en",
-    "type":"about"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/wallet/instant-buy/",
-    "timestamp": 1194884220000,
-    "image": "",
-    "title": "Android Pay APIs",
-    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Selling Apps in Multiple Currencies",
-    "summary": "Help Center document describing how pricing works in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1169947?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "以多种货币销售应用",
-    "summary": "如何在Google Play为应用定价",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Prices and supported currencies",
-    "summary": "Help Center document listing supported currencies for pricing your apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-    {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138412?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "各国家/地区获许定价范围和货币",
-    "summary": "各国家/地区获许定价范围和货币列表",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Transaction Fees",
-    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/112622?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "交易费用",
-    "summary": "销售的应用和应用内产品的交易费。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Specifying tax rates",
-    "summary": "Help Center document describing how to set tax rates for different countries.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/138000?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "税率",
-    "summary": "如何设置不同国家/地区的税率",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "guide/topics/resources/localization.html",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Localizing with Resources",
-    "summary": "Developer guide to localizing resources in your app.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Category types",
-    "summary": "Help Center document listing available categories for apps.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113475?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "类别",
-    "summary": "应用的类别列表。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Updates",
-    "summary": "Requirements for app updates in Google Play.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/113476?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "更新应用",
-    "summary": "更新Google Play应用的要求。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "In-app Billing",
-    "summary": "Help Center document describing how to correctly set up In-app Billing.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1153479?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "应用内结算",
-    "summary": "如何正确设置应用内商品和订阅结算。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gpfe",
-      "#googleplay"
-    ],
-    "url": "https://youtu.be/vzvpcEffvaE",
-    "timestamp": 1383243492000,
-    "image": "https://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
-    "title": "Introducing Tablets with Google Play for Education",
-    "summary": "Schools in Hillsborough, New Jersey were among the first to try out Nexus 7 tablets with Google Play for Education. See the difference it made for students, teachers, and administrators.",
-    "keywords": [],
-    "type": "video",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#engagement",
-    ],
-    "url": "https://www.youtube.com/yt/dev/",
-    "timestamp": 1383243492000,
-    "image": "https://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
-    "title": "YouTube for Developers",
-    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
-    "keywords": [],
-    "type": "youtube",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#engagement",
-    ],
-    "url": "https://www.google.com/analytics/mobile/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics",
-    "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
-    "keywords": ["analytics,user behavior"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gcm",
-    ],
-    "url": "https://www.youtube.com/watch?v=y76rjidm8cU",
-    "timestamp": 1383243492000,
-    "image": "https://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
-    "title": "Google Cloud Messaging at I/O 2013",
-    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
-    "keywords": ["gcm"],
-    "type": "youtube",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#gcm",
-    ],
-    "url": "https://developer.chrome.com/apps/cloudMessagingV2",
-    "timestamp": 1383243492000,
-    "image": "images/kk-chromium-icon.png",
-    "title": "Google Cloud Messaging for Chrome",
-    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
-    "keywords": ["gcm"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Make Beautiful Android App Icons",
-    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-     {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Localize Your Promotional Graphics",
-    "summary": "Learn how to capitalise on international audiences.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-   {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "#sdkupdates"
-    ],
-    "url": "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Make your App Content more Accessible with App Linking",
-    "summary": "About using search and deep linking to get more users.",
-    "keywords": [],
-    "type": "blog",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Sharing interactive posts to Google+ from your Android app",
-    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
-    "keywords": ["Interactive", "Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/",
-    "timestamp": 1194884220000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Google+ Platform",
-    "summary": "Find out about features such as interactive posts, Hangouts, accessing basic user details and their social graphs to make your app more personal.",
-    "keywords": ["Google+"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
-    "summary": "",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Adding deep linking to Google+ posts shared from your Android app",
-    "summary": "",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "google/play/licensing/index.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Application Licensing",
-    "summary": "Information on the features of Google Play to protect your apps’ licences.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "design/style/writing.html",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "Writing Style",
-    "summary": "Android Design guidelines for voice and style in your UI.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://en.wikipedia.org/wiki/XLIFF",
-    "timestamp": 1194884220000,
-    "image": null,
-    "title": "XML Localisation Interchange File Format (XLIFF)",
-    "summary": "Background information on XLIFF.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "Graphic Assets for your Application",
-    "summary": "Details about the graphics you can add to your product listing.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/googleplay/android-developer/answer/1078870?hl=zh-Hans",
-    "timestamp": 1194884220000,
-    "image": "images/play_dev.jpg",
-    "title": "为你的应用的图片资源",
-    "summary": "如何在你的应用的商品详情页面上添加图片资源。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/payments/answer/2741495",
-    "timestamp": null,
-    "image": null,
-    "title": "Issuing Refunds",
-    "summary": "Help Center document describing how to issue refunds.",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/payments/answer/2741495?hl=zh-Hans",
-    "timestamp": null,
-    "image": null,
-    "title": "退回訂單款項",
-    "summary": "如何退还已收取的订单款项。",
-    "keywords": [],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
-    "timestamp": null,
-    "image": "distribute/images/gp-edu-apps-image.jpg",
-    "title": "Google play for education",
-    "summary": " ",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["localization", "pricing", "developer support"],
-    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Supported locations for distributing your apps in Google Play",
-    "summary": "Countries and regions where you can distribute your app in Google Play.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": ["localization", "pricing", "developer support"],
-    "url": "https://support.google.com/googleplay/android-developer/table/3541286?hl=zh-Hans",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "支持向Google Play用户发布应用的地区",
-    "summary": "支持向Google Play用户发布应用的国家/地区。",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["games", "localization", "quality"],
-    "url": "https://www.youtube.com/watch?v=SkHHPf3EdzE",
-    "timestamp": null,
-    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
-    "title": "Level Up Your Android Game",
-    "summary": "Learn how to take your game to the next level in this Google I/O session.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support"],
-    "url": "https://support.google.com/groups/answer/46601",
-    "timestamp": null,
-    "image": null,
-    "title": "Google Groups",
-    "summary": "Create a group for your community.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support"],
-    "url": "https://support.google.com/plus/topic/2888488",
-    "timestamp": null,
-    "image": null,
-    "title": "Google+ Communities",
-    "summary": "Host a Google+ community for testers or users.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "ads"],
-    "url": "https://www.google.com/doubleclick/publishers/small-business/index.html",
-    "timestamp": null,
-    "image": "https://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
-    "title": "DoubleClick for Publishers",
-    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
-    "keywords": ["ads"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "ads"],
-    "url": "https://support.google.com/googleplay/android-developer/topic/2985714",
-    "timestamp": null,
-    "image":"images/play_dev.jpg",
-    "title": "Policy Center: Ads",
-    "summary": "Introduction to ads and system interference policies in Google Play.",
-    "keywords": ["ads"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611404",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Create Audience lists in Google Analytics",
-    "summary": "Find out how to use your analytics data to discover high value users and create remarketing audiences to use in AdMob.",
-    "keywords": ["ads, analytics, monetize"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://admob.blogspot.com/",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Inside Admob",
-    "summary": "Google’s official blog for news, tips, and information on the AdMob developer platform.",
-    "keywords": ["ads, analytics, monetize"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3111064",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob in-app conversion tracking",
-    "summary": "Use in-app conversion tracking to attribute revenue back to your IAP promotion campaigns and determine which ones earn you the most.",
-    "keywords": ["ads, analytics, conversions"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "giftcards"],
-    "url": "https://play.google.com/about/giftcards/",
-    "timestamp": null,
-    "image": "images/gp-balance.png",
-    "title": "Google Play Gift Cards",
-    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
-    "keywords": ["gift card"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["monetize", "paymentmethods"],
-    "url": "https://support.google.com/googleplay/answer/2651410",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play accepted payment methods",
-    "summary": "Support details on the payment methods supported in Google Play.",
-    "keywords": ["gift card"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/2471188",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "AdWords Conversion Optimizer",
-    "summary": "Learn how Conversion Optimizer works to find the users who are most likely to convert and to serve them your conversion ads.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-conversion-tracking/",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Track conversions with the AdWords SDK or server API",
-    "summary": "Use the lightweight AdWords app SDK or server-to-server API to track remarketing conversions.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611404",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Create Remarketing Audiences in Google Analytics",
-    "summary": "Learn how to use preconfigured audiences created by the Analytics team or create your own to use in your conversion campaigns.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/1704341",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Link your Google Analytics and AdWords accounts",
-    "summary": "Gain greater insight into how AdWords is driving app engagement and conversions, and use this insight to improve your ads and app.",
-    "keywords": [],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["plus", "social"],
-    "url": "https://plus.google.com/+AndroidDevelopers/",
-    "timestamp": null,
-    "image": "images/plus.jpg",
-    "title": "+Android Developers",
-    "summary": "Sharing news, ideas, and techniques for success.",
-    "keywords": ["+AndroidDevelopers"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["plus", "social"],
-    "url": "https://plus.google.com/+GooglePlay",
-    "timestamp": null,
-    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
-    "title": "+Google Play",
-    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
-    "keywords": ["+GooglePlay"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["support", "android"],
-    "url": "support.html",
-    "timestamp": null,
-    "image": null,
-    "title": "Developer Support",
-    "summary": "Links to community and support resources for Android developers.",
-    "keywords": ["support"],
-    "type": "Google+",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics SDK",
-    "summary": "Measure everything about your app. Get started with the Google Analytics SDK for Android.",
-    "keywords": ["analytics, user behavior"],
-    "type": "sdk",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/guidelines",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
-    "title": "Education Guidelines",
-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "zh-cn",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/guidelines?hl=zh-Hans",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/edu-guidelines.jpg",
-    "title": "Education Guidelines",
-    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/faq",
-    "timestamp": null,
-    "image": "https://developer.android.com/distribute/images/gpfe-faq.jpg",
-    "title": "Education FAQ",
-    "summary": "Answers to common questions you might have about Google Play for Education.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/edu/",
-    "timestamp": null,
-    "image": "https://developers.google.com/edu/images/home-android.png",
-    "title": "Chrome Apps in Google Play for Education",
-    "summary": "Find out more about Chrome apps in Google Play for Education.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/edu/tablets/#tablets-family",
-    "timestamp": null,
-    "image": "https://www.google.com/edu/images/tablets/big-tablet.png",
-    "title": "Google Play for Education Tablets",
-    "summary": "Google Play for Education leverages a diverse set up tablets approved for the classroom which may help inform you how to build educational apps.",
-    "keywords": [],
-    "type": "",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.png",
-    "title": "Deer Hunter 2014 by Glu &mdash; Sign-in",
-    "summary": "Glu finds that Google Play Game Services helps improve the user experience which leads to increased player happiness. They also find that Play Games Services signed in users tend to play longer and have a higher lifetime value.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.png",
-    "title": "PBA® Bowling Challenge by Concrete Software &mdash; Quests",
-    "summary": "Concrete Software finds that Google Play Game Services' quests are a great way to create new content for users that leads to higher engagement.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.png",
-    "title": "Dragonplay Slots by Dragonplay &mdash; Sign-in",
-    "summary": "Dragonplay finds that players who sign in with Google Play Games services tend to be high quality users who were highly engaged. They also tend to be easier to convert to paying users.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.png",
-    "title": "Asphalt 8 by Gameloft &mdash; Friends invitations",
-    "summary": "Gameloft finds that Google Play Game Services users are more engaged than the average Android user and more likely to convert to paying players.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.png",
-    "title": "Eternity Warriors 3 by Glu &mdash; Gifting",
-    "summary": "Glu finds that Google Play Game Services gifting outperforms other implementations (including those with incentives) because of its seamless flow and consistent performance.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.jpg",
-    "title": "Rivals at War: Firefight by Hothead Games &mdash; Leaderboards",
-    "summary": "Hothead Games is planning to include Google Play Game Services features in all their games going forwards after seeing that players that signed in with Play Games Services tend to show higher retention and a higher average revenue.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.png",
-    "title": "Compulsive by TMSOFT &mdash; Cross-platform",
-    "summary": "TMSOFT finds that users who authenticate with Play Games Services on Android and iOS play Compulsive twice as much and purchase in-app products over four times as much.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.png",
-    "title": "Super Stickman Golf 2 by Noodlecake Studios &mdash; Multiplayer",
-    "summary": "Noodlecake Studios finds that Google Play Game Services’ multiplayer feature helps reduce attrition.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebelGames_DrWhoLegacy_pgps.png",
-    "title": "Dr. Doctor Who: Legacy by Tiny Rebel Games &mdash; Achievements",
-    "summary": "After integrating achievements and cloud services from Google Play Game Services, Tiny Rebel Games saw a dramatic increase in daily revenues as a result of an increase in daily installs and an increase in the average revenue per install.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf",
-    "timestamp": null,
-    "image": "https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.png",
-    "title": "Leo’s Fortune by 1337 &amp; Senri &mdash; Saved games",
-    "summary": "1337 + Senri finds that Google Play Game Services is easy to integrate and provides essential game functions like cloud saved games, achievements and leaderboards which have a very large adoption rate amongst players.",
-    "keywords": ["stories"],
-    "type": "Case Study Deck",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": ["play,protips"],
-    "url": "shareables/distribute/secrets_play/v2/web/secrets_to_app_success_v2_en.pdf",
-    "timestamp": 1447437450,
-    "image": "images/distribute/secrets_v2_banner.jpg",
-    "title": "The Secrets to App Success on Google Play",
-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
-    "keywords": ["secrets, success, play, google"],
-    "type": "Book",
-    "category": "distribute"
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-audio-apps.pdf",
-    "timestamp": null,
-    "image": "auto/images/assets/icons/media_app_playback.png",
-    "title": "Android Auto Audio Apps UI Guidelines",
-    "summary": "Guidelines for designing audio apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-messaging-apps.pdf",
-    "timestamp": null,
-    "image": "auto/images/assets/icons/messaging_app_notifications.png",
-    "title": "Android Auto Messaging Apps UI Guidelines",
-    "summary": "Guidelines for designing messaging apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "shareables/auto/AndroidAuto-custom-colors.pdf",
-    "timestamp": null,
-    "image": "auto/images/ui/gearhead_generic_UI.png",
-    "title": "Android Auto Color Customization UI Guidelines",
-    "summary": "Guidelines for color-customizing apps that work with Auto. ",
-    "keywords": ["design", "Auto", "Automotive"],
-    "type": "Design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "http://www.youtube.com/watch?v=RRelFvc6Czo",
-    "timestamp": null,
-    "image": "https://i1.ytimg.com/vi/RRelFvc6Czo/maxresdefault.jpg",
-    "title": "Android Developer Story: Smule",
-    "summary": "The creators of AutoRap, Magic Piano, and Songify talk about their experiences launching on Android and the explosive global growth they've seen on Google Play.",
-    "keywords": ["success", "users"],
-    "type": "video",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/solutions/mobile-implementation-guide",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile Analytics Implementation Guide",
-    "summary": "Learn how you can implement additional Google Analytics features to better understand your users and their behavior.",
-    "keywords": ["analytics", "Play", "users"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/tagmanager/",
-    "timestamp": null,
-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
-    "title": "Google Tag Manager",
-    "summary": "Google Tag Manager enables you to change configuration values in your mobile apps using the Google Tag Manager interface, without having to rebuild and resubmit application binaries to app marketplaces.",
-    "keywords": ["analytics", "tagmanager"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://analyticsacademy.withgoogle.com/course04",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Mobile App Analytics Fundamentals",
-    "summary": "This self-paced online course on mobile app measurement shows you how Google Analytics data can help you make your app more discoverable and profitable.",
-    "keywords": ["analytics"],
-    "type": "Open Source Project",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://github.com/googleanalytics/google-analytics-plugin-for-unity",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Analytics Plugin for Unity",
-    "summary": "If you're building games with Unity, you can now implement Analytics once and ship it on multiple platforms automatically.",
-    "keywords": ["analytics", "unity"],
-    "type": "Open Source Project",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/enhanced-ecommerce",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "In-App Purchases & Ecommerce",
-    "summary": "If your app sells virtual or real goods, ecommerce tracking can help you understand what behaviors lead to purchases.",
-    "keywords": ["analytics, ecommerce"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1032415",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Goals",
-    "summary": "Track important actions in your app as goals and measure performance against your objectives.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2568874?ref_topic=6012392",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Active Users",
-    "summary": "The active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you analyze performance over time.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/events",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Events",
-    "summary": "Events let you measure granular in-app activities and understand user journeys.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/customdimsmets",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Custom Dimensions",
-    "summary": "Custom dimensions enable the association of metadata with hits, users, and sessions in Google Analytics.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/user-id",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "User ID",
-    "summary": "The User ID feature enables Google Analytics to measure user activities that span across devices.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/display-features",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Demographic Reporting",
-    "summary": "By enabling display features, you can see just how different user segments engage and monetize.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/3123906",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "User Segmentation",
-    "summary": "Segments let you compare metrics for different subsets of users to identify trends and opportunities for your apps.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Campaign Tracking",
-    "summary": "Measuring campaigns in Google Analytics enables the attribution of campaigns and traffic sources to user activity within your app.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2956981",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Google Play Integration",
-    "summary": "By linking Analytics and the Play Developer Console, you can gain additional insights into the acquisition flow.",
-    "keywords": ["play, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1033961",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdWords Integration",
-    "summary": "Link Analytics and AdWords to see the entire picture of customer behavior, from ad click or impression through your site to conversion. ",
-    "keywords": ["adwords, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Campaign URL builder for Google Play",
-    "summary": "Easily create your URLs to track install campaigns.",
-    "keywords": ["play, analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/tagmanager/answer/6003007",
-    "timestamp": null,
-    "image": "https://www.google.com/tagmanager/images/gtm-hero-illustration-small.png",
-    "title": "In-App A/B Testing",
-    "summary": "With content experiments in Google Tag Manager you can test multiple variations of your app to find which works best.",
-    "keywords": ["tagmanager"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2785577",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Behavior Flow",
-    "summary": "The Behavior Flow report visualizes the path users traveled from one Screen or Event to the next. This report can help you discover what content keeps users engaged with your app.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/1151300",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Custom Reports",
-    "summary": "Custom Reports let you create your own reports in your Google Analytics account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2611268",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Audience Lists &amp; Remarketing",
-    "summary": "Remarketing with Google Analytics lets you deliver targeted ads to users who've already been to your site or app. You can even base those ads on the behavior those users displayed during their sessions.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3508177",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdMob Integration",
-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/analytics/solutions/mobile-campaign-deep-link",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Deep-Linking",
-    "summary": "Google Analytics gives you a full view of how returning users are interacting with your app, for a holistic view beyond the install.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/3508177",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "AdMob Integration",
-    "summary": "With Google Analytics in AdMob, you can view Google Analytics data for your linked apps from within your AdMob account.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/analytics/answer/2568874",
-    "timestamp": null,
-    "image": "images/cards/analytics-mobile_2x.jpg",
-    "title": "Active User Report",
-    "summary": "Active user report displays your 1-day, 7-day, 14-day and 30-day trailing active users next to each other, to help you run benchmark analyses of their performance over time.",
-    "keywords": ["analytics"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/animation/",
-    "timestamp": null,
-    "image": "images/cards/material-animation_2x.png",
-    "title": "Animation",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/style/",
-    "timestamp": null,
-    "image": "images/cards/material-style_2x.jpg",
-    "title": "Style",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/layout/",
-    "timestamp": null,
-    "image": "images/cards/material-layout_2x.png",
-    "title": "Layout",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/components/",
-    "timestamp": null,
-    "image": "images/cards/material-components_2x.jpg",
-    "title": "Components",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/patterns/",
-    "timestamp": null,
-    "image": "images/cards/material-patterns_2x.png",
-    "title": "Patterns",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/usability/",
-    "timestamp": null,
-    "image": "images/cards/material-usability_2x.png",
-    "title": "Usability",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/color-palettes.html",
-    "timestamp": null,
-    "image": "images/cards/material-color-palette_2x.jpg",
-    "title": "Color Palettes",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/layout-templates.html",
-    "timestamp": null,
-    "image": "images/cards/material-layout-template_2x.jpg",
-    "title": "Layout Templates",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/sticker-sheets-icons.html",
-    "timestamp": null,
-    "image": "images/cards/material-sticker-sheet_2x.jpg",
-    "title": "Sticker Sheets & Icons",
-    "summary": "",
-    "keywords": [],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.google.com/design/spec/resources/roboto-noto-fonts.html",
-    "timestamp": null,
-    "image": "images/cards/material-typography_2x.jpg",
-    "title": "Typography: Roboto and Noto Sans fonts",
-    "summary": "",
-    "keywords": [],
-    "type": "materialdesign",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "icons",
-      "material",
-      "iconography"
-    ],
-    "url": "https://www.google.com/design/icons/index.html",
-    "timestamp": null,
-    "image": "images/cards/card-material-icons-16x9_2x.jpg",
-    "title": "Material icon collection",
-    "summary": "",
-    "keywords": ["icons"],
-    "type": "material design",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/6032059",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Setting up Mobile App Install Ads",
-    "summary": "With Mobile app installs campaigns on the Search and Display Networks, and TrueView for mobile app promotion on YouTube, you can create custom app install ads that run exclusively on phones and tablets.",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/nearby/",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Create features based on proximity",
-    "summary": "Build simple interactions between nearby devices and people.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.youtube.com/watch?v=hultDpBS22s",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Use Nearby Messages to collaborate",
-    "summary": "Nearby Messages is perfect for setting up ad-hoc groups, collaborative sessions, or sharing resources with people in a co-located space.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/beacons",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Mark up the world using beacons",
-    "summary": "Give your users better location and proximity experiences by providing a strong context signal for their devices in the form of Bluetooth low energy (BLE) beacons with Eddystone.",
-    "keywords": ["nearby", "engage"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/adwords/answer/6167164",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Best practices for Mobile App Engagement",
-    "summary": "Learn how to market to your user base to drive re-engagement with your app. ",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement",
-      "adwords1"
-    ],
-    "url": "https://support.google.com/adwords/answer/6032073",
-    "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
-    "title": "Setting up Mobile App Engagement Ads",
-    "summary": "Mobile app engagement campaigns are a great choice for advertisers focused on connecting with people who already have their app.",
-    "keywords": [
-      "marketing",
-      "engagement",
-      "adwords"
-    ],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement",
-      "translate"
-    ],
-    "url": "https://support.google.com/l10n/answer/6359997",
-    "timestamp": null,
-    "image": "images/play_dev.jpg",
-    "title": "Use the App Translation Service",
-    "summary": "The App Translation Service is a human translation service. It makes it easy to order translations for app UI strings, Play Store text, in-app purchase products, and universal app campaign ads.",
-    "keywords": [
-      "marketing",
-      "engagement",
-      "translate"
-    ],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [
-      "marketing",
-      "engagement"
-    ],
-    "url": "https://support.google.com/adwords/answer/6167162",
-    "timestamp": null,
-    "image": "https://www.gstatic.com/images/icons/material/product/2x/adwords_64dp.png",
-    "title": "Best Practices for Mobile App Installs",
-    "summary": "Getting your mobile app discovered can be challenging. Learn how to drive downloads of your app and grow a valuable user base.",
-    "keywords": ["marketing", "adwords"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/topic/2784623",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Set up your AdMob account",
-    "summary": "Setting up your AdMob account in the right way will help you get the most value, check out the Setup and Basics guide.",
-    "keywords": ["marketing", "admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-    },
-    {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://analyticsacademy.withgoogle.com/mobile-app",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Analytics Academy for Mobile Apps",
-    "summary": "Learn how to use Google Analytics to make your app more discoverable and profitable.",
-    "keywords": ["marketing", "analytics"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://www.udacity.com/courses/ud876-3",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Learn how to show ads in your Android app",
-    "summary": "Take this online course to learn how to use AdMob to display ads in your Android app.",
-    "keywords": ["marketing", "analytics"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/mobile-ads-sdk/download",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "Admob Ads",
-    "summary": "Use the Mobile Ads SDK to start showing AdMob ads in your apps.",
-    "keywords": ["marketing", "adwords"],
-    "type": "Guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob Help Center",
-    "summary": "For setup assistance, general info, and fixes for specific problems check out the AdMob Help Center.",
-    "keywords": ["admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://support.google.com/admob/answer/2753860",
-    "timestamp": null,
-    "image": "distribute/images/advertising.jpg",
-    "title": "AdMob Policy Guidelines",
-    "summary": "Learn about best practices for displaying AdMob ads in your apps to maximize revenue.",
-    "keywords": ["admob"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-invites/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Set up App Invites",
-    "summary": "Bring new users to your apps with personal recommendations, incentives, and offers.",
-    "keywords": ["invites", "appinvites", "engagement", "getusers"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-indexing/",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Set Up App Indexing",
-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
-    "keywords": ["search", "appindexing", "engagement", "getusers"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/app-indexing/webmasters/details",
-    "timestamp": null,
-    "image": "images/cards/google-search_2x.png",
-    "title": "Index your app",
-    "summary": "Index your app today by adding deep links and verifying its official web site to ensure it starts appearing in Google Search results. ",
-    "keywords": ["appindexing","search","getusers"],
-    "type": "distribute",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/identity/sign-in/android/people",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Get user profile details",
-    "summary": "After users sign-in with Google, you can access their age range, language, and public profile information.",
-    "keywords": ["signin", "identity", "google"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
-
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/identity/sign-in/android/",
-    "timestamp": "",
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Google Sign-In",
-    "summary": "Discover how you can enhance user experiences on your website or in your app using information provided by their Google identity.",
-    "keywords": ["signin", "identity", "google"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/features/play-installs",
-    "timestamp": 1383243492000,
-    "image": "images/cards/google-sign-in_2x.png",
-    "title": "Over-the-air installs",
-    "summary": "Follow this step-by-step guide to quickly add Google Sign-in and over-the-air app installs to your website.",
-    "keywords": ["signin", "google", "installs"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-  {
-    "lang": "en",
-    "group": "",
-    "tags": [],
-    "url": "https://developers.google.com/+/features/analytics",
-    "timestamp": 1383243492000,
-    "image": 'images/google/gps-googleplus.png',
-    "title": "Google+ Insights",
-    "summary": "Measure impressions of the over-the-air install prompt, resulting installs, and success rate by day, week, and month.",
-    "keywords": ["signin", "identity"],
-    "type": "guide",
-    "titleFriendly": ""
-  },
-
- // Online courses
-
- {
-    "title":"UX Design for Mobile Developers",
-    "titleFriendly":"",
-    "summary":"Learn how to design a 5-star app.",
-    "url":"https://www.udacity.com/course/ud849",
-    "group":"",
-    "keywords": ["mobile","ux","design"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/mobile_ux_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Developing Android Apps",
-    "titleFriendly":"",
-    "summary":"Learn Android and build an app!",
-    "url":"https://www.udacity.com/course/ud853",
-    "group":"",
-    "keywords": ["android", "start","firstapp","sdk"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/android_fundamentals_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Performance",
-    "titleFriendly":"",
-    "summary":"Optimize your apps for speed and usability.",
-    "url":"https://www.udacity.com/course/ud825",
-    "group":"",
-    "keywords": ["android, performance","battery"],
-    "tags": ["courses, performance"],
-    "image":"images/cards/courses/android_performance_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Enroll in the Android Nanodegree",
-    "titleFriendly":"",
-    "summary":"Enroll in the Android Nanodegree to build the skills to work as an Android developer.",
-    "url":"https://www.udacity.com/android",
-    "group":"",
-    "keywords": ["android, nanodegree"],
-    "tags": ["courses"],
-    "image":"images/cards/courses/android_nanodegree.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Advanced Android App Development",
-    "titleFriendly":"",
-    "summary":"Productionize and publish your apps.",
-    "url":"https://www.udacity.com/course/ud855",
-    "group":"",
-    "keywords": ["android, experts"],
-    "tags": ["courses, expert"],
-    "image":"images/cards/courses/advanced_android_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Material Design for Android Developers",
-    "titleFriendly":"",
-    "summary":"Learn how to make your apps material.",
-    "url":"https://www.udacity.com/course/ud862",
-    "group":"",
-    "keywords": ["android, design, pure, material"],
-    "tags": ["courses, start, material"],
-    "image":"images/cards/courses/android_design_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android for Beginners",
-    "titleFriendly":"",
-    "summary":"Make your first Android app, even if you don't write code.",
-    "url":"https://www.udacity.com/course/ud837",
-    "group":"",
-    "keywords": ["android, sdk, firstapp"],
-    "tags": ["courses, start"],
-    "image":"images/cards/courses/beginning_android_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Gradle for Android and Java",
-    "titleFriendly":"",
-    "summary":"Build better apps through automation",
-    "url":"https://www.udacity.com/course/ud867",
-    "group":"",
-    "keywords": ["gradle","studio", "sdk"],
-    "tags": ["courses, gradle, sdk"],
-    "image":"images/cards/courses/gradle_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Location and Context to your app",
-    "titleFriendly":"",
-    "summary":"Make Your Android App Location Aware.",
-    "url":"https://www.udacity.com/course/ud876-1",
-    "group":"",
-    "keywords": ["google services, context, location"],
-    "tags": ["courses, google, location, context"],
-    "image":"images/cards/courses/android_location_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Analytics and Tag Manager for Android",
-    "titleFriendly":"",
-    "summary":"Use Analytics and Tag Manager in Your Apps.",
-    "url":"https://www.udacity.com/course/ud876-2",
-    "group":"",
-    "keywords": ["google services, analytics, tag manager"],
-    "tags": ["courses, google, analytics"],
-    "image":"images/cards/courses/android_analytics_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"AdMob for Android",
-    "titleFriendly":"",
-    "summary":"Monetize Your App by Displaying Ads.",
-    "url":"https://www.udacity.com/course/ud876-3",
-    "group":"",
-    "keywords": ["monetize, google services, ads, admob"],
-    "tags": ["courses, google, ads, admob"],
-    "image":"images/cards/courses/admob_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Maps to your Android app",
-    "titleFriendly":"",
-    "summary":"Use maps, cameras, markers and more in your app.",
-    "url":"https://www.udacity.com/course/ud876-4",
-    "group":"",
-    "keywords": ["google, maps, marker, camera"],
-    "tags": ["courses, google, maps"],
-    "image":"images/cards/courses/android_maps_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Add Sign-in to your Android app",
-    "titleFriendly":"",
-    "summary":"Build a Seamless Sign-In Experience.",
-    "url":"https://www.udacity.com/course/ud876-5",
-    "group":"",
-    "keywords": ["google services, signin, authorization"],
-    "tags": ["courses, google, auth"],
-    "image":"images/cards/courses/android_identity_course.png",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Wear Development",
-    "titleFriendly":"",
-    "summary":"Extend your Apps to Android Smartwatches.",
-    "url":"https://www.udacity.com/course/ud875A",
-    "group":"",
-    "keywords": ["wear, wearables, smartwatch"],
-    "tags": ["courses, wear, wearable"],
-    "image":"images/cards/courses/android_wear_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android TV and Google Cast Development",
-    "titleFriendly":"",
-    "summary":"Extend your Apps to the Big Screen.",
-    "url":"https://www.udacity.com/course/ud875B",
-    "group":"",
-    "keywords": ["cast, living room"],
-    "tags": ["courses, cast, tv"],
-    "image":"images/cards/courses/android_tv_cast_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-  {
-    "title":"Android Auto Development",
-    "titleFriendly":"",
-    "summary":"Put your apps in the driver's seat.",
-    "url":"https://www.udacity.com/course/ud875C",
-    "group":"",
-    "keywords": ["auto"],
-    "tags": ["courses, auto"],
-    "image":"images/cards/courses/android_auto_course.jpg",
-    "lang":"en",
-    "type":"online course"
-  },
-
-
- // TODO remove this?
-  {
-    "title":"Android Wear Materials",
-    "titleFriendly":"",
-    "summary":"Drag and drop your way to beautifully designed Android Wear apps.",
-    "url":"design/downloads/index.html#Wear",
-    "group":"",
-    "keywords": ["icons","stencils","color swatches"],
-    "tags": ["icons","stencils","colorswatches"],
-    "image":"images/cards/android-wear-materials_2x.jpg",
-    "lang":"en",
-    "type":"design"
-  },
-  {
-    "title":"Watch Faces for Android Wear",
-    "titleFriendly":"",
-    "summary":"Watch faces let you customize the most prominent UI feature of Android wearables. The API is simple enough for rapid development and flexible enough to build something awesome.",
-    "url":"https://www.youtube.com/watch?v=AK38PJZmIW8&list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef",
-    "group":"",
-    "keywords": ["wear", "wearable", "watch face"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/AK38PJZmIW8/maxresdefault.jpg",
-    "lang":"en",
-    "type":"video"
-  },
-  {
-    "title":"Android Support Library",
-    "titleFriendly":"",
-    "summary":"These essential components help you build a great app that works on the huge variety of Android devices, faster.",
-    "url":"https://www.youtube.com/watch?v=3PIc-DuEU2s&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
-    "group":"",
-    "keywords": ["support", "compatibility"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/3PIc-DuEU2s/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Consistent Design with the AppCompat Support Library",
-    "titleFriendly":"",
-    "summary":"Getting a great looking app doesn't have to be hard: AppCompat, part of the Android Support Library, gives you a consistent design baseline that works on all Android 2.1 or higher devices.",
-    "url":"https://www.youtube.com/watch?v=5Be2mJzP-Uw&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX",
-    "group":"",
-    "keywords": ["support", "compatibility","design-code"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/5Be2mJzP-Uw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introducing Gradle",
-    "titleFriendly":"",
-    "summary":"Android Studio uses an entirely new and flexible Gradle-based build system. You will be able to create multiple build variants for a single project, manage library dependencies and always be sure that your application builds correctly across different environments.",
-    "url":"https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","gradle"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/cD7NPxuuXYY/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android Studio Layout Editor",
-    "titleFriendly":"",
-    "summary":"Android Studio includes a rich, visual layout editor that helps developers create better user interfaces. It eliminates the need to deploy the APK on a real device with each change, making iterations faster and helping eliminate common errors earlier in the development process.",
-    "url":"https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","layout"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/JLLnhwtDoHw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Debugging and testing in Android Studio",
-    "titleFriendly":"",
-    "summary":"Learn about new debugger features in Android Studio 1.2: value inlining, quick access to referring objects and a Java .class decompiler, just to name a few. See some new tools and views that let you monitor the CPU and memory performance of your app from within the IDE. ",
-    "url":"https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ",
-    "group":"",
-    "keywords": ["tools", "studio","debugging","profiling","performance"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/2I6fuD20qlY/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Scale with Google Cloud Platform",
-    "titleFriendly":"",
-    "summary":"Build, test, and deploy applications on Google's highly-scalable and reliable infrastructure for your web, mobile and backend solutions.",
-    "url":"https://cloud.google.com/docs/",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/cloud-platform_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"Opportunities & Programs",
-    "titleFriendly":"",
-    "summary":"Take advantage of the many ways you can distribute your app to consumers, students, and businesses through Google Play.",
-    "url":"distribute/googleplay/index.html#opportunities",
-    "group":"",
-    "keywords": [],
-    "tags": [],
-    "image":"images/cards/program-edu_2x.jpg",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"Join the Android for Work DevHub",
-    "titleFriendly":"",
-    "summary":"The Android for Work DevHub is a place to help developers keep up with Android in the workplace.",
-    "url":"https://www.google.com/work/android/developers/applyDevHub/",
-    "group":"",
-    "keywords": ["work", "enterprise", "isv", "devhub"],
-    "tags": [],
-    "image":"images/work/cards/work-devhub_600px.png",
-    "lang":"en",
-    "type":"Community"
-  },
-  {
-    "title":"Enterprise Mobility Managers",
-    "titleFriendly":"",
-    "summary":"Integrate Android for Work into your enterprise mobility management (EMM) solution.",
-    "url":"https://developers.google.com/android/work/",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-cloud_600px.png",
-    "lang":"en",
-    "type":"guide"
-  },
-  {
-    "title":"Learn More About Android for Work",
-    "titleFriendly":"",
-    "summary":"Android for Work makes your favorite phones and tablets the perfect business tools.",
-    "url":"https://www.google.com/work/android/",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-profile_600px.png",
-    "lang":"en",
-    "type":"about"
-  },
-  {
-    "title":"Build a Device Policy Controller",
-    "titleFriendly":"",
-    "summary":"Create and administer a managed profile on an employee's device.",
-    "url":"https://developers.google.com/android/work/build-dpc",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"images/work/cards/work-folder_600px.png",
-    "lang":"en",
-    "type":"guide"
-  },
-  {
-    "title":"Android for Work for Developers",
-    "titleFriendly":"",
-    "summary":"Watch the videos in this playlist to understand more about Android for Work and get tips on developing enterprise apps.",
-    "url":"https://www.youtube.com/watch?v=jQWB_-o1kz4&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/jQWB_-o1kz4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"App Configurations, Testing and Launchers",
-    "titleFriendly":"",
-    "summary":"With Android for Work you can make your apps remotely configurable. We also cover how to test your app in a managed environment.",
-    "url":"https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/39NkpWkaH8M/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Building an Enterprise Ready App",
-    "titleFriendly":"",
-    "summary":"A holistic view of Android for Work for developers.",
-    "url":"https://www.youtube.com/watch?v=dH41OutAMNM&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/dH41OutAMNM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Android for Work: Single Use Devices",
-    "titleFriendly":"",
-    "summary":"Single-purpose computers are everywhere, and Android can meet that need.",
-    "url":"https://www.youtube.com/watch?v=j3QC6hcpy90",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/j3QC6hcpy90/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Your Apps at Work",
-    "titleFriendly":"",
-    "summary":"In this Google I/O 2016 session we’ll give you details for making your app more attractive to businesses.",
-    "url":"https://www.youtube.com/watch?v=Za0OQo8DRM4",
-    "group":"",
-    "keywords": ["work", "enterprise", "emm"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/Za0OQo8DRM4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"youtube"
-  },
-  {
-    "title":"Discover YouTube cards",
-    "titleFriendly":"",
-    "summary":"Find out more about YouTube cards, the options available, and how to use them to get the most from your YouTube content.",
-    "url":"https://support.google.com/youtube/answer/6140493",
-    "group":"",
-    "keywords": ["youtube", "video", "users", "installs"],
-    "tags": [],
-    "image":"images/cards/card-youtube_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-    {
-    "title":"What is YouTube account good standing?",
-    "titleFriendly":"",
-    "summary":"Learn what it means for an account to be in good standing from the YouTube Help Center.",
-    "url":"https://support.google.com/youtube/answer/2797387",
-    "group":"",
-    "keywords": ["youtube", "video", "users", "installs"],
-    "tags": [],
-    "image":"images/cards/card-youtube_2x.png",
-    "lang":"en",
-    "type":"distribute"
-  },
-  {
-    "title":"What’s New in Android N Developer Preview",
-    "titleFriendly":"",
-    "summary":"Learn all about the new features in the Android N Preview.",
-    "url":"https://www.youtube.com/watch?v=CsulIu3UaUM",
-    "group":"",
-    "keywords": ["n preview"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/CsulIu3UaUM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Developing for Android 6.0 (Marshmallow)",
-    "titleFriendly":"",
-    "summary":"This video covers how to get started with the preview, important APIs to test and how to provide feedback on the preview.",
-    "url":"https://www.youtube.com/watch?v=yYU4DHLwoRk",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/yYU4DHLwoRk/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Google I/O 2015 - What's new in Android",
-    "titleFriendly":"",
-    "summary":"This session will highlight the most exciting new developer features of the Android platform.",
-    "url":"https://www.youtube.com/watch?v=ndBdf1_oOGA",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/ndBdf1_oOGA/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Fingerprint and payments APIs",
-    "titleFriendly":"",
-    "summary":"New fingerprint and payments APIs are introduced in M, to enable enhanced UX and security for online purchasing, banking, and retail payments.",
-    "url":"https://www.youtube.com/watch?v=VOn7VrTRlA4",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/VOn7VrTRlA4/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introduction to Voice Interaction API",
-    "titleFriendly":"",
-    "summary":"This video covers how to use the Voice Interaction API to support system or custom voice actions.",
-    "url":"https://www.youtube.com/watch?v=OW1A4XFRuyc",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/OW1A4XFRuyc/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android Auto Backup for Apps",
-    "titleFriendly":"",
-    "summary":"Android Backup is the automatic, cloud-based backup and restore of users’ apps when they set up a new device.",
-    "url":"https://www.youtube.com/watch?v=HXacyy0HSW0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/HXacyy0HSW0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"New APIs in M for Android for Work",
-    "titleFriendly":"",
-    "summary":"Android M extends Android for Work functionality with a new set of APIs for Enterprise Mobility Management providers to offer new features and policy controls to IT Departments.",
-    "url":"https://www.youtube.com/watch?v=vcSj8ln-BlE",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/vcSj8ln-BlE/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Runtime Permissions in Android 6.0 Marshmallow",
-    "titleFriendly":"",
-    "summary":"Learn how to integrate runtime permissions into your Android app.",
-    "url":"https://www.youtube.com/watch?v=C8lUdPVSzDk",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/C8lUdPVSzDk/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Introduction to Doze",
-    "titleFriendly":"",
-    "summary":"An overview of Doze and how to make sure that your app behaves as expected both in and out of Doze mode. ",
-    "url":"https://youtu.be/N72ksDKrX6c",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/N72ksDKrX6c/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"The Nexus 5X, Nexus 6P and Android Marshmallow",
-    "titleFriendly":"",
-    "summary":"The new Nexus 5X and Nexus 6P along with some of the most significant developer features in the latest Android release,.",
-    "url":"https://youtu.be/U9tw5ypqEN0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/U9tw5ypqEN0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Asking For Permission Fine",
-    "titleFriendly":"",
-    "summary":"Picking the right way and time to ask for a permission is critical to it being granted. ",
-    "url":"https://youtu.be/iZqDdvhTZj0",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/iZqDdvhTZj0/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Data Binding Library",
-    "titleFriendly":"",
-    "summary":"Data Binding Library is a way to write declarative layouts and minimize the glue code necessary to bind your application logic and layouts. ",
-    "url":"https://youtu.be/5sCQjeGoE7M",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/5sCQjeGoE7M/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"App Links",
-    "titleFriendly":"",
-    "summary":"App Links is a new feature of Android Marshmallow that brings a faster way of opening website links for domains that you own.",
-    "url":"https://youtu.be/LQoohRwojmw",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/LQoohRwojmw/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "title":"Android M Permissions",
-    "titleFriendly":"",
-    "summary":"An introduction to Android M runtime permissions in Android M from Google I/O 2015. ",
-    "url":"https://www.youtube.com/watch?v=f17qe9vZ8RM",
-    "group":"",
-    "keywords": ["Marshmallow"],
-    "tags": [],
-    "image":"https://i1.ytimg.com/vi/f17qe9vZ8RM/maxresdefault.jpg",
-    "lang":"en",
-    "type":"Video"
-  },
-  {
-    "lang": "ja",
-    "title": "Gaming Everywhere",
-    "titleFriendly": "",
-    "summary": "東京ゲームショウ 2014 の基調講演より。",
-    "url": "https://www.youtube.com/watch?v=xelYnWcYkuE",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/xelYnWcYkuE/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ja",
-    "title": "Playtime Tokyo",
-    "titleFriendly": "",
-    "summary": "アプリビジネスのノウハウを各担当者が講演しました。",
-    "url": "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/lJdjY3z6-LY/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ja",
-    "title": "Android Wear 関連の動画に日本語字幕が付きました",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/android-wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://i1.ytimg.com/vi/4JcDYkgqksY/maxresdefault.jpg",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Android Studio 1.0 をリリースしました",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://3.bp.blogspot.com/-1hV3sD1At74/VIaQSWBasUI/AAAAAAAABAU/9vYLJMsmMuQ/s1600/studio-logo.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Play 開発者サービス 6.5 のご紹介",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevjp.blogspot.jp/2014/12/google-play-65.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://1.bp.blogspot.com/-4BNREC0Jojo/VGo7ahW35wI/AAAAAAAABAc/9thZl94F6fY/s1600/GMS%2B-%2BRelease%2BBlog%2BNacho%2B-%2BMap%2BToolbar.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ja",
-    "title": "Alpha and Beta Testing",
-    "titleFriendly": "",
-    "summary": "アプリのローンチにまつわるリスクを最小限にするために必須のツールです。[英語コンテンツ]",
-    "url": "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-dc-ab.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Finding Success on Google Play",
-    "titleFriendly": "",
-    "summary": "Google Play での成功の秘訣がこの一冊に。[英語コンテンツ]",
-    "url": "intl/ja/distribute/googleplay/guide.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/play_dev_guide_b.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Core App Quality",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "intl/ja/distribute/essentials/quality/core.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-core-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Play アプリ ポリシー センター",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Developer Support",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "intl/ja/support.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Wear App Quality",
-    "titleFriendly": "",
-    "summary": "いよいよウェアラブルの時代が到来。[英語コンテンツ]",
-    "url": "intl/ja/distribute/essentials/quality/wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/gp-wear-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Google Cloud Platform が支える、新感覚リアルタイム RPG ユニゾンリーグ - 株式会社エイチームの GCP 導入事例",
-    "titleFriendly": "",
-    "summary": "スケーラブルなバックエンドを実現する Google Cloud Platform の最新導入事例。",
-    "url": "https://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://3.bp.blogspot.com/-xp7KoPkbne4/VI_PfoFil3I/AAAAAAAAA3U/-k1UZ0zjCBc/s1600/unison-league.jpeg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ja",
-    "title": "Monetize with Ads",
-    "titleFriendly": "",
-    "summary": "アプリ内広告成功のコツがここに。[英語コンテンツ]",
-    "url": "intl/ja/distribute/monetize/ads.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/advertising.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 2015년 비전",
-    "titleFriendly": "",
-    "summary": "G-Star 구글 컨퍼런스",
-    "url": "https://www.youtube.com/watch?v=7X9Ue0Nfdh4&index=2&list=PL_WJkTbDHdBksDBRoqfeyLchEQqBAOlNl",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/7X9Ue0Nfdh4/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 게임",
-    "titleFriendly": "",
-    "summary": "게임 프로필, 퀘스트, 세이브드 게임 등의 신기능 소개",
-    "url": "https://www.youtube.com/watch?v=83FpwuschCQ",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://img.youtube.com/vi/83FpwuschCQ/hqdefault.jpg",
-    "type": "youtube"
-  },
-  {
-    "lang": "ko",
-    "title": "안드로이드 5.0 롤리팝을 맞이하는 개발자를 위한 안내서",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/11/android50guidefordevelopers.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh5.googleusercontent.com/0Gx4Ob_WvIgNOMv3hVMuUm4O7KuSWyxCEFIvy39_6fgXh2q2azqjZf3bpZoEk-LMW-K8GwYMfyYfMUAwp38hhPQ6WFNnddhN2E2_GF3-XBQI_qjhISviz10h_mGgDWsZKA",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "안드로이드 앱을 위한 머티리얼 디자인 체크 리스트",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/10/material-design-on-android-checklist.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh4.googleusercontent.com/JKoxeDdmsj6gYHV8rmp96U1jHj7FKeMzGBaaFu35kXp5EpJR9Ei9MQFAYghjwJoycdgydw-FZTuFNY8pDx63MWhy37rKC96ajoDXEMzvo9W0sj5yC2-uSYJdhpazVOP2cA",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "App Compat 라이브러리",
-    "titleFriendly": "",
-    "summary": "",
-    "url": "https://googledevkr.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://2.bp.blogspot.com/-7fF9ayZ6PgI/U9iFpk5FNEI/AAAAAAAAAs0/4P4SCvdB_4M/s640/image00.png",
-    "type": "blog"
-  },
-  {
-    "lang": "ko",
-    "title": "Alpha and Beta Testing",
-    "titleFriendly": "",
-    "summary": "출시 전에 완벽한 사전 테스트 [영문]",
-    "url": "intl/ko/distribute/googleplay/developer-console.html#alpha-beta",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-dc-ab.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Finding Success on Google Play",
-    "titleFriendly": "",
-    "summary": "구글 플레이에서 성공하는 비결 [영문]",
-    "url": "intl/ko/distribute/googleplay/guide.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/play_dev_guide_b.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Core App Quality",
-    "titleFriendly": "",
-    "summary": "고품질 안드로이드 앱 개발 가이드 [영문]",
-    "url": "intl/ko/distribute/essentials/quality/core.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "images/gp-core-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Policy Guidelines and Practices",
-    "titleFriendly": "",
-    "summary": "숙지해야할 중요한 정책 [영문]",
-    "url": "https://support.google.com/googleplay/android-developer/answer/4430948?hl=ko",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Developer Support",
-    "titleFriendly": "",
-    "summary": "개발자 지원 센터 활용 [영문]",
-    "url": "intl/ko/support.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://lh3.googleusercontent.com/-mGTYed3Uh-E/AAAAAAAAAAI/AAAAAAAAF58/qNYbk4mMhI0/s120-c/photo.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Wear App Quality",
-    "titleFriendly": "",
-    "summary": "웨어러블 앱 개발 가이드 [영문]",
-    "url": "intl/ko/distribute/essentials/quality/wear.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/gp-wear-quality.png",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Android TV 어플리케이션 개발",
-    "titleFriendly": "",
-    "summary": "앱과 게임을 거실에서 가족과 함께 [영문]",
-    "url": "intl/ko/tv/index.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "design/tv/images/atv-home.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "구글 플레이 게임 서비스",
-    "titleFriendly": "",
-    "summary": "다양한 구글 플레이 게임 서비스 기능 알아보기 [영문]",
-    "url": "intl/ko/google/play-services/games.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "https://developers.google.com/games/services/images/gamescreen3.jpg",
-    "type": "distribute"
-  },
-  {
-    "lang": "ko",
-    "title": "Monetize with Ads",
-    "titleFriendly": "",
-    "summary": "광고로 수익 창출하기 [영문]",
-    "url": "intl/ko/distribute/monetize/ads.html",
-    "group": "",
-    "keywords": [],
-    "tags": [],
-    "image": "distribute/images/advertising.jpg",
-    "type": "distribute"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=QDM52bblwlg",
-    "image": "images/distribute/hero-family-discovery.jpg",
-    "title": "Introducing the new family discovery experience on Google Play",
-    "summary": "Help families create little moments on Google Play. Opt-in your apps now.",
-    "tags":["families","googleplay"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/wcjqBSei3a0/maxresdefault.jpg",
-    "title": "Developers connecting the world through Google Play",
-    "summary": "The mobile ecosystem is empowering developers to make good on the dream of connecting the world through technology to improve people's lives.",
-    "tags":["io15","googleplay"],
-    "keywords":["Google I/O 2015","io"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/B6ydLpkhq04/maxresdefault.jpg",
-    "title": "Store Listing Experiments for Google Play",
-    "summary": "Learn how to use Google Play’s new store listing optimization feature to get more installs of your app, and how to test different graphics and text to find out which options perform the best. ",
-    "tags":["io15","googleplay","store listing"],
-    "tags":["google i/o","google play","store listing"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "https://i1.ytimg.com/vi/jyO3-rF4Mu0/maxresdefault.jpg",
-    "title": "Growing games with Google",
-    "summary": "The games industry has never been more promising and full of opportunities. This talk covers how Google is helping developers across a broad range of existing and emerging platforms.",
-    "tags":["io15","android", "googleplay","games"],
-    "keywords":["Google I/O","google play","games"],
-    "type":"youtube"
-  },
-  {
-    "url":"https://www.youtube.com/watch?v=yJisuP94lHU",
-    "image": "images/distribute/hero-playtime-opener.jpg",
-    "title": "Playtime 2015: Innovation happens everywhere",
-    "type":"Video",
-    "tags":["googleplay"],
-    "summary": "Watch the opening video from Google Play's annual event series, Playtime, which celebrates inspirational developers who are changing the world around them.",
-  },
-{
-    "url":"https://www.youtube.com/watch?v=JrR6o5tYMWQ",
-    "image": "images/distribute/hero-acquisition-devbyte.jpg",
-    "title": "User acquisition and tracking on Google Play",
-    "type" : "Video",
-    "tags" : "users,googleplay,googleio",
-    "summary": "Learn how to get new users, using Universal app campaigns directly within the Google Play Developer Console to increase your installs from ads, and find out how your acquisition channels perform.",
-  },
-]);
-
-var CAROUSEL_OVERRIDE = {
-  "distribute/googleplay/guide.html": {
-    "image": "images/distribute/hero-secrets-to-app-success.jpg",
-    "title": "The Secrets to App Success on Google Play",
-    "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.",
-  },
-  "about/versions/lollipop.html": {
-    "image": "images/home/hero-lollipop_2x.png",
-    "heroColor": "#263238",
-    "heroInvert": true,
-    "title": "Android 5.0 Lollipop",
-    "summary": "The Android 5.0 update adds a variety of new features for your apps, such as notifications on the lock screen, an all-new camera API, OpenGL ES 3.1, the new naterial design interface, and much more.",
-  },
-  "http://www.youtube.com/watch?v=Pms0pcyPbAM": {
-    "url":"https://www.youtube.com/watch?v=Pms0pcyPbAM&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c]",
-    "image": "images/distribute/hero-carousel-giftedmom.jpg",
-    "title": "Gifted Mom reaches more mothers across Africa with Android",
-    "type":"youtube",
-    "summary": "Gifted Mom is an app developed in Cameroon which provides users with critical information about pregnancy, breastfeeding and child vaccinations. Hear the creators explain how they built their business on Google Play.",
-  },
-  "http://www.youtube.com/watch?v=9m6MoBM-sFI": {
-    "url":"https://www.youtube.com/watch?v=9m6MoBM-sFI&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=3",
-    "image": "images/distribute/hero-carousel-sgn.jpg",
-    "title": "SGN increases installs with Store Listing Experiments",
-    "type" : "youtube",
-    "summary": "Watch mobile game developer SGN talk about how using Store Listing Experiments to test multiple variants across their portfolio of games helped improve their ROI, conversion rates and gamer retention.",
-  },
-  "http://www.youtube.com/watch?v=e7t3svG9PTk": {
-    "url":"https://www.youtube.com/watch?v=e7t3svG9PTk&index=2&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c",
-    "image": "images/distribute/hero-carousel-djit.jpg",
-    "title": "DJiT builds higher quality experiences on Android",
-    "type" : "youtube",
-    "summary": "Learn how Music app developer DJiT create higher quality apps with improved latency on Android Marshmallow, as well as other Android and Google Play features.",
-  },
-  "http://www.youtube.com/watch?v=J3IvOfvH1ys": {
-    "url":"https://www.youtube.com/watch?v=J3IvOfvH1ys&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=1",
-    "image": "images/distribute/hero-carousel-wego.jpg",
-    "title": "Wego increases user retention with material design",
-    "type" : "youtube",
-    "summary": "Hear how online travel marketplace Wego, increased monthly user retention by 300% and reduced uninstall rates by up to 25% with material design.",
-  },
-  "https://www.youtube.com/watch?v=QDM52bblwlg": {
-    "url":"distribute/googleplay/families/about.html",
-    "image": "images/distribute/hero-family-discovery.jpg",
-    "title": "Designed for families",
-    "summary": "Introducing the new family discovery experience in Google Play. Your apps can benefit from enhanced discoverability and maintain their existing categories, rankings, and reviews elsewhere in the store. Opt-in your apps today.",
-    "type":"distribute",
-  },
-  "https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "url":"https://www.youtube.com/watch?v=wcjqBSei3a0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS",
-    "image": "images/distribute/hero-IO15-google-play.jpg",
-    "title": "Connecting the world through Google Play",
-    "tags":["io15"],
-    "summary": "In this this Google I/O talk, hear how the mobile ecosystem is empowering developers to connect the world through technology and improve people's lives.",
-  },
-  "https://www.youtube.com/watch?v=B6ydLpkhq04&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "image": "images/distribute/hero-store-listing-experience.jpg",
-    "title": "Using Google Play store listing experiments",
-    "tags":["io15"],
-    "summary": "Learn how to use Google Play store listing experiments to get more installs in this Google I/O talk. Test different graphics and text to find out which options perform the best. ",
-  },
-  "https://www.youtube.com/watch?v=jyO3-rF4Mu0&list=PLOU2XLYxmsIKLNUPiFCWVtcO7mZRZ9MmS": {
-    "image": "images/distribute/hero-IO15-growing-games.jpg",
-    "title": "Growing games with Google",
-    "tags":["io15"],
-    "summary": "The games industry has never been more promising and full of opportunities. This talk from Google I/O 2015 covers how Google is helping developers across a broad range of existing and emerging platforms.",
-  }
-};
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index c79ad88..f76cf36 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -156,6 +156,16 @@
     "lang":"en"
   },
   {
+    "title":"GPU Debugger",
+    "summary":"Use the GPU Debugger to analyze and debug your OpenGL ES apps. Inspect the GPU state and understand what caused a specific rendering outcome.",
+    "url":"studio/debug/am-gpu-debugger.html",
+    "image":"images/tools/thumbnails/am-gpu-debugger_2-2_2x.png",
+    "type":"tools",
+    "keywords": ["android","performance","profiling","tools","monitor","debug"],
+    "tags": ["android","performance","profiling","tools","monitor","debug"],
+    "lang":"en"
+  },
+  {
     "title":"HPROF Viewer and Analyzer",
     "summary":"Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks.",
     "url":"studio/profile/am-hprof.html",
@@ -1022,6 +1032,17 @@
     "type":"distribute"
   },
   {
+    "title": "Play Games Quality",
+    "category": "google",
+    "summary": "Meet the basic expectations of game players through compelling features and an intuitive, well-designed UI.",
+    "url": "https://developers.google.com/games/services/checklist",
+    "group": "",
+    "keywords": ["games", "play games", "quality"],
+    "tags": [],
+    "image": "images/cards/distribute/engage/card-game-services.png",
+    "type": "distribute"
+  },
+  {
     "title":"Get Started with Analytics",
     "category":"google",
     "summary":"Get advanced insight into how players discover and play your games.",
@@ -2969,7 +2990,7 @@
     "timestamp": 1383243492000,
     "image": "images/cards/google-search_2x.png",
     "title": "Set Up App Indexing",
-    "summary": "Surface your app content in Google seaerch. Deep link direct to your apps.",
+    "summary": "Surface your app content in Google search. Deep link direct to your apps.",
     "keywords": ["search", "appindexing", "engagement", "getusers"],
     "type": "distribute",
     "category": "google"
@@ -4117,8 +4138,8 @@
   "develop/landing/tools": {
     "title": "",
     "resources": [
-      "https://www.youtube.com/watch?v=ZOz_yr8Yxq8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
-      "https://www.youtube.com/watch?v=eOV2owswDkE&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
+      "https://www.youtube.com/watch?v=NbHsi3-uR8E&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
+      "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
       "https://www.youtube.com/watch?v=StqAZ1OQbqA&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
       "https://www.youtube.com/watch?v=-SY5nkNVUn0&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
       "https://www.youtube.com/watch?v=4rI4tTd7-J8&list=PLWz5rJ2EKKc_w6fodMGrA1_tsI3pqPbqa",
@@ -4366,6 +4387,7 @@
       "distribute/essentials/quality/wear.html",
       "distribute/essentials/quality/tv.html",
       "distribute/essentials/quality/auto.html",
+      "https://developers.google.com/games/services/checklist",
       "distribute/essentials/quality/billions.html",
       "https://developers.google.com/edu/guidelines"
     ]
@@ -5453,6 +5475,12 @@
        "studio/profile/am-sysinfo.html"
     ]
   },
+"tools/help/gpu": {
+    "title": "",
+    "resources": [
+       "studio/debug/am-gpu-debugger.html"
+    ]
+  },
   "tools/help/shot": {
     "title": "",
     "resources": [
@@ -5552,20 +5580,20 @@
     "title": "",
     "resources": [
     "https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x",
-    "http://android-developers.blogspot.com/2016/04/android-studio-2-0.html",
+    "https://android-developers.blogspot.com/2016/09/android-studio-2-2.html",
     "https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du",
     ]
   },
   "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 +5611,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/sdk/1.0_r1/installing.jd b/docs/html/sdk/1.0_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.0_r1/installing.jd
+++ b/docs/html/sdk/1.0_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.0_r1/requirements.jd
+++ b/docs/html/sdk/1.0_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r2/installing.jd b/docs/html/sdk/1.0_r2/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.0_r2/installing.jd
+++ b/docs/html/sdk/1.0_r2/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.0_r2/requirements.jd
+++ b/docs/html/sdk/1.0_r2/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.1_r1/installing.jd
+++ b/docs/html/sdk/1.1_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.1_r1/requirements.jd
+++ b/docs/html/sdk/1.1_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r1/installing.jd b/docs/html/sdk/1.5_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r1/installing.jd
+++ b/docs/html/sdk/1.5_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r1/requirements.jd
+++ b/docs/html/sdk/1.5_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r2/installing.jd b/docs/html/sdk/1.5_r2/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r2/installing.jd
+++ b/docs/html/sdk/1.5_r2/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r2/requirements.jd
+++ b/docs/html/sdk/1.5_r2/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r3/installing.jd b/docs/html/sdk/1.5_r3/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.5_r3/installing.jd
+++ b/docs/html/sdk/1.5_r3/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.5_r3/requirements.jd
+++ b/docs/html/sdk/1.5_r3/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.6_r1/installing.jd b/docs/html/sdk/1.6_r1/installing.jd
index 38c2a1a..eb02742 100644
--- a/docs/html/sdk/1.6_r1/installing.jd
+++ b/docs/html/sdk/1.6_r1/installing.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
index 96fdcb26..41774f0 100644
--- a/docs/html/sdk/1.6_r1/requirements.jd
+++ b/docs/html/sdk/1.6_r1/requirements.jd
@@ -1,3 +1,4 @@
+excludeFromSuggestions=true
 @jd:body
 
 <script type="text/javascript">
diff --git a/docs/html/sdk/api_diff/23/changes/alldiffs_index_additions.html b/docs/html/sdk/api_diff/23/changes/alldiffs_index_additions.html
index 2383e43..6a3f641 100644
--- a/docs/html/sdk/api_diff/23/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/alldiffs_index_additions.html
@@ -4182,8 +4182,7 @@
 <!-- Field YUV_444_888 -->
 <nobr><A HREF="android.graphics.ImageFormat.html#android.graphics.ImageFormat.YUV_444_888" class="hiddenlink" target="rightframe">YUV_444_888</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/alldiffs_index_all.html b/docs/html/sdk/api_diff/23/changes/alldiffs_index_all.html
index e87800d..1fd3725 100644
--- a/docs/html/sdk/api_diff/23/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/alldiffs_index_all.html
@@ -6082,8 +6082,7 @@
 <!-- Field YUV_444_888 -->
 <nobr><A HREF="android.graphics.ImageFormat.html#android.graphics.ImageFormat.YUV_444_888" class="hiddenlink" target="rightframe">YUV_444_888</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/alldiffs_index_changes.html b/docs/html/sdk/api_diff/23/changes/alldiffs_index_changes.html
index 826aa62..33cc0bd 100644
--- a/docs/html/sdk/api_diff/23/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/alldiffs_index_changes.html
@@ -1983,8 +1983,7 @@
 <!-- Field yearListSelectorColor -->
 <nobr><A HREF="android.R.attr.html#android.R.attr.yearListSelectorColor" class="hiddenlink" target="rightframe">yearListSelectorColor</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/alldiffs_index_removals.html b/docs/html/sdk/api_diff/23/changes/alldiffs_index_removals.html
index 19b6bb0..15930d0 100644
--- a/docs/html/sdk/api_diff/23/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/alldiffs_index_removals.html
@@ -973,8 +973,7 @@
 <nobr>&nbsp;in&nbsp;
 <A HREF="android.Manifest.permission_group.html#android.Manifest.permission_group.WRITE_USER_DICTIONARY" class="hiddenlink" target="rightframe"><strike>android.Manifest.permission_group</strike></A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.Manifest.permission.html b/docs/html/sdk/api_diff/23/changes/android.Manifest.permission.html
index be3ec69..501882a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.Manifest.permission.html
+++ b/docs/html/sdk/api_diff/23/changes/android.Manifest.permission.html
@@ -399,8 +399,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.Manifest.permission_group.html b/docs/html/sdk/api_diff/23/changes/android.Manifest.permission_group.html
index 1781743..9645fcd 100644
--- a/docs/html/sdk/api_diff/23/changes/android.Manifest.permission_group.html
+++ b/docs/html/sdk/api_diff/23/changes/android.Manifest.permission_group.html
@@ -319,8 +319,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.R.attr.html b/docs/html/sdk/api_diff/23/changes/android.R.attr.html
index 52d4ec2..8e86e0f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.R.attr.html
+++ b/docs/html/sdk/api_diff/23/changes/android.R.attr.html
@@ -503,8 +503,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.R.id.html b/docs/html/sdk/api_diff/23/changes/android.R.id.html
index 6e6537d..235afdf 100644
--- a/docs/html/sdk/api_diff/23/changes/android.R.id.html
+++ b/docs/html/sdk/api_diff/23/changes/android.R.id.html
@@ -185,8 +185,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.R.string.html b/docs/html/sdk/api_diff/23/changes/android.R.string.html
index d1f5a19..6f44837 100644
--- a/docs/html/sdk/api_diff/23/changes/android.R.string.html
+++ b/docs/html/sdk/api_diff/23/changes/android.R.string.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.R.style.html b/docs/html/sdk/api_diff/23/changes/android.R.style.html
index c076156..b265fe9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.R.style.html
+++ b/docs/html/sdk/api_diff/23/changes/android.R.style.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.accounts.AbstractAccountAuthenticator.html b/docs/html/sdk/api_diff/23/changes/android.accounts.AbstractAccountAuthenticator.html
index 7f3f24f..b3075446 100644
--- a/docs/html/sdk/api_diff/23/changes/android.accounts.AbstractAccountAuthenticator.html
+++ b/docs/html/sdk/api_diff/23/changes/android.accounts.AbstractAccountAuthenticator.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.accounts.AccountManager.html b/docs/html/sdk/api_diff/23/changes/android.accounts.AccountManager.html
index 9da3f90..b04bb6c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.accounts.AccountManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.accounts.AccountManager.html
@@ -148,8 +148,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Activity.html b/docs/html/sdk/api_diff/23/changes/android.app.Activity.html
index b37bb90..f7cf218 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Activity.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Activity.html
@@ -206,8 +206,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RecentTaskInfo.html b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RecentTaskInfo.html
index a2420b55..086938b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RecentTaskInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RecentTaskInfo.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RunningAppProcessInfo.html b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RunningAppProcessInfo.html
index 83fdcbc..a937792 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RunningAppProcessInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.RunningAppProcessInfo.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.html b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.html
index 0e0eab2..3d8a173 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.ActivityManager.html
@@ -176,8 +176,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.ActivityOptions.html b/docs/html/sdk/api_diff/23/changes/android.app.ActivityOptions.html
index e014f34..8fd496b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.ActivityOptions.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.ActivityOptions.html
@@ -144,8 +144,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.AlarmManager.html b/docs/html/sdk/api_diff/23/changes/android.app.AlarmManager.html
index c02ce3d..3e641cd 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.AlarmManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.AlarmManager.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.Builder.html b/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.Builder.html
index dc11ed4..1f1b513 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.Builder.html
@@ -111,8 +111,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.html b/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.html
index 98ac4ee..06f572b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.AlertDialog.html
@@ -146,8 +146,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.AppOpsManager.html b/docs/html/sdk/api_diff/23/changes/android.app.AppOpsManager.html
index 93ef93a..a641d72 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.AppOpsManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.AppOpsManager.html
@@ -305,8 +305,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Dialog.html b/docs/html/sdk/api_diff/23/changes/android.app.Dialog.html
index eb2c903..15babc5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Dialog.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Dialog.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Fragment.html b/docs/html/sdk/api_diff/23/changes/android.app.Fragment.html
index b7bf3af..0051c3e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Fragment.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Fragment.html
@@ -190,8 +190,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Instrumentation.html b/docs/html/sdk/api_diff/23/changes/android.app.Instrumentation.html
index b159575..0d98974 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Instrumentation.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Instrumentation.html
@@ -121,8 +121,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.KeyguardManager.html b/docs/html/sdk/api_diff/23/changes/android.app.KeyguardManager.html
index 14eecf4..93d0f63 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.KeyguardManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.KeyguardManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.Builder.html b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.Builder.html
index 53af4ae..763a0d6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.Builder.html
@@ -126,8 +126,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.html b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.html
index b19098e..2f6f3b9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Action.html
@@ -143,8 +143,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Notification.BigPictureStyle.html b/docs/html/sdk/api_diff/23/changes/android.app.Notification.BigPictureStyle.html
index 70b14d9..1ba93ca 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Notification.BigPictureStyle.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Notification.BigPictureStyle.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Builder.html b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Builder.html
index 8dab8ea..1109b07 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Notification.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Notification.Builder.html
@@ -133,8 +133,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.Notification.html b/docs/html/sdk/api_diff/23/changes/android.app.Notification.html
index ce5ef7c..81fb1a7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.Notification.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.Notification.html
@@ -171,8 +171,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.NotificationManager.html b/docs/html/sdk/api_diff/23/changes/android.app.NotificationManager.html
index 97655b4e..a035224 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.NotificationManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.NotificationManager.html
@@ -207,8 +207,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.PendingIntent.html b/docs/html/sdk/api_diff/23/changes/android.app.PendingIntent.html
index b88319d..722c1a9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.PendingIntent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.PendingIntent.html
@@ -123,8 +123,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.SharedElementCallback.html b/docs/html/sdk/api_diff/23/changes/android.app.SharedElementCallback.html
index 10129b1..934db81 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.SharedElementCallback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.SharedElementCallback.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.WallpaperManager.html b/docs/html/sdk/api_diff/23/changes/android.app.WallpaperManager.html
index c7cfcab..292b27556 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.WallpaperManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.WallpaperManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.admin.DeviceAdminReceiver.html b/docs/html/sdk/api_diff/23/changes/android.app.admin.DeviceAdminReceiver.html
index 2cbe178..09b492e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.admin.DeviceAdminReceiver.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.admin.DeviceAdminReceiver.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.admin.DevicePolicyManager.html b/docs/html/sdk/api_diff/23/changes/android.app.admin.DevicePolicyManager.html
index 122b54c..4cc2ccd 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.admin.DevicePolicyManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.admin.DevicePolicyManager.html
@@ -371,8 +371,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageEvents.Event.html b/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageEvents.Event.html
index 4f860ab..45ae543 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageEvents.Event.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageEvents.Event.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageStatsManager.html b/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageStatsManager.html
index 8761ae6..769af2e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageStatsManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.app.usage.UsageStatsManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothDevice.html b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothDevice.html
index d6b30ef..c9dbc8c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothDevice.html
+++ b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothDevice.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothProfile.html b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothProfile.html
index 6649c72..bffb4d6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothProfile.html
+++ b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothProfile.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothSocket.html b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothSocket.html
index dee2254..8479ea9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothSocket.html
+++ b/docs/html/sdk/api_diff/23/changes/android.bluetooth.BluetoothSocket.html
@@ -151,8 +151,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.Builder.html b/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.Builder.html
index 94d20f3..397e981 100644
--- a/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.Builder.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.html b/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.html
index 210a809..7fa4b7a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.html
+++ b/docs/html/sdk/api_diff/23/changes/android.bluetooth.le.ScanSettings.html
@@ -157,8 +157,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.AbstractThreadedSyncAdapter.html b/docs/html/sdk/api_diff/23/changes/android.content.AbstractThreadedSyncAdapter.html
index 38f5c6b..25ddd8d 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.AbstractThreadedSyncAdapter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.AbstractThreadedSyncAdapter.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.ComponentName.html b/docs/html/sdk/api_diff/23/changes/android.content.ComponentName.html
index a78ce74..3a1cb88 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.ComponentName.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.ComponentName.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.ContentProviderOperation.html b/docs/html/sdk/api_diff/23/changes/android.content.ContentProviderOperation.html
index bd570f0..1b047aa 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.ContentProviderOperation.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.ContentProviderOperation.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.Context.html b/docs/html/sdk/api_diff/23/changes/android.content.Context.html
index be00806..ad2f8e1 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.Context.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.Context.html
@@ -189,8 +189,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.ContextWrapper.html b/docs/html/sdk/api_diff/23/changes/android.content.ContextWrapper.html
index 6e48e64..17c3b93 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.ContextWrapper.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.ContextWrapper.html
@@ -253,8 +253,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.Intent.html b/docs/html/sdk/api_diff/23/changes/android.content.Intent.html
index d71904b..4a0e289 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.Intent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.Intent.html
@@ -164,8 +164,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.RestrictionEntry.html b/docs/html/sdk/api_diff/23/changes/android.content.RestrictionEntry.html
index 4e78b31..e368453 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.RestrictionEntry.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.RestrictionEntry.html
@@ -151,8 +151,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.RestrictionsManager.html b/docs/html/sdk/api_diff/23/changes/android.content.RestrictionsManager.html
index 0b5c0b6..7ca3272 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.RestrictionsManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.RestrictionsManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.pm.ApplicationInfo.html b/docs/html/sdk/api_diff/23/changes/android.content.pm.ApplicationInfo.html
index 3262fe3..66c10ef 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.pm.ApplicationInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.pm.ApplicationInfo.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageInfo.html b/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageInfo.html
index 28be185..924dca5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageInfo.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageManager.html b/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageManager.html
index d00bffa..e7ff620 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.pm.PackageManager.html
@@ -158,8 +158,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.pm.PermissionInfo.html b/docs/html/sdk/api_diff/23/changes/android.content.pm.PermissionInfo.html
index c85a871..1148ad4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.pm.PermissionInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.pm.PermissionInfo.html
@@ -178,8 +178,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.res.ColorStateList.html b/docs/html/sdk/api_diff/23/changes/android.content.res.ColorStateList.html
index ce13686..358f993 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.res.ColorStateList.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.res.ColorStateList.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.res.Configuration.html b/docs/html/sdk/api_diff/23/changes/android.content.res.Configuration.html
index 398bcd8..06b13a0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.res.Configuration.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.res.Configuration.html
@@ -144,8 +144,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.Theme.html b/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.Theme.html
index 7339619..bb3a197 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.Theme.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.Theme.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.html b/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.html
index a2df740..799d2dd 100644
--- a/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.html
+++ b/docs/html/sdk/api_diff/23/changes/android.content.res.Resources.html
@@ -151,8 +151,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.database.AbstractCursor.html b/docs/html/sdk/api_diff/23/changes/android.database.AbstractCursor.html
index 2a16c48..463080ac 100644
--- a/docs/html/sdk/api_diff/23/changes/android.database.AbstractCursor.html
+++ b/docs/html/sdk/api_diff/23/changes/android.database.AbstractCursor.html
@@ -172,8 +172,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.database.Cursor.html b/docs/html/sdk/api_diff/23/changes/android.database.Cursor.html
index 53dd3d5..383f11e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.database.Cursor.html
+++ b/docs/html/sdk/api_diff/23/changes/android.database.Cursor.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.database.CursorWrapper.html b/docs/html/sdk/api_diff/23/changes/android.database.CursorWrapper.html
index 72326bb..cbaa49b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.database.CursorWrapper.html
+++ b/docs/html/sdk/api_diff/23/changes/android.database.CursorWrapper.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.Canvas.html b/docs/html/sdk/api_diff/23/changes/android.graphics.Canvas.html
index 2941907..1ba777a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.Canvas.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.Canvas.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.ImageFormat.html b/docs/html/sdk/api_diff/23/changes/android.graphics.ImageFormat.html
index e79f471..2e560e3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.ImageFormat.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.ImageFormat.html
@@ -157,8 +157,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.Paint.html b/docs/html/sdk/api_diff/23/changes/android.graphics.Paint.html
index a318b03..f5a9b6c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.Paint.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.Paint.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.AnimatedVectorDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.AnimatedVectorDrawable.html
index 5b69bf5..ca61893 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.AnimatedVectorDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.AnimatedVectorDrawable.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ClipDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ClipDrawable.html
index 837e800..2f0c6c4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ClipDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ClipDrawable.html
@@ -177,8 +177,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.Drawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.Drawable.html
index f47da86..30b0c36 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.Drawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.Drawable.html
@@ -154,8 +154,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.InsetDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.InsetDrawable.html
index 133fbaa..5c2dfa2 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.InsetDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.InsetDrawable.html
@@ -187,8 +187,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.LayerDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.LayerDrawable.html
index 4a74187..aa314ce 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.LayerDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.LayerDrawable.html
@@ -318,8 +318,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RippleDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RippleDrawable.html
index 11b3cd5..9d27715 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RippleDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RippleDrawable.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RotateDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RotateDrawable.html
index 201aad5..4dad05f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RotateDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.RotateDrawable.html
@@ -197,8 +197,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ScaleDrawable.html b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ScaleDrawable.html
index 9a8f973..033edec 100644
--- a/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ScaleDrawable.html
+++ b/docs/html/sdk/api_diff/23/changes/android.graphics.drawable.ScaleDrawable.html
@@ -187,8 +187,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.Camera.html b/docs/html/sdk/api_diff/23/changes/android.hardware.Camera.html
index f6cd4b4..6313228 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.Camera.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.Camera.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraAccessException.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraAccessException.html
index c814d74..3e894ae 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraAccessException.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraAccessException.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.StateCallback.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.StateCallback.html
index f7dea8a..ccb7a52 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.StateCallback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.StateCallback.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.html
index 4a90974..5dd352d 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCaptureSession.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCharacteristics.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCharacteristics.html
index 5b0b7d1..ecab6df 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCharacteristics.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraCharacteristics.html
@@ -199,8 +199,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraDevice.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraDevice.html
index 6d82a71..2f74d97 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraDevice.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraDevice.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraManager.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraManager.html
index 673e92b..e927f0b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraManager.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraMetadata.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraMetadata.html
index 62d7ace..e4b9195 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraMetadata.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CameraMetadata.html
@@ -209,8 +209,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureRequest.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureRequest.html
index 72e5ce5..936c076 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureRequest.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureRequest.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureResult.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureResult.html
index 0b1d532..0137f79 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureResult.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.CaptureResult.html
@@ -150,8 +150,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.params.StreamConfigurationMap.html b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.params.StreamConfigurationMap.html
index b71163a..d95a6ac 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.params.StreamConfigurationMap.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.camera2.params.StreamConfigurationMap.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.hardware.usb.UsbDevice.html b/docs/html/sdk/api_diff/23/changes/android.hardware.usb.UsbDevice.html
index 7e76be3..0a7732f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.hardware.usb.UsbDevice.html
+++ b/docs/html/sdk/api_diff/23/changes/android.hardware.usb.UsbDevice.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AsyncPlayer.html b/docs/html/sdk/api_diff/23/changes/android.media.AsyncPlayer.html
index f68d1e8..f74a543 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AsyncPlayer.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AsyncPlayer.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.Builder.html b/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.Builder.html
index c56efd8..bdbeb51 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.Builder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.html b/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.html
index cf84a6f..412bcb3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AudioFormat.html
@@ -161,8 +161,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AudioManager.html b/docs/html/sdk/api_diff/23/changes/android.media.AudioManager.html
index f479b11..bd9df5d 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AudioManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AudioManager.html
@@ -221,8 +221,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AudioRecord.html b/docs/html/sdk/api_diff/23/changes/android.media.AudioRecord.html
index ad8a1da..a1d5a9c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AudioRecord.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AudioRecord.html
@@ -200,8 +200,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.AudioTrack.html b/docs/html/sdk/api_diff/23/changes/android.media.AudioTrack.html
index 62022ed..ea3bd18 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.AudioTrack.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.AudioTrack.html
@@ -185,8 +185,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.ExifInterface.html b/docs/html/sdk/api_diff/23/changes/android.media.ExifInterface.html
index 5318461..2b79d99 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.ExifInterface.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.ExifInterface.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.Image.html b/docs/html/sdk/api_diff/23/changes/android.media.Image.html
index d05aa87..63c18eb 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.Image.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.Image.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CodecException.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CodecException.html
index 2c30a5a..0e1c9b5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CodecException.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CodecException.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CryptoException.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CryptoException.html
index bc9f887..985125a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CryptoException.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.CryptoException.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.html
index dc5ccdb..293ec08 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodec.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecCapabilities.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecCapabilities.html
index f3ac732..cbb34c3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecCapabilities.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecCapabilities.html
@@ -501,8 +501,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecProfileLevel.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecProfileLevel.html
index 440e651..181a607 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecProfileLevel.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.CodecProfileLevel.html
@@ -171,8 +171,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.VideoCapabilities.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.VideoCapabilities.html
index acceec8..7983a12 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.VideoCapabilities.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCodecInfo.VideoCapabilities.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaCrypto.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaCrypto.html
index 8751953..9206dfc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaCrypto.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaCrypto.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.Builder.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.Builder.html
index de70f44..a4f1496 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.Builder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.html
index 869ae0f..b92a242 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaDescription.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.KeyRequest.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.KeyRequest.html
index 2ecbc24..c807b8b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.KeyRequest.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.KeyRequest.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.html
index 2b2967a..4254172 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaDrm.html
@@ -147,8 +147,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaExtractor.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaExtractor.html
index 0f99c34..bce1b1c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaExtractor.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaExtractor.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaFormat.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaFormat.html
index f308bfb..09fd3c6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaFormat.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaFormat.html
@@ -150,8 +150,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaMetadataRetriever.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaMetadataRetriever.html
index 1290ded..ca59780 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaMetadataRetriever.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaMetadataRetriever.html
@@ -123,8 +123,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.TrackInfo.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.TrackInfo.html
index d222c25..831c6fb 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.TrackInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.TrackInfo.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.html
index 87b3eff..45d23e4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaPlayer.html
@@ -150,8 +150,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.MediaRecorder.html b/docs/html/sdk/api_diff/23/changes/android.media.MediaRecorder.html
index d3eb76f..fc17d9b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.MediaRecorder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.MediaRecorder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.browse.MediaBrowser.html b/docs/html/sdk/api_diff/23/changes/android.media.browse.MediaBrowser.html
index 64bf6b6..7340a90 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.browse.MediaBrowser.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.browse.MediaBrowser.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.session.MediaController.TransportControls.html b/docs/html/sdk/api_diff/23/changes/android.media.session.MediaController.TransportControls.html
index 1bb85d3..30bd3e0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.session.MediaController.TransportControls.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.session.MediaController.TransportControls.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.session.MediaSession.Callback.html b/docs/html/sdk/api_diff/23/changes/android.media.session.MediaSession.Callback.html
index 2137ecb..c62343e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.session.MediaSession.Callback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.session.MediaSession.Callback.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.session.PlaybackState.html b/docs/html/sdk/api_diff/23/changes/android.media.session.PlaybackState.html
index 64160b3..9b1913c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.session.PlaybackState.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.session.PlaybackState.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContentRating.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContentRating.html
index a6ef2e7..2eb9289 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContentRating.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContentRating.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Channels.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Channels.html
index 5171bf5..0504ca0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Channels.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Channels.html
@@ -164,8 +164,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Programs.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Programs.html
index 49cee1d..e87dcb7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Programs.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvContract.Programs.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputManager.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputManager.html
index c1ea72f..b55a2d0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputManager.html
@@ -143,8 +143,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputService.Session.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputService.Session.html
index c66ace3..57f8357 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputService.Session.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvInputService.Session.html
@@ -164,8 +164,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.Builder.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.Builder.html
index 808a001..5660eb1 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.Builder.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.html
index 4d90aec..e5bc56b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvTrackInfo.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.TvInputCallback.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.TvInputCallback.html
index df8a7ce..b0b2837 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.TvInputCallback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.TvInputCallback.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.html b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.html
index b2ed301..fd3436f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.media.tv.TvView.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.ConnectivityManager.html b/docs/html/sdk/api_diff/23/changes/android.net.ConnectivityManager.html
index be3320d..2d502b9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.ConnectivityManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.ConnectivityManager.html
@@ -282,8 +282,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.IpPrefix.html b/docs/html/sdk/api_diff/23/changes/android.net.IpPrefix.html
index 82570e1..75c7810 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.IpPrefix.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.IpPrefix.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.Network.html b/docs/html/sdk/api_diff/23/changes/android.net.Network.html
index eb7203d..c1ee6e0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.Network.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.Network.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.NetworkCapabilities.html b/docs/html/sdk/api_diff/23/changes/android.net.NetworkCapabilities.html
index 4739b02..5d27820 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.NetworkCapabilities.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.NetworkCapabilities.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.Proxy.html b/docs/html/sdk/api_diff/23/changes/android.net.Proxy.html
index 847205a..2ecff4f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.Proxy.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.Proxy.html
@@ -110,8 +110,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.ProxyInfo.html b/docs/html/sdk/api_diff/23/changes/android.net.ProxyInfo.html
index 61e1552..3b1bb7c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.ProxyInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.ProxyInfo.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.SSLCertificateSocketFactory.html b/docs/html/sdk/api_diff/23/changes/android.net.SSLCertificateSocketFactory.html
index 9066e26..1c39138 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.SSLCertificateSocketFactory.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.SSLCertificateSocketFactory.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.wifi.ScanResult.html b/docs/html/sdk/api_diff/23/changes/android.net.wifi.ScanResult.html
index 640f0e2..acb7f4b6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.wifi.ScanResult.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.wifi.ScanResult.html
@@ -193,8 +193,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiConfiguration.html b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiConfiguration.html
index c49efb6..8319235 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiConfiguration.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiConfiguration.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.Eap.html b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.Eap.html
index 9a6cb9e..8ce143c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.Eap.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.Eap.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.html b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.html
index ac0d9c3..a7ce4e2 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiEnterpriseConfig.html
@@ -185,8 +185,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiManager.html b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiManager.html
index 21c1048..eb631ad 100644
--- a/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.net.wifi.WifiManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.nfc.NfcEvent.html b/docs/html/sdk/api_diff/23/changes/android.nfc.NfcEvent.html
index 39adff8..7a7310a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.nfc.NfcEvent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.nfc.NfcEvent.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.BatteryManager.html b/docs/html/sdk/api_diff/23/changes/android.os.BatteryManager.html
index 1970c7b..12542d8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.BatteryManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.BatteryManager.html
@@ -145,8 +145,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION.html b/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION.html
index 9726626..ee3040c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION_CODES.html b/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION_CODES.html
index 1d42a0f..8cf9c73 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION_CODES.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Build.VERSION_CODES.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.DeadObjectException.html b/docs/html/sdk/api_diff/23/changes/android.os.DeadObjectException.html
index ccbf91b..908c9c7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.DeadObjectException.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.DeadObjectException.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Debug.InstructionCount.html b/docs/html/sdk/api_diff/23/changes/android.os.Debug.InstructionCount.html
index 801afaf..cbdf07f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Debug.InstructionCount.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Debug.InstructionCount.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Debug.MemoryInfo.html b/docs/html/sdk/api_diff/23/changes/android.os.Debug.MemoryInfo.html
index 77ee3a0..f409353 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Debug.MemoryInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Debug.MemoryInfo.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Debug.html b/docs/html/sdk/api_diff/23/changes/android.os.Debug.html
index a97af60..583f481 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Debug.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Debug.html
@@ -350,8 +350,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Environment.html b/docs/html/sdk/api_diff/23/changes/android.os.Environment.html
index e4d759a..56315a8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Environment.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Environment.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Looper.html b/docs/html/sdk/api_diff/23/changes/android.os.Looper.html
index e70904e..e200aed 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Looper.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Looper.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.MessageQueue.html b/docs/html/sdk/api_diff/23/changes/android.os.MessageQueue.html
index 31ac6891..1ac8eb3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.MessageQueue.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.MessageQueue.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Parcel.html b/docs/html/sdk/api_diff/23/changes/android.os.Parcel.html
index 2d5daba..9d724db 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Parcel.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Parcel.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.PowerManager.html b/docs/html/sdk/api_diff/23/changes/android.os.PowerManager.html
index a0e4809..af683c7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.PowerManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.PowerManager.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.Process.html b/docs/html/sdk/api_diff/23/changes/android.os.Process.html
index 73fcb63..84b9fa8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.Process.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.Process.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.RecoverySystem.html b/docs/html/sdk/api_diff/23/changes/android.os.RecoverySystem.html
index 19fc015..48dcc36 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.RecoverySystem.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.RecoverySystem.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.ThreadPolicy.Builder.html b/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.ThreadPolicy.Builder.html
index 414a7ca..90b3dbe 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.ThreadPolicy.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.ThreadPolicy.Builder.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.VmPolicy.Builder.html b/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.VmPolicy.Builder.html
index ed031a0..780f1bc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.VmPolicy.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.StrictMode.VmPolicy.Builder.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.TransactionTooLargeException.html b/docs/html/sdk/api_diff/23/changes/android.os.TransactionTooLargeException.html
index b4c452f..fb9883d 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.TransactionTooLargeException.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.TransactionTooLargeException.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.os.UserManager.html b/docs/html/sdk/api_diff/23/changes/android.os.UserManager.html
index c8cb278..d77c6b9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.os.UserManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.os.UserManager.html
@@ -169,8 +169,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.Builder.html b/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.Builder.html
index 69d6fad..45b754c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.Builder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.html b/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.html
index a607bdb..34938b5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.html
+++ b/docs/html/sdk/api_diff/23/changes/android.print.PrintAttributes.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.Builder.html b/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.Builder.html
index dc00459..a2ba700 100644
--- a/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.Builder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.html b/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.html
index 1fc8ff6..94bd989 100644
--- a/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.print.PrinterCapabilitiesInfo.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.printservice.PrintService.html b/docs/html/sdk/api_diff/23/changes/android.printservice.PrintService.html
index 7ffa278..32fe84c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.printservice.PrintService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.printservice.PrintService.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.AlarmClock.html b/docs/html/sdk/api_diff/23/changes/android.provider.AlarmClock.html
index 15b2c45..0d7a2ce 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.AlarmClock.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.AlarmClock.html
@@ -164,8 +164,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Browser.html b/docs/html/sdk/api_diff/23/changes/android.provider.Browser.html
index 3a5ba25..27b667c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Browser.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Browser.html
@@ -305,8 +305,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.CallLog.Calls.html b/docs/html/sdk/api_diff/23/changes/android.provider.CallLog.Calls.html
index 812e33c..5f91a2a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.CallLog.Calls.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.CallLog.Calls.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.CommonDataKinds.Email.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.CommonDataKinds.Email.html
index 2b1f7434..eb560eb 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.CommonDataKinds.Email.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.CommonDataKinds.Email.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Contacts.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Contacts.html
index a5b4618..13eb03a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Contacts.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Contacts.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DataColumns.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DataColumns.html
index d9dc7aa..95690b9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DataColumns.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DataColumns.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DisplayNameSources.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DisplayNameSources.html
index ebcf996..8e9ec5b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DisplayNameSources.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.DisplayNameSources.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Intents.Insert.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Intents.Insert.html
index d399871..e9dbed6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Intents.Insert.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.Intents.Insert.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.QuickContact.html b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.QuickContact.html
index f09d783..0f722e7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.QuickContact.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.ContactsContract.QuickContact.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.DocumentsContract.html b/docs/html/sdk/api_diff/23/changes/android.provider.DocumentsContract.html
index b65d7a4..530a1b9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.DocumentsContract.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.DocumentsContract.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.MediaStore.html b/docs/html/sdk/api_diff/23/changes/android.provider.MediaStore.html
index 4aeb95c..37516f0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.MediaStore.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.MediaStore.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Global.html b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Global.html
index 37b53e6..da128db 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Global.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Global.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Secure.html b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Secure.html
index 211e50b..518c7fe 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Secure.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.Secure.html
@@ -128,8 +128,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.System.html b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.System.html
index 9a18a09..22df972 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.System.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.System.html
@@ -201,8 +201,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.html b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.html
index 6224aec..3d60046 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Settings.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Settings.html
@@ -214,8 +214,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.Telephony.Threads.html b/docs/html/sdk/api_diff/23/changes/android.provider.Telephony.Threads.html
index 7ea8016..bc1a029 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.Telephony.Threads.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.Telephony.Threads.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Status.html b/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Status.html
index 9afd431..fb885fb 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Status.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Status.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Voicemails.html b/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Voicemails.html
index 237ded2..e577928 100644
--- a/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Voicemails.html
+++ b/docs/html/sdk/api_diff/23/changes/android.provider.VoicemailContract.Voicemails.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.Allocation.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.Allocation.html
index 04b9c76..f9e05cc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.Allocation.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.Allocation.html
@@ -241,8 +241,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.AllocationAdapter.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.AllocationAdapter.html
index 2e4a7d8..beb15c5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.AllocationAdapter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.AllocationAdapter.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.Element.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.Element.html
index 78583e4..de45493 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.Element.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.Element.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.RenderScript.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.RenderScript.html
index 24d4b9a..a9da0d8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.RenderScript.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.RenderScript.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.Script.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.Script.html
index b86c319..af71e31 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.Script.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.Script.html
@@ -122,8 +122,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.Builder.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.Builder.html
index aaf8ccd..8971916 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.Builder.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.html b/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.html
index c3aa6e7..c639619 100644
--- a/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.html
+++ b/docs/html/sdk/api_diff/23/changes/android.renderscript.ScriptGroup.html
@@ -158,8 +158,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.security.KeyChain.html b/docs/html/sdk/api_diff/23/changes/android.security.KeyChain.html
index 33dbc3a1..17845b4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.security.KeyChain.html
+++ b/docs/html/sdk/api_diff/23/changes/android.security.KeyChain.html
@@ -126,8 +126,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.Builder.html b/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.Builder.html
index a61cc22..ab27faf 100644
--- a/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.Builder.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.html b/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.html
index e6e22a3..bd25c91 100644
--- a/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.html
+++ b/docs/html/sdk/api_diff/23/changes/android.security.KeyPairGeneratorSpec.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.Builder.html b/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.Builder.html
index 8b0a592..8e3a063 100644
--- a/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.Builder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.Builder.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.html b/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.html
index 1200736..8aafe78 100644
--- a/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.security.KeyStoreParameter.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.carrier.CarrierMessagingService.html b/docs/html/sdk/api_diff/23/changes/android.service.carrier.CarrierMessagingService.html
index f82d8a3..46675f7 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.carrier.CarrierMessagingService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.carrier.CarrierMessagingService.html
@@ -187,8 +187,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.dreams.DreamService.html b/docs/html/sdk/api_diff/23/changes/android.service.dreams.DreamService.html
index 7285d81..f58cdc3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.dreams.DreamService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.dreams.DreamService.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.media.MediaBrowserService.html b/docs/html/sdk/api_diff/23/changes/android.service.media.MediaBrowserService.html
index 92e64f6..0128032 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.media.MediaBrowserService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.media.MediaBrowserService.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.notification.NotificationListenerService.html b/docs/html/sdk/api_diff/23/changes/android.service.notification.NotificationListenerService.html
index 635f562..b563ed6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.notification.NotificationListenerService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.notification.NotificationListenerService.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionService.html b/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionService.html
index 0a936f0..cedb8f1 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionService.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionService.html
@@ -144,8 +144,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionSession.html b/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionSession.html
index 5c2ebb6..64fe582 100644
--- a/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionSession.html
+++ b/docs/html/sdk/api_diff/23/changes/android.service.voice.VoiceInteractionSession.html
@@ -395,8 +395,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.speech.RecognitionService.Callback.html b/docs/html/sdk/api_diff/23/changes/android.speech.RecognitionService.Callback.html
index 4907e35..4a20d3a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.speech.RecognitionService.Callback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.speech.RecognitionService.Callback.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.speech.RecognizerIntent.html b/docs/html/sdk/api_diff/23/changes/android.speech.RecognizerIntent.html
index e347574..a27d165 100644
--- a/docs/html/sdk/api_diff/23/changes/android.speech.RecognizerIntent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.speech.RecognizerIntent.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.speech.tts.UtteranceProgressListener.html b/docs/html/sdk/api_diff/23/changes/android.speech.tts.UtteranceProgressListener.html
index 0384ecb..2de54e9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.speech.tts.UtteranceProgressListener.html
+++ b/docs/html/sdk/api_diff/23/changes/android.speech.tts.UtteranceProgressListener.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.system.OsConstants.html b/docs/html/sdk/api_diff/23/changes/android.system.OsConstants.html
index 4037e49..5c08aa4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.system.OsConstants.html
+++ b/docs/html/sdk/api_diff/23/changes/android.system.OsConstants.html
@@ -164,8 +164,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telecom.TelecomManager.html b/docs/html/sdk/api_diff/23/changes/android.telecom.TelecomManager.html
index 118d9f0..64ac489 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telecom.TelecomManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telecom.TelecomManager.html
@@ -326,8 +326,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.CellSignalStrength.html b/docs/html/sdk/api_diff/23/changes/android.telephony.CellSignalStrength.html
index 1ddc8b4..d57b76e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.CellSignalStrength.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.CellSignalStrength.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.PhoneNumberUtils.html b/docs/html/sdk/api_diff/23/changes/android.telephony.PhoneNumberUtils.html
index 1146436..9d2b92f 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.PhoneNumberUtils.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.PhoneNumberUtils.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.SignalStrength.html b/docs/html/sdk/api_diff/23/changes/android.telephony.SignalStrength.html
index de6e283..79db91e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.SignalStrength.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.SignalStrength.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.SmsManager.html b/docs/html/sdk/api_diff/23/changes/android.telephony.SmsManager.html
index 1a4344c..792d85a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.SmsManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.SmsManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.SmsMessage.html b/docs/html/sdk/api_diff/23/changes/android.telephony.SmsMessage.html
index 7954e44..36b74dc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.SmsMessage.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.SmsMessage.html
@@ -130,8 +130,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.telephony.TelephonyManager.html b/docs/html/sdk/api_diff/23/changes/android.telephony.TelephonyManager.html
index 8a2dadc..7b6b39c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.telephony.TelephonyManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.telephony.TelephonyManager.html
@@ -190,8 +190,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockContext.html b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockContext.html
index ae21729..9607b95 100644
--- a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockContext.html
+++ b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockContext.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockCursor.html b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockCursor.html
index e8abcf7..d61754c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockCursor.html
+++ b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockCursor.html
@@ -136,8 +136,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockPackageManager.html b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockPackageManager.html
index add80e0..3cca46a 100644
--- a/docs/html/sdk/api_diff/23/changes/android.test.mock.MockPackageManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.test.mock.MockPackageManager.html
@@ -129,8 +129,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.text.Layout.html b/docs/html/sdk/api_diff/23/changes/android.text.Layout.html
index 891e507..1764a94 100644
--- a/docs/html/sdk/api_diff/23/changes/android.text.Layout.html
+++ b/docs/html/sdk/api_diff/23/changes/android.text.Layout.html
@@ -143,8 +143,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.text.SpannableStringBuilder.html b/docs/html/sdk/api_diff/23/changes/android.text.SpannableStringBuilder.html
index 54dd172..fa301b4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.text.SpannableStringBuilder.html
+++ b/docs/html/sdk/api_diff/23/changes/android.text.SpannableStringBuilder.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.transition.Transition.html b/docs/html/sdk/api_diff/23/changes/android.transition.Transition.html
index 0e3c3a2..c3dc5d2 100644
--- a/docs/html/sdk/api_diff/23/changes/android.transition.Transition.html
+++ b/docs/html/sdk/api_diff/23/changes/android.transition.Transition.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.transition.TransitionManager.html b/docs/html/sdk/api_diff/23/changes/android.transition.TransitionManager.html
index ff5355d..9f42e74 100644
--- a/docs/html/sdk/api_diff/23/changes/android.transition.TransitionManager.html
+++ b/docs/html/sdk/api_diff/23/changes/android.transition.TransitionManager.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.util.ArrayMap.html b/docs/html/sdk/api_diff/23/changes/android.util.ArrayMap.html
index 15df685..1c14a56 100644
--- a/docs/html/sdk/api_diff/23/changes/android.util.ArrayMap.html
+++ b/docs/html/sdk/api_diff/23/changes/android.util.ArrayMap.html
@@ -123,8 +123,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.util.DisplayMetrics.html b/docs/html/sdk/api_diff/23/changes/android.util.DisplayMetrics.html
index 4973462..a58b13d 100644
--- a/docs/html/sdk/api_diff/23/changes/android.util.DisplayMetrics.html
+++ b/docs/html/sdk/api_diff/23/changes/android.util.DisplayMetrics.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.util.EventLog.html b/docs/html/sdk/api_diff/23/changes/android.util.EventLog.html
index bed26da..5258217 100644
--- a/docs/html/sdk/api_diff/23/changes/android.util.EventLog.html
+++ b/docs/html/sdk/api_diff/23/changes/android.util.EventLog.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.util.FloatMath.html b/docs/html/sdk/api_diff/23/changes/android.util.FloatMath.html
index 894398b..d55276c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.util.FloatMath.html
+++ b/docs/html/sdk/api_diff/23/changes/android.util.FloatMath.html
@@ -157,8 +157,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ActionMode.html b/docs/html/sdk/api_diff/23/changes/android.view.ActionMode.html
index d8112b3..d9ca5cc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ActionMode.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ActionMode.html
@@ -165,8 +165,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ContextThemeWrapper.html b/docs/html/sdk/api_diff/23/changes/android.view.ContextThemeWrapper.html
index d7481cc..33f2874 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ContextThemeWrapper.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ContextThemeWrapper.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.Display.html b/docs/html/sdk/api_diff/23/changes/android.view.Display.html
index b3917b5..b665292 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.Display.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.Display.html
@@ -155,8 +155,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.SimpleOnGestureListener.html b/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.SimpleOnGestureListener.html
index 8810d92..4241464 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.SimpleOnGestureListener.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.SimpleOnGestureListener.html
@@ -109,8 +109,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.html b/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.html
index f778072..ad933b0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.GestureDetector.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.HapticFeedbackConstants.html b/docs/html/sdk/api_diff/23/changes/android.view.HapticFeedbackConstants.html
index f9e878c..97e572c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.HapticFeedbackConstants.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.HapticFeedbackConstants.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.InputDevice.html b/docs/html/sdk/api_diff/23/changes/android.view.InputDevice.html
index ec45ec9..638b588 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.InputDevice.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.InputDevice.html
@@ -123,8 +123,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.KeyEvent.html b/docs/html/sdk/api_diff/23/changes/android.view.KeyEvent.html
index ce5e897..80a7567 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.KeyEvent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.KeyEvent.html
@@ -157,8 +157,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.MotionEvent.html b/docs/html/sdk/api_diff/23/changes/android.view.MotionEvent.html
index 59b9393..494bd99 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.MotionEvent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.MotionEvent.html
@@ -144,8 +144,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ScaleGestureDetector.html b/docs/html/sdk/api_diff/23/changes/android.view.ScaleGestureDetector.html
index b5ecc30..898cf1b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ScaleGestureDetector.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ScaleGestureDetector.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.Surface.html b/docs/html/sdk/api_diff/23/changes/android.view.Surface.html
index 1b77929..0483d2b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.Surface.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.Surface.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.View.html b/docs/html/sdk/api_diff/23/changes/android.view.View.html
index 2a15daf..8edfdd4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.View.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.View.html
@@ -340,8 +340,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ViewConfiguration.html b/docs/html/sdk/api_diff/23/changes/android.view.ViewConfiguration.html
index 069b569..3aa4ac3 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ViewConfiguration.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ViewConfiguration.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ViewGroup.html b/docs/html/sdk/api_diff/23/changes/android.view.ViewGroup.html
index 38a4519..5ddc109 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ViewGroup.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ViewGroup.html
@@ -190,8 +190,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.ViewParent.html b/docs/html/sdk/api_diff/23/changes/android.view.ViewParent.html
index 986b357..5f55d02b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.ViewParent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.ViewParent.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.Window.Callback.html b/docs/html/sdk/api_diff/23/changes/android.view.Window.Callback.html
index 397ca61..b120060 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.Window.Callback.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.Window.Callback.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.WindowManager.LayoutParams.html b/docs/html/sdk/api_diff/23/changes/android.view.WindowManager.LayoutParams.html
index 936b438..b54ae82 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.WindowManager.LayoutParams.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.WindowManager.LayoutParams.html
@@ -125,8 +125,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityEvent.html b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityEvent.html
index c107c65..f0f5381 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityEvent.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityEvent.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.html b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.html
index f0876f3..13a4a42 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.html
@@ -150,8 +150,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.html b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.html
index 56997e2..670b4fc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.html
+++ b/docs/html/sdk/api_diff/23/changes/android.view.accessibility.AccessibilityNodeInfo.html
@@ -137,8 +137,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.webkit.PermissionRequest.html b/docs/html/sdk/api_diff/23/changes/android.webkit.PermissionRequest.html
index 4e50f62e..ea81394 100644
--- a/docs/html/sdk/api_diff/23/changes/android.webkit.PermissionRequest.html
+++ b/docs/html/sdk/api_diff/23/changes/android.webkit.PermissionRequest.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.webkit.WebSettings.html b/docs/html/sdk/api_diff/23/changes/android.webkit.WebSettings.html
index 7f8d15e..cb7b0fc 100644
--- a/docs/html/sdk/api_diff/23/changes/android.webkit.WebSettings.html
+++ b/docs/html/sdk/api_diff/23/changes/android.webkit.WebSettings.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.webkit.WebView.html b/docs/html/sdk/api_diff/23/changes/android.webkit.WebView.html
index e8da78a..7c2e7a0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.webkit.WebView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.webkit.WebView.html
@@ -170,8 +170,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.webkit.WebViewClient.html b/docs/html/sdk/api_diff/23/changes/android.webkit.WebViewClient.html
index 9fcd572..2029886 100644
--- a/docs/html/sdk/api_diff/23/changes/android.webkit.WebViewClient.html
+++ b/docs/html/sdk/api_diff/23/changes/android.webkit.WebViewClient.html
@@ -144,8 +144,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.ActionMenuView.html b/docs/html/sdk/api_diff/23/changes/android.widget.ActionMenuView.html
index 2cf6bbd..b74eb0b 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.ActionMenuView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.ActionMenuView.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.AnalogClock.html b/docs/html/sdk/api_diff/23/changes/android.widget.AnalogClock.html
index 27f89f9..ce830a8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.AnalogClock.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.AnalogClock.html
@@ -94,8 +94,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.ArrayAdapter.html b/docs/html/sdk/api_diff/23/changes/android.widget.ArrayAdapter.html
index d6ec494..d50b405 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.ArrayAdapter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.ArrayAdapter.html
@@ -116,8 +116,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.CalendarView.html b/docs/html/sdk/api_diff/23/changes/android.widget.CalendarView.html
index a758674..03dbcb0 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.CalendarView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.CalendarView.html
@@ -251,8 +251,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.CompoundButton.html b/docs/html/sdk/api_diff/23/changes/android.widget.CompoundButton.html
index 72b241e..7daa319 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.CompoundButton.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.CompoundButton.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.CursorAdapter.html b/docs/html/sdk/api_diff/23/changes/android.widget.CursorAdapter.html
index b89641f..99187d4 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.CursorAdapter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.CursorAdapter.html
@@ -116,8 +116,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.FrameLayout.html b/docs/html/sdk/api_diff/23/changes/android.widget.FrameLayout.html
index b784075..87adf30 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.FrameLayout.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.FrameLayout.html
@@ -181,8 +181,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.ImageView.html b/docs/html/sdk/api_diff/23/changes/android.widget.ImageView.html
index 3337cb6..bc03aa9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.ImageView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.ImageView.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.ListPopupWindow.html b/docs/html/sdk/api_diff/23/changes/android.widget.ListPopupWindow.html
index 8f9b81e..def2ab5 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.ListPopupWindow.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.ListPopupWindow.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.PopupMenu.html b/docs/html/sdk/api_diff/23/changes/android.widget.PopupMenu.html
index 9f50f47..7c70493 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.PopupMenu.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.PopupMenu.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.PopupWindow.html b/docs/html/sdk/api_diff/23/changes/android.widget.PopupWindow.html
index 0a9003c..9336793 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.PopupWindow.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.PopupWindow.html
@@ -161,8 +161,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.QuickContactBadge.html b/docs/html/sdk/api_diff/23/changes/android.widget.QuickContactBadge.html
index e2d0228..0a22ffb 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.QuickContactBadge.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.QuickContactBadge.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.RelativeLayout.LayoutParams.html b/docs/html/sdk/api_diff/23/changes/android.widget.RelativeLayout.LayoutParams.html
index a3f9f45..fd0e043 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.RelativeLayout.LayoutParams.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.RelativeLayout.LayoutParams.html
@@ -108,8 +108,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.RemoteViews.html b/docs/html/sdk/api_diff/23/changes/android.widget.RemoteViews.html
index ec6c99d..510c9a8 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.RemoteViews.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.RemoteViews.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.SimpleAdapter.html b/docs/html/sdk/api_diff/23/changes/android.widget.SimpleAdapter.html
index 393dc93..8a7f9e9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.SimpleAdapter.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.SimpleAdapter.html
@@ -116,8 +116,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.Spinner.html b/docs/html/sdk/api_diff/23/changes/android.widget.Spinner.html
index 00a97ee..cb1ca3e 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.Spinner.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.Spinner.html
@@ -123,8 +123,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.Switch.html b/docs/html/sdk/api_diff/23/changes/android.widget.Switch.html
index f034770..bdbed7c 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.Switch.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.Switch.html
@@ -157,8 +157,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.TextView.html b/docs/html/sdk/api_diff/23/changes/android.widget.TextView.html
index 015f191..67a9611 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.TextView.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.TextView.html
@@ -196,8 +196,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.TimePicker.html b/docs/html/sdk/api_diff/23/changes/android.widget.TimePicker.html
index bad99a3..82541e9 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.TimePicker.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.TimePicker.html
@@ -177,8 +177,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/android.widget.Toolbar.html b/docs/html/sdk/api_diff/23/changes/android.widget.Toolbar.html
index 22cc2e5..3cbeea6 100644
--- a/docs/html/sdk/api_diff/23/changes/android.widget.Toolbar.html
+++ b/docs/html/sdk/api_diff/23/changes/android.widget.Toolbar.html
@@ -115,8 +115,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/changes-summary.html b/docs/html/sdk/api_diff/23/changes/changes-summary.html
index 39be588..604e4d2 100644
--- a/docs/html/sdk/api_diff/23/changes/changes-summary.html
+++ b/docs/html/sdk/api_diff/23/changes/changes-summary.html
@@ -697,8 +697,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/classes_index_additions.html b/docs/html/sdk/api_diff/23/changes/classes_index_additions.html
index bdea58d..a36f690 100644
--- a/docs/html/sdk/api_diff/23/changes/classes_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/classes_index_additions.html
@@ -404,8 +404,7 @@
 <A HREF="pkg_android.webkit.html#WebMessagePort.WebMessageCallback" class="hiddenlink" target="rightframe"><b>WebMessagePort.WebMessageCallback</b></A><br>
 <A HREF="pkg_android.webkit.html#WebResourceError" class="hiddenlink" target="rightframe"><b>WebResourceError</b></A><br>
 <A HREF="pkg_android.webkit.html#WebView.VisualStateCallback" class="hiddenlink" target="rightframe"><b>WebView.VisualStateCallback</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/classes_index_all.html b/docs/html/sdk/api_diff/23/changes/classes_index_all.html
index d1d50f1..f8b9958 100644
--- a/docs/html/sdk/api_diff/23/changes/classes_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/classes_index_all.html
@@ -1009,8 +1009,7 @@
 <A HREF="android.net.wifi.WifiManager.html" class="hiddenlink" target="rightframe">WifiManager</A><br>
 <A HREF="android.view.Window.Callback.html" class="hiddenlink" target="rightframe"><i>Window.Callback</i></A><br>
 <A HREF="android.view.WindowManager.LayoutParams.html" class="hiddenlink" target="rightframe">WindowManager.LayoutParams</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/classes_index_changes.html b/docs/html/sdk/api_diff/23/changes/classes_index_changes.html
index a52e320..a2cef35 100644
--- a/docs/html/sdk/api_diff/23/changes/classes_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/classes_index_changes.html
@@ -854,8 +854,7 @@
 <A HREF="android.net.wifi.WifiManager.html" class="hiddenlink" target="rightframe">WifiManager</A><br>
 <A HREF="android.view.Window.Callback.html" class="hiddenlink" target="rightframe"><i>Window.Callback</i></A><br>
 <A HREF="android.view.WindowManager.LayoutParams.html" class="hiddenlink" target="rightframe">WindowManager.LayoutParams</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/classes_index_removals.html b/docs/html/sdk/api_diff/23/changes/classes_index_removals.html
index 7b780a6..5a939b2 100644
--- a/docs/html/sdk/api_diff/23/changes/classes_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/classes_index_removals.html
@@ -213,8 +213,7 @@
 <p><div style="line-height:1.5em;color:black">
 <A HREF="pkg_org.apache.http.conn.scheme.html#Scheme" class="hiddenlink" target="rightframe"><strike>Scheme</strike></A><br>
 <A HREF="pkg_org.apache.http.conn.scheme.html#SchemeRegistry" class="hiddenlink" target="rightframe"><strike>SchemeRegistry</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/constructors_index_additions.html b/docs/html/sdk/api_diff/23/changes/constructors_index_additions.html
index 53e7ab5..dec3a51 100644
--- a/docs/html/sdk/api_diff/23/changes/constructors_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/constructors_index_additions.html
@@ -113,8 +113,7 @@
 <p><div style="line-height:1.5em;color:black">
 <nobr><A HREF="android.os.TransactionTooLargeException.html#android.os.TransactionTooLargeException.ctor_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>TransactionTooLargeException</b>
 (<code>String</code>)</A></nobr>&nbsp;constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/constructors_index_all.html b/docs/html/sdk/api_diff/23/changes/constructors_index_all.html
index 6c7df45..de56e33 100644
--- a/docs/html/sdk/api_diff/23/changes/constructors_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/constructors_index_all.html
@@ -159,8 +159,7 @@
 <p><div style="line-height:1.5em;color:black">
 <nobr><A HREF="android.os.TransactionTooLargeException.html#android.os.TransactionTooLargeException.ctor_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>TransactionTooLargeException</b>
 (<code>String</code>)</A></nobr>&nbsp;constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/constructors_index_changes.html b/docs/html/sdk/api_diff/23/changes/constructors_index_changes.html
index 409c83f..ac9eca1 100644
--- a/docs/html/sdk/api_diff/23/changes/constructors_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/constructors_index_changes.html
@@ -55,8 +55,7 @@
 (<code>int, CharSequence, PendingIntent</code>)</A></nobr>&nbsp;constructor<br>
 <nobr><A HREF="android.app.Notification.Action.Builder.html#android.app.Notification.Action.Builder.ctor_changed(int, java.lang.CharSequence, android.app.PendingIntent)" class="hiddenlink" target="rightframe">Notification.Action.Builder
 (<code>int, CharSequence, PendingIntent</code>)</A></nobr>&nbsp;constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/constructors_index_removals.html b/docs/html/sdk/api_diff/23/changes/constructors_index_removals.html
index 002ee1c..bff4a22 100644
--- a/docs/html/sdk/api_diff/23/changes/constructors_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/constructors_index_removals.html
@@ -71,8 +71,7 @@
 <p><div style="line-height:1.5em;color:black">
 <nobr><A HREF="android.os.RecoverySystem.html#android.os.RecoverySystem.ctor_removed()" class="hiddenlink" target="rightframe"><strike>RecoverySystem</strike>
 ()</A></nobr>&nbsp;constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/fields_index_additions.html b/docs/html/sdk/api_diff/23/changes/fields_index_additions.html
index 59b8967..8ca1d60 100644
--- a/docs/html/sdk/api_diff/23/changes/fields_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/fields_index_additions.html
@@ -1622,8 +1622,7 @@
 </nobr><br>
 <nobr><A HREF="android.graphics.ImageFormat.html#android.graphics.ImageFormat.YUV_444_888" class="hiddenlink" target="rightframe">YUV_444_888</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/fields_index_all.html b/docs/html/sdk/api_diff/23/changes/fields_index_all.html
index 8d2742f..6ca8cd9 100644
--- a/docs/html/sdk/api_diff/23/changes/fields_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/fields_index_all.html
@@ -1972,8 +1972,7 @@
 </nobr><br>
 <nobr><A HREF="android.graphics.ImageFormat.html#android.graphics.ImageFormat.YUV_444_888" class="hiddenlink" target="rightframe">YUV_444_888</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/fields_index_changes.html b/docs/html/sdk/api_diff/23/changes/fields_index_changes.html
index d1c45ba..d622434 100644
--- a/docs/html/sdk/api_diff/23/changes/fields_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/fields_index_changes.html
@@ -532,8 +532,7 @@
 </nobr><br>
 <nobr><A HREF="android.R.attr.html#android.R.attr.yearListSelectorColor" class="hiddenlink" target="rightframe">yearListSelectorColor</A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/fields_index_removals.html b/docs/html/sdk/api_diff/23/changes/fields_index_removals.html
index 0725278..0882d50 100644
--- a/docs/html/sdk/api_diff/23/changes/fields_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/fields_index_removals.html
@@ -556,8 +556,7 @@
 <nobr>&nbsp;in&nbsp;
 <A HREF="android.Manifest.permission_group.html#android.Manifest.permission_group.WRITE_USER_DICTIONARY" class="hiddenlink" target="rightframe"><strike>android.Manifest.permission_group</strike></A>
 </nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/jdiff_help.html b/docs/html/sdk/api_diff/23/changes/jdiff_help.html
index acb8508..f909615 100644
--- a/docs/html/sdk/api_diff/23/changes/jdiff_help.html
+++ b/docs/html/sdk/api_diff/23/changes/jdiff_help.html
@@ -120,8 +120,7 @@
 There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
 In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
 </BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/jdiff_statistics.html b/docs/html/sdk/api_diff/23/changes/jdiff_statistics.html
index 26531a41..28a9e71 100644
--- a/docs/html/sdk/api_diff/23/changes/jdiff_statistics.html
+++ b/docs/html/sdk/api_diff/23/changes/jdiff_statistics.html
@@ -1673,8 +1673,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/jdiff_topleftframe.html b/docs/html/sdk/api_diff/23/changes/jdiff_topleftframe.html
index 36f9836..fc5c9d4 100644
--- a/docs/html/sdk/api_diff/23/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/api_diff/23/changes/jdiff_topleftframe.html
@@ -49,8 +49,7 @@
   <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
 </TR>
 </TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/methods_index_additions.html b/docs/html/sdk/api_diff/23/changes/methods_index_additions.html
index 4cb030a..5788a46 100644
--- a/docs/html/sdk/api_diff/23/changes/methods_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/methods_index_additions.html
@@ -1752,8 +1752,7 @@
 (<code>int, float</code>)</A></nobr><br>
 <nobr><A HREF="android.os.Parcel.html#android.os.Parcel.writeTypedObject_added(T, int)" class="hiddenlink" target="rightframe"><b>writeTypedObject</b>
 (<code>T, int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/methods_index_all.html b/docs/html/sdk/api_diff/23/changes/methods_index_all.html
index a5e688d..4fac9c7 100644
--- a/docs/html/sdk/api_diff/23/changes/methods_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/methods_index_all.html
@@ -2190,8 +2190,7 @@
 (<code>int, float</code>)</A></nobr><br>
 <nobr><A HREF="android.os.Parcel.html#android.os.Parcel.writeTypedObject_added(T, int)" class="hiddenlink" target="rightframe"><b>writeTypedObject</b>
 (<code>T, int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/methods_index_changes.html b/docs/html/sdk/api_diff/23/changes/methods_index_changes.html
index 6923ce2..ff0f73e 100644
--- a/docs/html/sdk/api_diff/23/changes/methods_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/methods_index_changes.html
@@ -511,8 +511,7 @@
 &nbsp;&nbsp;<nobr><A HREF="android.graphics.drawable.ScaleDrawable.html#android.graphics.drawable.ScaleDrawable.unscheduleDrawable_changed(android.graphics.drawable.Drawable, java.lang.Runnable)" class="hiddenlink" target="rightframe">type&nbsp;
 (<code>Drawable, Runnable</code>)&nbsp;in&nbsp;android.graphics.drawable.ScaleDrawable
 </A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/methods_index_removals.html b/docs/html/sdk/api_diff/23/changes/methods_index_removals.html
index 4f81ae9..c99af38 100644
--- a/docs/html/sdk/api_diff/23/changes/methods_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/methods_index_removals.html
@@ -336,8 +336,7 @@
 <p><div style="line-height:1.5em;color:black">
 <nobr><A HREF="android.provider.Browser.html#android.provider.Browser.updateVisitedHistory_removed(android.content.ContentResolver, java.lang.String, boolean)" class="hiddenlink" target="rightframe"><strike>updateVisitedHistory</strike>
 (<code>ContentResolver, String, boolean</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/packages_index_additions.html b/docs/html/sdk/api_diff/23/changes/packages_index_additions.html
index cefe356..7fc99fa 100644
--- a/docs/html/sdk/api_diff/23/changes/packages_index_additions.html
+++ b/docs/html/sdk/api_diff/23/changes/packages_index_additions.html
@@ -55,8 +55,7 @@
 <A HREF="changes-summary.html#android.media.midi" class="hiddenlink" target="rightframe"><b>android.media.midi</b></A><br>
 <A HREF="changes-summary.html#android.security.keystore" class="hiddenlink" target="rightframe"><b>android.security.keystore</b></A><br>
 <A HREF="changes-summary.html#android.service.chooser" class="hiddenlink" target="rightframe"><b>android.service.chooser</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/packages_index_all.html b/docs/html/sdk/api_diff/23/changes/packages_index_all.html
index 1245d79..dd2cf5d 100644
--- a/docs/html/sdk/api_diff/23/changes/packages_index_all.html
+++ b/docs/html/sdk/api_diff/23/changes/packages_index_all.html
@@ -136,8 +136,7 @@
 <A HREF="pkg_org.apache.http.params.html" class="hiddenlink" target="rightframe">org.apache.http.params</A><br>
 <A HREF="changes-summary.html#org.apache.http.protocol" class="hiddenlink" target="rightframe"><strike>org.apache.http.protocol</strike></A><br>
 <A HREF="changes-summary.html#org.apache.http.util" class="hiddenlink" target="rightframe"><strike>org.apache.http.util</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/packages_index_changes.html b/docs/html/sdk/api_diff/23/changes/packages_index_changes.html
index a06866b..ec301a6 100644
--- a/docs/html/sdk/api_diff/23/changes/packages_index_changes.html
+++ b/docs/html/sdk/api_diff/23/changes/packages_index_changes.html
@@ -103,8 +103,7 @@
 <A HREF="pkg_org.apache.http.conn.html" class="hiddenlink" target="rightframe">org.apache.http.conn</A><br>
 <A HREF="pkg_org.apache.http.conn.scheme.html" class="hiddenlink" target="rightframe">org.apache.http.conn.scheme</A><br>
 <A HREF="pkg_org.apache.http.params.html" class="hiddenlink" target="rightframe">org.apache.http.params</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/packages_index_removals.html b/docs/html/sdk/api_diff/23/changes/packages_index_removals.html
index 06f8ca7..fd7e1bd 100644
--- a/docs/html/sdk/api_diff/23/changes/packages_index_removals.html
+++ b/docs/html/sdk/api_diff/23/changes/packages_index_removals.html
@@ -78,8 +78,7 @@
 <A HREF="changes-summary.html#org.apache.http.message" class="hiddenlink" target="rightframe"><strike>org.apache.http.message</strike></A><br>
 <A HREF="changes-summary.html#org.apache.http.protocol" class="hiddenlink" target="rightframe"><strike>org.apache.http.protocol</strike></A><br>
 <A HREF="changes-summary.html#org.apache.http.util" class="hiddenlink" target="rightframe"><strike>org.apache.http.util</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.accounts.html b/docs/html/sdk/api_diff/23/changes/pkg_android.accounts.html
index f959c44..4e34f17 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.accounts.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.accounts.html
@@ -112,8 +112,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.app.admin.html b/docs/html/sdk/api_diff/23/changes/pkg_android.app.admin.html
index 5e7a3fa..62d0b1d 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.app.admin.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.app.admin.html
@@ -127,8 +127,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.app.html b/docs/html/sdk/api_diff/23/changes/pkg_android.app.html
index d6294d2..fcb19b1 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.app.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.app.html
@@ -379,8 +379,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.app.usage.html b/docs/html/sdk/api_diff/23/changes/pkg_android.app.usage.html
index d206bb0..075cc0a 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.app.usage.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.app.usage.html
@@ -141,8 +141,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.html b/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.html
index 183589d..2a44372 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.le.html b/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.le.html
index 2301b5a..f606cad 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.le.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.bluetooth.le.html
@@ -112,8 +112,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.content.html b/docs/html/sdk/api_diff/23/changes/pkg_android.content.html
index b7104d5..d883af0 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.content.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.content.html
@@ -154,8 +154,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.content.pm.html b/docs/html/sdk/api_diff/23/changes/pkg_android.content.pm.html
index 790ca7a..612eb4e 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.content.pm.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.content.pm.html
@@ -126,8 +126,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.content.res.html b/docs/html/sdk/api_diff/23/changes/pkg_android.content.res.html
index 1caebb8..f9dea56 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.content.res.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.content.res.html
@@ -126,8 +126,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.database.html b/docs/html/sdk/api_diff/23/changes/pkg_android.database.html
index 6267710..356534f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.database.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.database.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.drawable.html b/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.drawable.html
index dab2acb..4ba1c23 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.drawable.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.drawable.html
@@ -197,8 +197,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.html b/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.html
index 165d9eb..81037e3 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.graphics.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.html b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.html
index e5f179d..bc66e2e 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.html
@@ -183,8 +183,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.params.html b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.params.html
index 8a78e5e..fb7a8e3 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.params.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.camera2.params.html
@@ -120,8 +120,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.html b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.html
index 52fd539..8be6ae2 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.usb.html b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.usb.html
index 2862880..2f0318f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.usb.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.hardware.usb.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.html b/docs/html/sdk/api_diff/23/changes/pkg_android.html
index 3ccac32..096a6f4 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.html
@@ -140,8 +140,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.media.browse.html b/docs/html/sdk/api_diff/23/changes/pkg_android.media.browse.html
index 54ab1a2..016384b 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.media.browse.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.media.browse.html
@@ -120,8 +120,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.media.html b/docs/html/sdk/api_diff/23/changes/pkg_android.media.html
index 4dfad89..5014aa3 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.media.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.media.html
@@ -435,8 +435,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.media.session.html b/docs/html/sdk/api_diff/23/changes/pkg_android.media.session.html
index cad4d34..6788832 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.media.session.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.media.session.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.media.tv.html b/docs/html/sdk/api_diff/23/changes/pkg_android.media.tv.html
index f11fb38..f9e5705 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.media.tv.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.media.tv.html
@@ -176,8 +176,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.net.html b/docs/html/sdk/api_diff/23/changes/pkg_android.net.html
index 9ccdbe5..8f803e5 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.net.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.net.html
@@ -162,8 +162,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.net.http.html b/docs/html/sdk/api_diff/23/changes/pkg_android.net.http.html
index 0377a16..2ffbe52 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.net.http.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.net.http.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.net.wifi.html b/docs/html/sdk/api_diff/23/changes/pkg_android.net.wifi.html
index 894e26d..97cc79a 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.net.wifi.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.net.wifi.html
@@ -133,8 +133,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.nfc.html b/docs/html/sdk/api_diff/23/changes/pkg_android.nfc.html
index cd49ac9..9914d0f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.nfc.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.nfc.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.os.html b/docs/html/sdk/api_diff/23/changes/pkg_android.os.html
index 8dce606..68cda00 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.os.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.os.html
@@ -239,8 +239,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.print.html b/docs/html/sdk/api_diff/23/changes/pkg_android.print.html
index cdc3ad1..0543c691 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.print.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.print.html
@@ -126,8 +126,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.printservice.html b/docs/html/sdk/api_diff/23/changes/pkg_android.printservice.html
index 4129503..bb0617f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.printservice.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.printservice.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.provider.html b/docs/html/sdk/api_diff/23/changes/pkg_android.provider.html
index d129a28..e1b48cc 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.provider.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.provider.html
@@ -317,8 +317,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.renderscript.html b/docs/html/sdk/api_diff/23/changes/pkg_android.renderscript.html
index 82cf241..30ab1b7 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.renderscript.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.renderscript.html
@@ -204,8 +204,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.security.html b/docs/html/sdk/api_diff/23/changes/pkg_android.security.html
index 222b20a..af4daf0 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.security.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.security.html
@@ -148,8 +148,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.service.carrier.html b/docs/html/sdk/api_diff/23/changes/pkg_android.service.carrier.html
index a2d5e6d..fb256f8 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.service.carrier.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.service.carrier.html
@@ -127,8 +127,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.service.dreams.html b/docs/html/sdk/api_diff/23/changes/pkg_android.service.dreams.html
index 32d27bd..aa6ded8 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.service.dreams.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.service.dreams.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.service.media.html b/docs/html/sdk/api_diff/23/changes/pkg_android.service.media.html
index 8596421..aa586e1 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.service.media.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.service.media.html
@@ -120,8 +120,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.service.notification.html b/docs/html/sdk/api_diff/23/changes/pkg_android.service.notification.html
index 3fb4785..d599f80 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.service.notification.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.service.notification.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.service.voice.html b/docs/html/sdk/api_diff/23/changes/pkg_android.service.voice.html
index 1f27d84..32fa5b4 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.service.voice.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.service.voice.html
@@ -169,8 +169,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.speech.html b/docs/html/sdk/api_diff/23/changes/pkg_android.speech.html
index a88f1ba..6b18133 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.speech.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.speech.html
@@ -112,8 +112,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.speech.tts.html b/docs/html/sdk/api_diff/23/changes/pkg_android.speech.tts.html
index 59de522..ebe7ab4 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.speech.tts.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.speech.tts.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.system.html b/docs/html/sdk/api_diff/23/changes/pkg_android.system.html
index ef568e0..fd9765f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.system.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.system.html
@@ -105,8 +105,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.telecom.html b/docs/html/sdk/api_diff/23/changes/pkg_android.telecom.html
index 39f0245..10f3af7 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.telecom.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.telecom.html
@@ -302,8 +302,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.telephony.html b/docs/html/sdk/api_diff/23/changes/pkg_android.telephony.html
index b4abb53..4bdcf13 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.telephony.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.telephony.html
@@ -155,8 +155,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.test.mock.html b/docs/html/sdk/api_diff/23/changes/pkg_android.test.mock.html
index b1f13ee..fae868d 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.test.mock.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.test.mock.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.text.html b/docs/html/sdk/api_diff/23/changes/pkg_android.text.html
index c8e15ac..37443f1 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.text.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.text.html
@@ -127,8 +127,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.transition.html b/docs/html/sdk/api_diff/23/changes/pkg_android.transition.html
index 03173a1..d15a1bb 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.transition.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.transition.html
@@ -127,8 +127,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.util.html b/docs/html/sdk/api_diff/23/changes/pkg_android.util.html
index 8156cfb..23e26da 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.util.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.util.html
@@ -141,8 +141,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.view.accessibility.html b/docs/html/sdk/api_diff/23/changes/pkg_android.view.accessibility.html
index ae13a87..9f919e3 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.view.accessibility.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.view.accessibility.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.view.html b/docs/html/sdk/api_diff/23/changes/pkg_android.view.html
index ec3257a..07378a2 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.view.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.view.html
@@ -274,8 +274,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.webkit.html b/docs/html/sdk/api_diff/23/changes/pkg_android.webkit.html
index 80b4df0..331bd20 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.webkit.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.webkit.html
@@ -169,8 +169,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_android.widget.html b/docs/html/sdk/api_diff/23/changes/pkg_android.widget.html
index fb7ef96..0864272 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_android.widget.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_android.widget.html
@@ -253,8 +253,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.html b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.html
index 249df56..268c66f 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.html
@@ -203,8 +203,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.scheme.html b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.scheme.html
index fe7b3c7..870afbe 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.scheme.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.conn.scheme.html
@@ -119,8 +119,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.params.html b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.params.html
index 28f3469..792596c 100644
--- a/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.params.html
+++ b/docs/html/sdk/api_diff/23/changes/pkg_org.apache.http.params.html
@@ -154,8 +154,7 @@
     </div> <!-- end footer -->
     </div><!-- end doc-content -->
     </div> <!-- end body-content --> 
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
-</script>
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript"></script>
 <script type="text/javascript">
   try {
     var pageTracker = _gat._getTracker("UA-5831155-1");
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes.html
new file mode 100644
index 0000000..cdf8f36
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<!-- on Tue Aug 16 14:03:10 EDT 2016 -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
+</TITLE>
+<link href="../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</head>
+<frameset cols="242,**" framespacing="1" frameborder="yes" border="1" bordercolor="#e9e9e9"> 
+<frameset rows="174,**" framespacing="1" frameborder="yes"  border="1" bordercolor="#e9e9e9">
+    <frame src="changes/jdiff_topleftframe.html" scrolling="no" name="topleftframe" frameborder="1">
+    <frame src="changes/alldiffs_index_all.html" scrolling="auto" name="bottomleftframe" frameborder="1">
+  </frameset>
+  <frame src="changes/changes-summary.html" scrolling="auto" name="rightframe" frameborder="1">
+</frameset>
+<noframes>
+<h2>
+Frame Alert
+</h2>
+
+<p>
+This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+<br>
+Link to <a href="changes/changes-summary.html" target="_top">Non-frame version.</A>
+</noframes>
+</html>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
new file mode 100644
index 0000000..cb62aa8
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
@@ -0,0 +1,947 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+All Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
+  <br>
+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
+<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
+<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
+</nobr><br>
+<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
+</nobr><br>
+<!-- Field ACTION_ARGUMENT_ROW_INT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
+</nobr><br>
+<!-- Field ACTION_CONTEXT_CLICK -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_DOWN -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_LEFT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_RIGHT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_TO_POSITION -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_UP -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
+</nobr><br>
+<!-- Field ACTION_SET_PROGRESS -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
+</nobr><br>
+<!-- Field ACTION_SHOW_ON_SCREEN -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
+</nobr><br>
+<!-- Class ActionBarActivity -->
+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
+<!-- Class ActionMenuView -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
+<!-- Class ActionMenuView.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
+<!-- Class ActionMenuView.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
+<!-- Method addTouchExplorationStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<!-- Package android.support.transition -->
+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
+<!-- Package android.support.v4.text.util -->
+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
+<!-- Class AppCompatActivity -->
+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
+<!-- Class AppCompatAutoCompleteTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
+<!-- Class AppCompatButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
+<!-- Class AppCompatCheckBox -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
+<!-- Class AppCompatCheckedTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
+<!-- Class AppCompatDialogFragment -->
+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
+<!-- Class AppCompatEditText -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
+<!-- Class AppCompatImageButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
+<!-- Class AppCompatImageView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
+<!-- Class AppCompatMultiAutoCompleteTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
+<!-- Class AppCompatRadioButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
+<!-- Class AppCompatRatingBar -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
+<!-- Class AppCompatSeekBar -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
+<!-- Class AppCompatSpinner -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
+<!-- Class AppCompatTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
+<!-- Class BatchingListUpdateCallback -->
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
+<!-- Field BT_FOLDER_TYPE_ALBUMS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_ARTISTS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_GENRES -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_MIXED -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_TITLES -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_YEARS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
+</nobr><br>
+<!-- Method buildMediaButtonPendingIntent -->
+<i>buildMediaButtonPendingIntent</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<!-- Method buildMediaButtonPendingIntent -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<!-- Class CardView -->
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
+<!-- Method clearColorFilter -->
+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
+(<code>Drawable</code>)</A></nobr><br>
+<!-- Method clearOnTabSelectedListeners -->
+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
+()</A></nobr><br>
+<!-- Method computeScrollVectorForPosition -->
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
+(<code>int</code>)</A></nobr><br>
+<!-- Class DiffUtil -->
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
+<!-- Class DiffUtil.Callback -->
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
+<!-- Class DiffUtil.DiffResult -->
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
+<!-- Field dodgeInsetEdges -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
+</nobr><br>
+<!-- Field EXTRA_BT_FOLDER_TYPE -->
+<A NAME="E"></A>
+<br><font size="+2">E</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
+</nobr><br>
+<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
+</nobr><br>
+<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
+</nobr><br>
+<!-- Field EXTRA_USAGE_TIME_REPORT -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
+</nobr><br>
+<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
+</nobr><br>
+<!-- Method findFragmentByWho -->
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
+(<code>String</code>)</A></nobr><br>
+<!-- Method fromMediaItem -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method fromMediaItemList -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<!-- Method fromMediaSession -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
+(<code>Context, Object</code>)</A></nobr><br>
+<!-- Method fromQueueItem -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method fromQueueItemList -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<!-- Method getAction -->
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<!-- Method getCompoundDrawablesRelative -->
+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
+(<code>TextView</code>)</A></nobr><br>
+<!-- Method getDependents -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
+(<code>View</code>)</A></nobr><br>
+<!-- Method getDominantColor -->
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
+(<code>int</code>)</A></nobr><br>
+<!-- Method getDominantSwatch -->
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
+()</A></nobr><br>
+<!-- Method getDrawable -->
+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
+(<code>Context, int</code>)</A></nobr><br>
+<!-- Method getDrawerArrowDrawable -->
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
+()</A></nobr><br>
+<!-- Method getInsetDodgeRect -->
+<i>getInsetDodgeRect</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<!-- Method getInsetDodgeRect -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
+</A></nobr><br>
+<!-- Method getLaunchBounds -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
+()</A></nobr><br>
+<!-- Method getMediaItemNumberViewFlipper -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
+()</A></nobr><br>
+<!-- Method getMediaItemPausedView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
+()</A></nobr><br>
+<!-- Method getMediaItemPlayingView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
+()</A></nobr><br>
+<!-- Method getMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method getMovementGranularity -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<!-- Method getOnFlingListener -->
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
+()</A></nobr><br>
+<!-- Method getPasswordVisibilityToggleContentDescription -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
+()</A></nobr><br>
+<!-- Method getPasswordVisibilityToggleDrawable -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
+()</A></nobr><br>
+<!-- Method getSelectionMode -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
+()</A></nobr><br>
+<!-- Class GridLayout -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
+<!-- Class GridLayout.Alignment -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
+<!-- Class GridLayout.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
+<!-- Class GridLayout.Spec -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
+<!-- Field HOST_VIEW_ID -->
+<A NAME="H"></A>
+<br><font size="+2">H</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
+</nobr><br>
+<!-- Field insetEdge -->
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
+</nobr><br>
+<!-- Method isAtLeastNMR1 -->
+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
+()</A></nobr><br>
+<!-- Method isAutoHideEnabled -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
+()</A></nobr><br>
+<!-- Method isContextClickable -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
+()</A></nobr><br>
+<!-- Method isImmediateNotifySupported -->
+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
+()</A></nobr><br>
+<!-- Method isImportantForAccessibility -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
+(<code>View</code>)</A></nobr><br>
+<!-- Method isPasswordVisibilityToggleEnabled -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
+()</A></nobr><br>
+<!-- Class LinearLayoutCompat -->
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
+<!-- Class LinearLayoutCompat.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
+<!-- Class LinearSnapHelper -->
+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
+<!-- Class ListPopupWindow -->
+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
+<!-- Class ListUpdateCallback -->
+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
+<!-- Method loadDescription -->
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
+<!-- Method makeBasic -->
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
+()</A></nobr><br>
+<!-- Method makeClipRevealAnimation -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
+(<code>View, int, int, int, int</code>)</A></nobr><br>
+<!-- Method makeTaskLaunchBehind -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
+()</A></nobr><br>
+<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
+</nobr><br>
+<!-- Field METADATA_KEY_MEDIA_URI -->
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
+</nobr><br>
+<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
+<!-- Class NotificationCompat -->
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
+<!-- Class NotificationCompat.Builder -->
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
+<!-- Class NotificationCompat.MediaStyle -->
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
+<!-- Method notifyPlayStateChanged -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
+()</A></nobr><br>
+<!-- Method obtain -->
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
+</A></nobr><br>
+<!-- Method onAttachedToLayoutParams -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
+(<code>LayoutParams</code>)</A></nobr><br>
+<!-- Method onBindMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<!-- Method onChanged -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
+(<code>int, int, Object</code>)</A></nobr><br>
+<!-- Method onDetachedFromLayoutParams -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
+()</A></nobr><br>
+<!-- Method onRequestChildRectangleOnScreen -->
+<i>onRequestChildRectangleOnScreen</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
+</A></nobr><br>
+<!-- Method onRequestChildRectangleOnScreen -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<!-- Method onSharedElementsArrived -->
+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
+<!-- Method onStart -->
+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
+()</A></nobr><br>
+<!-- Method onUnbindMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<!-- Class PatternsCompat -->
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
+<!-- Field PEEK_HEIGHT_AUTO -->
+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
+</nobr><br>
+<!-- Field PLAY_STATE_INITIAL -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
+</nobr><br>
+<!-- Field PLAY_STATE_PAUSED -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
+</nobr><br>
+<!-- Field PLAY_STATE_PLAYING -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
+</nobr><br>
+<!-- Class PopupMenu -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
+<!-- Class PopupMenu.OnDismissListener -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
+<!-- Class PopupMenu.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
+<!-- Class RecyclerView.OnFlingListener -->
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
+<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
+<!-- Method removeTouchExplorationStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<!-- Method requestUsageTimeReport -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
+(<code>PendingIntent</code>)</A></nobr><br>
+<!-- Class SearchView -->
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
+<!-- Class SearchView.OnCloseListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
+<!-- Class SearchView.OnQueryTextListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
+<!-- Class SearchView.OnSuggestionListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
+<!-- Class SearchViewCompat.OnCloseListener -->
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
+<!-- Class SearchViewCompat.OnQueryTextListener -->
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
+<!-- Method setAction -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<!-- Method setAlwaysUseBrowserUI -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<!-- Method setAutoHideEnabled -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setCollapsedTitleTextColor -->
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setContextClickable -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setDrawerArrowDrawable -->
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
+<!-- Method setExpandedTitleTextColor -->
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setInstantAppsEnabled -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setLaunchBounds -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
+(<code>Rect</code>)</A></nobr><br>
+<!-- Method setMovementGranularity -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<!-- Method setOnChildScrollUpCallback -->
+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
+<!-- Method setOnFlingListener -->
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
+(<code>OnFlingListener</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleContentDescription -->
+<i>setPasswordVisibilityToggleContentDescription</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleContentDescription -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleDrawable -->
+<i>setPasswordVisibilityToggleDrawable</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleDrawable -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleEnabled -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleTintList -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleTintMode -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
+(<code>Mode</code>)</A></nobr><br>
+<!-- Method setSecondaryToolbarViews -->
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
+<!-- Method setSelectedMediaItemNumberView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
+(<code>int</code>)</A></nobr><br>
+<!-- Class ShareActionProvider -->
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
+<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
+<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
+<!-- Method shouldAlwaysUseBrowserUI -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<!-- Class SnapHelper -->
+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
+<!-- Class Space -->
+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
+<!-- Field STOP_FOREGROUND_DETACH -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
+</nobr><br>
+<!-- Field STOP_FOREGROUND_REMOVE -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
+</nobr><br>
+<!-- Method stopForeground -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
+(<code>Service, int</code>)</A></nobr><br>
+<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
+<!-- Class SwitchCompat -->
+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
+<!-- Class ThemedSpinnerAdapter -->
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
+<!-- Class ThemedSpinnerAdapter.Helper -->
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
+<!-- Method toKeyCode -->
+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
+(<code>long</code>)</A></nobr><br>
+<!-- Class Toolbar -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
+<!-- Class Toolbar.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
+<!-- Class Toolbar.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
+<!-- Class Toolbar.SavedState -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
+<!-- Field TYPE_ASSIST_READING_CONTEXT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
+</nobr><br>
+<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
+</nobr><br>
+<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
+</nobr><br>
+<!-- Field TYPE_WINDOWS_CHANGED -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
+</nobr><br>
+<!-- Constructor WindowInsetsCompat -->
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
new file mode 100644
index 0000000..719f9af
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
@@ -0,0 +1,1327 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+All Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>All Differences</b>
+  <br>
+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<!-- Class AbstractMediaItemPresenter -->
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
+<!-- Class AbstractMediaItemPresenter.ViewHolder -->
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
+<!-- Class AccessibilityEventCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
+<!-- Class AccessibilityManagerCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListener -->
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
+<!-- Class AccessibilityManagerCompat.TouchExplorationStateChangeListener -->
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
+<!-- Class AccessibilityNodeInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
+<!-- Class AccessibilityNodeProviderCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
+<!-- Class AccessibilityServiceInfoCompat -->
+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
+<!-- Class AccessibilityWindowInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
+<!-- Field ACTION_ARGUMENT_COLUMN_INT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
+</nobr><br>
+<!-- Field ACTION_ARGUMENT_PROGRESS_VALUE -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
+</nobr><br>
+<!-- Field ACTION_ARGUMENT_ROW_INT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
+</nobr><br>
+<!-- Field ACTION_CONTEXT_CLICK -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_DOWN -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_LEFT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_RIGHT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_TO_POSITION -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
+</nobr><br>
+<!-- Field ACTION_SCROLL_UP -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
+</nobr><br>
+<!-- Field ACTION_SET_PROGRESS -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
+</nobr><br>
+<!-- Field ACTION_SHOW_ON_SCREEN -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
+</nobr><br>
+<!-- Class ActionBarActivity -->
+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
+<!-- Class ActionBarDrawerToggle -->
+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
+<!-- Class ActionMenuView -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
+<!-- Class ActionMenuView.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
+<!-- Class ActionMenuView.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
+<!-- Class ActivityCompat -->
+<i>ActivityCompat</i><br>
+&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<!-- Constructor ActivityCompat -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
+()</A></nobr>&nbsp;constructor<br>
+<!-- Class ActivityOptionsCompat -->
+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
+<!-- Method addAccessibilityStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<!-- Method addTouchExplorationStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<!-- Package android.support.customtabs -->
+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
+<!-- Package android.support.design.widget -->
+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
+<!-- Package android.support.transition -->
+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
+<!-- Package android.support.v14.preference -->
+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
+<!-- Package android.support.v17.leanback.widget -->
+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
+<!-- Package android.support.v17.preference -->
+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
+<!-- Package android.support.v4.accessibilityservice -->
+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
+<!-- Package android.support.v4.app -->
+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<!-- Package android.support.v4.content -->
+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<!-- Package android.support.v4.graphics.drawable -->
+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
+<!-- Package android.support.v4.media -->
+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
+<!-- Package android.support.v4.media.session -->
+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
+<!-- Package android.support.v4.os -->
+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
+<!-- Package android.support.v4.text.util -->
+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
+<!-- Package android.support.v4.util -->
+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
+<!-- Package android.support.v4.view -->
+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
+<!-- Package android.support.v4.view.accessibility -->
+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
+<!-- Package android.support.v4.widget -->
+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
+<!-- Package android.support.v7.app -->
+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
+<!-- Package android.support.v7.appcompat -->
+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
+<!-- Package android.support.v7.content.res -->
+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
+<!-- Package android.support.v7.graphics -->
+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
+<!-- Package android.support.v7.preference -->
+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
+<!-- Package android.support.v7.recyclerview -->
+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
+<!-- Package android.support.v7.util -->
+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
+<!-- Package android.support.v7.widget -->
+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
+<!-- Package android.support.v8.renderscript -->
+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
+<!-- Class AppBarLayout.ScrollingViewBehavior -->
+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
+<!-- Class AppCompatActivity -->
+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
+<!-- Class AppCompatAutoCompleteTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
+<!-- Class AppCompatButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
+<!-- Class AppCompatCheckBox -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
+<!-- Class AppCompatCheckedTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
+<!-- Class AppCompatDelegate -->
+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
+<!-- Class AppCompatDialogFragment -->
+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
+<!-- Class AppCompatEditText -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
+<!-- Class AppCompatImageButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
+<!-- Class AppCompatImageView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
+<!-- Class AppCompatMultiAutoCompleteTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
+<!-- Class AppCompatRadioButton -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
+<!-- Class AppCompatRatingBar -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
+<!-- Class AppCompatResources -->
+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
+<!-- Class AppCompatSeekBar -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
+<!-- Class AppCompatSpinner -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
+<!-- Class AppCompatTextView -->
+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
+<!-- Class BatchingListUpdateCallback -->
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
+<!-- Class BottomSheetBehavior -->
+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
+<!-- Field BT_FOLDER_TYPE_ALBUMS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_ARTISTS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_GENRES -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_MIXED -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_PLAYLISTS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_TITLES -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
+</nobr><br>
+<!-- Field BT_FOLDER_TYPE_YEARS -->
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
+</nobr><br>
+<!-- Class BuildCompat -->
+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
+<!-- Method buildMediaButtonPendingIntent -->
+<i>buildMediaButtonPendingIntent</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<!-- Method buildMediaButtonPendingIntent -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<!-- Class CardView -->
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
+<!-- Method clearColorFilter -->
+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
+(<code>Drawable</code>)</A></nobr><br>
+<!-- Method clearOnTabSelectedListeners -->
+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
+()</A></nobr><br>
+<!-- Class CollapsingToolbarLayout -->
+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
+<!-- Method computeScrollVectorForPosition -->
+<i>computeScrollVectorForPosition</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
+</A></nobr><br>
+<!-- Method computeScrollVectorForPosition -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
+</A></nobr><br>
+<!-- Class ContextCompat -->
+<i>ContextCompat</i><br>
+&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<!-- Constructor ContextCompat -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
+()</A></nobr>&nbsp;constructor<br>
+<!-- Class CoordinatorLayout -->
+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
+<!-- Class CoordinatorLayout.Behavior -->
+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
+<!-- Class CoordinatorLayout.LayoutParams -->
+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
+<!-- Class CustomTabsIntent -->
+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
+<!-- Class CustomTabsIntent.Builder -->
+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
+<!-- Class CustomTabsSession -->
+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
+<!-- Class DiffUtil -->
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
+<!-- Class DiffUtil.Callback -->
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
+<!-- Class DiffUtil.DiffResult -->
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
+<!-- Method dispatch -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
+<!-- Field dodgeInsetEdges -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
+</nobr><br>
+<!-- Class DrawableCompat -->
+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
+<!-- Field EXTRA_BT_FOLDER_TYPE -->
+<A NAME="E"></A>
+<br><font size="+2">E</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
+</nobr><br>
+<!-- Field EXTRA_ENABLE_INSTANT_APPS -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
+</nobr><br>
+<!-- Field EXTRA_SUGGESTION_KEYWORDS -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
+</nobr><br>
+<!-- Field EXTRA_USAGE_TIME_REPORT -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
+</nobr><br>
+<!-- Field EXTRA_USAGE_TIME_REPORT_PACKAGES -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
+</nobr><br>
+<!-- Method findFragmentByWho -->
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
+(<code>String</code>)</A></nobr><br>
+<!-- Method findPointerIndex -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Class FloatingActionButton.Behavior -->
+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
+<!-- Class FragmentController -->
+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
+<!-- Method fromMediaItem -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method fromMediaItemList -->
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<!-- Method fromMediaSession -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
+(<code>Context, Object</code>)</A></nobr><br>
+<!-- Method fromQueueItem -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method fromQueueItemList -->
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<!-- Method getAction -->
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<!-- Method getCompoundDrawablesRelative -->
+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
+(<code>TextView</code>)</A></nobr><br>
+<!-- Method getDependents -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
+(<code>View</code>)</A></nobr><br>
+<!-- Method getDescription -->
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
+<!-- Method getDominantColor -->
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
+(<code>int</code>)</A></nobr><br>
+<!-- Method getDominantSwatch -->
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
+()</A></nobr><br>
+<!-- Method getDrawable -->
+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
+(<code>Context, int</code>)</A></nobr><br>
+<!-- Method getDrawerArrowDrawable -->
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
+()</A></nobr><br>
+<!-- Method getInsetDodgeRect -->
+<i>getInsetDodgeRect</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<!-- Method getInsetDodgeRect -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
+</A></nobr><br>
+<!-- Method getKeyDispatcherState -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
+(<code>View</code>)</A></nobr><br>
+<!-- Method getLaunchBounds -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
+()</A></nobr><br>
+<!-- Method getMediaItemNumberViewFlipper -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
+()</A></nobr><br>
+<!-- Method getMediaItemPausedView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
+()</A></nobr><br>
+<!-- Method getMediaItemPlayingView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
+()</A></nobr><br>
+<!-- Method getMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
+(<code>Object</code>)</A></nobr><br>
+<!-- Method getMovementGranularity -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<!-- Method getOnFlingListener -->
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
+()</A></nobr><br>
+<!-- Method getOverScrollMode -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
+(<code>View</code>)</A></nobr><br>
+<!-- Method getPasswordVisibilityToggleContentDescription -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
+()</A></nobr><br>
+<!-- Method getPasswordVisibilityToggleDrawable -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
+()</A></nobr><br>
+<!-- Method getPointerCount -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
+(<code>MotionEvent</code>)</A></nobr><br>
+<!-- Method getPointerId -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Method getReferrer -->
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
+(<code>Activity</code>)</A></nobr><br>
+<!-- Method getScaledPagingTouchSlop -->
+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
+(<code>ViewConfiguration</code>)</A></nobr><br>
+<!-- Method getSelectionMode -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
+()</A></nobr><br>
+<!-- Method getSource -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
+(<code>MotionEvent</code>)</A></nobr><br>
+<!-- Method getX -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Method getY -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Class GridLayout -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
+<!-- Class GridLayout.Alignment -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
+<!-- Class GridLayout.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
+<!-- Class GridLayout.Spec -->
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
+<!-- Field HOST_VIEW_ID -->
+<A NAME="H"></A>
+<br><font size="+2">H</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
+</nobr><br>
+<!-- Field insetEdge -->
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
+</nobr><br>
+<!-- Method isAtLeastNMR1 -->
+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
+()</A></nobr><br>
+<!-- Method isAutoHideEnabled -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
+()</A></nobr><br>
+<!-- Method isContextClickable -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
+()</A></nobr><br>
+<!-- Method isDirty -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
+<!-- Method isImmediateNotifySupported -->
+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
+()</A></nobr><br>
+<!-- Method isImportantForAccessibility -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
+(<code>View</code>)</A></nobr><br>
+<!-- Method isOpaque -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
+(<code>View</code>)</A></nobr><br>
+<!-- Method isPasswordVisibilityToggleEnabled -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
+()</A></nobr><br>
+<!-- Method isTracking -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<!-- Class KeyEventCompat -->
+<A NAME="K"></A>
+<br><font size="+2">K</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
+<!-- Method layoutDependsOn -->
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<!-- Class LeanbackSettingsFragment -->
+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
+<!-- Class LinearLayoutCompat -->
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
+<!-- Class LinearLayoutCompat.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
+<!-- Class LinearLayoutManager -->
+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
+<!-- Class LinearSmoothScroller -->
+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
+<!-- Class LinearSnapHelper -->
+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
+<!-- Class ListPopupWindow -->
+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
+<!-- Class ListUpdateCallback -->
+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
+<!-- Method loadDescription -->
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
+<!-- Method makeBasic -->
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
+()</A></nobr><br>
+<!-- Method makeClipRevealAnimation -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
+(<code>View, int, int, int, int</code>)</A></nobr><br>
+<!-- Method makeTaskLaunchBehind -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
+()</A></nobr><br>
+<!-- Class MediaBrowserCompat.MediaItem -->
+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
+<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
+<!-- Class MediaButtonReceiver -->
+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
+<!-- Class MediaDescriptionCompat -->
+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
+<!-- Class MediaMetadataCompat -->
+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
+<!-- Class MediaSessionCompat -->
+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
+<!-- Class MediaSessionCompat.QueueItem -->
+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
+<!-- Field METADATA_KEY_BT_FOLDER_TYPE -->
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
+</nobr><br>
+<!-- Field METADATA_KEY_MEDIA_URI -->
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
+</nobr><br>
+<!-- Class MotionEventCompat -->
+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
+<!-- Class MultiSelectListPreferenceDialogFragmentCompat -->
+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
+<!-- Class NotificationCompat -->
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
+<!-- Class NotificationCompat.Builder -->
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
+<!-- Class NotificationCompat.MediaStyle -->
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
+<!-- Method notifyPlayStateChanged -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
+()</A></nobr><br>
+<!-- Class ObjectAdapter -->
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
+<!-- Method obtain -->
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
+</A></nobr><br>
+<!-- Method onAccessibilityStateChanged -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method onAttachedToLayoutParams -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
+(<code>LayoutParams</code>)</A></nobr><br>
+<!-- Method onBindMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<!-- Method onChanged -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
+(<code>int, int, Object</code>)</A></nobr><br>
+<!-- Method onDependentViewRemoved -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<!-- Method onDetachedFromLayoutParams -->
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
+()</A></nobr><br>
+<!-- Method onInserted -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method onMoved -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method onRemoved -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method onRequestChildRectangleOnScreen -->
+<i>onRequestChildRectangleOnScreen</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
+</A></nobr><br>
+<!-- Method onRequestChildRectangleOnScreen -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<!-- Method onSharedElementsArrived -->
+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
+<!-- Method onStart -->
+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
+()</A></nobr><br>
+<!-- Method onUnbindMediaPlayState -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<!-- Field OVER_SCROLL_ALWAYS -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
+</nobr><br>
+<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
+</nobr><br>
+<!-- Field OVER_SCROLL_NEVER -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
+</nobr><br>
+<!-- Class Palette -->
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
+<!-- Class PatternsCompat -->
+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
+<!-- Field PEEK_HEIGHT_AUTO -->
+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
+</nobr><br>
+<!-- Field PLAY_STATE_INITIAL -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
+</nobr><br>
+<!-- Field PLAY_STATE_PAUSED -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
+</nobr><br>
+<!-- Field PLAY_STATE_PLAYING -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
+</nobr><br>
+<!-- Class PlaybackStateCompat -->
+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
+<!-- Class PopupMenu -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
+<!-- Class PopupMenu.OnDismissListener -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
+<!-- Class PopupMenu.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
+<!-- Class PreferenceFragment -->
+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
+<!-- Method prepareForDrop -->
+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
+(<code>View, View, int, int</code>)</A></nobr><br>
+<!-- Class RecyclerView -->
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
+<!-- Class RecyclerView.OnFlingListener -->
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
+<!-- Class RecyclerView.SmoothScroller.ScrollVectorProvider -->
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
+<!-- Method removeAccessibilityStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<!-- Method removeTouchExplorationStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<!-- Method requestUsageTimeReport -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
+(<code>PendingIntent</code>)</A></nobr><br>
+<!-- Class SearchView -->
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
+<!-- Class SearchView.OnCloseListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
+<!-- Class SearchView.OnQueryTextListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
+<!-- Class SearchView.OnSuggestionListener -->
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
+<!-- Class SearchViewCompat -->
+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
+<!-- Class SearchViewCompat.OnCloseListener -->
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
+<!-- Class SearchViewCompat.OnCloseListenerCompat -->
+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
+<!-- Class SearchViewCompat.OnQueryTextListener -->
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
+<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
+<!-- Class ServiceCompat -->
+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
+<!-- Method setAction -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<!-- Method setAlwaysUseBrowserUI -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<!-- Method setAutoHideEnabled -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setCollapsedTitleTextColor -->
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setContextClickable -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setDrawerArrowDrawable -->
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
+<!-- Method setExpandedTitleTextColor -->
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setInstantAppsEnabled -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setLaunchBounds -->
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
+(<code>Rect</code>)</A></nobr><br>
+<!-- Method setMovementGranularity -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<!-- Method setOnChildScrollUpCallback -->
+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
+<!-- Method setOnCloseListener -->
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
+(<code>View, OnCloseListener</code>)</A></nobr><br>
+<!-- Method setOnFlingListener -->
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
+(<code>OnFlingListener</code>)</A></nobr><br>
+<!-- Method setOnQueryTextListener -->
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
+<!-- Method setOverScrollMode -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
+(<code>View, int</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleContentDescription -->
+<i>setPasswordVisibilityToggleContentDescription</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleContentDescription -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleDrawable -->
+<i>setPasswordVisibilityToggleDrawable</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleDrawable -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleEnabled -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleTintList -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<!-- Method setPasswordVisibilityToggleTintMode -->
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
+(<code>Mode</code>)</A></nobr><br>
+<!-- Method setSecondaryToolbarViews -->
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
+<!-- Method setSelectedMediaItemNumberView -->
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
+(<code>int</code>)</A></nobr><br>
+<!-- Method setToolbarItem -->
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
+(<code>int, Bitmap, String</code>)</A></nobr><br>
+<!-- Class ShareActionProvider -->
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
+<!-- Class ShareActionProvider.OnShareTargetSelectedListener -->
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
+<!-- Class SharedElementCallback -->
+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
+<!-- Class SharedElementCallback.OnSharedElementsReadyListener -->
+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
+<!-- Method shouldAlwaysUseBrowserUI -->
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<!-- Class SnapHelper -->
+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
+<!-- Class SortedList.Callback -->
+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
+<!-- Class Space -->
+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
+<!-- Class StaggeredGridLayoutManager -->
+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
+<!-- Method startTracking -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<!-- Field STOP_FOREGROUND_DETACH -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
+</nobr><br>
+<!-- Field STOP_FOREGROUND_REMOVE -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
+</nobr><br>
+<!-- Method stopForeground -->
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
+(<code>Service, int</code>)</A></nobr><br>
+<!-- Class SwipeRefreshLayout -->
+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
+<!-- Class SwipeRefreshLayout.OnChildScrollUpCallback -->
+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
+<!-- Class SwitchCompat -->
+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
+<!-- Class TabLayout -->
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
+<!-- Field TAG -->
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
+</nobr><br>
+<!-- Class TextInputLayout -->
+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
+<!-- Class TextViewCompat -->
+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
+<!-- Class ThemedSpinnerAdapter -->
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
+<!-- Class ThemedSpinnerAdapter.Helper -->
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
+<!-- Method toKeyCode -->
+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
+(<code>long</code>)</A></nobr><br>
+<!-- Class Toolbar -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
+<!-- Class Toolbar.LayoutParams -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
+<!-- Class Toolbar.OnMenuItemClickListener -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
+<!-- Class Toolbar.SavedState -->
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
+<!-- Field TYPE_ASSIST_READING_CONTEXT -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
+</nobr><br>
+<!-- Field TYPE_SPLIT_SCREEN_DIVIDER -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
+</nobr><br>
+<!-- Field TYPE_VIEW_CONTEXT_CLICKED -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
+</nobr><br>
+<!-- Field TYPE_WINDOWS_CHANGED -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
+</nobr><br>
+<!-- Class ViewCompat -->
+<A NAME="V"></A>
+<br><font size="+2">V</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
+<!-- Class ViewConfigurationCompat -->
+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
+<!-- Class WindowInsetsCompat -->
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>WindowInsetsCompat</i><br>
+&nbsp;&nbsp;<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
+<!-- Constructor WindowInsetsCompat -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
new file mode 100644
index 0000000..854a487
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
@@ -0,0 +1,666 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+All Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
+  <br>
+<A HREF="alldiffs_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<!-- Class AbstractMediaItemPresenter -->
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
+<!-- Class AbstractMediaItemPresenter.ViewHolder -->
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
+<!-- Class AccessibilityEventCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
+<!-- Class AccessibilityManagerCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
+<!-- Class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.AccessibilityActionCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.CollectionInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.CollectionItemInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
+<!-- Class AccessibilityNodeInfoCompat.RangeInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
+<!-- Class AccessibilityNodeProviderCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
+<!-- Class AccessibilityServiceInfoCompat -->
+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
+<!-- Class AccessibilityWindowInfoCompat -->
+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
+<!-- Class ActionBarDrawerToggle -->
+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
+<!-- Class ActivityCompat -->
+<i>ActivityCompat</i><br>
+&nbsp;&nbsp;<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<!-- Constructor ActivityCompat -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
+()</A></nobr>&nbsp;constructor<br>
+<!-- Class ActivityOptionsCompat -->
+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
+<!-- Method addAccessibilityStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<!-- Package android.support.customtabs -->
+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
+<!-- Package android.support.design.widget -->
+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
+<!-- Package android.support.v14.preference -->
+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
+<!-- Package android.support.v17.leanback.widget -->
+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
+<!-- Package android.support.v17.preference -->
+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
+<!-- Package android.support.v4.accessibilityservice -->
+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
+<!-- Package android.support.v4.app -->
+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<!-- Package android.support.v4.content -->
+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<!-- Package android.support.v4.graphics.drawable -->
+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
+<!-- Package android.support.v4.media -->
+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
+<!-- Package android.support.v4.media.session -->
+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
+<!-- Package android.support.v4.os -->
+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
+<!-- Package android.support.v4.util -->
+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
+<!-- Package android.support.v4.view -->
+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
+<!-- Package android.support.v4.view.accessibility -->
+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
+<!-- Package android.support.v4.widget -->
+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
+<!-- Package android.support.v7.app -->
+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
+<!-- Package android.support.v7.content.res -->
+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
+<!-- Package android.support.v7.graphics -->
+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
+<!-- Package android.support.v7.preference -->
+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
+<!-- Package android.support.v7.util -->
+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
+<!-- Package android.support.v7.widget -->
+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
+<!-- Class AppBarLayout.ScrollingViewBehavior -->
+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
+<!-- Class AppCompatDelegate -->
+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
+<!-- Class AppCompatResources -->
+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
+<!-- Class BottomSheetBehavior -->
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
+<!-- Class BuildCompat -->
+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
+<!-- Class CollapsingToolbarLayout -->
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
+<!-- Method computeScrollVectorForPosition -->
+<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
+(<code>int</code>)</A></nobr><br>
+<!-- Class ContextCompat -->
+<i>ContextCompat</i><br>
+&nbsp;&nbsp;<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<!-- Constructor ContextCompat -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
+()</A></nobr>&nbsp;constructor<br>
+<!-- Class CoordinatorLayout -->
+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
+<!-- Class CoordinatorLayout.Behavior -->
+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
+<!-- Class CoordinatorLayout.LayoutParams -->
+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
+<!-- Class CustomTabsIntent -->
+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
+<!-- Class CustomTabsIntent.Builder -->
+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
+<!-- Class CustomTabsSession -->
+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
+<!-- Method dispatch -->
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
+<!-- Class DrawableCompat -->
+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
+<!-- Method findPointerIndex -->
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Class FloatingActionButton.Behavior -->
+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
+<!-- Class FragmentController -->
+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
+<!-- Method getDescription -->
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
+<!-- Method getKeyDispatcherState -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
+(<code>View</code>)</A></nobr><br>
+<!-- Method getOverScrollMode -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
+(<code>View</code>)</A></nobr><br>
+<!-- Method getPointerCount -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
+(<code>MotionEvent</code>)</A></nobr><br>
+<!-- Method getPointerId -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Method getReferrer -->
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
+(<code>Activity</code>)</A></nobr><br>
+<!-- Method getScaledPagingTouchSlop -->
+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
+(<code>ViewConfiguration</code>)</A></nobr><br>
+<!-- Method getSource -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
+(<code>MotionEvent</code>)</A></nobr><br>
+<!-- Method getX -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Method getY -->
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<!-- Method isDirty -->
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
+<!-- Method isOpaque -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
+(<code>View</code>)</A></nobr><br>
+<!-- Method isTracking -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<!-- Class KeyEventCompat -->
+<A NAME="K"></A>
+<br><font size="+2">K</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
+<!-- Class LeanbackSettingsFragment -->
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
+<!-- Class LinearLayoutManager -->
+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
+<!-- Class LinearSmoothScroller -->
+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
+<!-- Class MediaBrowserCompat.MediaItem -->
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
+<!-- Class MediaBrowserServiceCompat.BrowserRoot -->
+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
+<!-- Class MediaButtonReceiver -->
+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
+<!-- Class MediaDescriptionCompat -->
+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
+<!-- Class MediaMetadataCompat -->
+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
+<!-- Class MediaSessionCompat -->
+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
+<!-- Class MediaSessionCompat.QueueItem -->
+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
+<!-- Class MotionEventCompat -->
+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
+<!-- Class ObjectAdapter -->
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
+<!-- Method obtain -->
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
+</A></nobr><br>
+<!-- Method obtain -->
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
+</A></nobr><br>
+<!-- Field OVER_SCROLL_ALWAYS -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
+</nobr><br>
+<!-- Field OVER_SCROLL_IF_CONTENT_SCROLLS -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
+</nobr><br>
+<!-- Field OVER_SCROLL_NEVER -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
+</nobr><br>
+<!-- Class Palette -->
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
+<!-- Class PlaybackStateCompat -->
+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
+<!-- Class PreferenceFragment -->
+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
+<!-- Class RecyclerView -->
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
+<!-- Method removeAccessibilityStateChangeListener -->
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<!-- Class SearchViewCompat -->
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
+<!-- Class SearchViewCompat.OnCloseListenerCompat -->
+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
+<!-- Class SearchViewCompat.OnQueryTextListenerCompat -->
+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
+<!-- Class ServiceCompat -->
+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
+<!-- Method setOnCloseListener -->
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
+(<code>View, OnCloseListener</code>)</A></nobr><br>
+<!-- Method setOnQueryTextListener -->
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
+<!-- Method setOverScrollMode -->
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
+(<code>View, int</code>)</A></nobr><br>
+<!-- Method setToolbarItem -->
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
+(<code>int, Bitmap, String</code>)</A></nobr><br>
+<!-- Class SharedElementCallback -->
+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
+<!-- Class SortedList.Callback -->
+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
+<!-- Class StaggeredGridLayoutManager -->
+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
+<!-- Method startTracking -->
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<!-- Class SwipeRefreshLayout -->
+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
+<!-- Class TabLayout -->
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
+<!-- Class TextInputLayout -->
+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
+<!-- Class TextViewCompat -->
+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
+<!-- Class ViewCompat -->
+<A NAME="V"></A>
+<br><font size="+2">V</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
+<!-- Class ViewConfigurationCompat -->
+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
+<!-- Class WindowInsetsCompat -->
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
new file mode 100644
index 0000000..e6d9e07
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+All Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for All Differences" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="alldiffs_index_all.html" xclass="hiddenlink">All Differences</a>
+  <br>
+<b>Removals</b>
+  <br>
+<A HREF="alldiffs_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="alldiffs_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<!-- Package android.support.v7.appcompat -->
+<A NAME="A"></A>
+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
+<!-- Package android.support.v7.recyclerview -->
+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
+<!-- Package android.support.v8.renderscript -->
+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
+<!-- Method layoutDependsOn -->
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<!-- Method onAccessibilityStateChanged -->
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
+(<code>boolean</code>)</A></nobr><br>
+<!-- Method onDependentViewRemoved -->
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<!-- Method onInserted -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method onMoved -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method onRemoved -->
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<!-- Method prepareForDrop -->
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
+(<code>View, View, int, int</code>)</A></nobr><br>
+<!-- Field TAG -->
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
+</nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
new file mode 100644
index 0000000..d6a9415
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.customtabs.CustomTabsIntent.Builder
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html" target="_top"><font size="+2"><code>CustomTabsIntent.Builder</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"></A>
+  <nobr><code>Builder</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.Builder.html#setInstantAppsEnabled(boolean)" target="_top"><code>setInstantAppsEnabled</code></A>(<code>boolean</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
new file mode 100644
index 0000000..dd0b511
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.customtabs.CustomTabsIntent
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html" target="_top"><font size="+2"><code>CustomTabsIntent</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"></A>
+  <nobr><code>Intent</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>setAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#shouldAlwaysUseBrowserUI(android.content.Intent)" target="_top"><code>shouldAlwaysUseBrowserUI</code></A>(<code>Intent</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsIntent.html#EXTRA_ENABLE_INSTANT_APPS" target="_top"><code>EXTRA_ENABLE_INSTANT_APPS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
new file mode 100644
index 0000000..16cac31
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.customtabs.CustomTabsSession
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.customtabs.<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html" target="_top"><font size="+2"><code>CustomTabsSession</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)" target="_top"><code>setSecondaryToolbarViews</code></A>(<code>RemoteViews,</nobr> int[]<nobr>,</nobr> PendingIntent<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/customtabs/CustomTabsSession.html#setToolbarItem(int, android.graphics.Bitmap, java.lang.String)" target="_top"><code>setToolbarItem</code></A>(<code>int,</nobr> Bitmap<nobr>,</nobr> String<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
new file mode 100644
index 0000000..7e1e59a
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.AppBarLayout.ScrollingViewBehavior
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html" target="_top"><font size="+2"><code>AppBarLayout.ScrollingViewBehavior</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/AppBarLayout.ScrollingViewBehavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> View<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
new file mode 100644
index 0000000..e98c6f3
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.BottomSheetBehavior
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html" target="_top"><font size="+2"><code>BottomSheetBehavior</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/BottomSheetBehavior.html#PEEK_HEIGHT_AUTO" target="_top"><code>PEEK_HEIGHT_AUTO</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
new file mode 100644
index 0000000..ebfdce1
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.CollapsingToolbarLayout
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html" target="_top"><font size="+2"><code>CollapsingToolbarLayout</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setCollapsedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setCollapsedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CollapsingToolbarLayout.html#setExpandedTitleTextColor(android.content.res.ColorStateList)" target="_top"><code>setExpandedTitleTextColor</code></A>(<code>ColorStateList</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
new file mode 100644
index 0000000..8cf6146
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
@@ -0,0 +1,161 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.CoordinatorLayout.Behavior
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html" target="_top"><font size="+2"><code>CoordinatorLayout.Behavior</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)" target="_top"><code>onAttachedToLayoutParams</code></A>(<code>LayoutParams</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onDetachedFromLayoutParams()" target="_top"><code>onDetachedFromLayoutParams</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" target="_top"><code>onRequestChildRectangleOnScreen</code></A>(<code>CoordinatorLayout,</nobr> V<nobr>,</nobr> Rect<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.Behavior.html#isDirty(android.support.design.widget.CoordinatorLayout, V)" target="_top"><code>isDirty</code></A>(<code>CoordinatorLayout,</nobr> V<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
new file mode 100644
index 0000000..a36eab0
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.CoordinatorLayout.LayoutParams
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html" target="_top"><font size="+2"><code>CoordinatorLayout.LayoutParams</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#dodgeInsetEdges" target="_top"><code>dodgeInsetEdges</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#insetEdge" target="_top"><code>insetEdge</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
new file mode 100644
index 0000000..4a7247a
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.CoordinatorLayout
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html" target="_top"><font size="+2"><code>CoordinatorLayout</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v4.view.NestedScrollingParent</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"></A>
+  <nobr><code>List&lt;View&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/CoordinatorLayout.html#getDependents(android.view.View)" target="_top"><code>getDependents</code></A>(<code>View</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
new file mode 100644
index 0000000..633db38
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.FloatingActionButton.Behavior
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html" target="_top"><font size="+2"><code>FloatingActionButton.Behavior</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
+  <nobr><code>boolean</code>&nbsp;layoutDependsOn(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"></A>
+  <nobr><code>void</code>&nbsp;onDependentViewRemoved(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> View<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" target="_top"><code>getInsetDodgeRect</code></A>(<code>CoordinatorLayout,</nobr> FloatingActionButton<nobr>,</nobr> Rect<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#isAutoHideEnabled()" target="_top"><code>isAutoHideEnabled</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/FloatingActionButton.Behavior.html#setAutoHideEnabled(boolean)" target="_top"><code>setAutoHideEnabled</code></A>(<code>boolean</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
new file mode 100644
index 0000000..01d4b6d
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.TabLayout
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TabLayout.html" target="_top"><font size="+2"><code>TabLayout</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TabLayout.html#clearOnTabSelectedListeners()" target="_top"><code>clearOnTabSelectedListeners</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
new file mode 100644
index 0000000..ecd6fd4
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
@@ -0,0 +1,185 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget.TextInputLayout
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.design.widget.<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html" target="_top"><font size="+2"><code>TextInputLayout</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"></A>
+  <nobr><code>CharSequence</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleContentDescription()" target="_top"><code>getPasswordVisibilityToggleContentDescription</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"></A>
+  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#getPasswordVisibilityToggleDrawable()" target="_top"><code>getPasswordVisibilityToggleDrawable</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#isPasswordVisibilityToggleEnabled()" target="_top"><code>isPasswordVisibilityToggleEnabled</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(int)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>int</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)" target="_top"><code>setPasswordVisibilityToggleContentDescription</code></A>(<code>CharSequence</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>Drawable</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleDrawable(int)" target="_top"><code>setPasswordVisibilityToggleDrawable</code></A>(<code>int</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleEnabled(boolean)" target="_top"><code>setPasswordVisibilityToggleEnabled</code></A>(<code>boolean</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)" target="_top"><code>setPasswordVisibilityToggleTintList</code></A>(<code>ColorStateList</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/design/widget/TextInputLayout.html#setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)" target="_top"><code>setPasswordVisibilityToggleTintMode</code></A>(<code>Mode</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
new file mode 100644
index 0000000..9b31c9e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v14.preference.PreferenceFragment
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v14.preference.<A HREF="../../../../reference/android/support/v14/preference/PreferenceFragment.html" target="_top"><font size="+2"><code>PreferenceFragment</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v7.preference.DialogPreference.TargetFragment</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
new file mode 100644
index 0000000..9df6536
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter.ViewHolder</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"></A>
+  <nobr><code>ViewFlipper</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemNumberViewFlipper()" target="_top"><code>getMediaItemNumberViewFlipper</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"></A>
+  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPausedView()" target="_top"><code>getMediaItemPausedView</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"></A>
+  <nobr><code>View</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#getMediaItemPlayingView()" target="_top"><code>getMediaItemPlayingView</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#notifyPlayStateChanged()" target="_top"><code>notifyPlayStateChanged</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.ViewHolder.html#setSelectedMediaItemNumberView(int)" target="_top"><code>setSelectedMediaItemNumberView</code></A>(<code>int</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
new file mode 100644
index 0000000..16b03ad
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.leanback.widget.AbstractMediaItemPresenter
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html" target="_top"><font size="+2"><code>AbstractMediaItemPresenter</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#getMediaPlayState(java.lang.Object)" target="_top"><code>getMediaPlayState</code></A>(<code>Object</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onBindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" target="_top"><code>onUnbindMediaPlayState</code></A>(<code>ViewHolder</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_INITIAL" target="_top"><code>PLAY_STATE_INITIAL</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PAUSED" target="_top"><code>PLAY_STATE_PAUSED</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/AbstractMediaItemPresenter.html#PLAY_STATE_PLAYING" target="_top"><code>PLAY_STATE_PLAYING</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
new file mode 100644
index 0000000..3e3ded0
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.leanback.widget.ObjectAdapter
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v17.leanback.widget.<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html" target="_top"><font size="+2"><code>ObjectAdapter</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v17/leanback/widget/ObjectAdapter.html#isImmediateNotifySupported()" target="_top"><code>isImmediateNotifySupported</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
new file mode 100644
index 0000000..6e54465
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.preference.LeanbackSettingsFragment
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v17.preference.<A HREF="../../../../reference/android/support/v17/preference/LeanbackSettingsFragment.html" target="_top"><font size="+2"><code>LeanbackSettingsFragment</code></font></A>
+</H2>
+<p><font xsize="+1">Added interfaces <code>android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback, android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
new file mode 100644
index 0000000..0600e44
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.accessibilityservice.<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityServiceInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" target="_top"><code>loadDescription</code></A>(<code>AccessibilityServiceInfo,</nobr> PackageManager<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#getDescription(android.accessibilityservice.AccessibilityServiceInfo)" target="_top"><code>getDescription</code></A>(<code>AccessibilityServiceInfo</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
new file mode 100644
index 0000000..74ae6f6
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app.ActivityCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html" target="_top"><font size="+2"><code>ActivityCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Constructors" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityCompat.ctor_changed()"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#ActivityCompat()" target="_top"><code>ActivityCompat</code></A>()  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"></A>
+  <nobr><code>Uri</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityCompat.html#getReferrer(android.app.Activity)" target="_top"><code>getReferrer</code></A>(<code>Activity</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
new file mode 100644
index 0000000..ce96b49
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
@@ -0,0 +1,179 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app.ActivityOptionsCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html" target="_top"><font size="+2"><code>ActivityOptionsCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"></A>
+  <nobr><code>Rect</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#getLaunchBounds()" target="_top"><code>getLaunchBounds</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"></A>
+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeBasic()" target="_top"><code>makeBasic</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"></A>
+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(android.view.View, int, int, int, int)" target="_top"><code>makeClipRevealAnimation</code></A>(<code>View,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"></A>
+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#makeTaskLaunchBehind()" target="_top"><code>makeTaskLaunchBehind</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#requestUsageTimeReport(android.app.PendingIntent)" target="_top"><code>requestUsageTimeReport</code></A>(<code>PendingIntent</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"></A>
+  <nobr><code>ActivityOptionsCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#setLaunchBounds(android.graphics.Rect)" target="_top"><code>setLaunchBounds</code></A>(<code>Rect</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT" target="_top"><code>EXTRA_USAGE_TIME_REPORT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ActivityOptionsCompat.html#EXTRA_USAGE_TIME_REPORT_PACKAGES" target="_top"><code>EXTRA_USAGE_TIME_REPORT_PACKAGES</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
new file mode 100644
index 0000000..13b2ce1
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app.FragmentController
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/FragmentController.html" target="_top"><font size="+2"><code>FragmentController</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"></A>
+  <nobr><code>Fragment</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/FragmentController.html#findFragmentByWho(java.lang.String)" target="_top"><code>findFragmentByWho</code></A>(<code>String</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
new file mode 100644
index 0000000..6a404eb
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app.ServiceCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html" target="_top"><font size="+2"><code>ServiceCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#stopForeground(android.app.Service, int)" target="_top"><code>stopForeground</code></A>(<code>Service,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_DETACH" target="_top"><code>STOP_FOREGROUND_DETACH</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/ServiceCompat.html#STOP_FOREGROUND_REMOVE" target="_top"><code>STOP_FOREGROUND_REMOVE</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
new file mode 100644
index 0000000..1495fb4
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app.SharedElementCallback
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.app.<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html" target="_top"><font size="+2"><code>SharedElementCallback</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.html#onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" target="_top"><code>onSharedElementsArrived</code></A>(<code>List&lt;String&gt;,</nobr> List&lt;View&gt;<nobr>,</nobr> OnSharedElementsReadyListener<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
new file mode 100644
index 0000000..1d6b9b1
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.content.ContextCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.content.<A HREF="../../../../reference/android/support/v4/content/ContextCompat.html" target="_top"><font size="+2"><code>ContextCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Constructors" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Constructors</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.content.ContextCompat.ctor_changed()"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/content/ContextCompat.html#ContextCompat()" target="_top"><code>ContextCompat</code></A>()  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
new file mode 100644
index 0000000..3408caa
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.graphics.drawable.DrawableCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.graphics.drawable.<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html" target="_top"><font size="+2"><code>DrawableCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/graphics/drawable/DrawableCompat.html#clearColorFilter(android.graphics.drawable.Drawable)" target="_top"><code>clearColorFilter</code></A>(<code>Drawable</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
new file mode 100644
index 0000000..acc16c1
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.MediaBrowserCompat.MediaItem
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html" target="_top"><font size="+2"><code>MediaBrowserCompat.MediaItem</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"></A>
+  <nobr><code>MediaItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItem(java.lang.Object)" target="_top"><code>fromMediaItem</code></A>(<code>Object</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)"></A>
+  <nobr><code>List&lt;MediaItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserCompat.MediaItem.html#fromMediaItemList(java.util.List<?>)" target="_top"><code>fromMediaItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
new file mode 100644
index 0000000..7a9c73311
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html" target="_top"><font size="+2"><code>MediaBrowserServiceCompat.BrowserRoot</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaBrowserServiceCompat.BrowserRoot.html#EXTRA_SUGGESTION_KEYWORDS" target="_top"><code>EXTRA_SUGGESTION_KEYWORDS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
new file mode 100644
index 0000000..fbbaa19
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.MediaDescriptionCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html" target="_top"><font size="+2"><code>MediaDescriptionCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ALBUMS" target="_top"><code>BT_FOLDER_TYPE_ALBUMS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_ARTISTS" target="_top"><code>BT_FOLDER_TYPE_ARTISTS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_GENRES" target="_top"><code>BT_FOLDER_TYPE_GENRES</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_MIXED" target="_top"><code>BT_FOLDER_TYPE_MIXED</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_PLAYLISTS" target="_top"><code>BT_FOLDER_TYPE_PLAYLISTS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_TITLES" target="_top"><code>BT_FOLDER_TYPE_TITLES</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"></A>
+  <nobr><code>long</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#BT_FOLDER_TYPE_YEARS" target="_top"><code>BT_FOLDER_TYPE_YEARS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaDescriptionCompat.html#EXTRA_BT_FOLDER_TYPE" target="_top"><code>EXTRA_BT_FOLDER_TYPE</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
new file mode 100644
index 0000000..e52493b
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.MediaMetadataCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html" target="_top"><font size="+2"><code>MediaMetadataCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_BT_FOLDER_TYPE" target="_top"><code>METADATA_KEY_BT_FOLDER_TYPE</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/MediaMetadataCompat.html#METADATA_KEY_MEDIA_URI" target="_top"><code>METADATA_KEY_MEDIA_URI</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
new file mode 100644
index 0000000..3e2c68b
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.session.MediaButtonReceiver
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html" target="_top"><font size="+2"><code>MediaButtonReceiver</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"></A>
+  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> ComponentName<nobr>,</nobr> long<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"></A>
+  <nobr><code>PendingIntent</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaButtonReceiver.html#buildMediaButtonPendingIntent(android.content.Context, long)" target="_top"><code>buildMediaButtonPendingIntent</code></A>(<code>Context,</nobr> long<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
new file mode 100644
index 0000000..5ce173f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.session.MediaSessionCompat.QueueItem
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html" target="_top"><font size="+2"><code>MediaSessionCompat.QueueItem</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"></A>
+  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem(java.lang.Object)" target="_top"><code>fromQueueItem</code></A>(<code>Object</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)"></A>
+  <nobr><code>List&lt;QueueItem&gt;</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItemList(java.util.List<?>)" target="_top"><code>fromQueueItemList</code></A>(<code>List&lt;?&gt;</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"></A>
+  <nobr><code>QueueItem</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#obtain(java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Object</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
new file mode 100644
index 0000000..ee71244
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.session.MediaSessionCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html" target="_top"><font size="+2"><code>MediaSessionCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"></A>
+  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession(android.content.Context, java.lang.Object)" target="_top"><code>fromMediaSession</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"></A>
+  <nobr><code>MediaSessionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/MediaSessionCompat.html#obtain(android.content.Context, java.lang.Object)" target="_top"><code>obtain</code></A>(<code>Context,</nobr> Object<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
new file mode 100644
index 0000000..2c54c1d
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.session.PlaybackStateCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.media.session.<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html" target="_top"><font size="+2"><code>PlaybackStateCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/media/session/PlaybackStateCompat.html#toKeyCode(long)" target="_top"><code>toKeyCode</code></A>(<code>long</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
new file mode 100644
index 0000000..eb59ddb
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.os.BuildCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.os.<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html" target="_top"><font size="+2"><code>BuildCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/os/BuildCompat.html#isAtLeastNMR1()" target="_top"><code>isAtLeastNMR1</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
new file mode 100644
index 0000000..b5f4371
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
@@ -0,0 +1,155 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.KeyEventCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html" target="_top"><font size="+2"><code>KeyEventCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" target="_top"><code>dispatch</code></A>(<code>KeyEvent,</nobr> Callback<nobr>,</nobr> Object<nobr>,</nobr> Object<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"></A>
+  <nobr><code>Object</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#getKeyDispatcherState(android.view.View)" target="_top"><code>getKeyDispatcherState</code></A>(<code>View</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#isTracking(android.view.KeyEvent)" target="_top"><code>isTracking</code></A>(<code>KeyEvent</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/KeyEventCompat.html#startTracking(android.view.KeyEvent)" target="_top"><code>startTracking</code></A>(<code>KeyEvent</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
new file mode 100644
index 0000000..9f85dab
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
@@ -0,0 +1,175 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.MotionEventCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html" target="_top"><font size="+2"><code>MotionEventCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#findPointerIndex(android.view.MotionEvent, int)" target="_top"><code>findPointerIndex</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerCount(android.view.MotionEvent)" target="_top"><code>getPointerCount</code></A>(<code>MotionEvent</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getPointerId(android.view.MotionEvent, int)" target="_top"><code>getPointerId</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getSource(android.view.MotionEvent)" target="_top"><code>getSource</code></A>(<code>MotionEvent</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"></A>
+  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getX(android.view.MotionEvent, int)" target="_top"><code>getX</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"></A>
+  <nobr><code>float</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/MotionEventCompat.html#getY(android.view.MotionEvent, int)" target="_top"><code>getY</code></A>(<code>MotionEvent,</nobr> int<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
new file mode 100644
index 0000000..1b4ea0f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.ViewCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html" target="_top"><font size="+2"><code>ViewCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isImportantForAccessibility(android.view.View)" target="_top"><code>isImportantForAccessibility</code></A>(<code>View</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#getOverScrollMode(android.view.View)" target="_top"><code>getOverScrollMode</code></A>(<code>View</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#isOpaque(android.view.View)" target="_top"><code>isOpaque</code></A>(<code>View</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#setOverScrollMode(android.view.View, int)" target="_top"><code>setOverScrollMode</code></A>(<code>View,</nobr> int<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_ALWAYS" target="_top"><code>OVER_SCROLL_ALWAYS</code></font></A></nobr>  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_IF_CONTENT_SCROLLS" target="_top"><code>OVER_SCROLL_IF_CONTENT_SCROLLS</code></font></A></nobr>  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewCompat.html#OVER_SCROLL_NEVER" target="_top"><code>OVER_SCROLL_NEVER</code></font></A></nobr>  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
new file mode 100644
index 0000000..dcb2023
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.ViewConfigurationCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html" target="_top"><font size="+2"><code>ViewConfigurationCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/ViewConfigurationCompat.html#getScaledPagingTouchSlop(android.view.ViewConfiguration)" target="_top"><code>getScaledPagingTouchSlop</code></A>(<code>ViewConfiguration</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+<b>Now deprecated</b>.<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
new file mode 100644
index 0000000..e0f77c9
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.WindowInsetsCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.<A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html" target="_top"><font size="+2"><code>WindowInsetsCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Constructors" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Constructors</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/view/WindowInsetsCompat.html#WindowInsetsCompat(android.support.v4.view.WindowInsetsCompat)" target="_top"><code>WindowInsetsCompat</code></A>(<code>WindowInsetsCompat</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
new file mode 100644
index 0000000..6ff46b8
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityEventCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html" target="_top"><font size="+2"><code>AccessibilityEventCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getAction(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getAction</code></A>(<code>AccessibilityEvent</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#getMovementGranularity(android.view.accessibility.AccessibilityEvent)" target="_top"><code>getMovementGranularity</code></A>(<code>AccessibilityEvent</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setAction(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setAction</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)" target="_top"><code>setMovementGranularity</code></A>(<code>AccessibilityEvent,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_ASSIST_READING_CONTEXT" target="_top"><code>TYPE_ASSIST_READING_CONTEXT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_VIEW_CONTEXT_CLICKED" target="_top"><code>TYPE_VIEW_CONTEXT_CLICKED</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityEventCompat.html#TYPE_WINDOWS_CHANGED" target="_top"><code>TYPE_WINDOWS_CHANGED</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
new file mode 100644
index 0000000..5d63b93a
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener</code>.<br></font>
+<p><b>Now deprecated</b>.<br>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"></A>
+  <nobr><code>void</code>&nbsp;onAccessibilityStateChanged(<code>boolean</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
new file mode 100644
index 0000000..004d89e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityManagerCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html" target="_top"><font size="+2"><code>AccessibilityManagerCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>addTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" target="_top"><code>removeTouchExplorationStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> TouchExplorationStateChangeListener<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>addAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.html#removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" target="_top"><code>removeAccessibilityStateChangeListener</code></A>(<code>AccessibilityManager,</nobr> AccessibilityStateChangeListener<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+Change in signature from (<code>AccessibilityManager, AccessibilityStateChangeListenerCompat</code>) to (<code>AccessibilityManager, AccessibilityStateChangeListener</code>).<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
new file mode 100644
index 0000000..695028b
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.AccessibilityActionCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_CONTEXT_CLICK" target="_top"><code>ACTION_CONTEXT_CLICK</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_DOWN" target="_top"><code>ACTION_SCROLL_DOWN</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_LEFT" target="_top"><code>ACTION_SCROLL_LEFT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_RIGHT" target="_top"><code>ACTION_SCROLL_RIGHT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_TO_POSITION" target="_top"><code>ACTION_SCROLL_TO_POSITION</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SCROLL_UP" target="_top"><code>ACTION_SCROLL_UP</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SET_PROGRESS" target="_top"><code>ACTION_SET_PROGRESS</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"></A>
+  <nobr><code>AccessibilityActionCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#ACTION_SHOW_ON_SCREEN" target="_top"><code>ACTION_SHOW_ON_SCREEN</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
new file mode 100644
index 0000000..17109ec
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#getSelectionMode()" target="_top"><code>getSelectionMode</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"></A>
+  <nobr><code>CollectionInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionInfoCompat.html#obtain(int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
new file mode 100644
index 0000000..30df540
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.CollectionItemInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"></A>
+  <nobr><code>CollectionItemInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#obtain(int, int, int, int, boolean)" target="_top"><code>obtain</code></A>(<code>int,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> int<nobr>,</nobr> boolean<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
new file mode 100644
index 0000000..1d5a250
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat.RangeInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"></A>
+  <nobr><code>RangeInfoCompat</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.RangeInfoCompat.html#obtain(int, float, float, float)" target="_top"><code>obtain</code></A>(<code>int,</nobr> float<nobr>,</nobr> float<nobr>,</nobr> float<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
new file mode 100644
index 0000000..727576d
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"></A>
+  <nobr><code>boolean</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#isContextClickable()" target="_top"><code>isContextClickable</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#setContextClickable(boolean)" target="_top"><code>setContextClickable</code></A>(<code>boolean</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_COLUMN_INT" target="_top"><code>ACTION_ARGUMENT_COLUMN_INT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_PROGRESS_VALUE" target="_top"><code>ACTION_ARGUMENT_PROGRESS_VALUE</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"></A>
+  <nobr><code>String</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.html#ACTION_ARGUMENT_ROW_INT" target="_top"><code>ACTION_ARGUMENT_ROW_INT</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
new file mode 100644
index 0000000..101070c
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityNodeProviderCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html" target="_top"><font size="+2"><code>AccessibilityNodeProviderCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.html#HOST_VIEW_ID" target="_top"><code>HOST_VIEW_ID</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
new file mode 100644
index 0000000..a3b8d96
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility.AccessibilityWindowInfoCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.view.accessibility.<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html" target="_top"><font size="+2"><code>AccessibilityWindowInfoCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.html#TYPE_SPLIT_SCREEN_DIVIDER" target="_top"><code>TYPE_SPLIT_SCREEN_DIVIDER</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
new file mode 100644
index 0000000..cba004e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnCloseListenerCompat</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnCloseListener</code>.<br></font>
+<p><b>Now deprecated</b>.<br>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
new file mode 100644
index 0000000..c15d1b9
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListenerCompat.html" target="_top"><font size="+2"><code>SearchViewCompat.OnQueryTextListenerCompat</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v4.widget.SearchViewCompat.OnQueryTextListener</code>.<br></font>
+<p><b>Now deprecated</b>.<br>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
new file mode 100644
index 0000000..cbb3925
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget.SearchViewCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html" target="_top"><font size="+2"><code>SearchViewCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" target="_top"><code>setOnCloseListener</code></A>(<code>View,</nobr> OnCloseListener<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+Change in signature from (<code>View, OnCloseListenerCompat</code>) to (<code>View, OnCloseListener</code>).<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.html#setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" target="_top"><code>setOnQueryTextListener</code></A>(<code>View,</nobr> OnQueryTextListener<nobr><nobr></code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+Change in signature from (<code>View, OnQueryTextListenerCompat</code>) to (<code>View, OnQueryTextListener</code>).<br>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
new file mode 100644
index 0000000..77dbdf6
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget.SwipeRefreshLayout
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html" target="_top"><font size="+2"><code>SwipeRefreshLayout</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.html#setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" target="_top"><code>setOnChildScrollUpCallback</code></A>(<code>OnChildScrollUpCallback</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
new file mode 100644
index 0000000..a803634
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget.TextViewCompat
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v4.widget.<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html" target="_top"><font size="+2"><code>TextViewCompat</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"></A>
+  <nobr><code>Drawable[]</code>&nbsp;<A HREF="../../../../reference/android/support/v4/widget/TextViewCompat.html#getCompoundDrawablesRelative(android.widget.TextView)" target="_top"><code>getCompoundDrawablesRelative</code></A>(<code>TextView</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
new file mode 100644
index 0000000..2a864f0
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.app.ActionBarDrawerToggle
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html" target="_top"><font size="+2"><code>ActionBarDrawerToggle</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"></A>
+  <nobr><code>DrawerArrowDrawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#getDrawerArrowDrawable()" target="_top"><code>getDrawerArrowDrawable</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/ActionBarDrawerToggle.html#setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)" target="_top"><code>setDrawerArrowDrawable</code></A>(<code>DrawerArrowDrawable</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
new file mode 100644
index 0000000..adfcabb
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.app.AppCompatDelegate
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.app.<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html" target="_top"><font size="+2"><code>AppCompatDelegate</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.app.AppCompatDelegate.onStart_added()"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/app/AppCompatDelegate.html#onStart()" target="_top"><code>onStart</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
new file mode 100644
index 0000000..e26c32b
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.content.res.AppCompatResources
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.content.res.<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html" target="_top"><font size="+2"><code>AppCompatResources</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"></A>
+  <nobr><code>Drawable</code>&nbsp;<A HREF="../../../../reference/android/support/v7/content/res/AppCompatResources.html#getDrawable(android.content.Context, int)" target="_top"><code>getDrawable</code></A>(<code>Context,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
new file mode 100644
index 0000000..f588384
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.graphics.Palette
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.graphics.<A HREF="../../../../reference/android/support/v7/graphics/Palette.html" target="_top"><font size="+2"><code>Palette</code></font></A>
+</H2>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.graphics.Palette.getDominantColor_added(int)"></A>
+  <nobr><code>int</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantColor(int)" target="_top"><code>getDominantColor</code></A>(<code>int</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.graphics.Palette.getDominantSwatch_added()"></A>
+  <nobr><code>Swatch</code>&nbsp;<A HREF="../../../../reference/android/support/v7/graphics/Palette.html#getDominantSwatch()" target="_top"><code>getDominantSwatch</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
new file mode 100644
index 0000000..d2350979
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
@@ -0,0 +1,152 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.util.SortedList.Callback
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.util.<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html" target="_top"><font size="+2"><code>SortedList.Callback</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v7.util.ListUpdateCallback</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"></A>
+  <nobr><code>void</code>&nbsp;onInserted(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"></A>
+  <nobr><code>void</code>&nbsp;onMoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"></A>
+  <nobr><code>void</code>&nbsp;onRemoved(<code>int,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/util/SortedList.Callback.html#onChanged(int, int, java.lang.Object)" target="_top"><code>onChanged</code></A>(<code>int,</nobr> int<nobr>,</nobr> Object<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
new file mode 100644
index 0000000..cf5c0f6
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.widget.LinearLayoutManager
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearLayoutManager.html" target="_top"><font size="+2"><code>LinearLayoutManager</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"></A>
+  <nobr><code>void</code>&nbsp;prepareForDrop(<code>View,</nobr> View<nobr>,</nobr> int<nobr>,</nobr> int<nobr><nobr></code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
new file mode 100644
index 0000000..3e13735
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.widget.LinearSmoothScroller
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html" target="_top"><font size="+2"><code>LinearSmoothScroller</code></font></A>
+</H2>
+<p>Changed from abstract to non-abstract.
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"></A>
+  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/LinearSmoothScroller.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)  </nobr>
+  </TD>
+  <TD VALIGN="TOP" WIDTH="30%">
+Changed from abstract to non-abstract.
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
new file mode 100644
index 0000000..d5e36f0
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.widget.RecyclerView
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html" target="_top"><font size="+2"><code>RecyclerView</code></font></A>
+</H2>
+<p><font xsize="+1">Added interfaces <code>android.support.v4.view.NestedScrollingChild, android.support.v4.view.ScrollingView</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"></A>
+  <nobr><code>OnFlingListener</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#getOnFlingListener()" target="_top"><code>getOnFlingListener</code></A>()</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"></A>
+  <nobr><code>void</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/RecyclerView.html#setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)" target="_top"><code>setOnFlingListener</code></A>(<code>OnFlingListener</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
new file mode 100644
index 0000000..640ef38
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
@@ -0,0 +1,138 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.widget.StaggeredGridLayoutManager
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Class android.support.v7.widget.<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html" target="_top"><font size="+2"><code>StaggeredGridLayoutManager</code></font></A>
+</H2>
+<p><font xsize="+1">Added interface <code>android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider</code>.<br></font>
+<a NAME="constructors"></a>
+<a NAME="methods"></a>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Methods" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Methods</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"></A>
+  <nobr><code>PointF</code>&nbsp;<A HREF="../../../../reference/android/support/v7/widget/StaggeredGridLayoutManager.html#computeScrollVectorForPosition(int)" target="_top"><code>computeScrollVectorForPosition</code></A>(<code>int</code>)</nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<a NAME="fields"></a>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Fields" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Fields</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget.StaggeredGridLayoutManager.TAG"></A>
+  <code>String</code>&nbsp;TAG
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
new file mode 100644
index 0000000..12dfb4e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
@@ -0,0 +1,329 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<body class="gc-documentation">
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+    <div id="docTitleContainer">
+    <h1>Support&nbsp;Library&nbsp;API&nbsp;Differences&nbsp;Report</h1>
+<p>This report details the changes in the Android Support Library API between two versions. 
+It shows additions, modifications, and removals for packages, classes, methods, and fields. 
+The report also includes general statistics that characterize the extent and type of the differences.</p>
+<p>This report is based a comparison of the Support Library API specifications 
+whose version level identifiers are given in the upper-right corner of this page. It compares a 
+newer "to" version's API to an older "from" version's API, noting all changes relative to the 
+older API. So, for example, API elements marked as removed are no longer present in the "to" 
+API specification.</p>
+<p>To navigate the report, use the "Select a Diffs Index" and "Filter the Index" 
+controls on the left. The report uses text formatting to indicate <em>interface names</em>, 
+<a href= ><code>links to reference documentation</code></a>, and <a href= >links to change 
+description</a>. The statistics are accessible from the "Statistics" link in the upper-right corner.</p>
+<p>For more information about the Android API and SDK, 
+see the <a href="http://developer.android.com/index.html" target="_top">Android Developers site</a>.</p>
+<p>
+<a NAME="Removed"></a>
+<TABLE summary="Removed Packages" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Removed Packages</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.appcompat"></A>
+  android.support.v7.appcompat  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.recyclerview"></A>
+  android.support.v7.recyclerview  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v8.renderscript"></A>
+  android.support.v8.renderscript  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Packages" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Packages</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.transition"></A>
+  <nobr><A HREF="../../../../reference/android/support/transition/package-summary.html" target="_top"><code>android.support.transition</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.text.util"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/text/util/package-summary.html" target="_top"><code>android.support.v4.text.util</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Packages" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=3>Changed Packages</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.customtabs"></A>
+  <nobr><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.design.widget"></A>
+  <nobr><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v14.preference"></A>
+  <nobr><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.leanback.widget"></A>
+  <nobr><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v17.preference"></A>
+  <nobr><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.accessibilityservice"></A>
+  <nobr><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.app"></A>
+  <nobr><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.content"></A>
+  <nobr><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.graphics.drawable"></A>
+  <nobr><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media"></A>
+  <nobr><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.media.session"></A>
+  <nobr><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.os"></A>
+  <nobr><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.util"></A>
+  <nobr><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view"></A>
+  <nobr><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.view.accessibility"></A>
+  <nobr><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v4.widget"></A>
+  <nobr><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.app"></A>
+  <nobr><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.content.res"></A>
+  <nobr><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.graphics"></A>
+  <nobr><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.preference"></A>
+  <nobr><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.util"></A>
+  <nobr><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="android.support.v7.widget"></A>
+  <nobr><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- End of API section -->
+<!-- Start of packages section -->
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
new file mode 100644
index 0000000..f3eb2ed
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
@@ -0,0 +1,305 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Class Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="classes_index_all.html" class="staysblack">All Classes</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
new file mode 100644
index 0000000..410ac8a
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
@@ -0,0 +1,528 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Class Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>Classes</b>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.AccessibilityStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.AccessibilityStateChangeListener</i></b></A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
+<A HREF="pkg_android.support.v4.view.accessibility.html#AccessibilityManagerCompat.TouchExplorationStateChangeListener" class="hiddenlink" target="rightframe"><b><i>AccessibilityManagerCompat.TouchExplorationStateChangeListener</i></b></A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
+<A HREF="pkg_android.support.v7.app.html#ActionBarActivity" class="hiddenlink" target="rightframe"><b>ActionBarActivity</b></A><br>
+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView" class="hiddenlink" target="rightframe"><b>ActionMenuView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.LayoutParams" class="hiddenlink" target="rightframe"><b>ActionMenuView.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ActionMenuView.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>ActionMenuView.OnMenuItemClickListener</i></b></A><br>
+<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
+<A HREF="pkg_android.support.v7.app.html#AppCompatActivity" class="hiddenlink" target="rightframe"><b>AppCompatActivity</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatAutoCompleteTextView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatButton" class="hiddenlink" target="rightframe"><b>AppCompatButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckBox" class="hiddenlink" target="rightframe"><b>AppCompatCheckBox</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatCheckedTextView" class="hiddenlink" target="rightframe"><b>AppCompatCheckedTextView</b></A><br>
+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
+<A HREF="pkg_android.support.v7.app.html#AppCompatDialogFragment" class="hiddenlink" target="rightframe"><b>AppCompatDialogFragment</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatEditText" class="hiddenlink" target="rightframe"><b>AppCompatEditText</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageButton" class="hiddenlink" target="rightframe"><b>AppCompatImageButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatImageView" class="hiddenlink" target="rightframe"><b>AppCompatImageView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatMultiAutoCompleteTextView" class="hiddenlink" target="rightframe"><b>AppCompatMultiAutoCompleteTextView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRadioButton" class="hiddenlink" target="rightframe"><b>AppCompatRadioButton</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatRatingBar" class="hiddenlink" target="rightframe"><b>AppCompatRatingBar</b></A><br>
+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSeekBar" class="hiddenlink" target="rightframe"><b>AppCompatSeekBar</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatSpinner" class="hiddenlink" target="rightframe"><b>AppCompatSpinner</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#AppCompatTextView" class="hiddenlink" target="rightframe"><b>AppCompatTextView</b></A><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#BatchingListUpdateCallback" class="hiddenlink" target="rightframe"><b>BatchingListUpdateCallback</b></A><br>
+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#CardView" class="hiddenlink" target="rightframe"><b>CardView</b></A><br>
+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
+<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.util.html#DiffUtil" class="hiddenlink" target="rightframe"><b>DiffUtil</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.Callback" class="hiddenlink" target="rightframe"><b>DiffUtil.Callback</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#DiffUtil.DiffResult" class="hiddenlink" target="rightframe"><b>DiffUtil.DiffResult</b></A><br>
+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#GridLayout" class="hiddenlink" target="rightframe"><b>GridLayout</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Alignment" class="hiddenlink" target="rightframe"><b>GridLayout.Alignment</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.LayoutParams" class="hiddenlink" target="rightframe"><b>GridLayout.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#GridLayout.Spec" class="hiddenlink" target="rightframe"><b>GridLayout.Spec</b></A><br>
+<A NAME="K"></A>
+<br><font size="+2">K</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#LinearLayoutCompat.LayoutParams" class="hiddenlink" target="rightframe"><b>LinearLayoutCompat.LayoutParams</b></A><br>
+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
+<A HREF="pkg_android.support.v7.widget.html#LinearSnapHelper" class="hiddenlink" target="rightframe"><b>LinearSnapHelper</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ListPopupWindow" class="hiddenlink" target="rightframe"><b>ListPopupWindow</b></A><br>
+<A HREF="pkg_android.support.v7.util.html#ListUpdateCallback" class="hiddenlink" target="rightframe"><b><i>ListUpdateCallback</i></b></A><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
+<A HREF="pkg_android.support.v7.preference.html#MultiSelectListPreferenceDialogFragmentCompat" class="hiddenlink" target="rightframe"><b>MultiSelectListPreferenceDialogFragmentCompat</b></A><br>
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat" class="hiddenlink" target="rightframe"><b>NotificationCompat</b></A><br>
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.Builder" class="hiddenlink" target="rightframe"><b>NotificationCompat.Builder</b></A><br>
+<A HREF="pkg_android.support.v7.app.html#NotificationCompat.MediaStyle" class="hiddenlink" target="rightframe"><b>NotificationCompat.MediaStyle</b></A><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
+<A HREF="pkg_android.support.v4.util.html#PatternsCompat" class="hiddenlink" target="rightframe"><b>PatternsCompat</b></A><br>
+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu" class="hiddenlink" target="rightframe"><b>PopupMenu</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnDismissListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnDismissListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#PopupMenu.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>PopupMenu.OnMenuItemClickListener</i></b></A><br>
+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.OnFlingListener" class="hiddenlink" target="rightframe"><b>RecyclerView.OnFlingListener</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#RecyclerView.SmoothScroller.ScrollVectorProvider" class="hiddenlink" target="rightframe"><b><i>RecyclerView.SmoothScroller.ScrollVectorProvider</i></b></A><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="pkg_android.support.v7.widget.html#SearchView" class="hiddenlink" target="rightframe"><b>SearchView</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnCloseListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnQueryTextListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SearchView.OnSuggestionListener" class="hiddenlink" target="rightframe"><b><i>SearchView.OnSuggestionListener</i></b></A><br>
+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnCloseListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnCloseListener</i></b></A><br>
+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
+<A HREF="pkg_android.support.v4.widget.html#SearchViewCompat.OnQueryTextListener" class="hiddenlink" target="rightframe"><b><i>SearchViewCompat.OnQueryTextListener</i></b></A><br>
+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider" class="hiddenlink" target="rightframe"><b>ShareActionProvider</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ShareActionProvider.OnShareTargetSelectedListener" class="hiddenlink" target="rightframe"><b><i>ShareActionProvider.OnShareTargetSelectedListener</i></b></A><br>
+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
+<A HREF="pkg_android.support.v4.app.html#SharedElementCallback.OnSharedElementsReadyListener" class="hiddenlink" target="rightframe"><b><i>SharedElementCallback.OnSharedElementsReadyListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SnapHelper" class="hiddenlink" target="rightframe"><b>SnapHelper</b></A><br>
+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
+<A HREF="pkg_android.support.v7.widget.html#Space" class="hiddenlink" target="rightframe"><b>Space</b></A><br>
+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
+<A HREF="pkg_android.support.v4.widget.html#SwipeRefreshLayout.OnChildScrollUpCallback" class="hiddenlink" target="rightframe"><b><i>SwipeRefreshLayout.OnChildScrollUpCallback</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#SwitchCompat" class="hiddenlink" target="rightframe"><b>SwitchCompat</b></A><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter" class="hiddenlink" target="rightframe"><b><i>ThemedSpinnerAdapter</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#ThemedSpinnerAdapter.Helper" class="hiddenlink" target="rightframe"><b>ThemedSpinnerAdapter.Helper</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar" class="hiddenlink" target="rightframe"><b>Toolbar</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
+<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
+<A NAME="V"></A>
+<br><font size="+2">V</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
new file mode 100644
index 0000000..1baef5c
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
@@ -0,0 +1,394 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Class Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="classes_index_all.html" class="staysblack">All Classes</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter</A><br>
+<A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html" class="hiddenlink" target="rightframe">AbstractMediaItemPresenter.ViewHolder</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html" class="hiddenlink" target="rightframe">AccessibilityEventCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html" class="hiddenlink" target="rightframe">AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.AccessibilityActionCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeInfoCompat.RangeInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html" class="hiddenlink" target="rightframe">AccessibilityNodeProviderCompat</A><br>
+<A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityServiceInfoCompat</A><br>
+<A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html" class="hiddenlink" target="rightframe">AccessibilityWindowInfoCompat</A><br>
+<A HREF="android.support.v7.app.ActionBarDrawerToggle.html" class="hiddenlink" target="rightframe">ActionBarDrawerToggle</A><br>
+<A HREF="android.support.v4.app.ActivityCompat.html" class="hiddenlink" target="rightframe">ActivityCompat</A><br>
+<A HREF="android.support.v4.app.ActivityOptionsCompat.html" class="hiddenlink" target="rightframe">ActivityOptionsCompat</A><br>
+<A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html" class="hiddenlink" target="rightframe">AppBarLayout.ScrollingViewBehavior</A><br>
+<A HREF="android.support.v7.app.AppCompatDelegate.html" class="hiddenlink" target="rightframe">AppCompatDelegate</A><br>
+<A HREF="android.support.v7.content.res.AppCompatResources.html" class="hiddenlink" target="rightframe">AppCompatResources</A><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.BottomSheetBehavior.html" class="hiddenlink" target="rightframe">BottomSheetBehavior</A><br>
+<A HREF="android.support.v4.os.BuildCompat.html" class="hiddenlink" target="rightframe">BuildCompat</A><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.CollapsingToolbarLayout.html" class="hiddenlink" target="rightframe">CollapsingToolbarLayout</A><br>
+<A HREF="android.support.v4.content.ContextCompat.html" class="hiddenlink" target="rightframe">ContextCompat</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.html" class="hiddenlink" target="rightframe">CoordinatorLayout</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html" class="hiddenlink" target="rightframe">CoordinatorLayout.Behavior</A><br>
+<A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html" class="hiddenlink" target="rightframe">CoordinatorLayout.LayoutParams</A><br>
+<A HREF="android.support.customtabs.CustomTabsIntent.html" class="hiddenlink" target="rightframe">CustomTabsIntent</A><br>
+<A HREF="android.support.customtabs.CustomTabsIntent.Builder.html" class="hiddenlink" target="rightframe">CustomTabsIntent.Builder</A><br>
+<A HREF="android.support.customtabs.CustomTabsSession.html" class="hiddenlink" target="rightframe">CustomTabsSession</A><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.graphics.drawable.DrawableCompat.html" class="hiddenlink" target="rightframe">DrawableCompat</A><br>
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.FloatingActionButton.Behavior.html" class="hiddenlink" target="rightframe">FloatingActionButton.Behavior</A><br>
+<A HREF="android.support.v4.app.FragmentController.html" class="hiddenlink" target="rightframe">FragmentController</A><br>
+<A NAME="K"></A>
+<br><font size="+2">K</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.KeyEventCompat.html" class="hiddenlink" target="rightframe">KeyEventCompat</A><br>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.preference.LeanbackSettingsFragment.html" class="hiddenlink" target="rightframe">LeanbackSettingsFragment</A><br>
+<A HREF="android.support.v7.widget.LinearLayoutManager.html" class="hiddenlink" target="rightframe">LinearLayoutManager</A><br>
+<A HREF="android.support.v7.widget.LinearSmoothScroller.html" class="hiddenlink" target="rightframe">LinearSmoothScroller</A><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html" class="hiddenlink" target="rightframe">MediaBrowserCompat.MediaItem</A><br>
+<A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html" class="hiddenlink" target="rightframe">MediaBrowserServiceCompat.BrowserRoot</A><br>
+<A HREF="android.support.v4.media.session.MediaButtonReceiver.html" class="hiddenlink" target="rightframe">MediaButtonReceiver</A><br>
+<A HREF="android.support.v4.media.MediaDescriptionCompat.html" class="hiddenlink" target="rightframe">MediaDescriptionCompat</A><br>
+<A HREF="android.support.v4.media.MediaMetadataCompat.html" class="hiddenlink" target="rightframe">MediaMetadataCompat</A><br>
+<A HREF="android.support.v4.media.session.MediaSessionCompat.html" class="hiddenlink" target="rightframe">MediaSessionCompat</A><br>
+<A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html" class="hiddenlink" target="rightframe">MediaSessionCompat.QueueItem</A><br>
+<A HREF="android.support.v4.view.MotionEventCompat.html" class="hiddenlink" target="rightframe">MotionEventCompat</A><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v17.leanback.widget.ObjectAdapter.html" class="hiddenlink" target="rightframe">ObjectAdapter</A><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.graphics.Palette.html" class="hiddenlink" target="rightframe">Palette</A><br>
+<A HREF="android.support.v4.media.session.PlaybackStateCompat.html" class="hiddenlink" target="rightframe">PlaybackStateCompat</A><br>
+<A HREF="android.support.v14.preference.PreferenceFragment.html" class="hiddenlink" target="rightframe">PreferenceFragment</A><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v7.widget.RecyclerView.html" class="hiddenlink" target="rightframe">RecyclerView</A><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.widget.SearchViewCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat</A><br>
+<A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnCloseListenerCompat</A><br>
+<A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html" class="hiddenlink" target="rightframe">SearchViewCompat.OnQueryTextListenerCompat</A><br>
+<A HREF="android.support.v4.app.ServiceCompat.html" class="hiddenlink" target="rightframe">ServiceCompat</A><br>
+<A HREF="android.support.v4.app.SharedElementCallback.html" class="hiddenlink" target="rightframe">SharedElementCallback</A><br>
+<A HREF="android.support.v7.util.SortedList.Callback.html" class="hiddenlink" target="rightframe">SortedList.Callback</A><br>
+<A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html" class="hiddenlink" target="rightframe">StaggeredGridLayoutManager</A><br>
+<A HREF="android.support.v4.widget.SwipeRefreshLayout.html" class="hiddenlink" target="rightframe">SwipeRefreshLayout</A><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.design.widget.TabLayout.html" class="hiddenlink" target="rightframe">TabLayout</A><br>
+<A HREF="android.support.design.widget.TextInputLayout.html" class="hiddenlink" target="rightframe">TextInputLayout</A><br>
+<A HREF="android.support.v4.widget.TextViewCompat.html" class="hiddenlink" target="rightframe">TextViewCompat</A><br>
+<A NAME="V"></A>
+<br><font size="+2">V</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
+<A HREF="android.support.v4.view.ViewConfigurationCompat.html" class="hiddenlink" target="rightframe">ViewConfigurationCompat</A><br>
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#K"><font size="-2">K</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+<a href="#V"><font size="-2">V</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
new file mode 100644
index 0000000..e6da73f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Class Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Classes" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="classes_index_all.html" class="staysblack">All Classes</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="classes_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="classes_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
new file mode 100644
index 0000000..b0c0587
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Constructor Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
new file mode 100644
index 0000000..91568db
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Constructor Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>Constructors</b>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
+()</A></nobr>&nbsp;constructor<br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#W"><font size="-2">W</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
+()</A></nobr>&nbsp;constructor<br>
+<A NAME="W"></A>
+<br><font size="+2">W</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
+(<code>WindowInsetsCompat</code>)</A></nobr>&nbsp;constructor<br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
new file mode 100644
index 0000000..b4142ed
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Constructor Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#C"><font size="-2">C</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.ctor_changed()" class="hiddenlink" target="rightframe">ActivityCompat
+()</A></nobr>&nbsp;constructor<br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
+()</A></nobr>&nbsp;constructor<br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
new file mode 100644
index 0000000..f1a9952
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Constructor Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Constructors" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="constructors_index_all.html" class="staysblack">All Constructors</a>
+  <br>
+<font color="#999999">Removals</font>
+  <br>
+<A HREF="constructors_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="constructors_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
new file mode 100644
index 0000000..8923dbe
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
@@ -0,0 +1,267 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Field Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="fields_index_all.html" class="staysblack">All Fields</a>
+  <br>
+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
+</nobr><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
+</nobr><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
+</nobr><br>
+<A NAME="E"></A>
+<br><font size="+2">E</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
+</nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
+</nobr><br>
+<A NAME="H"></A>
+<br><font size="+2">H</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
+</nobr><br>
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
+</nobr><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
+</nobr><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
+</nobr><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
+</nobr><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
+</nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
new file mode 100644
index 0000000..19cebb7
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
@@ -0,0 +1,299 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Field Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>Fields</b>
+  <br>
+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_COLUMN_INT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_PROGRESS_VALUE</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT" class="hiddenlink" target="rightframe">ACTION_ARGUMENT_ROW_INT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK" class="hiddenlink" target="rightframe">ACTION_CONTEXT_CLICK</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN" class="hiddenlink" target="rightframe">ACTION_SCROLL_DOWN</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT" class="hiddenlink" target="rightframe">ACTION_SCROLL_LEFT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT" class="hiddenlink" target="rightframe">ACTION_SCROLL_RIGHT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION" class="hiddenlink" target="rightframe">ACTION_SCROLL_TO_POSITION</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP" class="hiddenlink" target="rightframe">ACTION_SCROLL_UP</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS" class="hiddenlink" target="rightframe">ACTION_SET_PROGRESS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN" class="hiddenlink" target="rightframe">ACTION_SHOW_ON_SCREEN</A>
+</nobr><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ALBUMS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_ARTISTS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_GENRES</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_MIXED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_PLAYLISTS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_TITLES</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS" class="hiddenlink" target="rightframe">BT_FOLDER_TYPE_YEARS</A>
+</nobr><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges" class="hiddenlink" target="rightframe">dodgeInsetEdges</A>
+</nobr><br>
+<A NAME="E"></A>
+<br><font size="+2">E</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html#android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">EXTRA_BT_FOLDER_TYPE</A>
+</nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS" class="hiddenlink" target="rightframe">EXTRA_ENABLE_INSTANT_APPS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html#android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS" class="hiddenlink" target="rightframe">EXTRA_SUGGESTION_KEYWORDS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES" class="hiddenlink" target="rightframe">EXTRA_USAGE_TIME_REPORT_PACKAGES</A>
+</nobr><br>
+<A NAME="H"></A>
+<br><font size="+2">H</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html#android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID" class="hiddenlink" target="rightframe">HOST_VIEW_ID</A>
+</nobr><br>
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html#android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge" class="hiddenlink" target="rightframe">insetEdge</A>
+</nobr><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE" class="hiddenlink" target="rightframe">METADATA_KEY_BT_FOLDER_TYPE</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html#android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI" class="hiddenlink" target="rightframe">METADATA_KEY_MEDIA_URI</A>
+</nobr><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
+</nobr><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html#android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO" class="hiddenlink" target="rightframe">PEEK_HEIGHT_AUTO</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL" class="hiddenlink" target="rightframe">PLAY_STATE_INITIAL</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED" class="hiddenlink" target="rightframe">PLAY_STATE_PAUSED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING" class="hiddenlink" target="rightframe">PLAY_STATE_PLAYING</A>
+</nobr><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH" class="hiddenlink" target="rightframe">STOP_FOREGROUND_DETACH</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE" class="hiddenlink" target="rightframe">STOP_FOREGROUND_REMOVE</A>
+</nobr><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#E"><font size="-2">E</font></a> 
+<a href="#H"><font size="-2">H</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT" class="hiddenlink" target="rightframe">TYPE_ASSIST_READING_CONTEXT</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html#android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER" class="hiddenlink" target="rightframe">TYPE_SPLIT_SCREEN_DIVIDER</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED" class="hiddenlink" target="rightframe">TYPE_VIEW_CONTEXT_CLICKED</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
+</nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
new file mode 100644
index 0000000..b5ab769
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Field Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="fields_index_all.html" class="staysblack">All Fields</a>
+  <br>
+<A HREF="fields_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS" class="hiddenlink" target="rightframe">OVER_SCROLL_ALWAYS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS" class="hiddenlink" target="rightframe">OVER_SCROLL_IF_CONTENT_SCROLLS</A>
+</nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
+</nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
new file mode 100644
index 0000000..09ffac4
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Field Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Fields" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="fields_index_all.html" class="staysblack">All Fields</a>
+  <br>
+<b>Removals</b>
+  <br>
+<A HREF="fields_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="fields_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
+</nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
new file mode 100644
index 0000000..ca0931f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+JDiff Help
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<TABLE summary="Navigation bar" BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+  <TABLE summary="Navigation bar" BORDER="0" CELLPADDING="0" CELLSPACING="3">
+    <TR ALIGN="center" VALIGN="top">
+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../reference/index.html" target="_top"><FONT CLASS="NavBarFont1"><B><code>24.2.0</code></B></FONT></A>&nbsp;</TD>
+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="changes-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+      <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1"> &nbsp;<FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="jdiff_statistics.html"><FONT CLASS="NavBarFont1"><B>Statistics</B></FONT></A>&nbsp;</TD>
+      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
+    </TR>
+  </TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM><b>Generated by<br><a href="http://www.jdiff.org" class="staysblack" target="_top">JDiff</a></b></EM></TD>
+</TR>
+<TR>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2"></FONT>
+</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="../changes.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+  &nbsp;<A HREF="jdiff_help.html" TARGET="_top"><B>NO FRAMES</B></A></FONT></TD>
+</TR>
+</TABLE>
+<HR>
+<!-- End of nav bar -->
+<center>
+<H1>JDiff Documentation</H1>
+</center>
+<BLOCKQUOTE>
+JDiff is a <a href="http://java.sun.com/j2se/javadoc/" target="_top">Javadoc</a> doclet which generates a report of the API differences between two versions of a product. It does not report changes in Javadoc comments, or changes in what a class or method does. 
+This help page describes the different parts of the output from JDiff.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+ See the reference page in the <a href="http://www.jdiff.org">source for JDiff</a> for information about how to generate a report like this one.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+The indexes shown in the top-left frame help show each type of change in more detail. The index "All Differences" contains all the differences between the APIs, in alphabetical order. 
+These indexes all use the same format:
+<ul>
+<li>Removed packages, classes, constructors, methods and fields are <strike>struck through</strike>.</li>
+<li>Added packages, classes, constructors, methods and fields appear in <b>bold</b>.</li>
+<li>Changed packages, classes, constructors, methods and fields appear in normal text.</li>
+</ul>
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+You can always tell when you are reading a JDiff page, rather than a Javadoc page, by the color of the index bar and the color of the background. 
+Links which take you to a Javadoc page are always in a <code>typewriter</code> font. 
+Just like Javadoc, all interface names are in <i>italic</i>, and class names are not italicized. Where there are multiple entries in an index with the same name, the heading for them is also in italics, but is not a link.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3><b><code>Javadoc</code></b></H3>
+This is a link to the <a href="../../../../reference/index.html" target="_top">top-level</a> Javadoc page for the new version of the product.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Overview</H3>
+The <a href="changes-summary.html">overview</a> is the top-level summary of what was removed, added and changed between versions.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Package</H3>
+This is a link to the package containing the current changed class or interface.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Class</H3>
+This is highlighted when you are looking at the changed class or interface.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Text Changes</H3>
+This is a link to the top-level index of all documentation changes for the current package or class. 
+If it is not present, then there are no documentation changes for the current package or class. 
+This link can be removed entirely by not using the <code>-docchanges</code> option.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Statistics</H3>
+This is a link to a page which shows statistics about the changes between the two APIs.
+This link can be removed entirely by not using the <code>-stats</code> option.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Help</H3>
+A link to this Help page for JDiff.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Prev/Next</H3>
+These links take you to the previous  and next changed package or class.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H3>Frames/No Frames</H3>
+These links show and hide the HTML frames. All pages are available with or without frames.
+</BLOCKQUOTE>
+<BLOCKQUOTE>
+<H2>Complex Changes</H2>
+There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass. 
+In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes. 
+</BLOCKQUOTE>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
new file mode 100644
index 0000000..698dbec
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
@@ -0,0 +1,596 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+API Change Statistics
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<body class="gc-documentation">
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;xborder-bottom:none;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="../changes.html" target="_top">Top of Report</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<h1>API&nbsp;Change&nbsp;Statistics</h1>
+<p>The overall difference between API Levels 24.1.0 and 24.2.0 is approximately <span style="color:222;font-weight:bold;">8.39%</span>.
+</p>
+<br>
+<a name="numbers"></a>
+<h2>Total of Differences, by Number and Type</h2>
+<p>
+The table below lists the numbers of program elements (packages, classes, constructors, methods, and fields) that were added, changed, or removed. The table includes only the highest-level program elements &mdash; that is, if a class with two methods was added, the number of methods added does not include those two methods, but the number of classes added does include that class.
+</p>
+<TABLE summary="Number of differences" WIDTH="100%">
+<TR>
+  <th>Type</th>
+  <TH ALIGN="center"><b>Additions</b></TH>
+  <TH ALIGN="center"><b>Changes</b></TH>
+  <TH ALIGN="center">Removals</TH>
+  <TH ALIGN="center"><b>Total</b></TH>
+</TR>
+<TR>
+  <TD>Packages</TD>
+  <TD ALIGN="right">2</TD>
+  <TD ALIGN="right">22</TD>
+  <TD ALIGN="right">3</TD>
+  <TD ALIGN="right">27</TD>
+</TR>
+<TR>
+  <TD>Classes and <i>Interfaces</i></TD>
+  <TD ALIGN="right">64</TD>
+  <TD ALIGN="right">63</TD>
+  <TD ALIGN="right">0</TD>
+  <TD ALIGN="right">127</TD>
+</TR>
+<TR>
+  <TD>Constructors</TD>
+  <TD ALIGN="right">1</TD>
+  <TD ALIGN="right">2</TD>
+  <TD ALIGN="right">0</TD>
+  <TD ALIGN="right">3</TD>
+</TR>
+<TR>
+  <TD>Methods</TD>
+  <TD ALIGN="right">80</TD>
+  <TD ALIGN="right">25</TD>
+  <TD ALIGN="right">7</TD>
+  <TD ALIGN="right">112</TD>
+</TR>
+<TR>
+  <TD>Fields</TD>
+  <TD ALIGN="right">38</TD>
+  <TD ALIGN="right">3</TD>
+  <TD ALIGN="right">1</TD>
+  <TD ALIGN="right">42</TD>
+</TR>
+<TR>
+  <TD style="background-color:#FAFAFA"><b>Total</b></TD>
+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>185</strong></TD>
+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>115</strong></TD>
+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>11</strong></TD>
+  <TD  style="background-color:#FAFAFA" ALIGN="right"><strong>311</strong></TD>
+</TR>
+</TABLE>
+<br>
+<a name="packages"></a>
+<h2>Changed Packages, Sorted by Percentage Difference</h2>
+<TABLE summary="Packages sorted by percentage difference" WIDTH="100%">
+<TR>
+  <TH  WIDTH="10%">Percentage Difference*</TH>
+  <TH>Package</TH>
+</TR>
+<TR>
+  <TD ALIGN="center">37</TD>
+  <TD><A HREF="pkg_android.support.v7.widget.html">android.support.v7.widget</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="pkg_android.support.v7.content.res.html">android.support.v7.content.res</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">32</TD>
+  <TD><A HREF="pkg_android.support.v7.util.html">android.support.v7.util</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">19</TD>
+  <TD><A HREF="pkg_android.support.v4.view.accessibility.html">android.support.v4.view.accessibility</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">12</TD>
+  <TD><A HREF="pkg_android.support.v7.app.html">android.support.v7.app</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">5</TD>
+  <TD><A HREF="pkg_android.support.v4.widget.html">android.support.v4.widget</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="pkg_android.support.v4.accessibilityservice.html">android.support.v4.accessibilityservice</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="pkg_android.support.customtabs.html">android.support.customtabs</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">3</TD>
+  <TD><A HREF="pkg_android.support.v4.util.html">android.support.v4.util</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">3</TD>
+  <TD><A HREF="pkg_android.support.v4.os.html">android.support.v4.os</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="pkg_android.support.v4.media.session.html">android.support.v4.media.session</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="pkg_android.support.v4.app.html">android.support.v4.app</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="pkg_android.support.design.widget.html">android.support.design.widget</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="pkg_android.support.v4.media.html">android.support.v4.media</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="pkg_android.support.v7.preference.html">android.support.v7.preference</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="pkg_android.support.v4.view.html">android.support.v4.view</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="pkg_android.support.v17.preference.html">android.support.v17.preference</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">&lt;1</TD>
+  <TD><A HREF="pkg_android.support.v4.graphics.drawable.html">android.support.v4.graphics.drawable</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">&lt;1</TD>
+  <TD><A HREF="pkg_android.support.v7.graphics.html">android.support.v7.graphics</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">&lt;1</TD>
+  <TD><A HREF="pkg_android.support.v17.leanback.widget.html">android.support.v17.leanback.widget</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">&lt;1</TD>
+  <TD><A HREF="pkg_android.support.v14.preference.html">android.support.v14.preference</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">&lt;1</TD>
+  <TD><A HREF="pkg_android.support.v4.content.html">android.support.v4.content</A></TD>
+</TR>
+</TABLE>
+<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
+<br>
+<a name="classes"></a>
+<h2>Changed Classes and <i>Interfaces</i>, Sorted by Percentage Difference</h2>
+<TABLE summary="Classes sorted by percentage difference" WIDTH="100%">
+<TR WIDTH="20%">
+  <TH WIDTH="10%">Percentage<br>Difference*</TH>
+  <TH><b>Class or <i>Interface</i></b></TH>
+</TR>
+<TR>
+  <TD ALIGN="center">60</TD>
+  <TD><A HREF="android.support.v4.app.ServiceCompat.html">
+android.support.v4.app.ServiceCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">38</TD>
+  <TD><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">
+android.support.design.widget.FloatingActionButton.Behavior</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="android.support.v4.app.ActivityOptionsCompat.html">
+android.support.v4.app.ActivityOptionsCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="android.support.v4.os.BuildCompat.html">
+android.support.v4.os.BuildCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">
+android.support.v4.view.accessibility.AccessibilityManagerCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">
+android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">33</TD>
+  <TD><A HREF="android.support.v7.content.res.AppCompatResources.html">
+android.support.v7.content.res.AppCompatResources</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">28</TD>
+  <TD><A HREF="android.support.customtabs.CustomTabsSession.html">
+android.support.customtabs.CustomTabsSession</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">28</TD>
+  <TD><A HREF="android.support.v7.util.SortedList.Callback.html">
+android.support.v7.util.SortedList.Callback</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">25</TD>
+  <TD><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">
+android.support.v4.media.session.MediaButtonReceiver</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">25</TD>
+  <TD><A HREF="android.support.v4.view.ViewConfigurationCompat.html">
+android.support.v4.view.ViewConfigurationCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">25</TD>
+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">
+android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">23</TD>
+  <TD><A HREF="android.support.v4.media.MediaDescriptionCompat.html">
+android.support.v4.media.MediaDescriptionCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">20</TD>
+  <TD><A HREF="android.support.v4.view.KeyEventCompat.html">
+android.support.v4.view.KeyEventCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">18</TD>
+  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">
+android.support.v17.leanback.widget.AbstractMediaItemPresenter</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">18</TD>
+  <TD><A HREF="android.support.design.widget.TextInputLayout.html">
+android.support.design.widget.TextInputLayout</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">17</TD>
+  <TD><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">
+android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">16</TD>
+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">
+android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">15</TD>
+  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">
+android.support.v4.media.session.MediaSessionCompat.QueueItem</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">13</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">12</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">11</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">
+android.support.v4.view.accessibility.AccessibilityEventCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">11</TD>
+  <TD><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">
+android.support.design.widget.AppBarLayout.ScrollingViewBehavior</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">10</TD>
+  <TD><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">
+android.support.v17.preference.LeanbackSettingsFragment</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">9</TD>
+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">
+android.support.design.widget.CoordinatorLayout.Behavior</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">8</TD>
+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">
+android.support.design.widget.CoordinatorLayout.LayoutParams</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">8</TD>
+  <TD><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">
+android.support.v4.media.MediaBrowserCompat.MediaItem</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">7</TD>
+  <TD><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">
+android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">7</TD>
+  <TD><A HREF="android.support.v4.widget.TextViewCompat.html">
+android.support.v4.widget.TextViewCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">7</TD>
+  <TD><A HREF="android.support.v4.app.ActivityCompat.html">
+android.support.v4.app.ActivityCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v4.app.SharedElementCallback.html">
+android.support.v4.app.SharedElementCallback</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeProviderCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v4.widget.SearchViewCompat.html">
+android.support.v4.widget.SearchViewCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">6</TD>
+  <TD><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">
+android.support.v7.app.ActionBarDrawerToggle</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">5</TD>
+  <TD><A HREF="android.support.customtabs.CustomTabsIntent.html">
+android.support.customtabs.CustomTabsIntent</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">
+android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="android.support.v4.view.MotionEventCompat.html">
+android.support.v4.view.MotionEventCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="android.support.v7.graphics.Palette.html">
+android.support.v7.graphics.Palette</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">4</TD>
+  <TD><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">
+android.support.v7.widget.StaggeredGridLayoutManager</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">3</TD>
+  <TD><A HREF="android.support.v4.media.session.MediaSessionCompat.html">
+android.support.v4.media.session.MediaSessionCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">3</TD>
+  <TD><A HREF="android.support.v4.content.ContextCompat.html">
+android.support.v4.content.ContextCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">3</TD>
+  <TD><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">
+android.support.customtabs.CustomTabsIntent.Builder</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.design.widget.BottomSheetBehavior.html">
+android.support.design.widget.BottomSheetBehavior</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.design.widget.CoordinatorLayout.html">
+android.support.design.widget.CoordinatorLayout</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">
+android.support.v4.graphics.drawable.DrawableCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.view.WindowInsetsCompat.html">
+android.support.v4.view.WindowInsetsCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v14.preference.PreferenceFragment.html">
+android.support.v14.preference.PreferenceFragment</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">
+android.support.v4.view.accessibility.AccessibilityWindowInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.view.ViewCompat.html">
+android.support.v4.view.ViewCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">
+android.support.design.widget.CollapsingToolbarLayout</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">
+android.support.v17.leanback.widget.ObjectAdapter</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.media.MediaMetadataCompat.html">
+android.support.v4.media.MediaMetadataCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v7.widget.LinearSmoothScroller.html">
+android.support.v7.widget.LinearSmoothScroller</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">2</TD>
+  <TD><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">
+android.support.v4.widget.SwipeRefreshLayout</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v7.widget.LinearLayoutManager.html">
+android.support.v7.widget.LinearLayoutManager</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">
+android.support.v4.view.accessibility.AccessibilityNodeInfoCompat</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.design.widget.TabLayout.html">
+android.support.design.widget.TabLayout</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v4.app.FragmentController.html">
+android.support.v4.app.FragmentController</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v7.app.AppCompatDelegate.html">
+android.support.v7.app.AppCompatDelegate</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v7.widget.RecyclerView.html">
+android.support.v7.widget.RecyclerView</A></TD>
+</TR>
+<TR>
+  <TD ALIGN="center">1</TD>
+  <TD><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">
+android.support.v4.media.session.PlaybackStateCompat</A></TD>
+</TR>
+</TABLE>
+<p style="font-size:10px">* See <a href="#calculation">Calculation of Change Percentages</a>, below.</p>
+<br>
+<h2 id="calculation">Calculation of Change Percentages</h2>
+<p>
+The percent change statistic reported for all elements in the &quot;to&quot; API Level specification is defined recursively as follows:</p>
+<pre>
+Percentage difference = 100 * (added + removed + 2*changed)
+                        -----------------------------------
+                        sum of public elements in BOTH APIs
+</pre>
+<p>where <code>added</code> is the number of packages added, <code>removed</code> is the number of packages removed, and <code>changed</code> is the number of packages changed.
+This definition is applied recursively for the classes and their program elements, so the value for a changed package will be less than 1, unless every class in that package has changed.
+The definition ensures that if all packages are removed and all new packages are
+added, the change will be 100%.</p>
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY></HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
new file mode 100644
index 0000000..36f9836
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Android API Version Differences
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<table class="jdiffIndex" summary="Links to diff index files" BORDER="0" WIDTH="100%" cellspacing="0" cellpadding="0" style="margin:0">
+<TR>
+  <th class="indexHeader" nowrap>
+  Select a Diffs Index:</th>
+</TR>
+<TR>
+  <TD><FONT CLASS="indexText" size="-2"><A HREF="alldiffs_index_all.html" TARGET="bottomleftframe">All Differences</A></FONT><br></TD>
+</TR>
+<TR>
+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="packages_index_all.html" TARGET="bottomleftframe">By Package</A></FONT><br></TD>
+</TR>
+<TR>
+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="classes_index_all.html" TARGET="bottomleftframe">By Class</A></FONT><br></TD>
+</TR>
+<TR>
+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="constructors_index_all.html" TARGET="bottomleftframe">By Constructor</A></FONT><br></TD>
+</TR>
+<TR>
+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="methods_index_all.html" TARGET="bottomleftframe">By Method</A></FONT><br></TD>
+</TR>
+<TR>
+  <TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
+</TR>
+</TABLE>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
new file mode 100644
index 0000000..508018e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
@@ -0,0 +1,448 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Method Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="methods_index_all.html" class="staysblack">All Methods</a>
+  <br>
+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>buildMediaButtonPendingIntent</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
+(<code>Drawable</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe"><b>computeScrollVectorForPosition</b>
+(<code>int</code>)</A></nobr><br>
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
+(<code>String</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
+(<code>Context, Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
+(<code>TextView</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
+(<code>int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
+(<code>Context, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
+()</A></nobr><br>
+<i>getInsetDodgeRect</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
+</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
+()</A></nobr><br>
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
+()</A></nobr><br>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
+(<code>View, int, int, int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
+()</A></nobr><br>
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
+()</A></nobr><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
+</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
+(<code>LayoutParams</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
+(<code>int, int, Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
+()</A></nobr><br>
+<i>onRequestChildRectangleOnScreen</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
+(<code>PendingIntent</code>)</A></nobr><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
+(<code>Rect</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
+(<code>OnFlingListener</code>)</A></nobr><br>
+<i>setPasswordVisibilityToggleContentDescription</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<i>setPasswordVisibilityToggleDrawable</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
+(<code>Mode</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
+(<code>int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
+(<code>Service, int</code>)</A></nobr><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
+(<code>long</code>)</A></nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
new file mode 100644
index 0000000..a52d5c9
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
@@ -0,0 +1,579 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Method Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>Methods</b>
+  <br>
+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>addTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<A NAME="B"></A>
+<br><font size="+2">B</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>buildMediaButtonPendingIntent</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, ComponentName, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html#android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Context, long</code>)</b>&nbsp;in&nbsp;android.support.v4.media.session.MediaButtonReceiver
+</A></nobr><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html#android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe"><b>clearColorFilter</b>
+(<code>Drawable</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TabLayout.html#android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()" class="hiddenlink" target="rightframe"><b>clearOnTabSelectedListeners</b>
+()</A></nobr><br>
+<i>computeScrollVectorForPosition</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>int</code>)&nbsp;in&nbsp;android.support.v7.widget.LinearSmoothScroller
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.v7.widget.StaggeredGridLayoutManager
+</A></nobr><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.FragmentController.html#android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)" class="hiddenlink" target="rightframe"><b>findFragmentByWho</b>
+(<code>String</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaItem</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html#android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromMediaItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromMediaSession</b>
+(<code>Context, Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>fromQueueItem</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List<?>)" class="hiddenlink" target="rightframe"><b>fromQueueItemList</b>
+(<code>List&lt;?&gt;</code>)</A></nobr><br>
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getAction</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.TextViewCompat.html#android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)" class="hiddenlink" target="rightframe"><b>getCompoundDrawablesRelative</b>
+(<code>TextView</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.html#android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)" class="hiddenlink" target="rightframe"><b>getDependents</b>
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantColor_added(int)" class="hiddenlink" target="rightframe"><b>getDominantColor</b>
+(<code>int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.graphics.Palette.html#android.support.v7.graphics.Palette.getDominantSwatch_added()" class="hiddenlink" target="rightframe"><b>getDominantSwatch</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v7.content.res.AppCompatResources.html#android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)" class="hiddenlink" target="rightframe"><b>getDrawable</b>
+(<code>Context, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()" class="hiddenlink" target="rightframe"><b>getDrawerArrowDrawable</b>
+()</A></nobr><br>
+<i>getInsetDodgeRect</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, FloatingActionButton, Rect</code>)</b>&nbsp;in&nbsp;android.support.design.widget.FloatingActionButton.Behavior
+</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()" class="hiddenlink" target="rightframe"><b>getLaunchBounds</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()" class="hiddenlink" target="rightframe"><b>getMediaItemNumberViewFlipper</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPausedView</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()" class="hiddenlink" target="rightframe"><b>getMediaItemPlayingView</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)" class="hiddenlink" target="rightframe"><b>getMediaPlayState</b>
+(<code>Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)" class="hiddenlink" target="rightframe"><b>getMovementGranularity</b>
+(<code>AccessibilityEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.getOnFlingListener_added()" class="hiddenlink" target="rightframe"><b>getOnFlingListener</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleContentDescription</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()" class="hiddenlink" target="rightframe"><b>getPasswordVisibilityToggleDrawable</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
+(<code>MotionEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
+(<code>Activity</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
+(<code>ViewConfiguration</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()" class="hiddenlink" target="rightframe"><b>getSelectionMode</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
+(<code>MotionEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.os.BuildCompat.html#android.support.v4.os.BuildCompat.isAtLeastNMR1_added()" class="hiddenlink" target="rightframe"><b>isAtLeastNMR1</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()" class="hiddenlink" target="rightframe"><b>isAutoHideEnabled</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()" class="hiddenlink" target="rightframe"><b>isContextClickable</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html#android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()" class="hiddenlink" target="rightframe"><b>isImmediateNotifySupported</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)" class="hiddenlink" target="rightframe"><b>isImportantForAccessibility</b>
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()" class="hiddenlink" target="rightframe"><b>isPasswordVisibilityToggleEnabled</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)" class="hiddenlink" target="rightframe"><b>loadDescription</b>
+(<code>AccessibilityServiceInfo, PackageManager</code>)</A></nobr><br>
+<A NAME="M"></A>
+<br><font size="+2">M</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeBasic_added()" class="hiddenlink" target="rightframe"><b>makeBasic</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)" class="hiddenlink" target="rightframe"><b>makeClipRevealAnimation</b>
+(<code>View, int, int, int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()" class="hiddenlink" target="rightframe"><b>makeTaskLaunchBehind</b>
+()</A></nobr><br>
+<A NAME="N"></A>
+<br><font size="+2">N</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()" class="hiddenlink" target="rightframe"><b>notifyPlayStateChanged</b>
+()</A></nobr><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, int, int, int, boolean</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int, float, float, float</code>)</b>&nbsp;in&nbsp;android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat
+</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)" class="hiddenlink" target="rightframe"><b>onAttachedToLayoutParams</b>
+(<code>LayoutParams</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onBindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)" class="hiddenlink" target="rightframe"><b>onChanged</b>
+(<code>int, int, Object</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()" class="hiddenlink" target="rightframe"><b>onDetachedFromLayoutParams</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
+(<code>int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<i>onRequestChildRectangleOnScreen</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html#android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, View, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.AppBarLayout.ScrollingViewBehavior
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CoordinatorLayout, V, Rect, boolean</code>)</b>&nbsp;in&nbsp;android.support.design.widget.CoordinatorLayout.Behavior
+</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.SharedElementCallback.html#android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)" class="hiddenlink" target="rightframe"><b>onSharedElementsArrived</b>
+(<code>List&lt;String&gt;, List&lt;View&gt;, OnSharedElementsReadyListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.AppCompatDelegate.html#android.support.v7.app.AppCompatDelegate.onStart_added()" class="hiddenlink" target="rightframe"><b>onStart</b>
+()</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)" class="hiddenlink" target="rightframe"><b>onUnbindMediaPlayState</b>
+(<code>ViewHolder</code>)</A></nobr><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
+(<code>View, View, int, int</code>)</A></nobr><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)" class="hiddenlink" target="rightframe"><b>removeTouchExplorationStateChangeListener</b>
+(<code>AccessibilityManager, TouchExplorationStateChangeListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>requestUsageTimeReport</b>
+(<code>PendingIntent</code>)</A></nobr><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#T"><font size="-2">T</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setAction</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>setAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setAutoHideEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setCollapsedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html#android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)" class="hiddenlink" target="rightframe"><b>setContextClickable</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html#android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)" class="hiddenlink" target="rightframe"><b>setDrawerArrowDrawable</b>
+(<code>DrawerArrowDrawable</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html#android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setExpandedTitleTextColor</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html#android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setInstantAppsEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html#android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)" class="hiddenlink" target="rightframe"><b>setLaunchBounds</b>
+(<code>Rect</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)" class="hiddenlink" target="rightframe"><b>setMovementGranularity</b>
+(<code>AccessibilityEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html#android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)" class="hiddenlink" target="rightframe"><b>setOnChildScrollUpCallback</b>
+(<code>OnChildScrollUpCallback</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
+(<code>View, OnCloseListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.widget.RecyclerView.html#android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)" class="hiddenlink" target="rightframe"><b>setOnFlingListener</b>
+(<code>OnFlingListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
+(<code>View, int</code>)</A></nobr><br>
+<i>setPasswordVisibilityToggleContentDescription</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>CharSequence</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<i>setPasswordVisibilityToggleDrawable</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>Drawable</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)" class="hiddenlink" target="rightframe">type&nbsp;<b>
+(<code>int</code>)</b>&nbsp;in&nbsp;android.support.design.widget.TextInputLayout
+</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleEnabled</b>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintList</b>
+(<code>ColorStateList</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)" class="hiddenlink" target="rightframe"><b>setPasswordVisibilityToggleTintMode</b>
+(<code>Mode</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)" class="hiddenlink" target="rightframe"><b>setSecondaryToolbarViews</b>
+(<code>RemoteViews, int[], PendingIntent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html#android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)" class="hiddenlink" target="rightframe"><b>setSelectedMediaItemNumberView</b>
+(<code>int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
+(<code>int, Bitmap, String</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsIntent.html#android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)" class="hiddenlink" target="rightframe"><b>shouldAlwaysUseBrowserUI</b>
+(<code>Intent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ServiceCompat.html#android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)" class="hiddenlink" target="rightframe"><b>stopForeground</b>
+(<code>Service, int</code>)</A></nobr><br>
+<A NAME="T"></A>
+<br><font size="+2">T</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#B"><font size="-2">B</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#M"><font size="-2">M</font></a> 
+<a href="#N"><font size="-2">N</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
+(<code>long</code>)</A></nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
new file mode 100644
index 0000000..5faae42
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
@@ -0,0 +1,222 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Method Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="methods_index_all.html" class="staysblack">All Methods</a>
+  <br>
+<A HREF="methods_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="A"></A>
+<br><font size="+2">A</font>&nbsp;
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">addAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<A NAME="C"></A>
+<br><font size="+2">C</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html#android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)" class="hiddenlink" target="rightframe">computeScrollVectorForPosition
+(<code>int</code>)</A></nobr><br>
+<A NAME="D"></A>
+<br><font size="+2">D</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)" class="hiddenlink" target="rightframe">dispatch
+(<code>KeyEvent, Callback, Object, Object</code>)</A></nobr><br>
+<A NAME="F"></A>
+<br><font size="+2">F</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">findPointerIndex
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<A NAME="G"></A>
+<br><font size="+2">G</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html#android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)" class="hiddenlink" target="rightframe">getDescription
+(<code>AccessibilityServiceInfo</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)" class="hiddenlink" target="rightframe">getKeyDispatcherState
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)" class="hiddenlink" target="rightframe">getOverScrollMode
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getPointerCount
+(<code>MotionEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getPointerId
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.app.ActivityCompat.html#android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)" class="hiddenlink" target="rightframe">getReferrer
+(<code>Activity</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html#android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)" class="hiddenlink" target="rightframe">getScaledPagingTouchSlop
+(<code>ViewConfiguration</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)" class="hiddenlink" target="rightframe">getSource
+(<code>MotionEvent</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getX
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.MotionEventCompat.html#android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)" class="hiddenlink" target="rightframe">getY
+(<code>MotionEvent, int</code>)</A></nobr><br>
+<A NAME="I"></A>
+<br><font size="+2">I</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html#android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)" class="hiddenlink" target="rightframe">isDirty
+(<code>CoordinatorLayout, V</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)" class="hiddenlink" target="rightframe">isOpaque
+(<code>View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">isTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<i>obtain</i><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html#android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Context, Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat
+</A></nobr><br>
+&nbsp;&nbsp;<nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html#android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)" class="hiddenlink" target="rightframe">type&nbsp;
+(<code>Object</code>)&nbsp;in&nbsp;android.support.v4.media.session.MediaSessionCompat.QueueItem
+</A></nobr><br>
+<A NAME="R"></A>
+<br><font size="+2">R</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#S"><font size="-2">S</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)" class="hiddenlink" target="rightframe">removeAccessibilityStateChangeListener
+(<code>AccessibilityManager, AccessibilityStateChangeListener</code>)</A></nobr><br>
+<A NAME="S"></A>
+<br><font size="+2">S</font>&nbsp;
+<a href="#A"><font size="-2">A</font></a> 
+<a href="#C"><font size="-2">C</font></a> 
+<a href="#D"><font size="-2">D</font></a> 
+<a href="#F"><font size="-2">F</font></a> 
+<a href="#G"><font size="-2">G</font></a> 
+<a href="#I"><font size="-2">I</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#R"><font size="-2">R</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)" class="hiddenlink" target="rightframe">setOnCloseListener
+(<code>View, OnCloseListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.widget.SearchViewCompat.html#android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)" class="hiddenlink" target="rightframe">setOnQueryTextListener
+(<code>View, OnQueryTextListener</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)" class="hiddenlink" target="rightframe">setOverScrollMode
+(<code>View, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.customtabs.CustomTabsSession.html#android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)" class="hiddenlink" target="rightframe">setToolbarItem
+(<code>int, Bitmap, String</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
+(<code>KeyEvent</code>)</A></nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
new file mode 100644
index 0000000..062ac8f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Method Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Methods" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="methods_index_all.html" class="staysblack">All Methods</a>
+  <br>
+<b>Removals</b>
+  <br>
+<A HREF="methods_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="methods_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<A NAME="L"></A>
+<br><font size="+2">L</font>&nbsp;
+<a href="#O"><font size="-2">O</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>layoutDependsOn</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<A NAME="O"></A>
+<br><font size="+2">O</font>&nbsp;
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#P"><font size="-2">P</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html#android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)" class="hiddenlink" target="rightframe"><strike>onAccessibilityStateChanged</strike>
+(<code>boolean</code>)</A></nobr><br>
+<nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html#android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)" class="hiddenlink" target="rightframe"><strike>onDependentViewRemoved</strike>
+(<code>CoordinatorLayout, FloatingActionButton, View</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onInserted</strike>
+(<code>int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onMoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<nobr><A HREF="android.support.v7.util.SortedList.Callback.html#android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)" class="hiddenlink" target="rightframe"><strike>onRemoved</strike>
+(<code>int, int</code>)</A></nobr><br>
+<A NAME="P"></A>
+<br><font size="+2">P</font>&nbsp;
+<a href="#L"><font size="-2">L</font></a> 
+<a href="#O"><font size="-2">O</font></a> 
+ <a href="#topheader"><font size="-2">TOP</font></a>
+<p><div style="line-height:1.5em;color:black">
+<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
+(<code>View, View, int, int</code>)</A></nobr><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
new file mode 100644
index 0000000..2eff0f7
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Package Additions Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="packages_index_all.html" class="staysblack">All Packages</a>
+  <br>
+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<b>Additions</b>
+  <br>
+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<br>
+<div id="indexTableEntries">
+<A NAME="A"></A>
+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
new file mode 100644
index 0000000..58e51ed
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Package Differences Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<b>Packages</b>
+  <br>
+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<br>
+<div id="indexTableEntries">
+<A NAME="A"></A>
+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
+<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
+<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
new file mode 100644
index 0000000..1d9e428
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Package Changes Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="packages_index_all.html" class="staysblack">All Packages</a>
+  <br>
+<A HREF="packages_index_removals.html" xclass="hiddenlink">Removals</A>
+  <br>
+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<b>Changes</b>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<br>
+<div id="indexTableEntries">
+<A NAME="A"></A>
+<A HREF="pkg_android.support.customtabs.html" class="hiddenlink" target="rightframe">android.support.customtabs</A><br>
+<A HREF="pkg_android.support.design.widget.html" class="hiddenlink" target="rightframe">android.support.design.widget</A><br>
+<A HREF="pkg_android.support.v14.preference.html" class="hiddenlink" target="rightframe">android.support.v14.preference</A><br>
+<A HREF="pkg_android.support.v17.leanback.widget.html" class="hiddenlink" target="rightframe">android.support.v17.leanback.widget</A><br>
+<A HREF="pkg_android.support.v17.preference.html" class="hiddenlink" target="rightframe">android.support.v17.preference</A><br>
+<A HREF="pkg_android.support.v4.accessibilityservice.html" class="hiddenlink" target="rightframe">android.support.v4.accessibilityservice</A><br>
+<A HREF="pkg_android.support.v4.app.html" class="hiddenlink" target="rightframe">android.support.v4.app</A><br>
+<A HREF="pkg_android.support.v4.content.html" class="hiddenlink" target="rightframe">android.support.v4.content</A><br>
+<A HREF="pkg_android.support.v4.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v4.graphics.drawable</A><br>
+<A HREF="pkg_android.support.v4.media.html" class="hiddenlink" target="rightframe">android.support.v4.media</A><br>
+<A HREF="pkg_android.support.v4.media.session.html" class="hiddenlink" target="rightframe">android.support.v4.media.session</A><br>
+<A HREF="pkg_android.support.v4.os.html" class="hiddenlink" target="rightframe">android.support.v4.os</A><br>
+<A HREF="pkg_android.support.v4.util.html" class="hiddenlink" target="rightframe">android.support.v4.util</A><br>
+<A HREF="pkg_android.support.v4.view.html" class="hiddenlink" target="rightframe">android.support.v4.view</A><br>
+<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
+<A HREF="pkg_android.support.v4.widget.html" class="hiddenlink" target="rightframe">android.support.v4.widget</A><br>
+<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
+<A HREF="pkg_android.support.v7.content.res.html" class="hiddenlink" target="rightframe">android.support.v7.content.res</A><br>
+<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
+<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
+<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
+<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
new file mode 100644
index 0000000..d52d40d
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+Package Removals Index
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY class="gc-documentation" style="padding:12px;">
+<a NAME="topheader"></a>
+<table summary="Index for Packages" width="100%" class="jdiffIndex" border="0" cellspacing="0" cellpadding="0" style="padding-bottom:0;margin-bottom:0;">
+  <tr>
+  <th class="indexHeader">
+    Filter the Index:
+  </th>
+  </tr>
+  <tr>
+  <td class="indexText" style="line-height:1.3em;padding-left:2em;">
+<a href="packages_index_all.html" class="staysblack">All Packages</a>
+  <br>
+<b>Removals</b>
+  <br>
+<A HREF="packages_index_additions.html"xclass="hiddenlink">Additions</A>
+  <br>
+<A HREF="packages_index_changes.html"xclass="hiddenlink">Changes</A>
+  </td>
+  </tr>
+</table>
+<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
+Listed as: <span style="color:#069"><strong>Added</strong></span>,  <span style="color:#069"><strike>Removed</strike></span>,  <span style="color:#069">Changed</span></font>
+</div>
+<br>
+<div id="indexTableEntries">
+<A NAME="A"></A>
+<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
+<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
+<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
new file mode 100644
index 0000000..5959d63
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.customtabs
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/customtabs/package-summary.html" target="_top"><font size="+1"><code>android.support.customtabs</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CustomTabsIntent"></A>
+  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.html">CustomTabsIntent</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CustomTabsIntent.Builder"></A>
+  <nobr><A HREF="android.support.customtabs.CustomTabsIntent.Builder.html">CustomTabsIntent.Builder</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CustomTabsSession"></A>
+  <nobr><A HREF="android.support.customtabs.CustomTabsSession.html">CustomTabsSession</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
new file mode 100644
index 0000000..510b9bd
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
@@ -0,0 +1,175 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.design.widget
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/design/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.design.widget</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppBarLayout.ScrollingViewBehavior"></A>
+  <nobr><A HREF="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html">AppBarLayout.ScrollingViewBehavior</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="BottomSheetBehavior"></A>
+  <nobr><A HREF="android.support.design.widget.BottomSheetBehavior.html">BottomSheetBehavior</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CollapsingToolbarLayout"></A>
+  <nobr><A HREF="android.support.design.widget.CollapsingToolbarLayout.html">CollapsingToolbarLayout</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CoordinatorLayout"></A>
+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.html">CoordinatorLayout</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CoordinatorLayout.Behavior"></A>
+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.Behavior.html">CoordinatorLayout.Behavior</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CoordinatorLayout.LayoutParams"></A>
+  <nobr><A HREF="android.support.design.widget.CoordinatorLayout.LayoutParams.html">CoordinatorLayout.LayoutParams</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="FloatingActionButton.Behavior"></A>
+  <nobr><A HREF="android.support.design.widget.FloatingActionButton.Behavior.html">FloatingActionButton.Behavior</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="TabLayout"></A>
+  <nobr><A HREF="android.support.design.widget.TabLayout.html">TabLayout</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="TextInputLayout"></A>
+  <nobr><A HREF="android.support.design.widget.TextInputLayout.html">TextInputLayout</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
new file mode 100644
index 0000000..84efadc6
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v14.preference
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v14/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v14.preference</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PreferenceFragment"></A>
+  <nobr><A HREF="android.support.v14.preference.PreferenceFragment.html">PreferenceFragment</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
new file mode 100644
index 0000000..4ce1f32
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.leanback.widget
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v17/leanback/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.leanback.widget</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AbstractMediaItemPresenter"></A>
+  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.html">AbstractMediaItemPresenter</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AbstractMediaItemPresenter.ViewHolder"></A>
+  <nobr><A HREF="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html">AbstractMediaItemPresenter.<br>ViewHolder</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ObjectAdapter"></A>
+  <nobr><A HREF="android.support.v17.leanback.widget.ObjectAdapter.html">ObjectAdapter</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
new file mode 100644
index 0000000..ad0aadd
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v17.preference
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v17/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v17.preference</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LeanbackSettingsFragment"></A>
+  <nobr><A HREF="android.support.v17.preference.LeanbackSettingsFragment.html">LeanbackSettingsFragment</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
new file mode 100644
index 0000000..e904a76
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.accessibilityservice
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/accessibilityservice/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.accessibilityservice</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityServiceInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html">AccessibilityServiceInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
new file mode 100644
index 0000000..f8e4cb1
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.app
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.app</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Interfaces" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SharedElementCallback.OnSharedElementsReadyListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/app/SharedElementCallback.OnSharedElementsReadyListener.html" target="_top"><code><I>SharedElementCallback.<br>OnSharedElementsReadyListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActivityCompat"></A>
+  <nobr><A HREF="android.support.v4.app.ActivityCompat.html">ActivityCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActivityOptionsCompat"></A>
+  <nobr><A HREF="android.support.v4.app.ActivityOptionsCompat.html">ActivityOptionsCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="FragmentController"></A>
+  <nobr><A HREF="android.support.v4.app.FragmentController.html">FragmentController</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ServiceCompat"></A>
+  <nobr><A HREF="android.support.v4.app.ServiceCompat.html">ServiceCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SharedElementCallback"></A>
+  <nobr><A HREF="android.support.v4.app.SharedElementCallback.html">SharedElementCallback</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
new file mode 100644
index 0000000..31aa1da
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.content
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/content/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.content</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ContextCompat"></A>
+  <nobr><A HREF="android.support.v4.content.ContextCompat.html">ContextCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
new file mode 100644
index 0000000..b1efab3
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.graphics.drawable
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/graphics/drawable/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.graphics.drawable</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="DrawableCompat"></A>
+  <nobr><A HREF="android.support.v4.graphics.drawable.DrawableCompat.html">DrawableCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
new file mode 100644
index 0000000..612a1a0
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/media/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaBrowserCompat.MediaItem"></A>
+  <nobr><A HREF="android.support.v4.media.MediaBrowserCompat.MediaItem.html">MediaBrowserCompat.MediaItem</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaBrowserServiceCompat.BrowserRoot"></A>
+  <nobr><A HREF="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html">MediaBrowserServiceCompat.<br>BrowserRoot</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaDescriptionCompat"></A>
+  <nobr><A HREF="android.support.v4.media.MediaDescriptionCompat.html">MediaDescriptionCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaMetadataCompat"></A>
+  <nobr><A HREF="android.support.v4.media.MediaMetadataCompat.html">MediaMetadataCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
new file mode 100644
index 0000000..3e46335
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.media.session
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/media/session/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.media.session</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaButtonReceiver"></A>
+  <nobr><A HREF="android.support.v4.media.session.MediaButtonReceiver.html">MediaButtonReceiver</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaSessionCompat"></A>
+  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.html">MediaSessionCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MediaSessionCompat.QueueItem"></A>
+  <nobr><A HREF="android.support.v4.media.session.MediaSessionCompat.QueueItem.html">MediaSessionCompat.QueueItem</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PlaybackStateCompat"></A>
+  <nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html">PlaybackStateCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
new file mode 100644
index 0000000..b250855
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.os
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/os/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.os</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="BuildCompat"></A>
+  <nobr><A HREF="android.support.v4.os.BuildCompat.html">BuildCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
new file mode 100644
index 0000000..d34506e
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.util
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.util</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PatternsCompat"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/util/PatternsCompat.html" target="_top"><code>PatternsCompat</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
new file mode 100644
index 0000000..a6362fb
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
@@ -0,0 +1,204 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view.accessibility
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/view/accessibility/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view.accessibility</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Interfaces" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>AccessibilityStateChangeListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityManagerCompat.TouchExplorationStateChangeListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.TouchExplorationStateChangeListener.html" target="_top"><code><I>AccessibilityManagerCompat.<br>TouchExplorationStateChangeListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityEventCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html">AccessibilityEventCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityManagerCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.html">AccessibilityManagerCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html">AccessibilityManagerCompat.<br>AccessibilityStateChangeListenerCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html">AccessibilityNodeInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeInfoCompat.AccessibilityActionCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html">AccessibilityNodeInfoCompat.<br>AccessibilityActionCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeInfoCompat.CollectionInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeInfoCompat.CollectionItemInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html">AccessibilityNodeInfoCompat.<br>CollectionItemInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeInfoCompat.RangeInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html">AccessibilityNodeInfoCompat.<br>RangeInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityNodeProviderCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html">AccessibilityNodeProviderCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AccessibilityWindowInfoCompat"></A>
+  <nobr><A HREF="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html">AccessibilityWindowInfoCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
new file mode 100644
index 0000000..10b1334
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.view
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/view/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.view</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="KeyEventCompat"></A>
+  <nobr><A HREF="android.support.v4.view.KeyEventCompat.html">KeyEventCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MotionEventCompat"></A>
+  <nobr><A HREF="android.support.v4.view.MotionEventCompat.html">MotionEventCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ViewCompat"></A>
+  <nobr><A HREF="android.support.v4.view.ViewCompat.html">ViewCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ViewConfigurationCompat"></A>
+  <nobr><A HREF="android.support.v4.view.ViewConfigurationCompat.html">ViewConfigurationCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="WindowInsetsCompat"></A>
+  <nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html">WindowInsetsCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
new file mode 100644
index 0000000..5ed0f65
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v4.widget
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v4/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v4.widget</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Interfaces" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Interfaces</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchViewCompat.OnCloseListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnCloseListener.html" target="_top"><code><I>SearchViewCompat.OnCloseListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchViewCompat.OnQueryTextListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListener.html" target="_top"><code><I>SearchViewCompat.OnQueryTextListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SwipeRefreshLayout.OnChildScrollUpCallback"></A>
+  <nobr><A HREF="../../../../reference/android/support/v4/widget/SwipeRefreshLayout.OnChildScrollUpCallback.html" target="_top"><code><I>SwipeRefreshLayout.OnChildScrollUpCallback</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchViewCompat"></A>
+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.html">SearchViewCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchViewCompat.OnCloseListenerCompat"></A>
+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html">SearchViewCompat.OnCloseListenerCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchViewCompat.OnQueryTextListenerCompat"></A>
+  <nobr><A HREF="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html">SearchViewCompat.OnQueryTextListenerCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SwipeRefreshLayout"></A>
+  <nobr><A HREF="android.support.v4.widget.SwipeRefreshLayout.html">SwipeRefreshLayout</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="TextViewCompat"></A>
+  <nobr><A HREF="android.support.v4.widget.TextViewCompat.html">TextViewCompat</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
new file mode 100644
index 0000000..8eb58aa
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.app
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/app/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.app</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActionBarActivity"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/ActionBarActivity.html" target="_top"><code>ActionBarActivity</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatActivity"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatActivity.html" target="_top"><code>AppCompatActivity</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatDialogFragment"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/AppCompatDialogFragment.html" target="_top"><code>AppCompatDialogFragment</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="NotificationCompat"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.html" target="_top"><code>NotificationCompat</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="NotificationCompat.Builder"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.Builder.html" target="_top"><code>NotificationCompat.Builder</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="NotificationCompat.MediaStyle"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/app/NotificationCompat.MediaStyle.html" target="_top"><code>NotificationCompat.MediaStyle</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActionBarDrawerToggle"></A>
+  <nobr><A HREF="android.support.v7.app.ActionBarDrawerToggle.html">ActionBarDrawerToggle</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatDelegate"></A>
+  <nobr><A HREF="android.support.v7.app.AppCompatDelegate.html">AppCompatDelegate</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
new file mode 100644
index 0000000..90787f7
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.content.res
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/content/res/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.content.res</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatResources"></A>
+  <nobr><A HREF="android.support.v7.content.res.AppCompatResources.html">AppCompatResources</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
new file mode 100644
index 0000000..bd9cf24
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.graphics
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/graphics/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.graphics</code></font></A>
+</H2>
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Palette"></A>
+  <nobr><A HREF="android.support.v7.graphics.Palette.html">Palette</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
new file mode 100644
index 0000000..b80e005
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.preference
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/preference/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.preference</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="MultiSelectListPreferenceDialogFragmentCompat"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat.html" target="_top"><code>MultiSelectListPreferenceDialogFragmentCompat</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
new file mode 100644
index 0000000..365022f
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.util
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/util/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.util</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="BatchingListUpdateCallback"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/util/BatchingListUpdateCallback.html" target="_top"><code>BatchingListUpdateCallback</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="DiffUtil"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.html" target="_top"><code>DiffUtil</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="DiffUtil.Callback"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.Callback.html" target="_top"><code>DiffUtil.Callback</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="DiffUtil.DiffResult"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/util/DiffUtil.DiffResult.html" target="_top"><code>DiffUtil.DiffResult</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ListUpdateCallback"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/util/ListUpdateCallback.html" target="_top"><code><I>ListUpdateCallback</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SortedList.Callback"></A>
+  <nobr><A HREF="android.support.v7.util.SortedList.Callback.html">SortedList.Callback</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
new file mode 100644
index 0000000..e07d5b8
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
@@ -0,0 +1,463 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML style="overflow:auto;">
+<HEAD>
+<meta name="generator" content="JDiff v1.1.0">
+<!-- Generated by the JDiff Javadoc doclet -->
+<!-- (http://www.jdiff.org) -->
+<meta name="description" content="JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.">
+<meta name="keywords" content="diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet">
+<TITLE>
+android.support.v7.widget
+</TITLE>
+<link href="../../../../assets/android-developer-docs.css" rel="stylesheet" type="text/css" />
+<link href="../stylesheet-jdiff.css" rel="stylesheet" type="text/css" />
+<noscript>
+<style type="text/css">
+body{overflow:auto;}
+#body-content{position:relative; top:0;}
+#doc-content{overflow:visible;border-left:3px solid #666;}
+#side-nav{padding:0;}
+#side-nav .toggle-list ul {display:block;}
+#resize-packages-nav{border-bottom:3px solid #666;}
+</style>
+</noscript>
+<style type="text/css">
+</style>
+</HEAD>
+<BODY>
+<!-- Start of nav bar -->
+<a name="top"></a>
+<div id="header" style="margin-bottom:0;padding-bottom:0;">
+<div id="headerLeft">
+<a href="../../../../index.html" tabindex="-1" target="_top"><img src="../../../../assets/images/bg_logo.png" alt="Android Developers" /></a>
+</div>
+  <div id="headerRight">
+  <div id="headerLinks">
+<!-- <img src="/assets/images/icon_world.jpg" alt="" /> -->
+<span class="text">
+<!-- &nbsp;<a href="#">English</a> | -->
+<nobr><a href="http://developer.android.com" target="_top">Android Developers</a> | <a href="http://www.android.com" target="_top">Android.com</a></nobr>
+</span>
+</div>
+  <div class="and-diff-id" style="margin-top:6px;margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td colspan="2" class="diffspechead">API Diff Specification</td>
+      </tr>
+      <tr>
+        <td class="diffspec" style="padding-top:.25em">To Level:</td>
+        <td class="diffvaluenew" style="padding-top:.25em">24.2.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">From Level:</td>
+        <td class="diffvalueold">24.1.0</td>
+      </tr>
+      <tr>
+        <td class="diffspec">Generated</td>
+        <td class="diffvalue">2016.08.16 14:03</td>
+      </tr>
+    </table>
+    </div><!-- End and-diff-id -->
+  <div class="and-diff-id" style="margin-right:8px;">
+    <table class="diffspectable">
+      <tr>
+        <td class="diffspec" colspan="2"><a href="jdiff_statistics.html">Statistics</a>
+      </tr>
+    </table>
+  </div> <!-- End and-diff-id -->
+  </div> <!-- End headerRight -->
+  </div> <!-- End header -->
+<div id="body-content" xstyle="padding:12px;padding-right:18px;">
+<div id="doc-content" style="position:relative;">
+<div id="mainBodyFluid">
+<H2>
+Package <A HREF="../../../../reference/android/support/v7/widget/package-summary.html" target="_top"><font size="+1"><code>android.support.v7.widget</code></font></A>
+</H2>
+<p>
+<a NAME="Added"></a>
+<TABLE summary="Added Classes and Interfaces" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Added Classes and Interfaces</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActionMenuView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.html" target="_top"><code>ActionMenuView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActionMenuView.LayoutParams"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.LayoutParams.html" target="_top"><code>ActionMenuView.LayoutParams</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ActionMenuView.OnMenuItemClickListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ActionMenuView.OnMenuItemClickListener.html" target="_top"><code><I>ActionMenuView.OnMenuItemClickListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatAutoCompleteTextView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatAutoCompleteTextView.html" target="_top"><code>AppCompatAutoCompleteTextView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatButton"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatButton.html" target="_top"><code>AppCompatButton</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatCheckBox"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckBox.html" target="_top"><code>AppCompatCheckBox</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatCheckedTextView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatCheckedTextView.html" target="_top"><code>AppCompatCheckedTextView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatEditText"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatEditText.html" target="_top"><code>AppCompatEditText</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatImageButton"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageButton.html" target="_top"><code>AppCompatImageButton</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatImageView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatImageView.html" target="_top"><code>AppCompatImageView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatMultiAutoCompleteTextView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.html" target="_top"><code>AppCompatMultiAutoCompleteTextView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatRadioButton"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRadioButton.html" target="_top"><code>AppCompatRadioButton</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatRatingBar"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatRatingBar.html" target="_top"><code>AppCompatRatingBar</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatSeekBar"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSeekBar.html" target="_top"><code>AppCompatSeekBar</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatSpinner"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatSpinner.html" target="_top"><code>AppCompatSpinner</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="AppCompatTextView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/AppCompatTextView.html" target="_top"><code>AppCompatTextView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="CardView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/CardView.html" target="_top"><code>CardView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="GridLayout"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.html" target="_top"><code>GridLayout</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="GridLayout.Alignment"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Alignment.html" target="_top"><code>GridLayout.Alignment</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="GridLayout.LayoutParams"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.LayoutParams.html" target="_top"><code>GridLayout.LayoutParams</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="GridLayout.Spec"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/GridLayout.Spec.html" target="_top"><code>GridLayout.Spec</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LinearLayoutCompat"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.html" target="_top"><code>LinearLayoutCompat</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LinearLayoutCompat.LayoutParams"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearLayoutCompat.LayoutParams.html" target="_top"><code>LinearLayoutCompat.LayoutParams</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LinearSnapHelper"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/LinearSnapHelper.html" target="_top"><code>LinearSnapHelper</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ListPopupWindow"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ListPopupWindow.html" target="_top"><code>ListPopupWindow</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PopupMenu"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.html" target="_top"><code>PopupMenu</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PopupMenu.OnDismissListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnDismissListener.html" target="_top"><code><I>PopupMenu.OnDismissListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="PopupMenu.OnMenuItemClickListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/PopupMenu.OnMenuItemClickListener.html" target="_top"><code><I>PopupMenu.OnMenuItemClickListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="RecyclerView.OnFlingListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.OnFlingListener.html" target="_top"><code>RecyclerView.OnFlingListener</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="RecyclerView.SmoothScroller.ScrollVectorProvider"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/RecyclerView.SmoothScroller.ScrollVectorProvider.html" target="_top"><code><I>RecyclerView.SmoothScroller.<br>ScrollVectorProvider</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchView"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.html" target="_top"><code>SearchView</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchView.OnCloseListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnCloseListener.html" target="_top"><code><I>SearchView.OnCloseListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchView.OnQueryTextListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnQueryTextListener.html" target="_top"><code><I>SearchView.OnQueryTextListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SearchView.OnSuggestionListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SearchView.OnSuggestionListener.html" target="_top"><code><I>SearchView.OnSuggestionListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ShareActionProvider"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.html" target="_top"><code>ShareActionProvider</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ShareActionProvider.OnShareTargetSelectedListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ShareActionProvider.OnShareTargetSelectedListener.html" target="_top"><code><I>ShareActionProvider.OnShareTargetSelectedListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SnapHelper"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SnapHelper.html" target="_top"><code>SnapHelper</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Space"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Space.html" target="_top"><code>Space</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="SwitchCompat"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/SwitchCompat.html" target="_top"><code>SwitchCompat</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ThemedSpinnerAdapter"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.html" target="_top"><code><I>ThemedSpinnerAdapter</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="ThemedSpinnerAdapter.Helper"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/ThemedSpinnerAdapter.Helper.html" target="_top"><code>ThemedSpinnerAdapter.Helper</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Toolbar"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.html" target="_top"><code>Toolbar</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Toolbar.LayoutParams"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.LayoutParams.html" target="_top"><code>Toolbar.LayoutParams</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Toolbar.OnMenuItemClickListener"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.OnMenuItemClickListener.html" target="_top"><code><I>Toolbar.OnMenuItemClickListener</I></code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="Toolbar.SavedState"></A>
+  <nobr><A HREF="../../../../reference/android/support/v7/widget/Toolbar.SavedState.html" target="_top"><code>Toolbar.SavedState</code></A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<p>
+<a NAME="Changed"></a>
+<TABLE summary="Changed Classes" WIDTH="100%">
+<TR>
+  <TH VALIGN="TOP" COLSPAN=2>Changed Classes</FONT></TD>
+</TH>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LinearLayoutManager"></A>
+  <nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html">LinearLayoutManager</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="LinearSmoothScroller"></A>
+  <nobr><A HREF="android.support.v7.widget.LinearSmoothScroller.html">LinearSmoothScroller</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="RecyclerView"></A>
+  <nobr><A HREF="android.support.v7.widget.RecyclerView.html">RecyclerView</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="#FFFFFF" CLASS="TableRowColor">
+  <TD VALIGN="TOP" WIDTH="25%">
+  <A NAME="StaggeredGridLayoutManager"></A>
+  <nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html">StaggeredGridLayoutManager</A></nobr>
+  </TD>
+  <TD>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+      </div>	
+      <div id="footer">
+        <div id="copyright">
+        Except as noted, this content is licensed under 
+        <a href="http://creativecommons.org/licenses/by/2.5/"> Creative Commons Attribution 2.5</a>.
+        For details and restrictions, see the <a href="/license.html">Content License</a>.
+        </div>
+      <div id="footerlinks">
+      <p>
+        <a href="http://www.android.com/terms.html">Site Terms of Service</a> -
+        <a href="http://www.android.com/privacy.html">Privacy Policy</a> -
+        <a href="http://www.android.com/branding.html">Brand Guidelines</a>
+      </p>
+    </div>
+    </div> <!-- end footer -->
+    </div><!-- end doc-content -->
+    </div> <!-- end body-content --> 
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+</script>
+<script type="text/javascript">
+  try {
+    var pageTracker = _gat._getTracker("UA-5831155-1");
+    pageTracker._setAllowAnchor(true);
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  } catch(e) {}
+</script>
+</BODY>
+</HTML>
diff --git a/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
new file mode 100644
index 0000000..9514985
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/missingSinces.txt
@@ -0,0 +1,183 @@
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener Interface
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener Interface
+NO DOC BLOCK: android.support.v7.app.ActionBarActivity Class
+NO DOC BLOCK: android.support.v7.widget.ActionMenuView Class
+NO DOC BLOCK: android.support.v7.widget.ActionMenuView.LayoutParams Class
+NO DOC BLOCK: android.support.v7.widget.ActionMenuView.OnMenuItemClickListener Interface
+NO DOC BLOCK: android.support.v7.app.AppCompatActivity Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatAutoCompleteTextView Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatButton Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatCheckBox Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatCheckedTextView Class
+NO DOC BLOCK: android.support.v7.app.AppCompatDialogFragment Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatEditText Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatImageButton Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatImageView Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatMultiAutoCompleteTextView Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatRadioButton Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatRatingBar Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatSeekBar Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatSpinner Class
+NO DOC BLOCK: android.support.v7.widget.AppCompatTextView Class
+NO DOC BLOCK: android.support.v7.util.BatchingListUpdateCallback Class
+NO DOC BLOCK: android.support.v7.widget.CardView Class
+NO DOC BLOCK: android.support.v7.util.DiffUtil Class
+NO DOC BLOCK: android.support.v7.util.DiffUtil.Callback Class
+NO DOC BLOCK: android.support.v7.util.DiffUtil.DiffResult Class
+NO DOC BLOCK: android.support.v7.widget.GridLayout Class
+NO DOC BLOCK: android.support.v7.widget.GridLayout.Alignment Class
+NO DOC BLOCK: android.support.v7.widget.GridLayout.LayoutParams Class
+NO DOC BLOCK: android.support.v7.widget.GridLayout.Spec Class
+NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat Class
+NO DOC BLOCK: android.support.v7.widget.LinearLayoutCompat.LayoutParams Class
+NO DOC BLOCK: android.support.v7.widget.LinearSnapHelper Class
+NO DOC BLOCK: android.support.v7.widget.ListPopupWindow Class
+NO DOC BLOCK: android.support.v7.util.ListUpdateCallback Interface
+NO DOC BLOCK: android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat Class
+NO DOC BLOCK: android.support.v7.app.NotificationCompat Class
+NO DOC BLOCK: android.support.v7.app.NotificationCompat.Builder Class
+NO DOC BLOCK: android.support.v7.app.NotificationCompat.MediaStyle Class
+NO DOC BLOCK: android.support.v4.util.PatternsCompat Class
+NO DOC BLOCK: android.support.v7.widget.PopupMenu Class
+NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnDismissListener Interface
+NO DOC BLOCK: android.support.v7.widget.PopupMenu.OnMenuItemClickListener Interface
+NO DOC BLOCK: android.support.v7.widget.RecyclerView.OnFlingListener Class
+NO DOC BLOCK: android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider Interface
+NO DOC BLOCK: android.support.v7.widget.SearchView Class
+NO DOC BLOCK: android.support.v7.widget.SearchView.OnCloseListener Interface
+NO DOC BLOCK: android.support.v7.widget.SearchView.OnQueryTextListener Interface
+NO DOC BLOCK: android.support.v7.widget.SearchView.OnSuggestionListener Interface
+NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnCloseListener Interface
+NO DOC BLOCK: android.support.v4.widget.SearchViewCompat.OnQueryTextListener Interface
+NO DOC BLOCK: android.support.v7.widget.ShareActionProvider Class
+NO DOC BLOCK: android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener Interface
+NO DOC BLOCK: android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener Interface
+NO DOC BLOCK: android.support.v7.widget.SnapHelper Class
+NO DOC BLOCK: android.support.v7.widget.Space Class
+NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback Interface
+NO DOC BLOCK: android.support.v7.widget.SwitchCompat Class
+NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter Interface
+NO DOC BLOCK: android.support.v7.widget.ThemedSpinnerAdapter.Helper Class
+NO DOC BLOCK: android.support.v7.widget.Toolbar Class
+NO DOC BLOCK: android.support.v7.widget.Toolbar.LayoutParams Class
+NO DOC BLOCK: android.support.v7.widget.Toolbar.OnMenuItemClickListener Interface
+NO DOC BLOCK: android.support.v7.widget.Toolbar.SavedState Class
+NO DOC BLOCK: android.support.v4.view.WindowInsetsCompat Constructor (android.support.v4.view.WindowInsetsCompat)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
+NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long)
+NO DOC BLOCK: android.support.v4.media.session.MediaButtonReceiver Method buildMediaButtonPendingIntent(android.content.Context, long)
+NO DOC BLOCK: android.support.v4.graphics.drawable.DrawableCompat Method clearColorFilter(android.graphics.drawable.Drawable)
+NO DOC BLOCK: android.support.design.widget.TabLayout Method clearOnTabSelectedListeners()
+NO DOC BLOCK: android.support.v7.widget.StaggeredGridLayoutManager Method computeScrollVectorForPosition(int)
+NO DOC BLOCK: android.support.v4.app.FragmentController Method findFragmentByWho(java.lang.String)
+NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItem(java.lang.Object)
+NO DOC BLOCK: android.support.v4.media.MediaBrowserCompat.MediaItem Method fromMediaItemList(java.util.List<?>)
+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat Method fromMediaSession(android.content.Context, java.lang.Object)
+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItem(java.lang.Object)
+NO DOC BLOCK: android.support.v4.media.session.MediaSessionCompat.QueueItem Method fromQueueItemList(java.util.List<?>)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getAction(android.view.accessibility.AccessibilityEvent)
+NO DOC BLOCK: android.support.v4.widget.TextViewCompat Method getCompoundDrawablesRelative(android.widget.TextView)
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout Method getDependents(android.view.View)
+NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantColor(int)
+NO DOC BLOCK: android.support.v7.graphics.Palette Method getDominantSwatch()
+NO DOC BLOCK: android.support.v7.content.res.AppCompatResources Method getDrawable(android.content.Context, int)
+NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method getDrawerArrowDrawable()
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)
+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method getLaunchBounds()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemNumberViewFlipper()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPausedView()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method getMediaItemPlayingView()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method getMediaPlayState(java.lang.Object)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method getMovementGranularity(android.view.accessibility.AccessibilityEvent)
+NO DOC BLOCK: android.support.v7.widget.RecyclerView Method getOnFlingListener()
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleContentDescription()
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method getPasswordVisibilityToggleDrawable()
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method getSelectionMode()
+NO DOC BLOCK: android.support.v4.os.BuildCompat Method isAtLeastNMR1()
+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method isAutoHideEnabled()
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method isContextClickable()
+NO DOC BLOCK: android.support.v17.leanback.widget.ObjectAdapter Method isImmediateNotifySupported()
+NO DOC BLOCK: android.support.v4.view.ViewCompat Method isImportantForAccessibility(android.view.View)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method isPasswordVisibilityToggleEnabled()
+NO DOC BLOCK: android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat Method loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeBasic()
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeClipRevealAnimation(android.view.View, int, int, int, int)
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method makeTaskLaunchBehind()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method notifyPlayStateChanged()
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat Method obtain(int, int, boolean)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat Method obtain(int, int, int, int, boolean)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat Method obtain(int, float, float, float)
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams)
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onBindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
+NO DOC BLOCK: android.support.v7.util.SortedList.Callback Method onChanged(int, int, java.lang.Object)
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onDetachedFromLayoutParams()
+NO DOC BLOCK: android.support.design.widget.AppBarLayout.ScrollingViewBehavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.Behavior Method onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)
+NO DOC BLOCK: android.support.v4.app.SharedElementCallback Method onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)
+NO DOC BLOCK: android.support.v7.app.AppCompatDelegate Method onStart()
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Method onUnbindMediaPlayState(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityManagerCompat Method removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method requestUsageTimeReport(android.app.PendingIntent)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setAction(android.view.accessibility.AccessibilityEvent, int)
+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method setAlwaysUseBrowserUI(android.content.Intent)
+NO DOC BLOCK: android.support.design.widget.FloatingActionButton.Behavior Method setAutoHideEnabled(boolean)
+NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setCollapsedTitleTextColor(android.content.res.ColorStateList)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Method setContextClickable(boolean)
+NO DOC BLOCK: android.support.v7.app.ActionBarDrawerToggle Method setDrawerArrowDrawable(android.support.v7.graphics.drawable.DrawerArrowDrawable)
+NO DOC BLOCK: android.support.design.widget.CollapsingToolbarLayout Method setExpandedTitleTextColor(android.content.res.ColorStateList)
+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent.Builder Method setInstantAppsEnabled(boolean)
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Method setLaunchBounds(android.graphics.Rect)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Method setMovementGranularity(android.view.accessibility.AccessibilityEvent, int)
+NO DOC BLOCK: android.support.v4.widget.SwipeRefreshLayout Method setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)
+NO DOC BLOCK: android.support.v7.widget.RecyclerView Method setOnFlingListener(android.support.v7.widget.RecyclerView.OnFlingListener)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(int)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleContentDescription(java.lang.CharSequence)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleDrawable(int)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleEnabled(boolean)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintList(android.content.res.ColorStateList)
+NO DOC BLOCK: android.support.design.widget.TextInputLayout Method setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode)
+NO DOC BLOCK: android.support.customtabs.CustomTabsSession Method setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent)
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder Method setSelectedMediaItemNumberView(int)
+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Method shouldAlwaysUseBrowserUI(android.content.Intent)
+NO DOC BLOCK: android.support.v4.app.ServiceCompat Method stopForeground(android.app.Service, int)
+NO DOC BLOCK: android.support.v4.media.session.PlaybackStateCompat Method toKeyCode(long)
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_COLUMN_INT
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_PROGRESS_VALUE
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat Field ACTION_ARGUMENT_ROW_INT
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_CONTEXT_CLICK
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_DOWN
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_LEFT
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_RIGHT
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_TO_POSITION
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SCROLL_UP
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SET_PROGRESS
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat Field ACTION_SHOW_ON_SCREEN
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ALBUMS
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_ARTISTS
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_GENRES
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_MIXED
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_PLAYLISTS
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_TITLES
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field BT_FOLDER_TYPE_YEARS
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field dodgeInsetEdges
+NO DOC BLOCK: android.support.v4.media.MediaDescriptionCompat Field EXTRA_BT_FOLDER_TYPE
+NO DOC BLOCK: android.support.customtabs.CustomTabsIntent Field EXTRA_ENABLE_INSTANT_APPS
+NO DOC BLOCK: android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot Field EXTRA_SUGGESTION_KEYWORDS
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT
+NO DOC BLOCK: android.support.v4.app.ActivityOptionsCompat Field EXTRA_USAGE_TIME_REPORT_PACKAGES
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityNodeProviderCompat Field HOST_VIEW_ID
+NO DOC BLOCK: android.support.design.widget.CoordinatorLayout.LayoutParams Field insetEdge
+NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_BT_FOLDER_TYPE
+NO DOC BLOCK: android.support.v4.media.MediaMetadataCompat Field METADATA_KEY_MEDIA_URI
+NO DOC BLOCK: android.support.design.widget.BottomSheetBehavior Field PEEK_HEIGHT_AUTO
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_INITIAL
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PAUSED
+NO DOC BLOCK: android.support.v17.leanback.widget.AbstractMediaItemPresenter Field PLAY_STATE_PLAYING
+NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_DETACH
+NO DOC BLOCK: android.support.v4.app.ServiceCompat Field STOP_FOREGROUND_REMOVE
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_ASSIST_READING_CONTEXT
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityWindowInfoCompat Field TYPE_SPLIT_SCREEN_DIVIDER
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_VIEW_CONTEXT_CLICKED
+NO DOC BLOCK: android.support.v4.view.accessibility.AccessibilityEventCompat Field TYPE_WINDOWS_CHANGED
diff --git a/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
new file mode 100644
index 0000000..edafaa3
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/stylesheet-jdiff.css
@@ -0,0 +1,44 @@
+
+/* (http://www.jdiff.org) */
+
+div.and-diff-id {border: 1px solid #eee;position:relative;float:right;clear:both;padding:0px;}
+table.diffspectable {border:1px;padding:0px;margin:0px;}
+.diffspechead {background-color:#eee;}
+.diffspectable tr {border:0px;padding:0px;}
+.diffspectable td  {background-color:eee;border:0px;font-size:90%;font-weight:normal;padding:0px;padding-left:1px;padding-right:1px;text-align:center;color:777;}
+td.diffvalueold {color:orange;background-color:white;border:0px;font-size:80%;font-style:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
+td.diffvaluenew {color:green;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
+td.diffvalue {color:444;background-color:white;border:0px;font-size:80%;font-weight:normal;text-align:left;padding:0px;padding-left:1px;padding-right:1px;line-height:.95em;}
+td.diffspec {background-color:white;border:0px;font-size:80%;font-weight:normal;padding:1px;color:444;text-align:right;padding-right:.5em;line-height:.95em;}
+tt {font-size:11pt;font-family:monospace;}
+.indexHeader {
+  font-size:96%;
+  line-height:.8em;}
+.jdiffIndex td {
+  font-size:96%;
+  xline-height:.8em;
+  padding:2px;
+  padding-left:1em;}
+.indexText {
+  font-size:100%;
+  padding-left:1em;}
+#indexTableCaption {
+  font-size:96%;
+  margin-top:.25em;
+  margin-bottom:0;
+  }
+.hiddenlink {
+  font-size:96%;
+  line-height:.8em;
+  text-decoration:none;}
+a {
+  text-decoration:none;}
+a:hover {
+  text-decoration:underline;}
+.indexBox {
+  border: 1px solid red;
+  margin:1em 0 0 0;}
+.letterIndexHead {
+  font-size: 1.5em;font-weight:9;
+  margin:0 0 0em 0;
+  border: 1px solid red;}
diff --git a/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
new file mode 100644
index 0000000..5a1bfc6
--- /dev/null
+++ b/docs/html/sdk/support_api_diff/24.2.0/user_comments_for_24.1.0_to_24.2.0.xml
@@ -0,0 +1,1897 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
+<comments
+  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+  xsi:noNamespaceSchemaLocation='comments.xsd'
+  name="24.1.0_to_24.2.0"
+  jdversion="1.1.0">
+
+<!-- Use this file to enter an API change description. For example, when you remove a class, 
+     you can enter a comment for that class that points developers to the replacement class. 
+     You can also provide a change summary for modified API, to give an overview of the changes 
+     why they were made, workarounds, etc.  -->
+
+<!-- When the API diffs report is generated, the comments in this file get added to the tables of 
+     removed, added, and modified packages, classes, methods, and fields. This file does not ship 
+     with the final report. -->
+
+<!-- The id attribute in an identifier element identifies the change as noted in the report. 
+     An id has the form package[.class[.[ctor|method|field].signature]], where [] indicates optional 
+     text. A comment element can have multiple identifier elements, which will will cause the same 
+     text to appear at each place in the report, but will be converted to separate comments when the 
+     comments file is used. -->
+
+<!-- HTML tags in the text field will appear in the report. You also need to close p HTML elements, 
+     used for paragraphs - see the top-level documentation. -->
+
+<!-- You can include standard javadoc links in your change descriptions. You can use the @first command  
+     to cause jdiff to include the first line of the API documentation. You also need to close p HTML 
+     elements, used for paragraphs - see the top-level documentation. -->
+
+<comment>
+  <identifier id="android.support.customtabs"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent.Builder"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent.Builder.setInstantAppsEnabled_added(boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent.EXTRA_ENABLE_INSTANT_APPS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent.setAlwaysUseBrowserUI_added(android.content.Intent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsIntent.shouldAlwaysUseBrowserUI_added(android.content.Intent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsSession"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsSession.setSecondaryToolbarViews_added(android.widget.RemoteViews, int[], android.app.PendingIntent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.customtabs.CustomTabsSession.setToolbarItem_changed(int, android.graphics.Bitmap, java.lang.String)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.AppBarLayout.ScrollingViewBehavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.BottomSheetBehavior"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.BottomSheetBehavior.PEEK_HEIGHT_AUTO"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CollapsingToolbarLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setCollapsedTitleTextColor_added(android.content.res.ColorStateList)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CollapsingToolbarLayout.setExpandedTitleTextColor_added(android.content.res.ColorStateList)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.isDirty_changed(android.support.design.widget.CoordinatorLayout, V)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onAttachedToLayoutParams_added(android.support.design.widget.CoordinatorLayout.LayoutParams)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onDetachedFromLayoutParams_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.Behavior.onRequestChildRectangleOnScreen_added(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.dodgeInsetEdges"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.LayoutParams.insetEdge"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.CoordinatorLayout.getDependents_added(android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.getInsetDodgeRect_added(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.isAutoHideEnabled_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.layoutDependsOn_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.onDependentViewRemoved_removed(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.FloatingActionButton.Behavior.setAutoHideEnabled_added(boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TabLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TabLayout.clearOnTabSelectedListeners_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleContentDescription_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.getPasswordVisibilityToggleDrawable_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.isPasswordVisibilityToggleEnabled_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleContentDescription_added(java.lang.CharSequence)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(android.graphics.drawable.Drawable)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleDrawable_added(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleEnabled_added(boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintList_added(android.content.res.ColorStateList)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.design.widget.TextInputLayout.setPasswordVisibilityToggleTintMode_added(android.graphics.PorterDuff.Mode)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.transition"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v14.preference"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v14.preference.PreferenceFragment"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_INITIAL"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PAUSED"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.PLAY_STATE_PLAYING"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemNumberViewFlipper_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPausedView_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.getMediaItemPlayingView_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.notifyPlayStateChanged_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.setSelectedMediaItemNumberView_added(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.getMediaPlayState_added(java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onBindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.AbstractMediaItemPresenter.onUnbindMediaPlayState_added(android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.ObjectAdapter"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.leanback.widget.ObjectAdapter.isImmediateNotifySupported_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.preference"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v17.preference.LeanbackSettingsFragment"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.accessibilityservice"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.getDescription_changed(android.accessibilityservice.AccessibilityServiceInfo)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.loadDescription_added(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityCompat.ctor_changed()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityCompat.getReferrer_changed(android.app.Activity)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.EXTRA_USAGE_TIME_REPORT_PACKAGES"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.getLaunchBounds_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeBasic_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeClipRevealAnimation_added(android.view.View, int, int, int, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.makeTaskLaunchBehind_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.requestUsageTimeReport_added(android.app.PendingIntent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ActivityOptionsCompat.setLaunchBounds_added(android.graphics.Rect)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.FragmentController"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.FragmentController.findFragmentByWho_added(java.lang.String)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ServiceCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_DETACH"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ServiceCompat.STOP_FOREGROUND_REMOVE"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.ServiceCompat.stopForeground_added(android.app.Service, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.SharedElementCallback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.app.SharedElementCallback.onSharedElementsArrived_added(java.util.List&lt;java.lang.String&gt;, java.util.List&lt;android.view.View&gt;, android.support.v4.app.SharedElementCallback.OnSharedElementsReadyListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.content"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.content.ContextCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.content.ContextCompat.ctor_changed()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.graphics.drawable"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.graphics.drawable.DrawableCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.graphics.drawable.DrawableCompat.clearColorFilter_added(android.graphics.drawable.Drawable)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItemList_added(java.util.List&lt;?&gt;)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaBrowserCompat.MediaItem.fromMediaItem_added(java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.EXTRA_SUGGESTION_KEYWORDS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ALBUMS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_ARTISTS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_GENRES"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_MIXED"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_PLAYLISTS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_TITLES"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaMetadataCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.MediaMetadataCompat.METADATA_KEY_MEDIA_URI"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaButtonReceiver"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, android.content.ComponentName, long)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaButtonReceiver.buildMediaButtonPendingIntent_added(android.content.Context, long)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItemList_added(java.util.List&lt;?&gt;)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.fromQueueItem_added(java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.QueueItem.obtain_changed(java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.fromMediaSession_added(android.content.Context, java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.MediaSessionCompat.obtain_changed(android.content.Context, java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.PlaybackStateCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.os"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.os.BuildCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.os.BuildCompat.isAtLeastNMR1_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.text.util"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.util"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.util.PatternsCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.KeyEventCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.KeyEventCompat.dispatch_changed(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.KeyEventCompat.getKeyDispatcherState_changed(android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.KeyEventCompat.isTracking_changed(android.view.KeyEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.findPointerIndex_changed(android.view.MotionEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.getPointerCount_changed(android.view.MotionEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.getPointerId_changed(android.view.MotionEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.getSource_changed(android.view.MotionEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.getX_changed(android.view.MotionEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.MotionEventCompat.getY_changed(android.view.MotionEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_ALWAYS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.getOverScrollMode_changed(android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.isImportantForAccessibility_added(android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.isOpaque_changed(android.view.View)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewCompat.setOverScrollMode_changed(android.view.View, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewConfigurationCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.ViewConfigurationCompat.getScaledPagingTouchSlop_changed(android.view.ViewConfiguration)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.WindowInsetsCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_ASSIST_READING_CONTEXT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_CONTEXT_CLICKED"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getAction_added(android.view.accessibility.AccessibilityEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.getMovementGranularity_added(android.view.accessibility.AccessibilityEvent)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setAction_added(android.view.accessibility.AccessibilityEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityEventCompat.setMovementGranularity_added(android.view.accessibility.AccessibilityEvent, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.onAccessibilityStateChanged_removed(boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.addTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeAccessibilityStateChangeListener_changed(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityManagerCompat.removeTouchExplorationStateChangeListener_added(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.getSelectionMode_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain_added(int, int, boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain_added(int, int, int, int, boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.obtain_added(int, float, float, float)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.isContextClickable_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.setContextClickable_added(boolean)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.HOST_VIEW_ID"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.TYPE_SPLIT_SCREEN_DIVIDER"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.setOnCloseListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SearchViewCompat.setOnQueryTextListener_changed(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SwipeRefreshLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.SwipeRefreshLayout.setOnChildScrollUpCallback_added(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.TextViewCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v4.widget.TextViewCompat.getCompoundDrawablesRelative_added(android.widget.TextView)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.ActionBarActivity"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.ActionBarDrawerToggle"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.ActionBarDrawerToggle.getDrawerArrowDrawable_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.ActionBarDrawerToggle.setDrawerArrowDrawable_added(android.support.v7.graphics.drawable.DrawerArrowDrawable)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.AppCompatActivity"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.AppCompatDelegate"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.AppCompatDelegate.onStart_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.AppCompatDialogFragment"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.NotificationCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.NotificationCompat.Builder"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.app.NotificationCompat.MediaStyle"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.appcompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.content.res"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.content.res.AppCompatResources"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.content.res.AppCompatResources.getDrawable_added(android.content.Context, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.graphics"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.graphics.Palette"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.graphics.Palette.getDominantColor_added(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.graphics.Palette.getDominantSwatch_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.preference"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.preference.MultiSelectListPreferenceDialogFragmentCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.recyclerview"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.BatchingListUpdateCallback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.DiffUtil"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.DiffUtil.Callback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.DiffUtil.DiffResult"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.ListUpdateCallback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.SortedList.Callback"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.SortedList.Callback.onChanged_added(int, int, java.lang.Object)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.SortedList.Callback.onInserted_removed(int, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.SortedList.Callback.onMoved_removed(int, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.util.SortedList.Callback.onRemoved_removed(int, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ActionMenuView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ActionMenuView.LayoutParams"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ActionMenuView.OnMenuItemClickListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatAutoCompleteTextView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatButton"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatCheckBox"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatCheckedTextView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatEditText"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatImageButton"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatImageView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatMultiAutoCompleteTextView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatRadioButton"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatRatingBar"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatSeekBar"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatSpinner"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.AppCompatTextView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.CardView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.GridLayout"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.GridLayout.Alignment"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.GridLayout.LayoutParams"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.GridLayout.Spec"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearLayoutCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearLayoutCompat.LayoutParams"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearLayoutManager"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearSmoothScroller"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearSmoothScroller.computeScrollVectorForPosition_changed(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.LinearSnapHelper"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ListPopupWindow"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.PopupMenu"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.PopupMenu.OnDismissListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.PopupMenu.OnMenuItemClickListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.RecyclerView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.RecyclerView.OnFlingListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.RecyclerView.getOnFlingListener_added()"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.RecyclerView.setOnFlingListener_added(android.support.v7.widget.RecyclerView.OnFlingListener)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SearchView"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SearchView.OnCloseListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SearchView.OnQueryTextListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SearchView.OnSuggestionListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ShareActionProvider"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SnapHelper"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.Space"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.TAG"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.StaggeredGridLayoutManager.computeScrollVectorForPosition_added(int)"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.SwitchCompat"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.ThemedSpinnerAdapter.Helper"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.Toolbar"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.Toolbar.LayoutParams"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.Toolbar.OnMenuItemClickListener"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v7.widget.Toolbar.SavedState"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+<comment>
+  <identifier id="android.support.v8.renderscript"/>
+  <text>
+    InsertCommentsHere
+  </text>
+</comment>
+
+</comments>
diff --git a/docs/html/topic/arc/index.jd b/docs/html/topic/arc/index.jd
index d46fbc8..a025459 100644
--- a/docs/html/topic/arc/index.jd
+++ b/docs/html/topic/arc/index.jd
@@ -51,7 +51,7 @@
     &lt;!-- Some Chromebooks don't support touch. Although not essential,
          it's a good idea to explicitly include this declaration. --&gt;
     &lt;uses-feature android:name="android.hardware.touchscreen"
-                  required="false" /&gt;
+                  android:required="false" /&gt;
 &lt;/manifest&gt;
 </pre>
 
diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd
index ddcc9f2..0faa1db 100644
--- a/docs/html/topic/libraries/data-binding/index.jd
+++ b/docs/html/topic/libraries/data-binding/index.jd
@@ -162,7 +162,9 @@
 
 <p>
   To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong>
-  or higher is required.
+  or higher is required. See how to <a
+href="/studio/releases/gradle-plugin.html#updating-plugin">update the Android
+Plugin for Gradle</a>.
 </p>
 
 <h2 id="build_environment">
diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd
index 0f63bf6..b5f189a 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.1
 </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.1
+</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.1
+</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.1
+</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.1
+</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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </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.1
 </pre>
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 3b25fb0..9a24d15 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -6,9 +6,403 @@
 <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-1">
     <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.1</a>
+    <em>(September 2016)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Fixed issues:</p>
+
+<ul>
+  <li>{@link android.support.design.widget.FloatingActionButton} can no longer
+  be anchored to indirect children of {@link
+  android.support.design.widget.CoordinatorLayout}. (AOSP issue <a href=
+  "https://code.google.com/p/android/issues/detail?id=220250">220250</a>)
+  </li>
+
+  <li>Image inside {@link
+  android.support.design.widget.CollapsingToolbarLayout} doesn’t scale properly
+  with <code>fitsSystemWindows=true</code>. (AOSP issue <a href=
+  "https://code.google.com/p/android/issues/detail?id=220389">220389</a>)
+  </li>
+
+  <li>{@link android.support.design.widget.CoordinatorLayout} throws {@link
+  java.lang.IndexOutOfBoundsException} when {@link
+  android.support.design.widget.Snackbar} is shown and dismissed. (AOSP issue
+  <a href="https://code.google.com/p/android/issues/detail?id=220762"
+  >220762</a>)
+  </li>
+
+  <li>{@link android.support.design.widget.TextInputLayout} fails to resolve
+  error text color. (AOSP issue <a href=
+  "https://code.google.com/p/android/issues/detail?id=220305">220305</a>)
+  </li>
+
+  <li>{@link android.support.v7.util.SortedList.BatchedCallback#onMoved
+  BatchedCallback.onMoved()} calls {@link
+  android.support.v7.util.SortedList.BatchedCallback#onInserted
+  BatchedCallback.onInserted()}. (AOSP issue <a href=
+  "https://code.google.com/p/android/issues/detail?id=220309">220309</a>)
+  </li>
+
+  <li>{@link android.support.design.widget.TextInputLayout} overrides right
+  compound drawable. (AOSP issue <a href=
+  "https://code.google.com/p/android/issues/detail?id=220728">220728</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=label%3ATarget-Support-24.2.1">
+  AOSP Issue Tracker</a>.
+</p>
+
+
+  </div>
+</div>
+
+<!-- end of collapsible section: 24.2.1 -->
+
+<div class="toggle-content closed">
+  <p id="rev24-2-0">
+    <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.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>
+
+  <li>The Custom Tabs library now allows clients to request the standard
+  browser UI, rather than custom tabs UI, by calling <a href=
+  "/reference/android/support/customtabs/CustomTabsIntent.html#setAlwaysUseBrowserUI(android.content.Intent)">
+    <code>CustomTabsIntent.setAlwaysUseBrowserUI()</code></a>. This behavior is
+    useful in cases where the browser defaults to custom tabs UI but the user
+    has expressed a preference for the standard browser UI.
+  </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>
+
+<h4>MediaRouter library</h4>
+
+<p>
+  Bluetooth devices are no longer listed as media routes. Routing audio to
+  Bluetooth devices is now solely controlled at the Android system level.
+</p>
+
+
+<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 +470,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=
@@ -2580,8 +2974,6 @@
         <ul>
           <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the
             {@link android.widget.GridLayout} layout object.</li>
-          <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas
-            within a {@link android.support.v7.widget.GridLayout} layout object.</li>
         </ul>
     </dl>
   </div>
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/topic/libraries/testing-support-library/index.jd b/docs/html/topic/libraries/testing-support-library/index.jd
index 941f5c3..3d3c091 100644
--- a/docs/html/topic/libraries/testing-support-library/index.jd
+++ b/docs/html/topic/libraries/testing-support-library/index.jd
@@ -202,7 +202,7 @@
     <li><a href="{@docRoot}reference/android/support/test/filters/SdkSuppress.html">{@code @SdkSupress}</a>:
     Suppresses the test from running on a lower Android API level than the given level. For
     example, to suppress tests on all API levels lower than 18 from running, use the annotation
-    {@code @SDKSupress(minSdkVersion=18)}.
+    {@code @SdkSuppress(minSdkVersion=18)}.
     </li>
 
     <li>{@link android.test.suitebuilder.annotation.SmallTest &#64;SmallTest},
diff --git a/docs/html/topic/performance/_book.yaml b/docs/html/topic/performance/_book.yaml
index e053a2c..4021e85 100644
--- a/docs/html/topic/performance/_book.yaml
+++ b/docs/html/topic/performance/_book.yaml
@@ -1,34 +1,61 @@
 toc:
-- title: Reducing Network Battery Drain
-  path: /topic/performance/power/network/index.html
+- title: Optimizing for Battery Life
+  path: /topic/performance/power/index.html
   path_attributes:
   - name: description
-    value: Access the network while going easy on battery life.
+    value: Learn to make your app more battery-friendly.
   section:
-  - title: Collecting Network Traffic Data
-    path: /topic/performance/power/network/gather-data.html
-  - title: Analyzing Network Traffic Data
-    path: /topic/performance/power/network/analyze-data.html
-  - title: Optimizing User-Initiated Network Use
-    path: /topic/performance/power/network/action-user-traffic.html
-  - title: Optimizing Server-Initiated Network Use
-    path: /topic/performance/power/network/action-server-traffic.html
-  - title: Optimizing General Network Use
-    path: /topic/performance/power/network/action-any-traffic.html
-- title: Implementing Doze
-  path: /training/monitoring-device-state/doze-standby.html
+  - title: Network Use and Battery Consumption
+    path: /topic/performance/power/network/index.html
+    section:
+    - title: Collecting Network Traffic Data
+      path: /topic/performance/power/network/gather-data.html
+    - title: Analyzing Data Traffic
+      path: /topic/performance/power/network/analyze-data.html
+    - title: Optimizing User-Initiated Network Use
+      path: /topic/performance/power/network/action-user-traffic.html
+    - title: Optimizing App-Initiated Network Use
+      path: topic/performance/power/network/action-app-traffic.html
+    - title: Optimizing Server-Initiated Network Use
+      path: /topic/performance/power/network/action-server-traffic.html
+    - title: Optimizing General Network Use
+      path: /topic/performance/power/network/action-any-traffic.html
+  - title: Doze and App Standby
+    path: /training/monitoring-device-state/doze-standby.html
+    path_attributes:
+    - name: description
+      value: Help ensure the device isn't depleting the battery when not in use.
+  - title: Battery Historian
+    path: /topic/performance/power/battery-historian.html
+- title: Rendering
+  path: /topic/performance/rendering/index.html
   path_attributes:
   - name: description
-    value: Help ensure the device isn't depleting the battery when not in use.
+    value: Speed up your app's rendering
+  section:
+  - title: Reducing Overdraw
+    path: /topic/performance/rendering/overdraw.html
+  - title: Performance and View Hierarchies
+    path: /topic/performance/rendering/optimizing-view-hierarchies.html
+  - title: Analyzing with Profile GPU Rendering
+    path: /topic/performance/rendering/profile-gpu.html
+- title: Intelligent Job-Scheduling
+  path: /topic/performance/scheduling.html
+- title: Background Optimization
+  path: /topic/performance/background-optimization.html
+- title: Reducing APK Size
+  path: /topic/performance/reduce-apk-size.html
+- title: Reducing Image Download Sizes
+  path: /topic/performance/network-xfer.html
 - title: Launch-Time Performance
   path: /topic/performance/launch-time.html
 - title: Better Performance through Threading
   path: /topic/performance/threads.html
-- title: Optimizing View Hierarchies
-  path: /topic/performance/optimizing-view-hierarchies.html
-- title: Background Optimization
-  path: /topic/performance/background-optimization.html
-- title: Intelligent Job-Scheduling
-  path: /topic/performance/scheduling.html
-- title: Reducing APK Size
-  path: /topic/performance/reduce-apk-size.html
+- title: Manage Your App's Memory
+  path: /topic/performance/memory.html
+- title: Overview of Memory Managemement
+  path: /topic/performance/memory-overview.html
+  path_attributes:
+  - name: description
+    value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
+
diff --git a/docs/html/topic/performance/background-optimization.jd b/docs/html/topic/performance/background-optimization.jd
index 3e4c041..0a1a6f5 100644
--- a/docs/html/topic/performance/background-optimization.jd
+++ b/docs/html/topic/performance/background-optimization.jd
@@ -14,29 +14,31 @@
     <ol>
       <li>
         <a href="#connectivity-action">Restrictions on CONNECTIVITY_ACTION</a>
-      </li>
+        <ul>
+          <li>
+            <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
+            Connections</a>
+          </li>
 
-      <li>
-        <a href="#sched-jobs">Scheduling Network Jobs on Unmetered
-        Connections</a>
-      </li>
-
-      <li>
-        <a href="#monitor-conn">Monitoring Network Connectivity While the App
-        is Running</a>
+          <li>
+            <a href="#monitor-conn">Monitoring Network Connectivity While the
+            App is Running</a>
+          </li>
+        </ul>
       </li>
 
       <li>
         <a href="#media-broadcasts">Restrictions on NEW_PICTURE and
         NEW_VIDEO</a>
-      </li>
+        <ul>
+          <li>
+            <a href="#new-jobinfo">New JobInfo methods</a>
+          </li>
 
-      <li>
-        <a href="#new-jobinfo">New JobInfo methods</a>
-      </li>
-
-      <li>
-        <a href="#new-jobparam">New JobParameter Methods</a>
+          <li>
+            <a href="#new-jobparam">New JobParameter Methods</a>
+          </li>
+        </ul>
       </li>
 
       <li>
@@ -54,12 +56,12 @@
 </p>
 
 <p>
-  To alleviate this issue, Android N applies the following
+  To alleviate this issue, Android 7.0 (API level 24) applies the following
   restrictions:
 </p>
 
 <ul>
-  <li>Apps targeting the Preview do not receive {@link
+  <li>Apps targeting Android 7.0 (API level 24) do not receive {@link
   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
   register to receive them in their manifest. Apps that are running can still
   listen for {@code CONNECTIVITY_CHANGE} on their main thread by registering a
@@ -70,16 +72,16 @@
   <li>Apps cannot send or receive {@link
   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This optimization
-  affects all apps, not only those targeting the Preview.
+  affects all apps, not only those targeting Android 7.0 (API level 24).
   </li>
 </ul>
 
 <p>
-  If your app uses any of these intents, you should remove dependencies on
-  them as soon as possible so that you can target Android N devices properly.
-  The Android framework provides several solutions to mitigate the need for
-  these implicit broadcasts. For example, {@link android.app.job.JobScheduler}
-  and <a href=
+  If your app uses any of these intents, you should remove dependencies on them
+  as soon as possible so that you can target devices running Android 7.0
+  properly. The Android framework provides several solutions to mitigate the
+  need for these implicit broadcasts. For example, {@link
+  android.app.job.JobScheduler} and <a href=
   "https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
   {@code GcmNetworkManager}</a> provide robust mechanisms to schedule network
   operations when specified conditions, such as a connection to an unmetered
@@ -101,7 +103,7 @@
 </h2>
 
 <p>
-  Apps targeting the Android N do not receive {@link
+  Apps targeting Android 7.0 (API level 24) do not receive {@link
   android.net.ConnectivityManager#CONNECTIVITY_ACTION} broadcasts if they
   register to receive them in their manifest, and processes that depend on this
   broadcast will not start. This could pose a problem for apps that want
@@ -198,11 +200,11 @@
 </h2>
 
 <p>
-  In the Android N, apps are not able to send or receive {@link
+  In Android 7.0 (API level 24), apps are not able to send or receive {@link
   android.hardware.Camera#ACTION_NEW_PICTURE} or {@link
   android.hardware.Camera#ACTION_NEW_VIDEO} broadcasts. This restriction helps
   alleviate the performance and user experience impacts when several apps must
-  wake up in order to process a new image or video. Android N
+  wake up in order to process a new image or video. Android 7.0 (API level 24)
   extends {@link android.app.job.JobInfo} and {@link
   android.app.job.JobParameters} to provide an alternative solution.
 </p>
@@ -212,7 +214,7 @@
 </h3>
 
 <p>
-  To trigger jobs on content URI changes, Android N extends
+  To trigger jobs on content URI changes, Android 7.0 (API level 24) extends
   the {@link android.app.job.JobInfo} API with the following methods:
 </p>
 
@@ -287,7 +289,7 @@
 </h3>
 
 <p>
-  Android N also extends {@link android.app.job.JobParameters} to
+  Android 7.0 (API level 24) also extends {@link android.app.job.JobParameters} to
   allow your app to receive useful information about what content authorities
   and URIs triggered the job:
 </p>
@@ -361,13 +363,13 @@
   conditions, can improve performance and user experience. Removing
   dependencies on background services and statically-registered implicit
   broadcast receivers can help your app run better on such devices. Although
-  Android N takes steps to reduce some of these issues, it is
+  Android 7.0 (API level 24) takes steps to reduce some of these issues, it is
   recommended that you optimize your app to run without the use of these
   background processes entirely.
 </p>
 
 <p>
-  Android N introduces some additional <a href=
+  Android 7.0 (API level 24) introduces some additional <a href=
   "{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> commands that
   you can use to test app behavior with those background processes disabled:
 </p>
@@ -379,7 +381,7 @@
 
   <li style="list-style: none; display: inline">
 <pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND ignore}
+{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore}
 </pre>
   </li>
 
@@ -389,7 +391,7 @@
 
   <li style="list-style: none; display: inline">
 <pre class="no-pretty-print">
-{@code $ adb shell cmd appops set &lt;package_name&gt; RUN_IN_BACKGROUND allow}
+{@code $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow}
 </pre>
   </li>
 </ul>
diff --git a/docs/html/topic/performance/images/app-rankings.png b/docs/html/topic/performance/images/app-rankings.png
new file mode 100644
index 0000000..9dd60e5
--- /dev/null
+++ b/docs/html/topic/performance/images/app-rankings.png
Binary files differ
diff --git a/docs/html/topic/performance/images/bars.png b/docs/html/topic/performance/images/bars.png
new file mode 100644
index 0000000..3afea46
--- /dev/null
+++ b/docs/html/topic/performance/images/bars.png
Binary files differ
diff --git a/docs/html/topic/performance/images/beforeafterindexed.png b/docs/html/topic/performance/images/beforeafterindexed.png
new file mode 100644
index 0000000..dc7762e
--- /dev/null
+++ b/docs/html/topic/performance/images/beforeafterindexed.png
Binary files differ
diff --git a/docs/html/topic/performance/images/comparison.png b/docs/html/topic/performance/images/comparison.png
new file mode 100644
index 0000000..18f204c
--- /dev/null
+++ b/docs/html/topic/performance/images/comparison.png
Binary files differ
diff --git a/docs/html/topic/performance/images/decisions.png b/docs/html/topic/performance/images/decisions.png
new file mode 100644
index 0000000..d4f21f8
--- /dev/null
+++ b/docs/html/topic/performance/images/decisions.png
Binary files differ
diff --git a/docs/html/topic/performance/images/dropdown.png b/docs/html/topic/performance/images/dropdown.png
new file mode 100644
index 0000000..59ec6110
--- /dev/null
+++ b/docs/html/topic/performance/images/dropdown.png
Binary files differ
diff --git a/docs/html/topic/performance/images/generic-timeline.png b/docs/html/topic/performance/images/generic-timeline.png
new file mode 100644
index 0000000..04388b6
--- /dev/null
+++ b/docs/html/topic/performance/images/generic-timeline.png
Binary files differ
diff --git a/docs/html/topic/performance/images/moarparrots.png b/docs/html/topic/performance/images/moarparrots.png
new file mode 100644
index 0000000..ee10ec1
--- /dev/null
+++ b/docs/html/topic/performance/images/moarparrots.png
Binary files differ
diff --git a/docs/html/topic/performance/images/palette.png b/docs/html/topic/performance/images/palette.png
new file mode 100644
index 0000000..eb6be6b
--- /dev/null
+++ b/docs/html/topic/performance/images/palette.png
Binary files differ
diff --git a/docs/html/topic/performance/images/parrot.png b/docs/html/topic/performance/images/parrot.png
new file mode 100644
index 0000000..7a8b86a
--- /dev/null
+++ b/docs/html/topic/performance/images/parrot.png
Binary files differ
diff --git a/docs/html/topic/performance/images/pug-visualization.png b/docs/html/topic/performance/images/pug-visualization.png
new file mode 100644
index 0000000..8270d0e
--- /dev/null
+++ b/docs/html/topic/performance/images/pug-visualization.png
Binary files differ
diff --git a/docs/html/topic/performance/images/pugspecificdata.png b/docs/html/topic/performance/images/pugspecificdata.png
new file mode 100644
index 0000000..1c2be83
--- /dev/null
+++ b/docs/html/topic/performance/images/pugspecificdata.png
Binary files differ
diff --git a/docs/html/topic/performance/images/s-generic-closeup.png b/docs/html/topic/performance/images/s-generic-closeup.png
new file mode 100644
index 0000000..6685d51
--- /dev/null
+++ b/docs/html/topic/performance/images/s-generic-closeup.png
Binary files differ
diff --git a/docs/html/topic/performance/images/s-profiler-legend.png b/docs/html/topic/performance/images/s-profiler-legend.png
new file mode 100644
index 0000000..968fd38
--- /dev/null
+++ b/docs/html/topic/performance/images/s-profiler-legend.png
Binary files differ
diff --git a/docs/html/topic/performance/images/vq.gif b/docs/html/topic/performance/images/vq.gif
new file mode 100644
index 0000000..cbf6a35
--- /dev/null
+++ b/docs/html/topic/performance/images/vq.gif
Binary files differ
diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd
index e08db15..2b6b197 100644
--- a/docs/html/topic/performance/index.jd
+++ b/docs/html/topic/performance/index.jd
@@ -1,4 +1,4 @@
-page.title=Performance
+page.title=Performance and Power
 page.article=true
 page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance.
 
diff --git a/docs/html/topic/performance/memory-overview.jd b/docs/html/topic/performance/memory-overview.jd
new file mode 100644
index 0000000..58067d2
--- /dev/null
+++ b/docs/html/topic/performance/memory-overview.jd
@@ -0,0 +1,288 @@
+page.title=Overview of Android Memory Management
+page.tags=ram,memory,paging,mmap
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol class="nolist">
+  <li><a href="#gc">Garbage collection</a></li>
+  <li><a href="#SharingRAM">Sharing Memory</a></li>
+  <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
+  <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
+  <li><a href="#SwitchingApps">Switching Apps</a></li>
+</ol>
+<h2>See Also</h2>
+<ul>
+  <li><a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>
+  </li>
+  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+  </li>
+</ul>
+
+</div>
+</div>
+
+<p>
+  The Android Runtime (ART) and Dalvik virtual machine use
+  <a href="http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a>
+  and <a href="http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
+  (mmapping) to manage memory. This means that any memory an app
+  modifies&mdash;whether by allocating
+  new objects or touching mmapped pages&mdash;remains resident in RAM and
+  cannot be paged out. The only way to release memory from an app is to release
+  object references that the app holds, making the memory available to the
+  garbage collector.
+  That is with one exception: any files
+  mmapped in without modification, such as code,
+  can be paged out of RAM if the system wants to use that memory elsewhere.
+</p>
+
+<p>
+  This page explains how Android manages app processes and memory
+  allocation. For more information about how to manage memory more efficiently
+  in your app, see
+  <a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>.
+</p>
+
+<!-- Section 1 #################################################### -->
+
+<h2 id="gc">Garbage collection</h2>
+
+<p>
+  A managed memory environment, like the ART or Dalvik virtual machine,
+  keeps track of each memory allocation. Once it determines
+  that a piece of memory is no longer being used by the program,
+  it frees it back to the heap, without any intervention from the programmer.
+  The mechanism for reclaiming unused memory
+  within a managed memory environment
+  is known as <i>garbage collection</i>. Garbage collection has two goals:
+  find data objects in a program that cannot be accessed in the future; and
+  reclaim the resources used by those objects.
+</p>
+
+<p>
+  Android’s memory heap is a generational one, meaning that there are
+  different buckets of allocations that it tracks,
+  based on the expected life and size of an object being allocated.
+  For example, recently allocated objects belong in the <i>Young generation</i>.
+  When an object stays active long enough, it can be promoted
+  to an older generation, followed by a permanent generation.
+</p>
+
+<p>
+  Each heap generation has its own dedicated upper limit on the amount
+  of memory that objects there can occupy. Any time a generation starts
+  to fill up, the system executes a garbage collection
+  event in an attempt to free up memory. The duration of the garbage collection
+  depends on which generation of objects it's collecting
+  and how many active objects are in each generation.
+</p>
+
+<p>
+  Even though garbage collection can be quite fast, it can still
+  affect your app's performance. You don’t generally control
+  when a garbage collection event occurs from within your code.
+  The system has a running set of criteria for determining when to perform
+  garbage collection. When the criteria are satisfied,
+  the system stops executing the process and begins garbage collection. If
+  garbage collection occurs in the middle of an intensive processing loop
+  like an animation or during music playback, it can increase processing time.
+  This increase can potentially push code execution in your app past the
+  recommended 16ms threshold for efficient and smooth frame rendering.
+</p>
+
+<p>
+  Additionally, your code flow may perform kinds of work that
+  force garbage collection events to occur
+  more often or make them last longer-than-normal.
+  For example, if you allocate multiple objects in the
+  innermost part of a for-loop during each frame of an alpha
+  blending animation, you might pollute your memory heap with a
+  lot of objects.
+  In that circumstance, the garbage collector executes multiple garbage
+  collection events and can degrade the performance of your app.
+</p>
+
+<p>
+  For more general information about garbage collection, see
+  <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"
+  class="external-link">Garbage collection</a>.
+</p>
+
+<!-- Section 2 #################################################### -->
+
+<h2 id="SharingRAM">Sharing Memory</h2>
+
+<p>
+  In order to fit everything it needs in RAM,
+  Android tries to share RAM pages across processes. It
+  can do so in the following ways:
+</p>
+
+<ul>
+  <li>
+    Each app process is forked from an existing process called Zygote.
+    The Zygote process starts when the system boots and loads common
+    framework code and resources
+    (such as activity themes). To start a new app process,
+    the system forks the Zygote process then
+    loads and runs the app's code in the new process.
+    This approach allows most of the RAM pages allocated for
+    framework code and resources to be shared across all app processes.
+  </li>
+
+  <li>
+    Most static data is mmapped into a process.
+    This technique allows data to be shared
+    between processes, and also allows it to be paged
+    out when needed. Example static data include:
+    Dalvik code (by placing it in a pre-linked <code>.odex</code>
+    file for direct mmapping), app resources
+    (by designing the resource table to be a structure
+    that can be mmapped and by aligning the zip
+    entries of the APK), and traditional project
+    elements like native code in <code>.so</code> files.
+  </li>
+
+  <li>
+    In many places, Android shares the same dynamic
+    RAM across processes using explicitly allocated
+    shared memory regions (either with ashmem or gralloc).
+    For example, window surfaces use shared
+    memory between the app and screen compositor, and
+    cursor buffers use shared memory between the
+    content provider and client.
+  </li>
+</ul>
+
+<p>
+  Due to the extensive use of shared memory, determining
+  how much memory your app is using requires
+  care. Techniques to properly determine your app's
+  memory use are discussed in
+  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>.
+</p>
+
+<!-- Section 3 #################################################### -->
+
+<h2 id="AllocatingRAM">Allocating and Reclaiming App Memory</h2>
+
+<p>
+  The Dalvik heap is constrained to a
+  single virtual memory range for each app process. This defines
+  the logical heap size, which can grow as it needs to
+  but only up to a limit that the system defines
+  for each app.
+</p>
+
+<p>
+  The logical size of the heap is not the same as
+  the amount of physical memory used by the heap.
+  When inspecting your app's heap, Android computes
+  a value called the Proportional Set Size (PSS),
+  which accounts for both dirty and clean pages
+  that are shared with other processes—but only in an
+  amount that's proportional to how many apps share
+  that RAM. This (PSS) total is what the system
+  considers to be your physical memory footprint.
+  For more information about PSS, see the
+  <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+  guide.
+</p>
+
+<p>
+  The Dalvik heap does not compact the logical
+  size of the heap, meaning that Android does not
+  defragment the heap to close up space. Android
+  can only shrink the logical heap size when there
+  is unused space at the end of the heap. However,
+  the system can still reduce physical memory used by the heap.
+  After garbage collection, Dalvik
+  walks the heap and finds unused pages, then returns
+  those pages to the kernel using madvise. So, paired
+  allocations and deallocations of large
+  chunks should result in reclaiming all (or nearly all)
+  the physical memory used. However,
+  reclaiming memory from small allocations can be much
+  less efficient because the page used
+  for a small allocation may still be shared with
+  something else that has not yet been freed.
+
+</p>
+
+<!-- Section 4 #################################################### -->
+
+<h2 id="RestrictingMemory">Restricting App Memory</h2>
+
+<p>
+  To maintain a functional multi-tasking environment,
+  Android sets a hard limit on the heap size
+  for each app. The exact heap size limit varies
+  between devices based on how much RAM the device
+  has available overall. If your app has reached the
+  heap capacity and tries to allocate more
+  memory, it can receive an {@link java.lang.OutOfMemoryError}.
+</p>
+
+<p>
+  In some cases, you might want to query the
+  system to determine exactly how much heap space you
+  have available on the current device—for example, to
+  determine how much data is safe to keep in a
+  cache. You can query the system for this figure by calling
+  {@link android.app.ActivityManager#getMemoryClass() }.
+  This method returns an integer indicating the number of
+  megabytes available for your app's heap.
+</p>
+
+<!-- Section 5 #################################################### -->
+
+<h2 id="SwitchingApps">Switching apps</h2>
+
+<p>
+  When users switch between apps,
+  Android keeps apps that
+  are not foreground&mdash;that is, not visible to the user or running a
+  foreground service like music playback&mdash;
+  in a least-recently used (LRU) cache.
+  For example, when a user first launches an app,
+  a process is created for it; but when the user
+  leaves the app, that process does <em>not</em> quit.
+  The system keeps the process cached. If
+  the user later returns to the app, the system reuses the process, thereby
+  making the app switching faster.
+</p>
+
+<p>
+  If your app has a cached process and it retains memory
+  that it currently does not need,
+  then your app&mdash;even while the user is not using it&mdash;
+  affects the system's
+  overall performance. As the system runs low on memory,
+  it kills processes in the LRU cache
+  beginning with the process least recently used. The system also
+  accounts for processes that hold onto the most memory
+  and can terminate them to free up RAM.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> When the system begins killing processes in the
+  LRU cache, it primarily works bottom-up. The system also considers which
+  processes consume more memory and thus provide the system
+  more memory gain if killed.
+  The less memory you consume while in the LRU list overall,
+  the better your chances are
+  to remain in the list and be able to quickly resume.
+</p>
+
+<p>
+  For more information about how processes are cached while
+  not running in the foreground and how
+  Android decides which ones
+  can be killed, see the
+  <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
+  guide.
+</p>
diff --git a/docs/html/topic/performance/memory.jd b/docs/html/topic/performance/memory.jd
new file mode 100644
index 0000000..ef1c4ae
--- /dev/null
+++ b/docs/html/topic/performance/memory.jd
@@ -0,0 +1,593 @@
+page.title=Manage Your App's Memory
+page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#monitor">Monitor Available Memory and Memory Usage</a>
+    <ul>
+      <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li>
+      <li><a href="#release">Release memory in response to events</a></li>
+      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
+    </ul>
+  </li>
+  <li><a href="#code">Use More Efficient Code Constructs</a>
+    <ul>
+      <li><a href="#Services">Use services sparingly</a></li>
+      <li><a href="#DataContainers">Use optimized data containers</a></li>
+      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
+      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
+      <li><a href="#churn">Avoid memory churn</a></li>
+    </ul>
+  </li>
+  <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a>
+    <ul>
+      <li><a href="#reduce">Reduce overall APK size</a></li>
+      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
+      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
+    </ul>
+  </li>
+</ol>
+<h2>See Also</h2>
+<ul>
+  <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>
+  </li>
+  <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+  </li>
+  <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li>
+</ul>
+
+</div>
+</div>
+
+<!-- INTRO #################################################### -->
+
+<p>
+  Random-access memory (RAM) is a valuable
+  resource in any software development environment, but
+  it's even more valuable on a mobile operating system
+  where physical memory is often constrained.
+  Although both the Android Runtime (ART) and Dalvik virtual machine perform
+  routine garbage collection, this does not mean you can ignore
+  when and where your app allocates and releases memory.
+  You still need to avoid
+  introducing memory leaks, usually caused by holding onto
+  object references in static member variables, and
+  release any {@link java.lang.ref.Reference} objects at the appropriate
+  time as defined by
+  lifecycle callbacks.
+</p>
+
+<p>
+  This page explains how you can
+  proactively reduce memory usage within your app.
+  For more information about general
+  practices to clean up your resources when programming in Java,
+  refer to other books or online
+  documentation about managing resource references.
+  If you’re looking for information about how to
+  analyze memory in a running app, read
+  <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>.
+  For more detailed information about how the Android Runtime and Dalvik
+  virtual machine manage memory, see the
+  <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>.
+</p>
+
+<!-- Section 1 #################################################### -->
+
+<h2 id="monitor">Monitor Available Memory and Memory Usage</h2>
+
+<p>
+  The Android framework, Android Studio, and Android SDK
+  can help you analyze and adjust your app's memory usage.
+  The Android framework
+  exposes several APIs that allow your app to reduce its memory usage
+  dynamically during runtime. Android Studio and the Android SDK
+  contain several tools  that allow you to investigate how your
+  app uses memory.
+</p>
+
+<!-- Section 1.1 #################################################### -->
+
+<h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3>
+
+<p>
+  Before you can fix the memory usage problems in your app, you first need
+  to find them. Android Studio and the Android SDK include several tools
+  for analyzing memory usage in your app:
+</p>
+
+<ol>
+  <li>
+    The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows
+    you to inspect memory allocation within your app process.
+    You can use this information to understand how your
+    app uses memory overall. For example, you can force a garbage collection
+    event and then view the types of objects that remain in memory. You can
+    use this information to identify operations or actions within your app
+    that allocate or leave excessive amounts of objects in memory.
+
+    <p>For more information about how to use the DDMS tool, see
+      <a href="/studio/profile/ddms.html">Using DDMS</a>.
+    </p>
+  </li>
+
+  <li>
+    The Memory Monitor in Android Studio shows you how your app allocates
+    memory over the course of a single session.
+    The tool shows a graph of available
+    and allocated Java memory over time, including garbage collection events.
+    You can also initiate garbage collection events and take a snapshot of
+    the Java heap while your app runs. The output from the Memory Monitor tool
+    can help you identify points when your app experiences excessive garbage
+    collection events, leading to app slowness.
+    <p>
+      For more information about how to use Memory Monitor tool, see
+      <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>.
+    </p>
+  </li>
+
+  <li>
+    Garbage collection events also show up in the Traceview viewer. Traceview
+    allows you to view trace log files as both a timeline and as a profile
+    of what happened within a method. You can use this tool to determine
+    what code was executing when a garbage collection event occurred.
+    <p>
+      For more information about how to use the Traceview viewer, see
+      <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>.
+    </p>
+  </li>
+
+  <li>
+    The Allocation Tracker tool in Android Studio gives you a detailed look
+    at how your app allocates memory.
+    The Allocation Tracker records an app's memory allocations and lists
+    all allocated objects within the profiling snapshot. You can use this
+    tool to track down parts of your code that allocate too many objects.
+
+    <p>
+      For more information about how to use the Allocation Tracker tool, see
+      <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>.
+    </p>
+  </li>
+
+</ol>
+
+<!-- Section 1.2 #################################################### -->
+
+<h3 id="release">Release memory in response to events</h3>
+
+<p>
+  An Android device can run with varying amounts of free memory
+  depending on the physical amount of RAM on the device and how the user
+  operates it. The system broadcasts signals to indicate when it is under
+  memory pressure, and apps should listen for these signals and adjust
+  their memory usage as appropriate.
+</p>
+
+</p>
+  You can use the {@link android.content.ComponentCallbacks2} API
+  to listen for these signals and then adjust your memory
+  usage in response to app lifecycle
+  or device events. The
+  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+  method allows your app to listen for memory related events when the app runs
+  in the foreground (is visible) and when it runs in the background.
+</p>
+
+<p>
+  To listen for these events, implement the {@link
+  android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+  callback in your {@link android.app.Activity}
+  classes, as shown in the following code snippet.
+</p>
+
+<pre class="prettyprint">
+import android.content.ComponentCallbacks2;
+// Other import statements ...
+
+public class MainActivity extends AppCompatActivity
+    implements ComponentCallbacks2 {
+
+    // Other activity code ...
+
+    /**
+     * Release memory when the UI becomes hidden or when system resources become low.
+     * @param level the memory-related event that was raised.
+     */
+    public void onTrimMemory(int level) {
+
+        // Determine which lifecycle or system event was raised.
+        switch (level) {
+
+            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+
+                /*
+                   Release any UI objects that currently hold memory.
+
+                   The user interface has moved to the background.
+                */
+
+                break;
+
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+
+                /*
+                   Release any memory that your app doesn't need to run.
+
+                   The device is running low on memory while the app is running.
+                   The event raised indicates the severity of the memory-related event.
+                   If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
+                   begin killing background processes.
+                */
+
+                break;
+
+            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+
+                /*
+                   Release as much memory as the process can.
+
+                   The app is on the LRU list and the system is running low on memory.
+                   The event raised indicates where the app sits within the LRU list.
+                   If the event is TRIM_MEMORY_COMPLETE, the process will be one of
+                   the first to be terminated.
+                */
+
+                break;
+
+            default:
+                /*
+                  Release any non-critical data structures.
+
+                  The app received an unrecognized memory level value
+                  from the system. Treat this as a generic low-memory message.
+                */
+                break;
+        }
+    }
+}
+</pre>
+
+<p>
+  The
+  {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+  callback was added in Android 4.0 (API level 14). For earlier versions,
+  you can use the
+  {@link android.content.ComponentCallbacks#onLowMemory()}
+  callback as a fallback for older versions, which is roughly equivalent to the
+  {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.
+</p>
+
+<!-- Section 1.3 #################################################### -->
+
+<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
+
+<p>
+  To allow multiple running processes, Android sets a hard limit
+  on the heap size alloted for each app. The exact heap size limit varies
+  between devices based on how much RAM the device
+  has available overall. If your app has reached the heap capacity and
+  tries to allocate more
+  memory, the system throws an {@link java.lang.OutOfMemoryError}.
+</p>
+
+<p>
+  To avoid running out of memory, you can to query the system to determine
+  how much heap space you have available on the current device.
+  You can query the system for this figure by calling
+  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
+  This returns an
+  {@link android.app.ActivityManager.MemoryInfo } object that provides
+  information about the device's
+  current memory status, including available memory, total memory, and
+  the memory threshold&mdash;the memory level below which the system begins
+  to kill processes. The
+  {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple
+  boolean field,
+  {@link android.app.ActivityManager.MemoryInfo#lowMemory }
+  that tells you whether the device is running low on memory.
+</p>
+
+<p>
+  The following code snippet shows an example of how you can use the
+  {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
+  method in your application.
+</p>
+
+<pre class="prettyprint">
+public void doSomethingMemoryIntensive() {
+
+    // Before doing something that requires a lot of memory,
+    // check to see whether the device is in a low memory state.
+    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
+
+    if (!memoryInfo.lowMemory) {
+        // Do memory intensive work ...
+    }
+}
+
+// Get a MemoryInfo object for the device's current memory status.
+private ActivityManager.MemoryInfo getAvailableMemory() {
+    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
+    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+    activityManager.getMemoryInfo(memoryInfo);
+    return memoryInfo;
+}
+</pre>
+
+<!-- Section 2 #################################################### -->
+
+<h2 id="code">Use More Memory-Efficient Code Constructs</h2>
+
+<p>
+  Some Android features, Java classes, and code constructs tend to
+  use more memory than others. You can minimize how
+  much memory your app uses by choosing more efficient alternatives in
+  your code.
+</p>
+
+<!-- Section 2.1 #################################################### -->
+
+<h3 id="Services">Use services sparingly</h3>
+
+<p>
+  Leaving a service running when it’s not needed is
+  <strong>one of the worst memory-management
+  mistakes</strong> an Android app can make. If your app needs a
+  <a href="{@docRoot}guide/components/services.html">service</a>
+  to perform work in the background, do not keep it running unless
+  it needs to run a job. Remember to stop your service when it has completed
+  its task. Otherwise, you can inadvertently cause a memory leak.
+</p>
+
+<p>
+  When you start a service, the system prefers to always keep the process
+  for that service running. This behavior
+  makes services processes very expensive
+  because the RAM used by a service remains unavailable to other processes.
+  This reduces the number of cached processes that the system can keep in
+  the LRU cache, making app switching less efficient. It can even lead to
+  thrashing in the system when memory is tight and the system can’t
+  maintain enough processes to host all the services currently running.
+</p>
+
+<p>
+  You should generally avoid use of persistent services because of
+  the on-going demands they place on available memory. Instead, we
+  recommend that you use an alternative implementation
+  such as {@link android.app.job.JobScheduler}. For more information about
+  how to use {@link android.app.job.JobScheduler} to schedule background
+  processes, see
+  <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
+<p>
+  If you must use a service, the
+  best way to limit the lifespan of your service is to use an {@link
+  android.app.IntentService}, which finishes
+  itself as soon as it's done handling the intent that started it.
+  For more information, read
+  <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>.
+</p>
+
+<!-- Section 2.2 #################################################### -->
+
+<h3 id="DataContainers">Use optimized data containers</h3>
+
+<p>
+  Some of the classes provided by the programming language are not optimized for
+  use on mobile devices. For example, the generic
+  {@link java.util.HashMap} implementation can be quite memory
+  inefficient because it needs a separate entry object for every mapping.
+</p>
+
+<p>
+  The Android framework includes several optimized data containers, including
+  {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray},
+  and {@link android.support.v4.util.LongSparseArray}.
+  For example, the {@link android.util.SparseArray} classes are more
+  efficient because they avoid the system's need to
+  <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym>
+  the key and sometimes value (which creates yet another object or
+  two per entry).
+</p>
+
+<p>
+  If necessary, you can always switch to raw arrays for a really lean data
+  structure.
+</p>
+
+<!-- Section 2.3 #################################################### -->
+
+<h3 id="Abstractions">Be careful with code abstractions</h3>
+
+<p>
+  Developers often use abstractions simply as a good programming practice,
+  because abstractions can improve code flexibility and maintenance.
+  However, abstractions come at a significant cost:
+  generally they require a fair amount more code that
+  needs to be executed, requiring more time and
+  more RAM for that code to be mapped into memory.
+  So if your abstractions aren't supplying a
+  significant benefit, you should avoid them.
+</p>
+
+<p>
+  For example, enums often require more than twice as much memory as static
+  constants. You should strictly avoid using enums on Android.
+</p>
+
+<!-- Section 2.4 #################################################### -->
+
+<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
+
+<p>
+  <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a>
+  are a language-neutral, platform-neutral, extensible mechanism
+  designed by Google for serializing structured data&mdash;similar to XML, but
+  smaller, faster, and simpler. If you decide to use
+  protobufs for your data, you should always use nano protobufs in your
+  client-side code. Regular protobufs generate extremely verbose code, which
+  can cause many kinds of problems in your app such as
+  increased RAM use, significant APK size increase, and slower execution.
+</p>
+
+<p>
+  For more information, see the "Nano version" section in the
+  <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
+class="external-link">protobuf readme</a>.
+</p>
+
+<!-- Section 2.5 #################################################### -->
+
+<h3 id="churn">Avoid memory churn</h3>
+
+<p>
+  As mentioned previously, garbage collections events don't normally affect
+  your app's performance. However, many garbage collection events that occur
+  over a short period of time can quickly eat up your frame time. The more time
+  that the system spends on garbage collection, the less time it has to do
+  other stuff like rendering or streaming audio.
+</p>
+
+<p>
+  Often, <em>memory churn</em> can cause a large number of
+  garbage collection events to occur. In practice, memory churn describes the
+  number of allocated temporary objects that occur in a given amount of time.
+</p>
+
+<p>
+  For example, you might allocate multiple temporary objects within a
+  <code>for</code> loop. Or you might create new
+  {@link android.graphics.Paint} or {@link android.graphics.Bitmap}
+  objects inside the
+  {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
+  function of a view.
+  In both cases, the app creates a lot of objects quickly at high volume.
+  These can quickly consume all the available memory in the young generation,
+  forcing a garbage collection event to occur.
+</p>
+
+<p>
+  Of course, you need to find the places in your code where
+  the memory churn is high before you can fix them. Use the tools discussed in
+  <a href="#AnalyzeRam">Analyze your RAM usage</a>
+</p>
+
+<p>
+  Once you identify the problem areas in your code, try to reduce the number of
+  allocations within performance critical areas. Consider moving things out of
+  inner loops or perhaps moving them into a
+  <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a>
+  based allocation structure.
+</p>
+
+<!-- Section 3 #################################################### -->
+
+<h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2>
+
+<p>
+  Some resources and libraries within your code can gobble up memory without
+  you knowing it. Overall size of your APK, including third-party libraries
+  or embedded resources, can affect how much memory your app consumes. You can
+  improve your app's memory consumption by removing any redundant, unnecessary,
+  or bloated components, resources, or libraries from your code.
+</p>
+
+<!-- Section 3.1 #################################################### -->
+
+<h3 id="reduce">Reduce overall APK size</h3>
+
+<p>
+  You can significantly reduce your app's memory usage by reducing the overall
+  size of your app. Bitmap size, resources, animation frames, and third-party
+  libraries can all contribute to the size of your APK.
+  Android Studio and the Android SDK provide multiple tools
+  to help you reduce the size of your resources and external dependencies.
+</p>
+
+<p>
+  For more information about how to reduce your overall APK size, see
+  <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>.
+</p>
+
+<!-- Section 3.2 #################################################### -->
+
+<h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3>
+
+<p>
+  Dependency injection framework such as
+  <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a>
+  or
+  <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a>
+  can simplify the code you write and provide an adaptive environment
+  that's useful for testing and other configuration changes. However, dependency
+  frameworks aren't always optimized for mobile devices.
+</p>
+
+<p>
+  For example, these frameworks tend to initialize processes by
+  scanning your code for annotations. This which can require significant
+  amounts of your code to be mapped into RAM unnecessarily. The system
+  allocates these mapped pages into clean memory so Android can drop them; yet
+  that can't happen until the pages have remained in memory for a long period
+  of time.
+ </p>
+
+<p>
+  If you need to use a dependency injection framework in your app, consider
+  using
+  <a class="external-link" href="http://google.github.io/dagger/">Dagger</a>
+  instead. For example, Dagger does not use reflection to scan your app's code.
+  Dagger's strict implementation means that it can be used in Android apps
+  without needlessly increasing memory usage.
+</p>
+
+<!-- Section 3.3 #################################################### -->
+
+<h3 id="ExternalLibs">Be careful about using external libraries</h3>
+
+<p>
+  External library code is often not written for mobile environments and
+  can be inefficient when used
+  for work on a mobile client. When you decide to use an
+  external library, you may need to optimize that library for mobile devices.
+  Plan for that work up-front and analyze the library in terms of code size and
+  RAM footprint before deciding to use it at all.
+</p>
+
+<p>
+  Even some mobile-optimized libraries can cause problems due to differing
+  implementations. For example, one library may use nano protobufs
+  while another uses micro protobufs, resulting in two different protobuf
+  implementations in your app. This can happen with different
+  implementations of logging, analytics, image loading frameworks,
+  caching, and many other things you don't expect.
+</p>
+
+<p>
+  Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can
+  help to remove APIs and resources with the right flags, it can't remove a
+  library's large internal dependencies. The features that you want in these
+  libraries may require lower-level dependencies. This becomes especially
+  problematic when you use an {@link android.app.Activity } subclass from a
+  library (which will tend to have wide swaths of dependencies),
+  when libraries use reflection (which is common and means you need to spend a
+  lot of time manually tweaking ProGuard to get it to work), and so on.
+</p>
+
+<p>
+  Also avoid using a shared library for just one or two features out of dozens.
+  You don't want to pull in a large amount of code and overhead that
+  you don't even use. When you consider whether to use a library, look for
+  an implementation that strongly matches what you need. Otherwise, you might
+  decide to create your own implementation.
+</p>
+
diff --git a/docs/html/topic/performance/network-xfer.jd b/docs/html/topic/performance/network-xfer.jd
new file mode 100644
index 0000000..7fe5594
--- /dev/null
+++ b/docs/html/topic/performance/network-xfer.jd
@@ -0,0 +1,374 @@
+page.title=Reducing Image Download Sizes
+page.metaDescription=Improve network performance by optimizing image size.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+    <ol>
+
+      <li>
+        <a href="#uif">Understanding Image Formats</a>
+        <ul>
+           <li><a href="#png">PNG</a></li>
+           <li><a href="#jpg">JPG</a></li>
+           <li><a href="#webp">WebP</a></li>
+        </ul>
+      </li>
+      <li>
+        <a href="#sf">Selecting a Format</a></li>
+      <li><a href="#doqv">Determining Optimal Quality Values</a>
+        <ul>
+           <li><a href="#sv">Scalar Values (JPG, WebP only)</a></li>
+           <li><a href="#butter">Butteraugli</a></li>
+        </ul>
+      </li>
+      <li><a href="#sizes">Serving Sizes</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>
+Most download traffic consists of images. As a result, the smaller you can make
+your downloadable images, the better a network experience your app can provide
+for users. This page provides guidance on making image files smaller and more
+network-friendly.
+</p>
+
+<h2 id="uif">Understanding Image Formats</h2>
+
+<p>Android apps typically use images that are in one or more of the following file
+formats: PNG, JPG, and WebP. For each of these formats, there are steps you can
+take to reduce image sizes.
+</p>
+
+<h3 id="png">PNG</h3>
+
+<p>
+A key to making your PNG files smaller is reducing the number of unique
+colors used in each row of pixels that comprises the image. By using fewer
+colors, you improve the compression potential at all of the other stages of
+the pipeline.
+</p>
+
+<p>
+Reducing the number of unique colors makes a significant difference because PNG
+compression effectiveness is partly a function of the degree to which
+horizontally adjacent pixel colors vary. Thus, reducing the number of unique
+colors in each row of your PNG images can help in reducing their file sizes.
+</p>
+
+<p>
+When deciding whether to pursue this strategy, you should keep in mind that
+reducing the number of unique colors effectively amounts to applying a lossy
+encoding stage to the image. However, an encoding tool may not be a good
+judge of how bad a seemingly small error looks to the human eye. Therefore,
+you should perform this work manually in order to help ensure
+the right balance between efficient compression and acceptable image quality.
+</p>
+
+<p>
+There are two particularly useful approaches you can take: striving for indexed
+formats, and applying vector quantization.
+</p>
+
+
+<h4 id="strive">Strive for indexed formats</h4>
+
+<p>
+Any attempt at color reduction should start with trying to optimize your colors
+so that you can use the INDEXED format when exporting the image as a PNG. The
+INDEXED color mode works by choosing the best 256 colors to use, and replacing
+all pixel values with indices into that color palette. The result is a
+reduction from 16 million (potential) colors to only 256 colors: from 3 (without
+transparency) or 4 (with transparency) bytes per pixel to 1 byte per pixel.
+This change is a significant first-step file size reduction.
+</p>
+
+<p>
+Figure 1 shows shows an image and its indexed variant.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/beforeafterindexed.png">
+  <p class="img-caption">
+Figure 1. An image before and after conversion to the INDEXED format.
+  </p>
+
+
+<p>
+Figure 2 shows the color palette for the image in Figure 1:
+</p>
+
+  <img src="{@docRoot}topic/performance/images/palette.png">
+  <p class="img-caption">
+Figure 2. The color palette for the image in Figure 1.
+  </p>
+
+<p>
+Representing your image as a paletted image goes a long way toward
+significantly improving the file size, so it's worth investigating if the
+majority of your images can be converted.
+</p>
+
+<p>
+Of course, not every image can be accurately represented with only 256 colors.
+Some images, for example, might need 257, 310, 512, or 912 colors to
+look correct. In such cases, vector quantization can also be helpful.
+</p>
+
+<h4 id="vq">Vector quantization</h4>
+
+<p>
+The process of creating an indexed image may be better described as vector
+quantization (VQ). VQ serves as a rounding process for multidimensional
+numbers.  In this process, all the colors in your image get grouped based upon
+their similarity. For a given group, all colors in that group are replaced by a
+single <em>center point</em> value, which minimizes error for colors in that
+cell (or "site" if you're using the Voronoi terminology). In Figure 3,
+the green dots represent input colors, and the red dots are the center points
+that replace the input colors. Each cell is bounded by blue lines.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/vq.gif">
+  <p class="img-caption">
+Figure 3. Applying vector quantization to the colors in an image.
+</p>
+
+<p>
+The result of applying VQ to an image reduces the number of unique colors,
+replacing each group of colors with a single color that's "pretty close"
+in visual quality.
+</p>
+
+<p>
+This technique also allows you to define the maximum number of unique colors in
+your image. For example, Figure 4 shows the a parrot head in 16.7 million colors
+(24 bits per pixel, or bpp) alongside a version that only allows only
+16 (3 bpp) unique colors to be used.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/parrot.png">
+  <p class="img-caption">
+Figure 4. Image before and after application of vector quantification.
+  </p>
+
+<p>
+Immediately, you can see that there's a loss of quality; most of the gradient
+colors have been replaced, imparting a banding effect to the image. This image
+needs more than 16 unique colors.
+</p>
+
+<p>
+Setting up a VQ step in your pipeline can help you get a better sense of the
+true number of unique colors that your image uses, and can help you reduce them
+significantly. There are a number of readily available tools that you can use
+to help you implement this technique.
+</p>
+
+<h3 id="jpg">JPG</h3>
+
+<p>
+If you are using JPG images, there are several small changes you can make that
+potentially provide significant file-size savings. These include:
+</p>
+
+<ul>
+   <li>
+Producing a smaller file size through different encoding methods (without
+impacting quality).
+   </li>
+
+   <li>
+Adjusting quality slightly in order to yield better compression.
+   </li>
+</ul>
+
+<p>Pursuing these strategies can often net you file-size reductions of up to
+25%.
+</p>
+
+<p>
+When choosing tools, remember that photo exporting tools can
+insert unnecessary metadata, such as GPS information, into your images. At
+a minimum, try to leverage existing tools to help strip out this information
+from your files.
+</p>
+
+<h3 id="webp">WebP</h3>
+
+<p>
+WebP is a newer image format supported from Android 4.2.1 (API level 17). This
+format provides superior lossless and lossy compression for images on the web.
+Using WebP, developers can create smaller, richer images. WebP lossless image
+files are, on average,
+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#conclusions">
+26% smaller</a> than PNGs. These image files also support
+transparency (also known as alpha channel) at a cost of just
+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results">
+22% more</a> bytes.
+</p>
+
+<p>
+WebP lossy images are
+<a href="https://developers.google.com/speed/webp/docs/webp_study#experiment_1_webp_vs_jpeg_at_equal_ssim_index">
+25-34% smaller</a> than comparable JPG images at equivalent
+<a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a>
+quality indices. For cases when lossy RGB compression is acceptable, lossy
+WebP also supports transparency, typically producing file sizes 3 times smaller
+than PNG.
+</p>
+
+<p>
+For more information about WebP, visit the
+<a href="https://developers.google.com/speed/webp/">WebP site</a>.
+</p>
+
+<h2 id="sf">Selecting a Format</h2>
+
+<p>
+Different image formats are suitable for different types of images. JPG and PNG
+have very different compression processes, and they produce quite different
+results.
+</p>
+
+<p>
+The decision between PNG and JPG often comes down to the complexity of the
+image itself. Figure 5 shows two images that come out quite differently
+depending on which compression scheme the developer applies. The image on the
+left has many small details, and thus compresses more efficiently with JPG. The
+image on the right, with runs of the same color, compresses more efficiently
+with PNG.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/comparison.png">
+  <p class="img-caption">
+Figure 5. Suitable cases for JPG vs. PNG
+  </p>
+
+
+<p>
+WebP as a format can support both lossy and lossless modes, making it an ideal
+replacement for both PNG and JPG. The only thing to keep in mind is that it
+only has native support on devices running Android 4.2.1 (API level 17) and
+higher. Fortunately, the large
+<a
+href="https://developer.android.com/about/dashboards/index.html#Platform">
+majority of devices</a> satisfy that requirement.
+</p>
+
+<p>
+Figure 6 provides a simple visualization to help you decide which compression
+scheme to use.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/decisions.png">
+  <p class="img-caption">
+Figure 6. Deciding on a compression scheme
+  </p>
+
+<h2 id="doqv">Determining Optimal Quality Values</h2>
+
+<p>
+There are several techniques you can use to achieve the right balance between
+compression and image quality. One technique uses scalar values and therefore
+only works for JPG and WebP. The other technique takes advantage of the
+Butteraugli library, and is usable for all image formats.
+</p>
+
+<h3 id="sv">Scalar values (JPG and WebP only)</h3>
+
+<p>
+The power of JPG and WebP comes from the fact that you can use a scalar value
+to balance quality against file size. The trick is finding out what the correct
+quality value is for your image. Too low a quality level produces a small file
+at the cost of image quality. Too high a quality level increases file size
+without providing a noticeable benefit to the user.
+</p>
+
+<p>
+The most straightforward solution is to pick some non-maximum value, and use
+that value. However, be aware that the quality value affects every image
+differently. While a quality of 75%, for example, may look fine on most images,
+there may be some cases do not fare as well. You should make sure to test your
+chosen maximum value against a representative sample of images. Also, make
+sure to perform all of your tests against the original images, and not on
+compressed versions.
+</p>
+
+<p>
+For large media applications that upload and re-send millions of JPGs a day,
+hand-tuning for each asset is impractical. You might address this challenge by
+specifying several different quality levels, according to image category. For
+example, you might set 35% as the quality setting for thumbnails, since a
+smaller image hides more compression artifacts.
+</p>
+
+<h3 id="butter">Butteraugli</h4>
+
+<p>
+The Butteraugli project is a library to test an image's Psychovisual Error
+Threshold: the point at which a viewer starts to notice image degradation. In
+other words, this project attempts to quantify how distorted your compressed
+image is.
+</p>
+
+<p>
+Butteraugli allows you to define a goal for visual quality, and then run PNG,
+JPG, WebP lossy, and WebP lossless compressions. You can then choose the image
+that is the best balance of file size and Butteraugli level. Figure 7 shows an
+example of how Butteraugli was used to find the minimal JPG quality level
+before the visual distortion was high enough for a user could perceive a
+problem; the result is a roughly 65% reduction in file size.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/moarparrots.png">
+  <p class="img-caption">
+Figure 7. An image before and after application of Butteraugli technology.
+  </p>
+
+<p>
+Butteraugli allows you to proceed based on either output or input. That is, you
+can look for the lowest quality setting before a user perceives noticeable
+distortion in the resulting image, or you can iteratively set image-distortion
+levels to learn their associated quality levels.
+</p>
+
+<h2 id="sizes">Serving Sizes</h2>
+
+<p>
+It is tempting to keep only a single resolution of an image on a server. When a
+device accesses the image, the server serves it at that one resolution and
+leaves downscaling to the device.
+</p>
+
+<p>
+This solution is convenient for the developer, but potentially painful for the
+user, because the solution forces the user to download much more data than they
+need.
+
+You should instead store multiple sizes of images, and serve the size that is
+most appropriate for a particular use case. For example, for a thumbnail,
+serving an actual thumbnail image instead of serving and downscaling a
+full-size version consumes much less network bandwidth
+</p>
+
+</p>
+This approach is good for download speed, and is less costly for users who may
+be using limited or metered data plans. Proceeding like this also results in
+the image's taking less space on the device and in main memory. In the
+case of large images, such as 4K ones, this approach also saves the device
+from having to resize images before loading them.
+</p>
+
+<p>
+Implementing this approach requires that you have a backend image service to
+provide images at various resolutions with proper caching. There are existing
+services that can provide help with this task. For example,
+<a href="https://cloud.google.com/appengine/">App Engine</a> comes
+with image resizing functionality already installed.
+</p>
diff --git a/docs/html/topic/performance/power/battery-historian.jd b/docs/html/topic/performance/power/battery-historian.jd
new file mode 100644
index 0000000..79ea59d
--- /dev/null
+++ b/docs/html/topic/performance/power/battery-historian.jd
@@ -0,0 +1,247 @@
+page.title=Analyzing Power Use with Battery Historian
+page.metaDescription=Improve network performance by optimizing image size.
+
+meta.tags="power"
+page.tags="power"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+    <ol>
+      <li>
+        <a href="#sv">System-wide View</a>
+      </li>
+      <li>
+        <a href="#asd">App-Specific Data</a>
+      </li>
+      <li>
+        <a href="#usecases">Other Cases Where Battery Historian Can Help</a>
+      </li>
+    </ol>
+<h2>See also</h2>
+   <ol>
+      <li>
+      <a href="https://github.com/google/battery-historian">Battery Historian
+      on GitHub</a>
+      </li>
+
+      <li>
+      <a href="https://developer.android.com/studio/profile/battery-historian.html">
+      Batterystats and Battery Historian Walkthrough
+      </li>
+
+      <li>
+      <a href="https://youtu.be/VC2Hlb22mZM?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=2063"
+      target="_blank">
+      Battery Historian talk at Google I/O 2016</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>
+The Battery Historian tool provides insight into a device’s battery consumption
+over time. At a system-wide level, the tool visualizes power-related events from
+the system logs in an HTML representation. At an app-specific level, the tool
+provides a variety of data that can help you identify battery-draining app
+behavior.
+</p>
+
+<p>
+This document describes some of the ways you can use Battery Historian
+to learn about battery-consumption patterns. The document begins by explaining
+how to read the system-wide data that Battery Historian reports. Then,
+it presents ways in which you can use Battery Historian to diagnose
+and troubleshoot your own app's behavior related to battery consumption.
+Last, it offers several tips on scenarios in which Battery Historian may be
+particularly useful.
+</p>
+
+<h2 id="sv">System-wide View</h2>
+
+<p>
+The Battery Historian tool provides a system-wide visualization of various
+app and system behaviors, along with their correlation against battery
+consumption over time. This view, shown in Figure 1, can help you
+diagnose and identify power use issues with your app.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/generic-timeline.png">
+  <p class="img-caption">
+<strong>Figure 1.</strong>
+Battery Historian’s display of system-wide events affecting power
+consumption.
+  </p>
+
+<p>
+Of particular interest in this figure is the black, horizontal, downward trend
+line representing Battery Level, measured on the y-axis. For example, at the
+very beginning of the Battery Level line, at approximately 6:50 AM, the
+visualization shows a relatively steep drop in battery level.
+</p>
+
+<p>
+Figure 2 provides a close-up of that part of the display.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/s-generic-closeup.png">
+  <p class="img-caption">
+<strong>Figure 2.</strong>
+A close-up of the Battery Historian timeline from roughly 6:50 AM to 7:20 AM.
+  </p>
+
+<p>
+At the very beginning of the Battery Level line, as battery decline steeply,
+the display shows three things happening: The CPU is running, an app has
+acquired a wakelock, and the screen is on. In this way, Battery Historian helps
+you understand what events are happening when battery consumption is high. You
+can then target these behaviors in your app and investigate whether there are
+related optimizations you can make.
+</p>
+
+<p>
+The system-wide visualization can provide other clues, as well. For instance, if
+it shows that the mobile radio is frequently being turned off and on, there may
+be an opportunity to optimize this behavior through <a href=”intelligent
+scheduling page”>intelligent scheduling APIs</a> such as JobScheduler or
+Firebase Job Dispatcher.
+</p>
+
+<p>
+The next section explains how to investigate behavior and events specific to
+your own app.
+</p>
+
+<p>
+<h2 id="asd">App-Specific Data</h2>
+</p>
+
+<p>
+In addition to the macro-level data provided by the system-wide view, Battery
+Historian also provides tables and some visualization of data specific to each
+app running on your device. The tabular data includes:
+</p>
+
+<ul>
+   <li>The app’s estimated power use on the device.</li>
+   <li>Network information.</li>
+   <li>Wakelocks.</li>
+   <li>Services.</li>
+   <li>Process info.</li>
+</ul>
+
+<p>
+The tables provide two dimensions of data about your app. First, you can look
+up where your app’s power usage ranks compared to other apps. To do so, click
+<em>Device Power Estimates</em> table under <em>Tables</em>. This example
+examines a fictional app called Pug Power.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/app-rankings.png">
+  <p class="img-caption">
+<strong>Figure 3.</strong> Investigating which apps consume the most power.
+  </p>
+
+<p>
+The table in Figure 3 reveals that Pug Power is the ninth biggest consumer of
+battery power on this device, and the third biggest app that is not part of the
+OS. This data suggests that this app bears deeper investigation.
+</p>
+
+<p>
+To look up the data for a specific app, enter its package name into the lower
+of the two dropdown menus under <em>App Selection</em>, located under the left
+side of the visualization.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/dropdown.png">
+  <p class="img-caption">
+<strong>Figure 4.</strong> Entering a specific app whose data to view.
+  </p>
+
+<p>
+When you select a specific app, the following data visualization categories
+change to display app-specific data instead of system-wide data:
+</p>
+
+<ul>
+   <li>SyncManager.</li>
+   <li>Foreground process.</li>
+   <li>Userspace Wakelock.</li>
+   <li>Top app.</li>
+   <li>JobScheduler.</li>
+   <li>Activity Manager Proc.</li>
+</ul>
+
+The SyncManager and JobScheduler visualizations immediately make it obvious if
+your app performs syncs and executes jobs more frequently than necessary. In
+doing so, they can quickly reveal an opportunity to optimize your app’s
+behavior for improved battery performance.
+
+<p>
+You can also obtain one more piece of app-specific visualization data,
+<em>Userspace Wakelock</em>. To include this information in the bug report,
+enter the following command in your terminal window:
+</p>
+
+<pre>
+$ adb shell dumpsys batterystats --enable full-wake-history
+</pre>
+
+<p class="note">
+<strong>Note:</strong> From Android 6.0 (API level 23), the platform includes
+Doze functionality, which imposes certain optimizations on apps. For example,
+Doze batches jobs to take place during brief maintenance windows, regardless of
+how JobScheduler has scheduled them.
+</p>
+
+<p>
+Figures 5 and 6 show data for Pug Power: Figure 5
+shows the visualization of
+the app-specific data, and Figure 6 shows the corresponding tabular data.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/pug-visualization.png">
+  <p class="img-caption">
+<strong>Figure 5.</strong> Visualization of data for fictional app Pug Power.
+  </p>
+
+  <img src="{@docRoot}topic/performance/images/pugspecificdata.png">
+  <p class="img-caption">
+<strong>Figure 6.</strong> Tabular data for the fictional Pug Power app.
+  </p>
+
+<p>
+A look at the visualization does not show anything immediately obvious.
+The JobScheduler line shows that the app has no jobs scheduled. The SyncManager
+line shows that the app has not performed any syncs.
+</p>
+
+<p>
+However, examination of the <em>Wakelocks</em> segment of the tabular data
+reveals that Pug Power acquires wakelocks totaling over an hour. This unusual
+and costly behavior can account for the app’s high level of power consumption.
+This piece of information helps the developer target an area where optimization
+is likely to greatly help. In this case, why does the app acquire so much
+wakelock time, and how can the developer ameliorate this behavior?
+</p>
+
+<h2 id="usecases">Other Cases Where Battery Historian Can Help</h2>
+
+<p>
+There are many other cases in which Battery Historian can help you diagnose
+opportunities for improving battery behavior. For example, Battery Historian
+can tell you if your app is:
+</p>
+
+<ul>
+   <li>Firing wakeup alarms overly frequently (every 10 seconds or less).</li>
+   <li>Continuously holding a GPS lock.</li>
+   <li>Scheduling jobs every 30 seconds or less.</li>
+   <li>Scheduling syncs every 30 seconds or less.</li>
+   <li>Using the cellular radio more frequently than you expect.</li>
+</ul>
+
diff --git a/docs/html/topic/performance/power/index.jd b/docs/html/topic/performance/power/index.jd
new file mode 100644
index 0000000..88addce
--- /dev/null
+++ b/docs/html/topic/performance/power/index.jd
@@ -0,0 +1,125 @@
+page.title=Optimizing for Battery Life
+page.metaDescription=Learn how to help your app go easier on the battery.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>
+      In this document
+    </h2>
+    <ol>
+      <li>
+        <a href="#lazy">Lazy First</a>
+      </li>
+      <li>
+        <a href="#features">Platform Features</a>
+      </li>
+      <li>
+        <a href="#toolery">Tooling</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>Battery life is the single most important aspect of the mobile user
+experience. A device without power offers no functionality at all.
+For this reason, it is critically important that apps be as respectful of
+battery life as possible.</p>
+
+<p>There are three important things to keep in mind in keeping your app
+power-thrifty:</p>
+<ul>
+<li>Make your apps <em>Lazy First</em>.</li>
+<li>Take advantage of platform features that can help manage your app's battery
+consumption.</li>
+<li>Use tools that can help you identify battery-draining culprits.</li>
+</ul>
+
+<h2 id="lazy">Lazy First</h2>
+
+<p>Making your app Lazy First means looking for ways to reduce and optimize
+operations that are particularly battery-intensive. The core questions
+underpinning Lazy First design are:
+
+<ul>
+
+   <li><strong>Reduce:</strong> Are there redundant operations your app can cut
+out? For example, can it cache downloaded data instead of repeatedly waking
+   up the radio to re-download the data?</li>
+
+   <li><strong>Defer:</strong> Does an app need to perform an action right
+   away? For example,
+    can it wait until the device is charging before it backs data up to the
+    cloud?</li>
+
+   <li><strong>Coalesce:</strong> Can work be batched, instead of putting the
+   device
+   into an active state many times? For example, is it really necessary for
+   several dozen apps to each turn on the radio at separate times to send
+   their messages? Can the messages instead be transmitted during a
+   single awakening of the radio?</li>
+</ul>
+
+<p>
+You should ask these questions when it comes to using the CPU,
+the radio, and the screen. Lazy First design is often a good way
+to tame these battery killers.
+</p>
+
+<p>
+To help you achieve these and other efficiencies, the Android platform
+provides a number of features to help maximize battery life.
+</p>
+
+<h2 id="features">Platform Features</h2>
+
+<p>
+Broadly speaking, the Android platform provides two categories of help
+for you to optimize your app's battery use. First, it provides several
+APIs that you can implement in your app. You can learn more about these APIs in
+<a href="/topic/performance/scheduling.html">Intelligent Job Scheduling</a>
+and <a href="/performance/power/network/index.html">
+Network Use and Battery Consumption</a>.
+</p>
+
+<p>
+There are also internal mechanisms in the platform to help conserve
+battery life. While they are not APIs that you implement programmatically,
+you should still be aware of them so that your app can leverage them
+successfully. For more information, see
+<a href="/training/monitoring-device-state/doze-standby.html">Doze and
+App Standby</a>.</p>
+
+<p>
+You can get even more benefit out of these features by using the tools
+available for the platform to discover the parts of your app that consume
+the most power. Finding what to target is a big step toward
+successful optimization.
+</p>
+
+<h2 id ="toolery">Tooling</h2>
+
+<p>There are tools for Android, including
+<a href="/studio/profile/dev-options-rendering.html">Profile GPU Rendering</a>
+and <a class="external-link"
+href="https://github.com/google/battery-historian">Battery Historian</a>
+to help you identify areas that you can optimize for better battery life.
+Take advantage of these tools to target areas where you can apply the
+principles of Lazy First.
+</p>
+
+<section class="dac-section dac-small" id="latest-games"><div class="wrap">
+  <h2 class="norule" style="margin:0 0">More resources</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:develop/performance/landing"
+       data-sortOrder="random"
+       data-cardSizes="6x6"
+       data-maxResults="24"
+       data-items-per-page="24"
+       data-initial-results="3"></div>
+  </div>
+</section>
diff --git a/docs/html/topic/performance/rendering/index.jd b/docs/html/topic/performance/rendering/index.jd
new file mode 100644
index 0000000..1b16df0
--- /dev/null
+++ b/docs/html/topic/performance/rendering/index.jd
@@ -0,0 +1,60 @@
+page.title=Rendering
+page.article=true
+
+page.tags=battery
+page.metaDescription=Learn how to optimize your app's rendering performance.
+
+@jd:body
+
+
+<iframe width="448" height="252"
+    src="//www.youtube.com/embed/wIy8g8yNhNk?autohide=1&amp;showinfo=0"
+    frameborder="0" allowfullscreen=""
+    style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+<p>
+  A key aspect of your app that influences your users' perception of quality is
+  the smoothness with which it renders images and text to the screen. It is
+  important to avoid jank and sluggish responsiveness when your app is drawing
+  to the screen.
+</p>
+
+<p>
+  This section helps you learn several ways to optimize your app's rendering
+  performance: reducing overdraw, optimizing view hierarchies, and taking
+  advantage of the Profile GPU tool.
+</p>
+
+<h2>Rendering Actions</h2>
+
+<dl>
+  <dt>
+    <strong><a href="overdraw.html">
+        Reducing Overdraw</a></strong>
+  </dt>
+  <dd>
+    Minimize the number of times you app redraws the same pixel in a single
+    frame.
+  </dd>
+
+  <dt>
+    <strong><a href="optimizing-view-hierarchies.html">
+        Performance and View Hierarchies</a></strong>
+  </dt>
+  <dd>
+    Make sure your layout and measurement are executing efficiently, and
+    avoid double taxation.
+  </dd>
+
+
+  <dt>
+    <strong><a href="profile-gpu.html">
+        Analyzing with Profile GPU Rendering</a></strong>
+  </dt>
+  <dd>
+    Take advantage of this on-device tool to identify bottlenecks that
+    may be slowing your app's rendering down.
+  </dd>
+
+
+</dl>
diff --git a/docs/html/topic/performance/optimizing-view-hierarchies.jd b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
similarity index 100%
rename from docs/html/topic/performance/optimizing-view-hierarchies.jd
rename to docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
diff --git a/docs/html/topic/performance/rendering/overdraw.jd b/docs/html/topic/performance/rendering/overdraw.jd
new file mode 100644
index 0000000..c1feff5
--- /dev/null
+++ b/docs/html/topic/performance/rendering/overdraw.jd
@@ -0,0 +1,197 @@
+page.title=Reducing Overdraw
+page.metaDescription=Improve performance by reducing unnecessary rendering.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+    <ol>
+
+      <li>
+        <a href="#understanding">Understanding Overdraw</a>
+      </li>
+      <li>
+        <a href="#finding">Finding Overdraw Problems</a>
+      </li>
+      <li>
+        <a href="#fixing">Fixing Overdraw</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+<p>
+An app may draw the same pixel more than once within a single frame, an event
+called <em>overdraw</em>. Overdraw is usually unnecessary, and best
+eliminated. It manifests itself as a performance problem by wasting GPU time to
+render pixels that don't contribute to what the user sees on the screen.
+</p>
+
+<p>
+This document explains overdraw: what it is, how to diagnose it, and actions you
+can take to eliminate or mitigate it.
+</p>
+
+<h2 name="understanding">Understanding Overdraw</h2>
+
+<p>
+Overdraw refers to the system's drawing a pixel on the screen multiple times
+in a single frame of rendering. For example, if we have a bunch of stacked UI
+cards, each card hides a portion of the one below it.
+</p>
+
+<p>
+However, the system still needs to draw even the hidden portions of the cards
+in the stack. This is because stacked cards are rendered according to the
+<a class="external-link"
+href="https://en.wikipedia.org/wiki/Painter%27s_algorithm">painter's
+algorithm</a>: that is, in back-to-front order.
+This sequence of rendering allows the system to apply proper alpha blending to
+translucent objects such as shadows.
+</p>
+
+<h2 name="finding">Finding Overdraw Problems</h2>
+
+<p>
+The platform offers several tools to help you determine if overdraw is
+affecting your app's performance. These tools are available right on the device,
+and accessible by turning on <strong>Developer Settings</strong></a> under
+<em>Settings</em>. For more information about device developer settings, see
+<a href="/studio/run/device.html#developer-device-options">Run Apps on a
+Hardware Device</a>.
+</p>
+
+<h3 id="dgot">Debug GPU overdraw tool</h3>
+
+<p>
+The Debug GPU Overdraw tool uses color-coding to show the number of times your
+app draws each pixel on the screen. The higher this count, the
+more likely it is that overdraw affects your app's performance.
+</p>
+
+<p>
+For more information on how to use the tool, refer to the related
+<a href="/studio/profile/dev-options-overdraw.html">walkthrough</a>
+and
+<a href="https://io2015codelabs.appspot.com/codelabs/android-performance-debug-gpu-overdraw#1">
+codelab</a>.
+</p>
+
+<h3 id="pgrt">Profile GPU rendering tool</h3>
+
+<p>
+The Profile GPU Rendering tool displays, as a scrolling histogram, the time
+each stage of the rendering pipeline takes to display a single frame. The
+<em>Process</em> part of each bar, indicated in orange, shows when the system
+is swapping buffers; this metric provides important clues about overdraw.
+</p>
+
+<p>
+On less performant GPUs, available fill-rate (the speed at which the GPU can
+fill the frame buffer) can be quite low. As the number of
+pixels required to draw a frame increases, the GPU may take longer to process
+new commands, and ask the rest of the system to wait until it can catch up.
+The <em>Process</em> bar shows that this spike happens as the GPU gets
+overwhelmed trying to draw pixels as fast as possible. Issues other than
+raw numbers of pixels may also cause this metric to spike. For example,
+if the Debug GPU Overdraw tool shows heavy overdraw and <em>Process</em> spikes,
+there's likely an issue with overdraw.
+</p>
+
+<p class="note"><strong>Note: </strong>The
+<a href="https://developer.android.com/studio/profile/dev-options-rendering.html">
+Profile GPU Rendering</a> tool does not
+work with apps that use the NDK. This is because the system pushes framework
+messages to the background whenever OpenGL takes a full-screen context. In
+such cases, you may find a profiling tool provided by the GPU manufacturer
+helpful.</p>
+
+<h2 name="fixing">Fixing Overdraw</h2>
+
+<p>
+There are several strategies you can pursue to reduce or eliminate overdraw:
+</p>
+
+<ul>
+   <li>Removing unneeded backgrounds in layouts.</li>
+   <li>Flattening the view hierarchy.</li>
+   <li>Reducing transparency.</li>
+</ul>
+
+<p>
+This section provides information about each of these approaches.
+</p>
+
+<h3 id="rubil">Removing unneeded backgrounds in layouts</h3>
+
+<p>
+By default, a layout does not have a background, which means it does not render
+anything directly by itself. When layouts do have backgrounds, however, they may
+contribute to overdraw.
+</p>
+
+<p>
+Removing unnecessary backgrounds is a quick way of improving rendering
+performance. An unnecessary background may never be visible because it's
+completely covered by everything else the app is drawing on top of that
+view. For example, the system may entirely cover up a parent's
+background when it draws child views on top of it.
+</p>
+
+<p>
+To find out why you're overdrawing, walk through the hierarchy in
+the <a href="/studio/profile/hierarchy-viewer.html">Hierarchy Viewer</a> tool.
+As you do so, look out for any backgrounds you can eliminate because
+they are not visible to the user. Cases where many containers share a
+common background color offer another opportunity to eliminate unneeded
+backgrounds: You can set the window background to the main background color
+of your app, and leave all of the containers above it with no background values
+defined.
+</p>
+
+<h3 id="fvh">Flattening view hierarchy</h3>
+
+<p>
+Modern layouts make it easy to stack and layer views to produce beautiful
+design. However, doing so can degrade performance by resulting in overdraw,
+especially in scenarios where each stacked view object is opaque, requiring the
+drawing of both seen and unseen pixels to the screen.
+</p>
+
+<p>
+If you encounter this sort of issue, you may be able to improve performance by
+optimizing your view hierarchy to reduce the number of overlapping UI objects.
+For more information about how to accomplish this, see
+<a href="/topic/performance/optimizing-view-hierarchies.html">Optimizing View
+Hierarchies</a>.
+</p>
+
+<h3 id="rt">Reducing transparency</h3>
+
+<p>
+Rendering of transparent pixels on screen, known as alpha rendering, is a key
+contributor to overdraw. Unlike standard overdraw,
+in which the system completely hides existing drawn pixels by drawing
+opaque pixels on top of them, transparent
+objects require existing pixels to be drawn first, so that the right blending
+equation can occur.  Visual effects like transparent animations, fade-outs, and
+drop shadows all involve some sort of transparency, and can therefore contribute
+significantly to overdraw. You can improve overdraw in these situations by
+reducing the number of transparent objects you render. For example, you can get
+gray text by drawing black text in a {@link android.widget.TextView} with a
+translucent alpha value set on it. But you can get the same effect with far
+better performance by simply drawing the text in gray.
+</p>
+
+<p>
+To learn more about performance costs that transparency imposes throughout the
+entire drawing pipeline, watch the video
+<a href="https://www.youtube.com/watch?v=wIy8g8yNhNk&index=46&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+Hidden Costs of Transparency</a>.
+</p>
+
diff --git a/docs/html/topic/performance/rendering/profile-gpu.jd b/docs/html/topic/performance/rendering/profile-gpu.jd
new file mode 100644
index 0000000..fc98777
--- /dev/null
+++ b/docs/html/topic/performance/rendering/profile-gpu.jd
@@ -0,0 +1,406 @@
+page.title=Analyzing with Profile GPU Rendering
+page.metaDescription=Use the Profile GPU tool to help you optimize your app's rendering performance.
+
+meta.tags="power"
+page.tags="power"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+    <ol>
+      <li>
+        <a href="#visrep">Visual Representation</a></li>
+      </li>
+
+      <li>
+       <a href="#sam">Stages and Their Meanings</a>
+      
+      <ul>
+         <li>
+           <a href="#sv">Input Handling</a>
+         </li>
+         <li>
+           <a href="#asd">Animation</a>
+         </li>
+         <li>
+           <a href="#asd">Measurement/Layout</a>
+         </li>
+         <li>
+           <a href="#asd">Drawing</a>
+         </li>
+         </li>
+         <li>
+           <a href="#asd">Sync/Upload</a>
+         </li>
+         <li>
+           <a href="#asd">Issuing Commands</a>
+         </li>
+         <li>
+           <a href="#asd">Processing/Swapping Buffer</a>
+         </li>
+         <li>
+           <a href="#asd">Miscellaneous</a>
+         </li>
+      </ul>
+      </li>     
+     </ol>
+  </div>
+</div>
+
+<p>
+The <a href="/studio/profile/dev-options-rendering.html">
+Profile GPU Rendering</a> tool indicates the relative time that each stage of
+the rendering pipeline takes to render the previous frame. This knowledge
+can help you identify bottlenecks in the pipeline, so that you
+can know what to optimize to improve your app's rendering performance.
+</p>
+
+<p>
+This page briefly explains what happens during each pipeline stage, and
+discusses issues that can cause bottlenecks there. Before reading
+this page, you should be familiar with the information presented in the
+<a href="/studio/profile/dev-options-rendering.html">Profile GPU
+Rendering Walkthrough</a>. In addition, to understand how all of the
+stages fit together, it may be helpful to review
+<a href="https://www.youtube.com/watch?v=we6poP0kw6E&index=64&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+how the rendering pipeline works.</a>
+</p>
+
+<h2 id="#visrep">Visual Representation</h2>
+
+<p>
+The Profile GPU Rendering tool displays stages and their relative times in the
+form of a graph: a color-coded histogram. Figure 1 shows an example of
+such a display.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/bars.png">
+  <p class="img-caption">
+<strong>Figure 1.</strong> Profile GPU Rendering Graph
+  </p>
+
+</p>
+
+<p>
+Each segment of each vertical bar displayed in the Profile GPU Rendering
+graph represents a stage of the pipeline and is highlighted using a specific
+color in
+the bar graph. Figure 2 shows a key to the meaning of each displayed color.
+</p>
+
+  <img src="{@docRoot}topic/performance/images/s-profiler-legend.png">
+  <p class="img-caption">
+<strong>Figure 2.</strong> Profile GPU Rendering Graph Legend
+  </p>
+
+<p>
+Once you understand what each color signfiies,
+you can target specific aspects of your
+app to try to optimize its rendering performance.
+</p>
+
+<h2 id="sam">Stages and Their Meanings</a></h2>
+
+<p>
+This section explains what happens during each stage corresponding
+to a color in Figure 2, as well as bottleneck causes to look out for.
+</p>
+
+
+<h3 id="ih">Input Handling</h3>
+
+<p>
+The input handling stage of the pipeline measures how long the app
+spent handling input events. This metric indicates how long the app
+spent executing code called as a result of input event callbacks.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+High values in this area are typically a result of too much work, or
+too-complex work, occurring inside the input-handler event callbacks.
+Since these callbacks always occur on the main thread, solutions to this
+problem focus on optimizing the work directly, or offloading the work to a
+different thread.
+</p>
+
+<p>
+It’s also worth noting that {@link android.support.v7.widget.RecyclerView}
+scrolling can appear in this phase.
+{@link android.support.v7.widget.RecyclerView} scrolls immediately when it
+consumes the touch event. As a result,
+it can inflate or populate new item views. For this reason, it’s important to
+make this operation as fast as possible. Profiling tools like Traceview or
+Systrace can help you investigate further.
+</p>
+
+<h3 id="at">Animation</h3>
+
+<p>
+The Animations phase shows you just how long it took to evaluate all the
+animators that were running in that frame. The most common animators are
+{@link android.animation.ObjectAnimator},
+{@link android.view.ViewPropertyAnimator}, and
+<a href="/training/transitions/overview.html">Transitions</a>.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+High values in this area are typically a result of work that’s executing due
+to some property change of the animation. For example, a fling animation,
+which scrolls your {@link android.widget.ListView} or
+{@link android.support.v7.widget.RecyclerView}, causes large amounts of view
+inflation and population.
+</p>
+
+<h3 id="ml">Measurement/Layout</h3>
+
+<p>
+In order for Android to draw your view items on the screen, it executes
+two specific operations across layouts and views in your view hierarchy.
+</p>
+
+<p>
+First, the system measures the view items. Every view and layout has
+specific data that describes the size of the object on the screen. Some views
+can have a specific size; others have a size that adapts to the size
+of the parent layout container
+</p>
+
+<p>
+Second, the system lays out the view items. Once the system calculates
+the sizes of children views, the system can proceed with layout, sizing
+and positioning the views on the screen.
+</p>
+
+<p>
+The system performs measurement and layout not only for the views to be drawn,
+but also for the parent hierarchies of those views, all the way up to the root
+view.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+If your app spends a lot of time per frame in this area, it is
+usually either because of the sheer volume of views that need to be
+laid out, or problems such as
+<a href="/topic/performance/optimizing-view-hierarchies.html#double">
+double taxation</a> at the wrong spot in your
+hierarchy. In either of these cases, addressing performance involves
+<a href="/topic/performance/optimizing-view-hierarchies.html">improving
+the performance of your view hierarchies</a>.
+</p>
+
+<p>
+Code that you’ve added to
+{@link android.view.View#onLayout(boolean, int, int, int, int)} or
+{@link android.view.View#onMeasure(int, int)}
+can also cause performance
+issues. <a href="/studio/profile/traceview.html">Traceview</a> and
+<a href="/studio/profile/systrace.html">Systrace</a> can help you examine
+the callstacks to identify problems your code may have.
+</p>
+
+<h3 id="draw">Drawing</h3>
+
+<p>
+The draw stage translates a view’s rendering operations, such as drawing
+a background or drawing text, into a sequence of native drawing commands.
+The system captures these commands into a display list.
+</p>
+
+<p>
+The Draw bar records how much time it takes to complete capturing the commands
+into the display list, for all the views that needed to be updated on the screen
+this frame. The measured time applies to any code that you have added to the UI
+objects in your app. Examples of such code may be the
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()},
+{@link android.view.View#dispatchDraw(android.graphics.Canvas) dispatchDraw()},
+and the various <code>draw ()methods</code> belonging to the subclasses of the
+{@link android.graphics.drawable.Drawable} class.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+In simplified terms, you can understand this metric as showing how long it took
+to run all of the calls to
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
+for each invalidated view. This
+measurement includes any time spent dispatching draw commands to children and
+drawables that may be present. For this reason, when you see this bar spike, the
+cause could be that a bunch of views suddenly became invalidated. Invalidation
+makes it necessary to regenerate views' display lists. Alternatively, a
+lengthy time may be the result of a few custom views that have some extremely
+complex logic in their
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} methods.
+</p>
+
+<h3 id="su">Sync/Upload</h3>
+
+<p>
+The Sync & Upload metric represents the time it takes to transfer
+bitmap objects from CPU memory to GPU memory during the current frame.
+</p>
+
+<p>
+As different processors, the CPU and the GPU have different RAM areas
+dedicated to processing. When you draw a bitmap on Android, the system
+transfers the bitmap to GPU memory before the GPU can render it to the
+screen. Then, the GPU caches the bitmap so that the system doesn’t need to
+transfer the data again unless the texture gets evicted from the GPU texture
+cache.
+</p>
+
+<p class="note"><strong>Note:</strong> On Lollipop devices, this stage is
+purple.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+All resources for a frame need to reside in GPU memory before they can be
+used to draw a frame. This means that a high value for this metric could mean
+either a large number of small resource loads or a small number of very large
+resources. A common case is when an app displays a single bitmap that’s
+close to the size of the screen. Another case is when an app displays a
+large number of thumbnails.
+</p>
+
+<p>
+To shrink this bar, you can employ techniques such as:
+</p>
+
+<ul>
+   <li>
+Ensuring your bitmap resolutions are not much larger than the size at which they
+will be displayed. For example, your app should avoid displaying a 1024x1024
+image as a 48x48 image.
+   </li>
+
+   <li>
+Taking advantage of {@link android.graphics.Bitmap#prepareToDraw()}
+to asynchronously pre-upload a bitmap before the next sync phase.
+   </li>
+</ul>
+
+<h3 id="ic">Issuing Commands</h3>
+
+<p>
+The <em>Issue Commands</em> segment represents the time it takes to issue all
+of the commands necessary for drawing display lists to the screen.
+</p>
+
+<p>
+For the system to draw display lists to the screen, it sends the
+necessary commands to the GPU. Typically, it performs this action through the
+<a href="/guide/topics/graphics/opengl.html">OpenGL ES</a> API.
+</p>
+
+<p>
+This process takes some time, as the system performs final transformation
+and clipping for each command before sending the command to the GPU. Additional
+overhead then arises on the GPU side, which computes the final commands. These
+commands include final transformations, and additional clipping.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+The time spent in this stage is a direct measure of the complexity and
+quantity of display lists that the system renders in a given
+frame. For example, having many draw operations, especially in cases where
+there's a small inherent cost to each draw primitive, could inflate this time.
+For example:
+</p>
+
+<pre>
+for (int i = 0; i < 1000; i++)
+canvas.drawPoint()
+</pre>
+
+<p>
+is a lot more expensive to issue than:
+</p>
+
+<pre>
+canvas.drawPoints(mThousandPointArray);
+</pre>
+
+<p>
+There isn’t always a 1:1 correlation between issuing commands and
+actually drawing display lists. Unlike <em>Issue Commands</em>,
+which captures the time it takes to send drawing commands to the GPU,
+the <em>Draw</em> metric represents the time that it took to capture the issued
+commands into the display list.
+</p>
+
+<p>
+This difference arises because the display lists are cached by
+the system wherever possible. As a result, there are situations where a
+scroll, transform, or animation requires the system to re-send a display
+list, but not have to actually rebuild it&mdash;recapture the drawing
+commands&mdash;from scratch. As a result, you can see a high “Issue
+commands” bar without seeing a high <em>Draw commands</em> bar.
+</p>
+
+<h3 id="psb">Processing/Swapping Buffers</h3>
+
+<p>
+Once Android finishes submitting all its display list to the GPU,
+the system issues one final command to tell the graphics driver that it's
+done with the current frame. At this point, the driver can finally present
+the updated image to the screen.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+It’s important to understand that the GPU executes work in parallel with the
+CPU. The Android system issues draw commands to the GPU, and then moves on to
+the next task. The GPU reads those draw commands from a queue and processes
+them.
+</p>
+
+<p>
+In situations where the CPU issues commands faster than the GPU
+consumes them, the communications queue between the processors can become
+full. When this occurs, the CPU blocks, and waits until there is space in the
+queue to place the next command. This full-queue state arises often during the
+<em>Swap Buffers</em> stage, because at that point, a whole frame’s worth of
+commands have been submitted.
+</p>
+
+</p>
+The key to mitigating this problem is to reduce the complexity of work occurring
+on the GPU, in similar fashion to what you would do for the “Issue Commands”
+phase.
+</p>
+
+
+<h3 id="mt">Miscellaneous</h3>
+
+<p>
+In addition to the time it takes the rendering system to perform its work,
+there’s an additional set of work that occurs on the main thread and has
+nothing to do with rendering. Time that this work consumes is reported as
+<em>misc time</em>. Misc time generally represents work that might be occurring
+on the UI thread between two consecutive frames of rendering.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+If this value is high, it is likely that your app has callbacks, intents, or
+other work that should be happening on another thread. Tools such as
+<a href="/studio/profile/traceview.html">Method
+Tracing</a> or <a href="/studio/profile/systrace.html">Systrace</a> can provide
+visibility into the tasks that are running on
+the main thread. This information can help you target performance improvements.
+</p>
diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
index 891574f..47862e2 100644
--- a/docs/html/training/_book.yaml
+++ b/docs/html/training/_book.yaml
@@ -438,16 +438,6 @@
       path: /training/efficient-downloads/redundant_redundant.html
     - title: Modifying Patterns Based on the Connectivity Type
       path: /training/efficient-downloads/connectivity_patterns.html
-  - title: Backing up App Data to the Cloud
-    path: /training/backup/index.html
-    path_attributes:
-    - name: description
-      value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices.
-    section:
-    - title: Configuring Auto Backup
-      path: /training/backup/autosyncapi.html
-    - title: Using the Backup API
-      path: /training/backup/backupapi.html
   - title: Resolving Cloud Save Conflicts
     path: /training/cloudsave/conflict-res.html
     path_attributes:
@@ -695,6 +685,8 @@
         value: 再生中カードを表示する
     - title: Adding a Guided Step
       path: /training/tv/playback/guided-step.html
+    - title: Introducing First-time Users to Your App
+      path: /training/tv/playback/onboarding.html
     - title: Enabling Background Playback
       path: /training/tv/playback/options.html
     - title: Adding Picture-in-picture
@@ -898,6 +890,11 @@
         value: 順応性のある UI フローの実装
       - name: zh-cn-lang
         value: 实施自适应用户界面流程
+  - title: Build a Responsive UI with ConstraintLayout
+    path: /training/constraint-layout/index.html
+    path_attributes:
+    - name: description
+      value: How to build a layout using ConstraintLayout and the Android Studio Layout Editor.
   - title: Adding the App Bar
     path: /training/appbar/index.html
     path_attributes:
@@ -1149,6 +1146,8 @@
         value: 维护兼容性
       - name: zh-tw-lang
         value: 維持相容性
+    - title: Selecting Colors with the Palette API
+      path: /training/material/palette-colors.html
 
 - title: Best Practices for User Input
   path: /training/best-user-input.html
@@ -1233,15 +1232,9 @@
       path: /training/scheduling/wakelock.html
     - title: Scheduling Repeating Alarms
       path: /training/scheduling/alarms.html
-
 - title: Best Practices for Performance
   path: /training/best-performance.html
   section:
-  - title: Managing Your App's Memory
-    path: /training/articles/memory.html
-    path_attributes:
-    - name: description
-      value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
   - title: Performance Tips
     path: /training/articles/perf-tips.html
     path_attributes:
@@ -1273,23 +1266,6 @@
     - name: description
       value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals.
     section:
-    - title: Reducing Network Battery Drain
-      path: /training/performance/battery/network/index.html
-      section:
-      - title: Collecting Network Traffic Data
-        path: /training/performance/battery/network/gather-data.html
-      - title: Analyzing Network Traffic Data
-        path: /training/performance/battery/network/analyze-data.html
-      - title: Optimizing User-Initiated Network Use
-        path: /training/performance/battery/network/action-user-traffic.html
-      - title: Optimizing App-Initiated Network Use
-        path: /training/performance/battery/network/action-app-traffic.html
-      - title: Optimizing Server-Initiated Network Use
-        path: /training/performance/battery/network/action-server-traffic.html
-      - title: Optimizing General Network Use
-        path: /training/performance/battery/network/action-any-traffic.html
-    - title: Optimizing for Doze and App Standby
-      path: /training/monitoring-device-state/doze-standby.html
     - title: Monitoring the Battery Level and Charging State
       path: /training/monitoring-device-state/battery-monitoring.html
       path_attributes:
diff --git a/docs/html/training/accessibility/service.jd b/docs/html/training/accessibility/service.jd
index de00db7..c034145 100755
--- a/docs/html/training/accessibility/service.jd
+++ b/docs/html/training/accessibility/service.jd
@@ -17,7 +17,7 @@
   <li><a href="#create">Create Your Accessibility Service</a></li>
   <li><a href="#configure">Configure Your Accessibility Service</a></li>
   <li><a href="#events">Respond to AccessibilityEvents</a></li>
-  <li><a href="#query">Query the View Heirarchy for More Context</a></li>
+  <li><a href="#query">Query the View Hierarchy for More Context</a></li>
 </ol>
 
 <h2>You should also read</h2>
@@ -174,7 +174,7 @@
 In that method, use {@link
 android.view.accessibility.AccessibilityEvent#getEventType} to determine the
 type of event, and {@link
-android.view.accessibility.AccessibilityRecord#getContentDescription} to extract
+android.view.accessibility.AccessibilityEvent#getContentDescription} to extract
 any label text associated with the view that fired the event.</pre>
 
 <pre>
@@ -200,7 +200,7 @@
 }
 </pre>
 
-<h2 id="query">Query the View Heirarchy for More Context</h2>
+<h2 id="query">Query the View Hierarchy for More Context</h2>
 <p>This step is optional, but highly useful. The Android platform provides the ability for an
 {@link android.accessibilityservice.AccessibilityService} to query the view
 hierarchy, collecting information about the UI component that generated an event, and
@@ -211,7 +211,7 @@
 </pre>
 <p>Once that's done, get an {@link
 android.view.accessibility.AccessibilityNodeInfo} object using {@link
-android.view.accessibility.AccessibilityRecord#getSource}.  This call only
+android.view.accessibility.AccessibilityEvent#getSource}.  This call only
 returns an object if the window where the event originated is still the active
 window.  If not, it will return null, so <em>behave accordingly</em>.  The
 following example is a snippet of code that, when it receives an event, does
diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd
deleted file mode 100644
index de7af58..0000000
--- a/docs/html/training/articles/memory.jd
+++ /dev/null
@@ -1,740 +0,0 @@
-page.title=Managing Your App's Memory
-page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
-page.article=true
-@jd:body
-
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>In this document</h2>
-<ol class="nolist">
-  <li><a href="#Android">How Android Manages Memory</a>
-    <ol>
-      <li><a href="#SharingRAM">Sharing Memory</a></li>
-      <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
-      <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
-      <li><a href="#SwitchingApps">Switching Apps</a></li>
-    </ol>
-  </li>
-  <li><a href="#YourApp">How Your App Should Manage Memory</a>
-    <ol>
-      <li><a href="#Services">Use services sparingly</a></li>
-      <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
-      <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
-      <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
-      <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
-      <li><a href="#DataContainers">Use optimized data containers</a></li>
-      <li><a href="#Overhead">Be aware of memory overhead</a></li>
-      <li><a href="#Abstractions">Be careful with code abstractions</a></li>
-      <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
-      <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
-      <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
-      <li><a href="#OverallPerf">Optimize overall performance</a></li>
-      <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
-      <li><a href="#Zipalign">Use zipalign on your final APK</a></li>
-      <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
-      <li><a href="#MultipleProcesses">Use multiple processes</a></li>
-    </ol>
-  </li>
-</ol>
-<h2>See Also</h2>
-<ul>
-  <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
-  </li>
-</ul>
-
-</div>
-</div>
-
-
-<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
-it's even more valuable on a mobile operating system where physical memory is often constrained.
-Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
-you to ignore when and where your app allocates and releases memory.</p>
-
-<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
-introducing memory leaks (usually caused by holding onto object references in global members) and
-release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
-lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
-care of the rest: the system reclaims your memory allocations when the corresponding objects leave
-the scope of your app's active threads.</p>
-
-<p>This document explains how Android manages app processes and memory allocation, and how you can
-proactively reduce memory usage while developing for Android. For more information about general
-practices to clean up your resources when programming in Java, refer to other books or online
-documentation about managing resource references. If you’re looking for information about how to
-analyze your app’s memory once you’ve already built it, read <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-
-
-<h2 id="Android">How Android Manages Memory</h2>
-
-<p>Android does not offer swap space for memory, but it does use <a href=
-"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
-"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
-(mmapping) to manage memory. This means that any memory you modify&mdash;whether by allocating
-new objects or touching mmapped pages&mdash;remains resident in RAM and cannot be paged out.
-So the only way to completely release memory from your app is to release object references you may
-be holding, making the memory available to the garbage collector. That is with one exception:
-any files mmapped in without modification, such as code, can be paged out of RAM if the system
-wants to use that memory elsewhere.</p>
-
-
-<h3 id="SharingRAM">Sharing Memory</h3>
-
-<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
-can do so in the following ways:</p>
-<ul>
-<li>Each app process is forked from an existing process called Zygote.
-The Zygote process starts when the system boots and loads common framework code and resources
-(such as activity themes). To start a new app process, the system forks the Zygote process then
-loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
-framework code and resources to be shared across all app processes.</li>
-
-<li>Most static data is mmapped into a process. This not only allows that same data to be shared
-between processes but also allows it to be paged out when needed. Example static data include:
-Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
-(by designing the resource table to be a structure that can be mmapped and by aligning the zip
-entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
-
-<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
-shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
-memory between the app and screen compositor, and cursor buffers use shared memory between the
-content provider and client.</li>
-</ul>
-
-<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
-care. Techniques to properly determine your app's memory use are discussed in <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
-
-<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
-
-<ul>
-<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
-the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
-for each app).</li>
-
-<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
-When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
-which accounts for both dirty and clean pages that are shared with other processes&mdash;but only in an
-amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
-considers to be your physical memory footprint. For more information about PSS, see the <a
-href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
-RAM Usage</a> guide.</li>
-
-<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
-defragment the heap to close up space. Android can only shrink the logical heap size when there
-is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
-can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
-those pages to the kernel using madvise. So, paired allocations and deallocations of large
-chunks should result in reclaiming all (or nearly all) the physical memory used. However,
-reclaiming memory from small allocations can be much less efficient because the page used
-for a small allocation may still be shared with something else that has not yet been freed.</li>
-</ul>
-
-
-<h3 id="RestrictingMemory">Restricting App Memory</h3>
-
-<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
-for each app. The exact heap size limit varies between devices based on how much RAM the device
-has available overall. If your app has reached the heap capacity and tries to allocate more
-memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
-
-<p>In some cases, you might want to query the system to determine exactly how much heap space you
-have available on the current device&mdash;for example, to determine how much data is safe to keep in a
-cache. You can query the system for this figure by calling {@link
-android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
-megabytes available for your app's heap. This is discussed further below, under
-<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
-
-
-<h3 id="SwitchingApps">Switching Apps</h3>
-
-<p>Instead of using swap space when the user switches between apps, Android keeps processes that
-are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
-For example, when the user first launches an app, a process is created for it, but when the user
-leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
-the user later returns to the app, the process is reused for faster app switching.</p>
-
-<p>If your app has a cached process and it retains memory that it currently does not need,
-then your app&mdash;even while the user is not using it&mdash;is constraining the system's
-overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
-beginning with the process least recently used, but also giving some consideration toward
-which processes are most memory intensive. To keep your process cached as long as possible, follow
-the advice in the following sections about when to release your references.</p>
-
-<p>More information about how processes are cached while not running in the foreground and how
-Android decides which ones
-can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
->Processes and Threads</a> guide.</p>
-
-
-
-
-<h2 id="YourApp">How Your App Should Manage Memory</h2>
-
-<p>You should consider RAM constraints throughout all phases of development, including during app
-design (before you begin development). There are many
-ways you can design and write code that lead to more efficient results, through aggregation of the
-same techniques applied over and over.</p>
-
-<p>You should apply the following techniques while designing and implementing your app to make it
-more memory efficient.</p>
-
-
-<h3 id="Services">Use services sparingly</h3>
-
-<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
-to perform work in the background, do not keep it running unless
-it's actively performing a job. Also be careful to never leak your service by failing to stop it
-when its work is done.</p>
-
-<p>When you start a service, the system prefers to always keep the process for that service
-running. This makes the process very expensive because the RAM used by the service can’t be used by
-anything else or paged out. This reduces the number of cached processes that the system can keep in
-the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
-when memory is tight and the system can’t maintain enough processes to host all the services
-currently running.</p>
-
-<p>The best way to limit the lifespan of your service is to use an {@link
-android.app.IntentService}, which finishes
-itself as soon as it's done handling the intent that started it. For more information, read
-<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
-.</p>
-
-<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management
-mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app
-running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
-but users will discover such misbehaving apps and uninstall them.</p>
-
-
-<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
-
-<p>When the user navigates to a different app and your UI is no longer visible, you should
-release any resources that are used by only your UI. Releasing UI resources at this time can
-significantly increase the system's capacity for cached processes, which has a direct impact on the
-quality of the user experience.</p>
-
-<p>To be notified when the user exits your UI, implement the {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
-android.app.Activity} classes. You should use this
-method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
-which indicates your UI is now hidden from view and you should free resources that only your UI
-uses.</p>
-
-
-<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
-onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
-only when <em>all the UI components</em> of your app process become hidden from the user.
-This is distinct
-from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
-android.app.Activity} instance becomes hidden, which occurs even when the user moves to
-another activity in your app. So although you should implement {@link android.app.Activity#onStop
-onStop()} to release activity resources such as a network connection or to unregister broadcast
-receivers, you usually should not release your UI resources until you receive {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
-that if the user navigates <em>back</em> from another activity in your app, your UI resources are
-still available to resume the activity quickly.</p>
-
-
-
-<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
-
-<p>During any stage of your app's lifecycle, the {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
-the overall device memory is getting low. You should respond by further releasing resources based
-on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
-onTrimMemory()}:</p>
-
-<ul>
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
-<p>Your app is running and not considered killable, but the device is running low on memory and the
-system is actively killing processes in the LRU cache.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
-<p>Your app is running and not considered killable, but the device is running much lower on
-memory so you should release unused resources to improve system performance (which directly
-impacts your app's performance).</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
-<p>Your app is still running, but the system has already killed most of the processes in the
-LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
-sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
-the system prefers to keep alive, such as those hosting a running service.</p>
-</li>
-</ul>
-
-<p>Also, when your app process is currently cached, you may receive one of the following
-levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
-<ul>
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
-<p>The system is running low on memory and your process is near the beginning of the LRU list.
-Although your app process is not at a high risk of being killed, the system may already be killing
-processes in the LRU cache. You should release resources that are easy to recover so your process
-will remain in the list and resume quickly when the user returns to your app.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
-<p>The system is running low on memory and your process is near the middle of the LRU list. If the
-system becomes further constrained for memory, there's a chance your process will be killed.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
-<p>The system is running low on memory and your process is one of the first to be killed if the
-system does not recover memory now. You should release everything that's not critical to
-resuming your app state.</p>
-
-</li>
-</ul>
-
-<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
-added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
-callback as a fallback for older versions, which is roughly equivalent to the {@link
-android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
-
-<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
-although it primarily works bottom-up, it does give some consideration to which processes are
-consuming more memory and will thus provide the system more memory gain if killed.
-So the less memory you consume while in the LRU list overall, the better your chances are
-to remain in the list and be able to quickly resume.</p>
-
-
-
-<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
-
-<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
-system and thus provides a different heap limit for each app. You can call {@link
-android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
-megabytes. If your app tries to allocate more memory than is available here, it will receive an
-{@link java.lang.OutOfMemoryError}.</p>
-
-<p>In very special situations, you can request a larger heap size by setting the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
-attribute to "true" in the manifest <a
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
-tag. If you do so, you can call {@link
-android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
-
-<p>However, the ability to request a large heap is intended only for a small set of apps that can
-justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
-large heap simply because you've run out of memory</strong> and you need a quick fix&mdash;you
-should use it only when you know exactly where all your memory is being allocated and why it must
-be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
-requesting it to whatever extent possible. Using the extra memory will increasingly be to the
-detriment of the overall user experience because garbage collection will take longer and system
-performance may be slower when task switching or performing other common operations.</p>
-
-<p>Additionally, the large heap size is not the same on all devices and, when running on
-devices that have limited RAM, the large heap size may be exactly the same as the regular heap
-size. So even if you do request the large heap size, you should call {@link
-android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
-stay below that limit.</p>
-
-
-<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
-
-<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
-screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
-increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
-because both the X and Y dimensions increase.</p>
-
-<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
-always appear as the same size in your app heap regardless of the image resolution (the actual
-pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
-memory allocation because most heap analysis tools do not see the native allocation. However,
-beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
-heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
-trouble discovering why your app is using some memory on an older device, switch to a device
-running Android 3.0 or higher to debug it.</p>
-
-<p>For more tips about working with bitmaps, read <a
-href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
-
-
-<h3 id="DataContainers">Use optimized data containers</h3>
-
-<p>Take advantage of optimized containers in the Android framework, such as {@link
-android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
-android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
-implementation can be quite memory
-inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
-android.util.SparseArray} classes are more efficient because they avoid the system's need
-to <acronym title=
-"Automatic conversion from primitive types to object classes (such as int to Integer)"
->autobox</acronym>
-the key and sometimes value (which creates yet another object or two per entry). And don't be
-afraid of dropping down to raw arrays when that makes sense.</p>
-
-
-
-<h3 id="Overhead">Be aware of memory overhead</h3>
-
-<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
-keep this information in mind when you design your app, from start to finish. Often, things on the
-surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
-<ul>
-<li>Enums often require more than twice as much memory as static constants. You should strictly
-avoid using enums on Android.</li>
-
-<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
-
-<li>Every class instance has 12-16 bytes of RAM overhead.</li>
-
-<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
-additional entry object that takes 32 bytes (see the previous section about <a
-href="#DataContainers">optimized data containers</a>).</li>
-</ul>
-
-<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
-from this overhead. That can leave you in the difficult position of looking at a heap analysis and
-realizing your problem is a lot of small objects using up your RAM.</p>
-
-
-<h3 id="Abstractions">Be careful with code abstractions</h3>
-
-<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
-can improve code flexibility and maintenance. However, abstractions come at a significant cost:
-generally they require a fair amount more code that needs to be executed, requiring more time and
-more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
-significant benefit, you should avoid them.</p>
-
-
-<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
-
-<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
-buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
-serializing structured data&mdash;think XML, but smaller, faster, and simpler. If you decide to use
-protobufs for your data, you should always use nano protobufs in your client-side code. Regular
-protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
-increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
-symbol limit.</p>
-
-<p>For more information, see the "Nano version" section in the <a
-href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
-class="external-link">protobuf readme</a>.</p>
-
-
-
-<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
-
-<p>Using a dependency injection framework such as <a
-href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
-<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
-attractive because they can simplify the code you write and provide an adaptive environment
-that's useful for testing and other configuration changes. However, these frameworks tend to perform
-a lot of process initialization by scanning your code for annotations, which can require significant
-amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
-allocated into clean memory so Android can drop them, but that won't happen until the pages have
-been left in memory for a long period of time.</p>
-
-
-<h3 id="ExternalLibs">Be careful about using external libraries</h3>
-
-<p>External library code is often not written for mobile environments and can be inefficient when used
-for work on a mobile client. At the very least, when you decide to use an external library, you
-should assume you are taking on a significant porting and maintenance burden to optimize the
-library for mobile. Plan for that work up-front and analyze the library in terms of code size and
-RAM footprint before deciding to use it at all.</p>
-
-<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
-library may do things differently. For example, one library may use nano protobufs while another
-uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
-will also happen with different implementations of logging, analytics, image loading frameworks,
-caching, and all kinds of other things you don't expect. <a
-href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
-will all be lower-level dependencies that are required by the features for which you want the
-library. This becomes especially problematic when you use an {@link android.app.Activity}
-subclass from a library (which
-will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
-means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
-
-<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
-dozens of other things it does; you don't want to pull in a large amount of code and overhead that
-you don't even use. At the end of the day, if there isn't an existing implementation that is a
-strong match for what you need to do, it may be best if you create your own implementation.</p>
-
-
-<h3 id="OverallPerf">Optimize overall performance</h3>
-
-<p>A variety of information about optimizing your app's overall performance is available
-in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
-for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
-many of these tips also help optimize your app's memory use, such as by reducing the number of
-layout objects required by your UI.</p>
-
-<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
-your UI</a> with the layout debugging tools and take advantage of
-the optimization suggestions provided by the <a
-href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
-
-
-<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
-
-<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
-optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
-methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
-fewer RAM pages to be mapped.</p>
-
-
-<h3 id="Zipalign">Use zipalign on your final APK</h3>
-
-<p>If you do any post-processing of an APK generated by a build system (including signing it
-with your final production certificate), then you must run <a
-href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
-Failing to do so can cause your app to require significantly more RAM, because things like
-resources can no longer be mmapped from the APK.</p>
-
-<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
-are not zipaligned.</p>
-
-
-<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
-
-<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
-throughout all stages of its lifecycle. For information about how to analyze your app, read <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-
-
-<h3 id="MultipleProcesses">Use multiple processes</h3>
-
-<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
-memory is dividing components of your app into multiple processes. This technique must always be
-used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
-increase&mdash;rather than decrease&mdash;your RAM footprint if done incorrectly. It is primarily
-useful to apps that may run significant work in the background as well as the foreground and can
-manage those operations separately.</p>
-
-
-<p>An example of when multiple processes may be appropriate is when building a music player that
-plays music from a service for long period of time. If
-the entire app runs in one process, then many of the allocations performed for its activity UI must
-be kept around as long as it is playing music, even if the user is currently in another app and the
-service is controlling the playback. An app like this may be split into two process: one for its
-UI, and the other for the work that continues running in the background service.</p>
-
-<p>You can specify a separate process for each app component by declaring the <a href=
-"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
-for each component in the manifest file. For example, you can specify that your service should run
-in a process separate from your app's main process by declaring a new process named "background"
-(but you can name the process anything you like):</p>
-
-<pre>
-&lt;service android:name=".PlaybackService"
-         android:process=":background" />
-</pre>
-
-<p>Your process name should begin with a colon (':') to ensure that the process remains private to
-your app.</p>
-
-<p>Before you decide to create a new process, you need to understand the memory implications.
-To illustrate the consequences of each process, consider that an empty process doing basically
-nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
-dump below.</p>
-
-<pre class="no-pretty-print">
-adb shell dumpsys meminfo com.example.android.apis:empty
-
-** MEMINFO in pid 10172 [com.example.android.apis:empty] **
-                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
-              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
-             ------  ------  ------  ------  ------  ------  ------  ------  ------
-  Native Heap     0       0       0       0       0       0    1864    1800      63
-  Dalvik Heap   764       0    5228     316       0       0    5584    5499      85
- Dalvik Other   619       0    3784     448       0       0
-        Stack    28       0       8      28       0       0
-    Other dev     4       0      12       0       0       4
-     .so mmap   287       0    2840     212     972       0
-    .apk mmap    54       0       0       0     136       0
-    .dex mmap   250     148       0       0    3704     148
-   Other mmap     8       0       8       8      20       0
-      Unknown   403       0     600     380       0       0
-        TOTAL  2417     148   12480    1392    4832     152    7448    7299     148
-</pre>
-
-<p class="note"><strong>Note:</strong> More information about how to read this output is provided
-in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
-Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
-Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
-(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
-and another 150K of RAM for code that has been mapped in to execute.</p>
-
-<p>This memory footprint for an empty process is fairly significant and it can quickly
-grow as you start doing work in that process. For
-example, here is the memory use of a process that is created only to show an activity with some
-text in it:</p>
-
-<pre class="no-pretty-print">
-** MEMINFO in pid 10226 [com.example.android.helloactivity] **
-                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
-              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
-             ------  ------  ------  ------  ------  ------  ------  ------  ------
-  Native Heap     0       0       0       0       0       0    3000    2951      48
-  Dalvik Heap  1074       0    4928     776       0       0    5744    5658      86
- Dalvik Other   802       0    3612     664       0       0
-        Stack    28       0       8      28       0       0
-       Ashmem     6       0      16       0       0       0
-    Other dev   108       0      24     104       0       4
-     .so mmap  2166       0    2824    1828    3756       0
-    .apk mmap    48       0       0       0     632       0
-    .ttf mmap     3       0       0       0      24       0
-    .dex mmap   292       4       0       0    5672       4
-   Other mmap    10       0       8       8      68       0
-      Unknown   632       0     412     624       0       0
-        TOTAL  5169       4   11832    4032   10152       8    8744    8609     134
-</pre>
-
-<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
-leads to an important conclusion: If you are going to split your app into multiple processes, only
-one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
-increase the RAM required by the process (especially once you start loading bitmap assets and other
-resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
-
-<p>Additionally, when running more than one process, it's more important than ever that you keep your
-code as lean as possible, because any unnecessary RAM overhead for common implementations are now
-replicated in each process. For example, if you are using enums (though <a
-href="#Overhead">you should not use enums</a>), all of
-the RAM needed to create and initialize those constants is duplicated in each process, and any
-abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
-
-<p>Another concern with multiple processes is the dependencies that exist between them. For example,
-if your app has a content provider that you have running in the default process which also hosts
-your UI, then code in a background process that uses that content provider will also require that
-your UI process remain in RAM. If your goal is to have a background process that can run
-independently of a heavy-weight UI process, it can't have dependencies on content providers or
-services that execute in the UI process.</p>
-
-
-
-
-
-
-
-
-
-
-<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
-
-
-<p>You can examine the dependencies between your processes with the command:</p>
-
-<pre class="no-pretty-print">
-adb shell dumpsys activity
-</pre>
-
-<p>This dumps various information about the Activity Manager's state, ending with a list of all
-processes in their memory management order, including the reason each process is at its given
-level. For example, below is a dump with the Music app in the foreground.</p>
-
-<pre class="no-pretty-print">
-ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
-  Process LRU list (sorted by oom_adj):
-    PERS # 4: adj=sys  /F  trm= 0 20674:system/1000 (fixed)
-    PERS #39: adj=pers /F  trm= 0 20964:com.android.nfc/1027 (fixed)
-    PERS # 2: adj=pers /F  trm= 0 20959:com.android.phone/1001 (fixed)
-    PERS # 1: adj=pers /F  trm= 0 20779:com.android.systemui/u0a10057 (fixed)
-    Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
-    Proc #10: adj=fore /F  trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
-        com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
-    Proc # 6: adj=fore /F  trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
-        com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
-    Proc #38: adj=vis  /F  trm= 0 21028:com.android.nfc:handover/1027 (service)
-        com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
-    Proc # 7: adj=vis  /B  trm= 0 20935:com.google.process.location/u0a10023 (service)
-        com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
-    Proc # 3: adj=vis  /F  trm= 0 21225:com.android.bluetooth/1002 (service)
-        com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
-    Proc # 0: adj=vis  /F  trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
-        com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
-    Proc #34: adj=svc  /B  trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
-    Proc #14: adj=svc  /B  trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
-    Proc #12: adj=home /B  trm= 0 20989:com.android.launcher/u0a10036 (home)
-    Proc #37: adj=svcb /B  trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
-    Proc #17: adj=svcb /B  trm= 0 24537:android.process.media/u0a10016 (started-services)
-    Proc #35: adj=bak  /B  trm= 0 16087:com.android.defcontainer/u0a10013 (service)
-        com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
-    Proc #16: adj=bak  /B  trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
-    Proc #15: adj=bak  /B  trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
-    Proc # 9: adj=bak  /B  trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
-    Proc #26: adj=bak+1/B  trm= 0 9923:com.android.mms/u0a10042 (bg-act)
-    Proc #23: adj=bak+1/B  trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
-    Proc #22: adj=bak+1/B  trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
-        com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
-    Proc #19: adj=bak+1/B  trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
-    Proc #18: adj=bak+2/B  trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
-    Proc #13: adj=bak+2/B  trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
-    Proc #36: adj=bak+3/B  trm= 0 16050:com.android.settings/1000 (bg-act)
-    Proc #33: adj=bak+3/B  trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
-</pre>
-
-
-<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
-platform versions as process management policies are tweaked and improved.</p>
-
-
-<p>Details on the highlighted sections are:</p>
-
-<ol>
-<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
-class because it is the top activity on the activity stack.</li>
-
-<li>Persistent processes: These are processes that are part of the core system that must always be
-running.</li>
-
-<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
-dependency on the "main" process (through a content provider). So while the UI process is in use,
-the main process must also be kept around. This means the app's memory footprint is actually the
-sum of both processes. You will have this kind of connection on a content provider any time you
-have active calls into it or have unclosed cursors or file streams that came from it.</li>
-
-<li>Visible processes: These are processes that count in some way as "visible" to the user. This
-generally means that it is either something the user can literally see (such as a process hosting a
-paused but visible activity that is behind a non-full-screen dialog) or is something the user might
-notice if the process disappeared (such as a foreground service playing music). You should be
-certain that any process you have running at the "visible" level is indeed critical to the user,
-because they are very expensive to the overall RAM load.</li>
-
-<li>Service processes: These are processes running long-term jobs in a service. This level of the
-list is the start of less-critical processes, which the system has some freedom to kill if RAM is
-needed elsewhere. These services are still quite expensive because they can be killed only
-temporarily and the system tries to keep them running whenever possible.</li>
-
-<li>Home process: A special slot for the process that hosts the current Home activity, to try to
-prevent it from being killed as much as possible. Killing this process is much more damaging to the
-user experience than killing other cached processes, because so much user interaction goes through
-home.</li>
-
-<li>Secondary service processes: These are services that have been running for a relatively long time
-and so should be killed more aggressively when RAM is needed elsewhere.</li>
-
-<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
-switching and component launching. These processes are not required and the system will kill them
-as needed to reclaim memory. You will often see a process hosting a running service here—this is
-part of a platform policy of allowing very long-running services to drop down into the LRU list and
-eventually be killed. If the service should continue running (as defined by the {@link
-android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
-android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
-such services having memory leaks that over time reduce the number of regular cached processes that
-can be kept.</li>
-
-</ol>
-
-<p>This numbered list of processes is essentially the LRU list of processes that the framework
-provides to the kernel to help it determine which processes it should kill as it needs more RAM.
-The kernel's out of memory killer will generally begin from the bottom of this list, killing the
-last process and working its way up. It may not do it in exactly this order, as it can also take
-into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
-
-<p>There are many other options you can use with the activity command to analyze further details of
-your app's state&mdash;use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
-
--->
diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
index 8848354..58db3e2 100644
--- a/docs/html/training/articles/perf-anr.jd
+++ b/docs/html/training/articles/perf-anr.jd
@@ -14,6 +14,14 @@
   <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li>
 </ol>
 
+<h2>You should also read</h2>
+<ul>
+  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
+  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
+  <li><a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating Broadcast Receivers On Demand</a>
+  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
+</ul>
+
 </div>
 </div>
 
@@ -146,7 +154,7 @@
 
 <p>If you implement {@link java.lang.Thread} or {@link android.os.HandlerThread},
 be sure that your UI thread does not block while waiting for the worker thread to
-complete&mdash;do not call {@link java.lang.Object#wait Thread.wait()} or
+complete&mdash;do not call {@link java.lang.Thread#wait Thread.wait()} or
 {@link java.lang.Thread#sleep Thread.sleep()}. Instead of blocking while waiting for a worker
 thread to complete, your main thread should provide a {@link
 android.os.Handler} for the other threads to post back to upon completion.
@@ -165,6 +173,16 @@
 potentially long running action needs to be taken in response to an intent
 broadcast.</p>
 
+<p>
+  Another common issue with {@link android.content.BroadcastReceiver} objects
+  occurs when they execute too frequently. Frequent background execution can
+  reduce the amount of memory available to other apps.
+  For more information about how to enable and disable
+  {@link android.content.BroadcastReceiver} objects efficiently, see
+  <a href="/training/monitoring-device-state/manifest-receivers.html">Manipulating
+    Broadcast Receivers on Demand</a>.
+</p>
+
 <p class="note"><strong>Tip:</strong>
 You can use {@link android.os.StrictMode} to help find potentially
 long running operations such as network or database operations that
diff --git a/docs/html/training/articles/perf-tips.jd b/docs/html/training/articles/perf-tips.jd
index 82de69a..30cab14 100644
--- a/docs/html/training/articles/perf-tips.jd
+++ b/docs/html/training/articles/perf-tips.jd
@@ -28,7 +28,8 @@
 performance effects. Choosing the right algorithms and data structures should always be your
 priority, but is outside the scope of this document. You should use the tips in this document
 as general coding practices that you can incorporate into your habits for general code
-efficiency.</p>
+efficiency.
+</p>
 
 <p>There are two basic rules for writing efficient code:</p>
 <ul>
@@ -49,8 +50,7 @@
 without.</p>
 
 <p>To ensure your app performs well across a wide variety of devices, ensure
-your code is efficient at all levels and agressively optimize your performance.</p>
-
+your code is efficient at all levels and aggressively optimize your performance.</p>
 
 <h2 id="ObjectCreation">Avoid Creating Unnecessary Objects</h2>
 
diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
index 3a1b1e8..6588367 100644
--- a/docs/html/training/auto/audio/index.jd
+++ b/docs/html/training/auto/audio/index.jd
@@ -596,7 +596,7 @@
 </a>
 <h2 id="support_voice">Support Voice Actions</h2>
 
-<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
+<p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice
 action support, users can launch your app and play audio by providing voice input on Auto screens.
 If your audio playback app is already active and the user says
 <i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch
diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd
deleted file mode 100644
index e0df7bb..0000000
--- a/docs/html/training/backup/autosyncapi.jd
+++ /dev/null
@@ -1,370 +0,0 @@
-page.title=Configuring Auto Backup for Apps
-page.tags=backup, marshmallow, androidm
-page.keywords=backup, autobackup
-page.image=images/cards/card-auto-backup_2x.png
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-<h2>This lesson teaches you to</h2>
-<ol>
-        <li><a href="#configuring">Configure Data Backup</a></li>
-        <li><a href="#previous-androids">Support Lower Versions of Android</a></li>
-        <li><a href="#testing">Test Backup Configuration</a></li>
-        <li><a href="#issues">Handle Google Cloud Messaging</a></li>
-</ol>
-    <h2>You should also read</h2>
-    <ul>
-      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
-      <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a>
-      </li>
-    </ul>
-
-</div>
-</div>
-
-<p>
-  Users frequently invest time and effort to configure apps just the way they like them. Switching
-  to a new device can cancel out all that careful configuration. For apps whose <a href=
-  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a>
-  is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically
-  back up app data to the cloud. The system performs this automatic backup
-  for nearly all app data by default, and does so without your having to write any additional app
-  code.
-</p>
-
-<p class="note">
-<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google
-services for Auto Backup to work. The Google services opt-in dialog appears when the user goes
-through the Setup Wizard or configures the first Google account on the device.
-</p>
-
-<p>
-  When a user installs your app on
-  a new device, or reinstalls your app on one (for example, after a factory reset), the system
-  automatically restores the app data from the cloud. This lesson provides information about how to
-  configure the Auto Backup for Apps feature, explaining its default behavior and how to
-  exclude data that you don't want the system to back up.
-</p>
-
-<p>
-  The automatic backup feature preserves the data your app creates on a user device by uploading it
-  to the user’s Google Drive account and encrypting it. There is no charge to you or the user for
-  data storage, and the saved data does not count towards the user's personal Google Drive quota.
-  Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends
-  data to the cloud. If the system performs a data restore, it uses the last data snapshot that
-  the app had sent to the cloud.
-</p>
-
-<p>Automatic backups occur when the following conditions are met:</p>
-  <ul>
-     <li>The device is idle.</li>
-     <li>The device is charging.</li>
-     <li>The device is connected to a Wi-Fi network.</li>
-     <li>At least 24 hours have elapsed since the last backup.</li>
-  </ul>
-</p>
-
-<h2 id="configuring">Configure Data Backup</h2>
-
-<p>
-  On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up
-  almost all data that an app creates. The exception is <a href="#auto-exclude">
-  automatically excluded data files</a>. This section explains how you can use settings in
-  your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further
-  limit and configure what data the system backs up.
-</p>
-
-<h3 id="include-exclude">Including or excluding data</h3>
-
-<p>
-  Depending on what data your app needs and how you save it, you may need to set specific
-  rules for including or excluding certain files or directories. Auto Backup for Apps
-  lets you set these backup rules through the app manifest, in which you specify a backup scheme
-  configuration XML file. For example:
-</p>
-
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        package="com.my.appexample"&gt;
-    &lt;uses-sdk android:minSdkVersion="23"/&gt;
-    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
-    &lt;application ...
-<strong>        android:fullBackupContent="&#64;xml/mybackupscheme"&gt;</strong>
-    &lt;/app&gt;
-    ...
-&lt;/manifest&gt;
-</pre>
-
-<p>
-  In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file
-  called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your
-  app development project. This configuration file contains rules controlling which files are backed
-  up. The following example code shows a configuration file that excludes a specific file,
-  {@code device_info.db}:
-</p>
-
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;full-backup-content&gt;
-    &lt;exclude domain="database" path="device_info.db"/&gt;
-&lt;/full-backup-content&gt;
-</pre>
-
-<h3 id="auto-exclude">Automatically excluded data files</h3>
-
-<p>
-  Most apps do not need to, and in fact should not, back up all data. For example, the system
-  should not back up temporary files and caches. For this reason, the automatic backup
-  service excludes certain data files by default:
-</p>
-
-<ul>
-  <li>Files in the directories to which the
-  {@link android.content.Context#getCacheDir getCacheDir()} and
-  {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer.
-  </li>
-
-  <li>Files located on external storage, unless they reside in the directory to which the
-    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers.
-  </li>
-
-  <li>Files located in the directory to which the
-    {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers.
-  </li>
-</ul>
-<h3>Backup Configuration Syntax</h3>
-
-<p>
-  The backup service configuration allows you to specify what files to include or exclude from
-  backup. The syntax for the data backup configuration XML file is as follows:
-</p>
-
-<pre>
-&lt;full-backup-content&gt;
-    &lt;include domain=["file" | "database" | "sharedpref" | "external" | "root"]
-    path="string" /&gt;
-    &lt;exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
-    path="string" /&gt;
-&lt;/full-backup-content&gt;
-</pre>
-
-<p>
-  The following elements and attributes allow you to specify the files to include in, and exclude
-  from, backup:
-</p>
-
-<ul>
-  <li>
-  <code>&lt;include&gt;</code>: Specifies a set of resources to
-  back up, instead of having the system back up all data in your app by default. If you specify
-  an <code>&lt;include&gt;</code> element, the system backs up <em>only the resources specified</em>
-  with this element. You can specify multiple sets of resources to back up by using multiple
-  <code>&lt;include&gt;</code> elements
-  </li>
-
-  <li>
-  <code>&lt;exclude&gt;</code>: Specifies any data you want the system to exclude
-  when it does a full backup. If you target the same set of resources with both the
-  <code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code> elements,
-  <code>&lt;exclude&gt;</code> takes precedence.
-  </li>
-
-  <li>
-  <code>domain</code>: Specifies the type of resource you want to include in,
-  or exclude from, backup. Valid values for this attribute include:
-
-
-
-  <ul>
-    <li>
-    <code>root</code>: Specifies that the resource is in the app’s root directory.
-    </li>
-
-    <li>
-    <code>file</code>: Specifies a resource in the directory returned by the
-    {@link android.content.Context#getFilesDir getFilesDir()} method.
-    </li>
-
-    <li>
-    <code>database</code>: Specifies a database that the
-    {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that
-    the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class.
-    </li>
-
-    <li>
-    <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object
-    that the {@link android.content.Context#getSharedPreferences getSharedPreferences()}
-    method returns.
-    </li>
-
-    <li>
-    <code>external</code>: Specifies that the resource is in external storage, and corresponds
-    to a file in the directory that the
-    {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns.
-    </li>
-  </ul>
-  </li>
-    <li>
-    <code>path</code>: Specifies the file path to a resource that you want to include in, or
-    exclude from, backup.
-    </li>
-
-  </li>
-</ul>
-
-
-<h3 id="disabling">Disabling data backups</h3>
-
-<p>
-  You can choose to prevent automatic backups of any of your app data by setting the
-  <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of
-  your manifest. This setting is illustrated in the following example:
-</p>
-
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        package="com.my.appexample"&gt;
-    &lt;uses-sdk android:minSdkVersion="23"/&gt;
-    &lt;uses-sdk android:targetSdkVersion="23"/&gt;
-    &lt;application ...
-<strong>        android:allowBackup="false"&gt;</strong>
-    &lt;/application&gt;
-    ...
-&lt;/manifest&gt;
-</pre>
-
-<h2 id="previous-androids">Support Lower Versions of Android</h2>
-
-<p>There are two scenarios in which you may also need to support versions of Android lower
-than 6.0 (API level 23): You may be updating your existing app to take advantage of the
-new auto backup functionality in Android 6.0, while wanting
-to continue supporting earlier versions of Android. Or you may be releasing a new app, but
-want to make sure devices running on versions of Android predating 6.0 also have backup
-functionality.</p>
-
-<h3 id="updating">Updating an existing app to support auto backup</h3>
-
-<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app
-defines a subclass of {@link android.app.backup.BackupAgent} and sets
-<a href="{@docRoot}guide/topics/manifest/application-element.html#agent">
-{@code android:backupAgent}</a> in its
-<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app
-used this legacy approach, you can transition to full-data backups by adding the
-{@code android:fullBackupOnly="true"} attribute to the
-<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a>
-element in the manifest. When running on a device with Android 5.1
-(API level 22) or lower, your app ignores this value in the manifest, and continues performing
-backups in the previous manner.</p>
-
-<p>Even if you’re not using key/value backups, you can still use the approach described above to do
-any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
-or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that
-approach to receive a notification when a restore operation happens in
-{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain
-the system's default implementation of
-<a href="#include-exclude">XML include/exclude rules handling</a>, call
-{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p>
-
-<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3>
-
-<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup
-for devices running on Android 5.1 (API level 22) and lower, you must also
-<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p>
-
-<h2 id="testing">Test Backup Configuration</h2>
-
-<p>
-  Once you have created a backup configuration, you should test it to make sure your app saves data
-  and can restore it properly.
-</p>
-
-
-<h3>Enabling Backup Logging</h3>
-
-<p>
-  To help determine how the backup feature is parsing your XML file, enable logging before
-  performing a test backup:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE
-</pre>
-
-<h3>Testing Backup</h3>
-
-<p>To manually run a backup, first initialize the Backup Manager by executing the following
-  command:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell bmgr run
-</pre>
-
-<p>
-  Next, manually back up your application using the following command. Use the
-  <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your app:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell bmgr fullbackup &lt;PACKAGE&gt;</pre>
-
-
-<h3>Testing restore</h3>
-
-<p>
-  To manually initiate a restore after the system has backed up your app data, execute the following
-  command, using the <code>&lt;PACKAGE&gt;</code> parameter to specify the package name for your
-  app:
-</p>
-
-<pre class="noprettyprint">
-$ adb shell bmgr restore &lt;PACKAGE&gt;
-</pre>
-
-<p class="warning">
-  <b>Warning:</b> This action stops your app and wipes its data before performing the restore
-  operation.
-</p>
-
-<p>
-  You can test automatic restore for your app by uninstalling and reinstalling your app. The app
-  data is automatically restored from the cloud once the app installation is complete.
-</p>
-
-
-<h3>Troubleshooting backups</h3>
-
-<p>
-  If backup fails, you can clear the backup data and associated metadata either by turning backup
-  off and on in <strong>Settings &gt; Backup</strong>, factory-resetting the device, or
-  executing this command:
-</p>
-
-<pre>$ adb shell bmgr wipe &lt;TRANSPORT&gt; &lt;PACKAGE&gt;</pre>
-
-<p>
-  You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value.
-  To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the
-  following command:
-</p>
-
-<pre>$ adb shell bmgr list transports</pre>
-
-<h2 id="gcm">Handle Google Cloud Messaging</h2>
-
-  <p>
-  For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud
-  Messaging</a> (GCM) for push notifications, backing up the registration
-  token that Google Cloud Messaging registration returned can cause unexpected behavior in
-  notifications for the restored app. This is because when a user installs your app on a new device,
-  the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register">
-  query the GCM API for a new registration token</a>. If the old registration is present, because the
-  system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue
-  from arising, exclude the registration token from the set of backed-up files.
-  </p>
diff --git a/docs/html/training/backup/backupapi.jd b/docs/html/training/backup/backupapi.jd
deleted file mode 100644
index 2f3e939..0000000
--- a/docs/html/training/backup/backupapi.jd
+++ /dev/null
@@ -1,200 +0,0 @@
-page.title=Using the Backup API
-parent.title=Backing up App Data to the Cloud
-parent.link=index.html
-
-trainingnavtop=true
-
-next.title=Making the Most of Google Cloud Messaging
-next.link=gcm.html
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>This lesson teaches you to</h2>
-    <ol>
-      <li><a href="#register">Register for the Android Backup Service</a></li>
-      <li><a href="#manifest">Configure Your Manifest</a></li>
-      <li><a href="#agent">Write Your Backup Agent</a></li>
-      <li><a href="#backup">Request a Backup</a></li>
-      <li><a href="#restore">Restore from a Backup</a></li>
-    </ol>
-    <h2>You should also read</h2>
-    <ul>
-      <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
-      <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a>
-      (Android 6.0 (API level 23) and higher)</li>
-    </ul>
-  </div>
-</div>
-
-<p>When a user purchases a new device or resets their existing one, they might
-expect that when Google Play restores your app back to their device during the
-initial setup, the previous data associated with the app restores as well. On versions of Android
-prior to 6.0 (API level 23), app data is not restored by default, and all the user's accomplishments
-or settings in your app are lost.</p>
-<p>For situations where the volume of data is relatively light (less than a
-megabyte), like the user's preferences, notes, game high scores or other
-stats, the Backup API provides a lightweight solution.  This lesson walks you
-through integrating the Backup API into your application, and restoring data to
-new devices using the Backup API.
-
-<p class="note">
-<strong>Note:</strong> Devices running Android 6.0 and higher
-<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a>
-nearly all data by default.
-</p>
-
-<h2 id="register">Register for the Android Backup Service</h2>
-<p>This lesson requires the use of the <a
-  href="{@docRoot}google/backup/index.html">Android Backup
-  Service</a>, which requires registration.  Go ahead and <a
-  href="http://code.google.com/android/backup/signup.html">register here</a>.  Once
-that's done, the service pre-populates an XML tag for insertion in your Android
-Manifest, which looks like this:</p>
-<pre>
-&lt;meta-data android:name="com.google.android.backup.api_key"
-android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
-</pre>
-<p>Note that each backup key works with a specific package name.  If you have
-different applications, register separate keys for each one.</p>
-
-
-<h2 id="manifest">Configure Your Manifest</h2>
-<p>Use of the Android Backup Service requires two additions to your application
-manifest.  First, declare the name of the class that acts as your backup agent,
-then add the snippet above as a child element of the Application tag.  Assuming
-your backup agent is going to be called {@code TheBackupAgent}, here's an example of
-what the manifest looks like with this tag included:</p>
-
-<pre>
-&lt;application android:label="MyApp"
-             android:backupAgent="TheBackupAgent"&gt;
-    ...
-    &lt;meta-data android:name="com.google.android.backup.api_key"
-    android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" /&gt;
-    ...
-&lt;/application&gt;
-</pre>
-<h2 id="agent">Write Your Backup Agent</h2>
-<p>The easiest way to create your backup agent is by extending the wrapper class
-{@link android.app.backup.BackupAgentHelper}.  Creating this helper class is
-actually a very simple process.  Just create a class with the same name as you
-used in the manifest in the previous step (in this example, {@code
-TheBackupAgent}),
-and extend {@code BackupAgentHelper}.  Then override the {@link
-android.app.backup.BackupAgent#onCreate()}.</p>
-
-<p>Inside the {@link android.app.backup.BackupAgent#onCreate()} method, create a {@link
-android.app.backup.BackupHelper}.  These helpers are
-specialized classes for backing up certain kinds of data.  The Android framework
-currently includes two such helpers:  {@link
-android.app.backup.FileBackupHelper} and {@link
-android.app.backup.SharedPreferencesBackupHelper}.  After you create the helper
-and point it at the data you want to back up, just add it to the
-BackupAgentHelper using the {@link android.app.backup.BackupAgentHelper#addHelper(String, BackupHelper) addHelper()}
-method, adding a key which is used to
-retrieve the data later.  In most cases the entire
-implementation is perhaps 10 lines of code.</p>
-
-<p>Here's an example that backs up a high scores file.</p>
-
-<pre>
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.FileBackupHelper;
-
-
-public class TheBackupAgent extends BackupAgentHelper {
-  // The name of the SharedPreferences file
-  static final String HIGH_SCORES_FILENAME = "scores";
-
-  // A key to uniquely identify the set of backup data
-  static final String FILES_BACKUP_KEY = "myfiles";
-
-  // Allocate a helper and add it to the backup agent
-  &#64;Override
-  void onCreate() {
-      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
-      addHelper(FILES_BACKUP_KEY, helper);
-  }
-}
-</pre>
-<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
-constructor can take a variable number of filenames.  You could just as easily
-have backed up both a high scores file and a game progress file just by adding
-an extra parameter, like this:</p>
-<pre>
-&#64;Override
-  void onCreate() {
-      FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
-      addHelper(FILES_BACKUP_KEY, helper);
-  }
-</pre>
-<p>Backing up preferences is similarly easy.  Create a {@link
-android.app.backup.SharedPreferencesBackupHelper}  the same way you did a {@link
-android.app.backup.FileBackupHelper}.  In this case, instead of adding filenames
-to the constructor, add the names of the shared preference groups being used by
-your application.  Here's an example of how your backup agent helper might look if
-high scores are implemented as preferences instead of a flat file:</p>
-
-<pre>
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.SharedPreferencesBackupHelper;
-
-public class TheBackupAgent extends BackupAgentHelper {
-    // The names of the SharedPreferences groups that the application maintains.  These
-    // are the same strings that are passed to getSharedPreferences(String, int).
-    static final String PREFS_DISPLAY = "displayprefs";
-    static final String PREFS_SCORES = "highscores";
-
-    // An arbitrary string used within the BackupAgentHelper implementation to
-    // identify the SharedPreferencesBackupHelper's data.
-    static final String MY_PREFS_BACKUP_KEY = "myprefs";
-
-    // Simply allocate a helper and install it
-    void onCreate() {
-       SharedPreferencesBackupHelper helper =
-                new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
-        addHelper(MY_PREFS_BACKUP_KEY, helper);
-    }
-}
-</pre>
-
-<p>You can add as many backup helper instances to your backup agent helper as you
-like, but remember that you only need one of each type.  One {@link
-android.app.backup.FileBackupHelper} handles all the files that you need to back up, and one
-{@link android.app.backup.SharedPreferencesBackupHelper} handles all the shared
-preferencegroups you need backed up.
-</p>
-
-
-<h2 id="backup">Request a Backup</h2>
-<p>In order to request a backup, just create an instance of the {@link
-android.app.backup.BackupManager}, and call it's {@link
-android.app.backup.BackupManager#dataChanged()} method.</p>
-
-<pre>
-import android.app.backup.BackupManager;
-...
-
-public void requestBackup() {
-  BackupManager bm = new BackupManager(this);
-  bm.dataChanged();
-}
-</pre>
-
-<p>This call notifies the backup manager that there is data ready to be backed
-up to the cloud.  At some point in the future, the backup manager then calls
-your backup agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput,
-ParcelFileDescriptor) onBackup()} method.  You can make
-the call whenever your data has changed, without having to worry about causing
-excessive network activity.  If you request a backup twice before a backup
-occurs, the backup only occurs once.</p>
-
-
-<h2 id="restore">Restore from a Backup</h2>
-<p>Typically you shouldn't ever have to manually request a restore, as it
-happens automatically when your application is installed on a device.  However,
-if it <em>is</em> necessary to trigger a manual restore, just call the
-{@link android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} method.</p>
diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd
deleted file mode 100644
index 4449fde..0000000
--- a/docs/html/training/backup/index.jd
+++ /dev/null
@@ -1,47 +0,0 @@
-page.title=Backing up App Data to the Cloud
-page.tags=cloud,sync,backup
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
-<ul>
-  <li>Android 2.2 (API level 8) and higher</li>
-</ul>
-</div>
-</div>
-
-<p>Users often invest significant time and effort creating data and setting
-preferences within apps. Preserving that data for users if they replace a broken
-device or upgrade to a new one is an important part of ensuring a great user
-experience.</p>
-
-<p>This class covers techniques for backing up data to the cloud so that
-users can restore their data when recovering from a data loss (such as a factory
-reset) or installing your application on a new device.</p>
-
-<p>It is important to note that the API for cloud backup changed with the
-release of Android 6.0 (API level 23). For your app to support backup both
-on devices running Android 6.0, and those running Android 5.1 (API level
-22) and lower, you must implement both techniques that this class explains.</p>
-
-<h2>Lessons</h2>
-
-<dl>
-	<dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt>
-	<dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish
-  seamless app data backup and restore with zero additional lines of application code.</dd>
-</dl>
-
-<dl>
-  <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
-  <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup
-  API into your Android app, so all of that  app's user data, such as preferences, notes, and high
-  scores, updates seamlessly across all devices linked to that Google account.</dd>
-</dl>
-
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index f42bf65..0cd0ce1 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -75,16 +75,14 @@
 <pre>
 public final class FeedReaderContract {
     // To prevent someone from accidentally instantiating the contract class,
-    // give it an empty constructor.
-    public FeedReaderContract() {}
+    // make the constructor private.
+    private FeedReaderContract() {}
 
     /* Inner class that defines the table contents */
-    public static abstract class FeedEntry implements BaseColumns {
+    public static class FeedEntry implements BaseColumns {
         public static final String TABLE_NAME = &quot;entry&quot;;
-        public static final String COLUMN_NAME_ENTRY_ID = &quot;entryid&quot;;
         public static final String COLUMN_NAME_TITLE = &quot;title&quot;;
         public static final String COLUMN_NAME_SUBTITLE = &quot;subtitle&quot;;
-        ...
     }
 }
 </pre>
@@ -103,10 +101,8 @@
 private static final String SQL_CREATE_ENTRIES =
     &quot;CREATE TABLE &quot; + FeedEntry.TABLE_NAME + &quot; (&quot; +
     FeedEntry._ID + &quot; INTEGER PRIMARY KEY,&quot; +
-    FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
     FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
-    ... // Any other options for the CREATE command
-    &quot; )&quot;;
+    FeedEntry.COLUMN_NAME_SUBTITLE + TEXT_TYPE + &quot; )&quot;;
 
 private static final String SQL_DELETE_ENTRIES =
     &quot;DROP TABLE IF EXISTS &quot; + FeedEntry.TABLE_NAME;
@@ -189,23 +185,22 @@
 
 // Create a new map of values, where column names are the keys
 ContentValues values = new ContentValues();
-values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
 values.put(FeedEntry.COLUMN_NAME_TITLE, title);
-values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
+values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle);
 
 // Insert the new row, returning the primary key value of the new row
-long newRowId;
-newRowId = db.insert(
-         FeedEntry.TABLE_NAME,
-         FeedEntry.COLUMN_NAME_NULLABLE,
-         values);
+long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);
 </pre>
 
 <p>The first argument for {@link android.database.sqlite.SQLiteDatabase#insert insert()}
-is simply the table name. The second argument provides
-the name of a column in which the framework can insert NULL in the event that the
-{@link android.content.ContentValues} is empty (if you instead set this to {@code "null"},
-then the framework will not insert a row when there are no values).</p>
+is simply the table name. </p>
+
+<p>The second argument tells the framework what to do in the event that the
+{@link android.content.ContentValues} is empty (i.e., you did not
+{@link android.content.ContentValues#put put} any values).
+If you specify the name of a column, the framework inserts a row and sets
+the value of that column to null. If you specify <code>null</code>, like in this
+code sample, the framework does not insert a row when there are no values.</p>
 
 
 
@@ -227,16 +222,19 @@
 String[] projection = {
     FeedEntry._ID,
     FeedEntry.COLUMN_NAME_TITLE,
-    FeedEntry.COLUMN_NAME_UPDATED,
-    ...
+    FeedEntry.COLUMN_NAME_SUBTITLE
     };
 
+// Filter results WHERE "title" = 'My Title'
+String selection = FeedEntry.COLUMN_NAME_TITLE + &quot; = ?&quot;;
+String[] selectionArgs = { &quot;My Title&quot; };
+
 // How you want the results sorted in the resulting Cursor
 String sortOrder =
-    FeedEntry.COLUMN_NAME_UPDATED + " DESC";
+    FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
 
 Cursor c = db.query(
-    FeedEntry.TABLE_NAME,  // The table to query
+    FeedEntry.TABLE_NAME,                     // The table to query
     projection,                               // The columns to return
     selection,                                // The columns for the WHERE clause
     selectionArgs,                            // The values for the WHERE clause
@@ -280,11 +278,11 @@
 
 <pre>
 // Define 'where' part of query.
-String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
+String selection = FeedEntry.COLUMN_NAME_TITLE + &quot; LIKE ?&quot;;
 // Specify arguments in placeholder order.
-String[] selectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { &quot;MyTitle&quot; };
 // Issue SQL statement.
-db.delete(table_name, selection, selectionArgs);
+db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
 </pre>
 
 
@@ -305,9 +303,9 @@
 ContentValues values = new ContentValues();
 values.put(FeedEntry.COLUMN_NAME_TITLE, title);
 
-// Which row to update, based on the ID
-String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
-String[] selectionArgs = { String.valueOf(rowId) };
+// Which row to update, based on the title
+String selection = FeedEntry.COLUMN_NAME_TITLE + &quot; LIKE ?&quot;;
+String[] selectionArgs = { &quot;MyTitle&quot; };
 
 int count = db.update(
     FeedReaderDbHelper.FeedEntry.TABLE_NAME,
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index a680c73..6f321e9 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -71,17 +71,17 @@
 <h2 id="LinearLayout">Create a Linear Layout</h2>
 
 <ol>
-  <li>From the <code>res/layout/</code> directory, open the
-    <code>activity_main.xml</code> file.
+  <li>In Android Studio's <b>Project</b> window, open <b>app > res >
+    layout > activity_main.xml</b>.
     <p>This XML file defines the layout of your activity. It contains the
       default "Hello World" text view.</p>
   </li>
   <li>When you open a layout file, you’re first shown the design editor in the
     <a href="/studio/write/layout-editor.html">Layout Editor</a>. For this lesson,
-    you work directly with the XML, so click the <b>Text</b> tab to switch to
-    the text editor.
+    you work directly with the XML, so click the <b>Text</b> tab at the bottom
+    of the window to switch to the text editor.
   </li>
-  <li>Replace the contents of the file with the following XML:
+  <li>Delete everything and insert the following XML:
     <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
@@ -138,6 +138,9 @@
 &lt;/LinearLayout&gt;
 </pre>
 
+<p>Don't worry about the error that appears for
+<code>&#64;string/edit_message</code>; you'll fix that soon.</p>
+
 <p>Here is a description of the attributes in the
   {@link android.widget.EditText &lt;EditText>} you added:</p>
 
@@ -157,7 +160,7 @@
   <p>A resource object is a unique integer name that's associated with an app resource,
 such as a bitmap, layout file, or string.</p>
   <p>Every resource has a
-corresponding resource object defined in your project's {@code gen/R.java} file. You can use the
+corresponding resource object defined in your project's {@code R.java} file. You can use the
 object names in the {@code R} class to refer to your resources, such as when you need to specify a
 string value for the <a
 href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
@@ -174,7 +177,7 @@
 <p>The plus sign (<code>+</code>) before the resource type is needed only when you're defining a
 resource ID for the first time. When you compile the app,
 the SDK tools use the ID name to create a new resource ID in
-your project's {@code gen/R.java} file that refers to the {@link
+your project's {@code R.java} file that refers to the {@link
 android.widget.EditText} element. With the resource ID declared once this way,
 other references to the ID do not
 need the plus sign. Using the plus sign is necessary only when specifying a new resource ID and not
@@ -211,10 +214,10 @@
 <h2 id="Strings">Add String Resources</h2>
 
 <p>By default, your Android project includes a string resource file at
-<code>res/values/strings.xml</code>. Here, you'll add two new strings.</p>
+<b>res > values > strings.xml</b>. Here, you'll add two new strings.</p>
 
 <ol>
-<li>From the <code>res/values/</code> directory, open <code>strings.xml</code>.</li>
+<li>From the <b>Project</b> window, open <b>res > values > strings.xml</b>.</li>
 <li>Add two strings so that your file looks like this:
 <pre>&lt;?xml version="1.0" encoding="utf-8"?>
 &lt;resources>
@@ -340,15 +343,12 @@
 
 <h2>Run Your App</h2>
 
-<p>This layout is applied by the default {@link android.app.Activity} class
-that the SDK tools generated when you created the project.</p>
-
-<p>To run the app and see the results,
-  click <strong>Run 'app'</strong>
+<p>To see how the app now looks on your device or emulator,
+  click <strong>Run</strong>
     <img src="{@docRoot}images/tools/as-run.png"
     style="vertical-align:baseline;margin:0; max-height:1em" /> in the
     toolbar.</p>
 
-<p>Continue to the <a href="starting-activity.html">next
-lesson</a> to learn how to respond to button presses, read content
-from the text field, start another activity, and more.</p>
\ No newline at end of file
+<p>To add app behaviors such as responding to a button and starting
+another activity, continue to the <a href="starting-activity.html">next
+lesson</a>.</p>
\ No newline at end of file
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index cad32bf..60be5f6 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -31,129 +31,71 @@
 <ol>
   <li>In Android Studio, create a new project:
     <ul>
-      <li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click <strong>
-        New Project</strong>.</li>
-      <li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New
-        Project</strong>. The <em>Create New Project</em> screen appears.</li>
+      <li>If you don't have a project opened, in the <strong>Welcome to Android Studio</strong> window, click <strong>
+        Start a new Android Studio project</strong>.</li>
+      <li>If you have a project opened, select <strong>File > New Project</strong>.</li>
     </ul>
   </li>
-  <li>Fill out the fields on the screen. For <strong>Application Name</strong>
-    use "My First App". For <strong>Company Domain</strong>, use "example.com".
-    For the other fields, use the default values and click <strong>Next</strong>
-    <p>Here's a brief explanation of each field:</p>
+  <li>In the <b>New Project</b> screen, enter the following values:</p>
     <ul>
-      <li><strong>Application Name</strong> is the app name that appears to users.</li>
-      <li><strong>Company domain</strong> provides a qualifier that will be appended to the package
-        name; Android Studio will remember this qualifier for each new project you create.</li>
-      <li><strong>Package name</strong> is the fully qualified name for the project (following the
-        same rules as those for naming packages in the Java programming language). Your package name
-        must be unique across all packages installed on the Android system. You can <strong>
-        Edit</strong> this value independently from the application name or the company
-        domain.</li>
-      <li><strong>Project location</strong> is the directory on your system that holds the project
-        files.</li>
+      <li><strong>Application Name</strong>: "My First App" </li>
+      <li><strong>Company Domain</strong>: "example.com"</li>
     </ul>
+    <p>Android Studio fills in the package name and project location for you,
+    but you can edit these if you'd like.
   </li>
-  <li>Under <strong>Target Android Devices</strong>, accept the default values
-    and click <strong>Next</strong>.
-    <p>The Minimum Required SDK is the earliest version of Android that your app supports,
-      indicated using the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
+  <li>Click <b>Next</b>.</li>
+  <li>In the <b>Target Android Devices</b> screen, keep the default values and
+    click <b>Next</b>.
+    <p>The <b>Minimum Required SDK</b> is the earliest version of Android that your app supports,
+      which is indicated by the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">
       API level</a>. To support as many devices as possible, you should set this to the lowest
       version available that allows your app to provide its core feature set. If any feature of your
-      app is possible only on newer versions of Android and it's not critical to the app's core
-      feature set, you can enable the feature only when running on the versions that support it (as
-      discussed in <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
+      app is possible only on newer versions of Android and it's not critical to the core
+      feature set, enable that feature only when running on the versions that support it (see
+      <a href="{@docRoot}training/basics/supporting-devices/platforms.html">
       Supporting Different Platform Versions</a>).</p>
     </li>
 
-  <li>Under <strong>Add an Activity to Mobile</strong>, select <strong>Empty
+  <li>In the <strong>Add an Activity to Mobile</strong> screen, select <strong>Empty
     Activity</strong> and click <strong>Next</strong>.
   </li>
 
-  <div class="sidebox-wrapper">
-    <div class="sidebox">
-      <h3>Activities</h3>
-      <p>An activity is one of the distinguishing features of the Android framework. Activities
-        provide the user with access to your app, and there may be many activities. An application
-        will usually have a main activity for when the user launches the application, another
-        activity for when she selects some content to view, for example, and other activities for
-        when she performs other tasks within the app. See <a href="{@docRoot}guide/components/activities.html">
-        Activities</a> for more information.</p>
-    </div>
-  </div>
-
-  <li>Under <strong>Customize the Activity</strong>, accept the default values
+  <li>In the <strong>Customize the Activity</strong> screen, keep the default values
     and click <strong>Finish</strong>.
 </ol>
 
-<p>Your Android project is now a basic "Hello World" app that contains some default files. Take a
-moment to review the most important of these:</p>
+<p>After some processing, Android Studio opens and displays a "Hello World" app
+with default files. You will add functionality to some of
+these files in the following lessons.</p>
+
+<p>Now take a moment to review the most important files. First, be sure that
+the <b>Project</b> window is open (select <b>View > Tool Windows > Project</b>)
+and the <b>Android</b> view is selected from the drop-down list at the top.
+You can then see the following files:</p>
 
 <dl>
-  <dt><code>app/src/main/java/com.example.myfirstapp/MainActivity.java</code></dt>
+  <dt><b>app > java > com.example.myfirstapp > MainActivity.java</b></dt>
   <dd>This file appears in Android Studio after the New Project wizard finishes.
     It contains the class definition for the activity you created earlier. When you build
     and run the app, the {@link android.app.Activity} starts and loads the
     layout file that says "Hello World!"</dd>
 
-  <dt><code>app/src/main/res/layout/activity_main.xml</code></dt>
+  <dt><b>app > res > layout > activity_main.xml</b></dt>
   <dd>This XML file defines the layout of the activity. It contains a {@code TextView}
     element with the text "Hello world!".</dd>
 
-  <dt><code>app/src/main/AndroidManifest.xml</code></dt>
+  <dt><b>app > manifests > AndroidManifest.xml</b></dt>
   <dd>The <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a> describes
     the fundamental characteristics of the app and defines each of its components. You'll revisit
     this file as you follow these lessons and add more components to your app.</dd>
-  <dt><code>app/build.gradle</code></dt>
+
+  <dt><b>Gradle Scripts > build.gradle</b></dt>
   <dd>Android Studio uses Gradle to compile and build your app. There is a <code>build.gradle</code>
     file for each module of your project, as well as a <code>build.gradle</code> file for the entire
-    project. Usually, you're only interested in the <code>build.gradle</code> file for the module,
-    in this case the <code>app</code> or application module. This is where your app's build dependencies
-    are set, including the <code>defaultConfig</code> settings:
-    <ul>
-      <li><code>compiledSdkVersion</code> is the platform version against which you will compile
-        your app. By default, this is set to the latest version of Android available in your SDK.
-        By default, this is set to the latest version of Android SDK installed on your
-        development machine.
-        You can still build your app to support older versions, but setting this to the latest
-        version allows you to enable new features and optimize your app for a great user experience
-        on the latest devices.</li>
-      <li><code>applicationId</code> is the fully qualified package name for your application that
-        you specified in the New Project wizard.</li>
-      <li><code>minSdkVersion</code> is the Minimum SDK version you specified during the New Project
-        wizard. This is the earliest version of the Android SDK that your app supports.</li>
-      <li><code>targetSdkVersion</code> indicates the highest version of Android with which you have
-        tested your application. As new versions of Android become available, you should
-        test your app on the new version and update this value to match the latest API level and
-        thereby take advantage of new platform features. For more information, read
-        <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
-          Platform Versions</a>.</li>
-    </ul>
-    <p>See <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>
-    for more information about Gradle.</p></dd>
-</dl>
-
-<p>Note also the <code>/res</code> subdirectories that contain the
-<a href="{@docRoot}guide/topics/resources/overview.html">resources</a> for your application:</p>
-<dl>
-  <dt><code>drawable<em>-&lt;density&gt;</em>/</code></dt>
-    <dd>Directories for <a href="{@docRoot}guide/topics/resources/drawable-resource.html">
-    drawable resources</a>, other than launcher icons, designed
-    for various <a href="{@docRoot}training/multiscreen/screendensities.html">densities</a>.
-</dd>
-  <dt><code>layout/</code></dt>
-    <dd>Directory for files that define your app's user interface like {@code activity_main.xml},
-      discussed above, which describes a basic layout for the {@code MainActivity}
-      class.</dd>
-  <dt><code>menu/</code></dt>
-    <dd>Directory for files that define your app's menu items.</dd>
-  <dt><code>mipmap/</code></dt>
-    <dd>Launcher icons reside in the {@code mipmap/} folder rather than the
-    {@code drawable/} folders. This folder contains the {@code ic_launcher.png} image
-    that appears when you run the default app.</dd>
-  <dt><code>values/</code></dt>
-    <dd>Directory for other XML files that contain a collection of resources, such as
-      string and color definitions.</dd>
+    project. Usually, you're only interested in the <code>build.gradle</code> file for the module.
+    in this case the <code>app</code> or application module. For more information about this file,
+    see <a href="{@docRoot}studio/build/index.html">Building Your Project with Gradle</a>.</dd>
 </dl>
 
 <p>
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
index e809871..085849f 100755
--- a/docs/html/training/basics/firstapp/running-app.jd
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -3,9 +3,7 @@
 parent.link=index.html
 
 trainingnavtop=true
-
 page.tags=emulator
-helpoutsWidget=true
 
 @jd:body
 
@@ -18,7 +16,7 @@
 
 <ol>
   <li><a href="#RealDevice">Run on a Real Device</a></li>
-  <li><a href="#Emulator">Run on the Emulator</a></li>
+  <li><a href="#Emulator">Run on an Emulator</a></li>
 </ol>
 
 <h2>You should also read</h2>
@@ -34,8 +32,10 @@
 
 
 <p>In the <a href="creating-project.html">previous lesson</a>, you created an
-  Android project. The project contains a default app that displays
-  "Hello World". In this lesson, you will run the app on a device or emulator.</p>
+Android project that displays "Hello World." You can now run the app on a real
+device or on an emulator. If you don't have a real device available, skip to
+<a href="#Emulator">Run on an Emulator</a>.</p>
+
 
 <h2 id="RealDevice">Run on a Real Device</h2>
 
@@ -68,7 +68,7 @@
 <p>Android Studio installs the app on your connected device and starts it.</p>
 
 
-<h2 id="Emulator">Run on the Emulator</h2>
+<h2 id="Emulator">Run on an Emulator</h2>
 
 <p>Before you run your app on an emulator, you need to create an
   <a href="{@docRoot}tools/devices/index.html">Android Virtual Device</a> (AVD)
@@ -82,12 +82,14 @@
     <strong>Tools &gt; Android &gt; AVD Manager</strong>, or by clicking
     the AVD Manager icon <img src="{@docRoot}images/tools/avd-manager-studio.png"
     style="vertical-align:bottom;margin:0;height:19px"> in the toolbar.</li>
-  <li>On the AVD Manager main screen, click <strong>Create Virtual Device</strong>.</li>
-  <li>In the Select Hardware page, select a phone device, such as Nexus 6,
-    then click <strong>Next</strong>.
+  <li>In the <b>Your Virtual Devices</b> screen, click <strong>Create Virtual Device</strong>.</li>
+  <li>In the <b>Select Hardware</b> screen, select a phone device, such as Nexus 6,
+    and then click <strong>Next</strong>.
   </li>
-  <li>In the Select Image page, choose the desired system image for the AVD and
+  <li>In the <b>System Image</b> screen, choose the desired system image for the AVD and
     click <strong>Next</strong>.
+    <p>If you don't have a particular system image installed,
+    you can get it by clicking the <b>download</b> link.</p>
   </li>
   <li>Verify the configuration settings (for your first AVD, leave all the
     settings as they are), and then click <strong>Finish</strong>.
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index ebf42cb..4385d13 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -38,7 +38,7 @@
 <h2 id="RespondToButton">Respond to the Send Button</h2>
 
 <ol>
-  <li>In the file <code>res/layout/activity_main.xml</code>, add the
+  <li>In the file <b>res > layout > activity_main.xml</b>, add the
     <a href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
     attribute to the {@link android.widget.Button &lt;Button&gt;} element as
     shown below:
@@ -52,7 +52,7 @@
       method in your activity whenever a user clicks on the button.</p>
   </li>
 
-  <li>In the file <code>java/com.example.myfirstapp/MainActivity.java</code>,
+  <li>In the file <b>java > com.example.myfirstapp > MainActivity.java</b>,
     add the <code>sendMessage()</code> method stub as shown below:
 
     <pre>public class MainActivity extends AppCompatActivity {
@@ -85,7 +85,9 @@
 <p>Next, you’ll fill in this method to read the contents of the text field and deliver that text to
 another activity.</p>
 
+
 <h2 id="BuildIntent">Build an Intent</h2>
+
 <p>An {@link android.content.Intent} is an object that provides runtime binding
   between separate components (such as two activities). The
   {@link android.content.Intent} represents an app’s "intent to do something."
@@ -113,13 +115,22 @@
     }
 }</pre>
 
-<p class="note"><strong>Note: </strong>Android Studio will display
-  <code>Cannot resolve symbol</code> errors because the code references classes
-  like {@link android.content.Intent} and {@link android.widget.EditText}
-  that have not been imported. To import these classes, you can either 1)
-  use Android Studio's "import class" functionality by pressing Alt + Enter
-  (Option + Return on Mac) or 2) manually add import statements at the top of
-  the file.</p>
+<p>Android Studio will display <b>Cannot
+resolve symbol</b> errors because this code references classes that are not
+imported. You can solve some of these with Android Studio's "import class"
+functionality by pressing Alt + Enter (or Option + Return on Mac).
+Your imports should end up as the following:</p>
+<pre>
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+</pre>
+
+<p>An error remains for <code>DisplayMessageActivity</code>, but that's okay;
+you'll fix that in the next section.
+
 
 <p>There’s a lot going on in <code>sendMessage()</code>, so let’s explain
   what's going on.</p>
@@ -150,6 +161,7 @@
   method starts an instance of the <code>DisplayMessageActivity</code> specified
   by the {@link android.content.Intent}. Now you need to create the class.</p>
 
+
 <h2 id="CreateActivity">Create the Second Activity</h2>
 
 <ol>
@@ -169,7 +181,8 @@
   <li>Creates the corresponding layout file <code>activity_display_message.xml</code>
     </li>
   <li>Adds the required
-    <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+    <a href="{@docRoot}guide/topics/manifest/activity-element.html"
+    ><code>&lt;activity&gt;</code></a>
     element in <code>AndroidManifest.xml</code>.
 </ul>
 
@@ -199,7 +212,16 @@
    layout.addView(textView);
 }</pre>
   </li>
-  <li>Press Alt + Enter (option + return on Mac) to import missing classes.</li>
+  <li>Press Alt + Enter (or Option + Return on Mac) to import missing classes.
+  Your imports should end up as the following:
+<pre>
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.TextView;
+</pre>
+</li>
 </ol>
 
 <p>There’s a lot going on here, so let’s explain:</p>
diff --git a/docs/html/training/basics/network-ops/data-saver.jd b/docs/html/training/basics/network-ops/data-saver.jd
index 75b7264..babf7c6 100644
--- a/docs/html/training/basics/network-ops/data-saver.jd
+++ b/docs/html/training/basics/network-ops/data-saver.jd
@@ -45,7 +45,7 @@
 </p>
 
 <p>
-  The N Developer Preview extends the {@link android.net.ConnectivityManager}
+  Android 7.0 (API level 24) extends the {@link android.net.ConnectivityManager}
   API to provide apps with a way to <a href="#status">retrieve the user’s Data
   Saver preferences</a> and <a href="#monitor-changes">monitor preference
   changes</a>. It is considered good practice for apps to check whether the
@@ -58,7 +58,7 @@
 </h2>
 
 <p>
-  In the N Developer Preview, apps can use the {@link
+  In Android 7.0 (API level 24), apps can use the {@link
   android.net.ConnectivityManager} API to determine what data usage
   restrictions are being applied. The {@code getRestrictBackgroundStatus()}
   method returns one of the following values:
diff --git a/docs/html/training/best-performance.jd b/docs/html/training/best-performance.jd
index 8ea6fd5..bb88e99 100644
--- a/docs/html/training/best-performance.jd
+++ b/docs/html/training/best-performance.jd
@@ -5,4 +5,9 @@
 
 
 <p>These classes and articles help you build an app that's smooth, responsive,
-and uses as little battery as possible.</p>
\ No newline at end of file
+and uses as little battery as possible.</p>
+
+<p>Along with this section, you can find additional information about optimizing
+your app in the <a href="/topic/performance/index.html">Performance and
+Power</a> section.</p>
+
diff --git a/docs/html/training/camera/videobasics.jd b/docs/html/training/camera/videobasics.jd
index 6da239a..b20cfef 100644
--- a/docs/html/training/camera/videobasics.jd
+++ b/docs/html/training/camera/videobasics.jd
@@ -108,7 +108,7 @@
 
 <pre>
 &#64;Override
-protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
     if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
         Uri videoUri = intent.getData();
         mVideoView.setVideoURI(videoUri);
diff --git a/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png
new file mode 100644
index 0000000..1e4867e
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/alignment-constraint_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png
new file mode 100644
index 0000000..afe7d4a
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/baseline-constraint_2x.png b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png
new file mode 100644
index 0000000..dfc3522
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png
new file mode 100644
index 0000000..be9d54f
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/constraint-fail_2x.png b/docs/html/training/constraint-layout/images/constraint-fail_2x.png
new file mode 100644
index 0000000..3f28ef7
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/constraint-fail_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png
new file mode 100644
index 0000000..ace31a6
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png
new file mode 100644
index 0000000..0768022
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png
new file mode 100644
index 0000000..b4ffb2c
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png
new file mode 100644
index 0000000..72a4e40
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/parent-constraint_2x.png b/docs/html/training/constraint-layout/images/parent-constraint_2x.png
new file mode 100644
index 0000000..0414f1d
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/parent-constraint_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/position-constraint_2x.png b/docs/html/training/constraint-layout/images/position-constraint_2x.png
new file mode 100644
index 0000000..9f93e72
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/position-constraint_2x.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png
new file mode 100644
index 0000000..f863e5f
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png
new file mode 100644
index 0000000..d61e9b2
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png
new file mode 100644
index 0000000..9747102
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png
new file mode 100644
index 0000000..940b8495
--- /dev/null
+++ b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png
Binary files differ
diff --git a/docs/html/training/constraint-layout/index.html b/docs/html/training/constraint-layout/index.html
new file mode 100644
index 0000000..62eaf15
--- /dev/null
+++ b/docs/html/training/constraint-layout/index.html
@@ -0,0 +1,498 @@
+<html devsite>
+<head>
+  <title>Build a Responsive UI with ConstraintLayout</title>
+  <meta name="book_path" value="/training/_book.yaml" />
+  <meta name="top_category" value="develop" />
+  <meta name="subcategory" value="training" />
+</head>
+<body>
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#constraints-overview">Constraints overview</a></li>
+    <li><a href="#add-constraintlayout-to-your-project">Add ConstraintLayout to your project</a></li>
+    <li><a href="#add-a-constraint">Add a constraint</a></li>
+    <li><a href="#use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</a></li>
+    <li><a href="#adjust-the-view-size">Adjust the view size</a></li>
+    <li><a href="#adjust-the-constraint-bias">Adjust the constraint bias</a></li>
+    <li><a href="#adjust-the-view-margins">Adjust the view margins</a></li>
+  </ol>
+</div>
+</div>
+
+
+<p><code>ConstraintLayout</code> allows you to create large and complex layouts with a flat view
+hierarchy (no nested view groups). It's similar to <code>RelativeLayout</code> in that all views are
+layed out according to relationships between sibling views and the parent layout, but it's more
+flexible than <code>RelativeLayout</code> and easier to use with Android Studio's Layout Editor.
+</p>
+
+<p>Everything you can do with <code>ConstraintLayout</code> is available directly from the Layout Editor's visual
+tools, because the layout API and the Layout Editor were specially built for each other. So you can
+build your layout with <code>ConstraintLayout</code> entirely by drag-and-dropping instead of editing the XML.
+</p>
+
+<img src="/training/constraint-layout/images/layout-editor_2-2_2x.png" alt=""
+  width="640"/>
+<p class="img-caption"><b>Figure 1.</b> A <code>ConstraintLayout</code> in the Layout Editor</p>
+
+
+<p>
+<code>ConstraintLayout</code> is available in an API library that's compatible with Android
+2.3 (API level 9) and higher, and the new layout editor is available in Android
+Studio 2.2 and higher.
+</p>
+
+<p>
+This page provides a guide to building a layout with <code>ConstraintLayout</code> in Android
+Studio. If you'd like more information about the Layout Editor itself, see the
+Android Studio guide to <a href="/studio/write/layout-editor.html">Build a UI with
+Layout Editor</a>.
+</p>
+
+
+<h2 id="constraints-overview">Constraints overview</h2>
+<p>
+To define a view's position in <code>ConstraintLayout</code>, you must add two
+or more <em>constraints</em> for the view. Each constraint represents a connection or
+alignment to another view, the parent layout, or an invisible guideline. Each
+constraint defines the view's position along either the
+vertical or horizontal axis; so each view must have a minimum of one constraint for each
+axis, but often more are necessary.
+</p>
+
+<p>
+When you drop a view into the Layout Editor, it stays where you leave it even if
+it has no constraints. However, this is only to make editing easier; if a view has
+no constraints when you run your layout on a device, it is drawn at
+position [0,0] (the top-left corner).</p>
+
+<p>In figure 2, the layout looks good in the
+editor, but there's no vertical constraint on <code>TextView B</code>. When this
+layout draws on a device, <code>TextView B</code> horizontally aligns with the left and
+right edges of the <code>ImageView</code>, but appears at the top of the screen because
+it has no vertical constraint.
+</p>
+
+<div class="cols">
+<div class="col-1of2">
+<img src="/training/constraint-layout/images/constraint-fail_2x.png" width="100%" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> <code>TextView B</code> is missing a
+vertical constraint</p>
+</div>
+<div class="col-1of2">
+<img src="/training/constraint-layout/images/constraint-fail-fixed_2x.png" width="100%" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> <code>TextView B</code> is now vertically
+constrained to the <code>ImageView</code></p>
+</div>
+</div>
+
+<p>
+Although a missing constraint won't cause a compilation error, the Layout Editor
+indicates missing constraints as an error in the toolbar. To view the errors and
+other warnings, click <strong>Show Warnings and Errors</strong>
+<img src="/studio/images/buttons/layout-editor-errors.png" class="inline-icon" alt="" />.
+To help you avoid missing constraints, the Layout Editor can automatically add
+constraints for you with the <a
+href="#use-autoconnect-and-infer-constraints">Autoconnect and infer
+constraints</a> features.
+</p>
+
+
+<h2 id="add-constraintlayout-to-your-project">Add ConstraintLayout to your project</h2>
+<p>
+To use <code>ConstraintLayout</code> in your project, proceed as follows:
+</p>
+
+<ol>
+<li>Ensure you have the latest Constraint Layout library:
+<ol>
+ <li>Click <strong>Tools > Android > SDK Manager</strong>.
+ <li>Click the <strong>SDK Tools</strong> tab.
+ <li>Expand <strong>Support Repository</strong> and then check
+<b>ConstraintLayout for Android</b> and <b>Solver for ConstraintLayout</b>.
+Check <b>Show Package Details</b> and take note of the version you're downloading
+(you'll need this below).</p>
+ <li>Click <strong>OK</strong>.
+<li>Add the ConstraintLayout library as a dependency in your module-level
+  <code>build.gradle</code> file:
+<pre>
+dependencies {
+    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
+}
+</pre>
+  <p>The library version you download may be higher, so be sure the value you specify
+  here matches the version from step 3.</p>
+</li>
+<li>In the toolbar or sync notification, click <strong>Sync Project with Gradle
+Files</strong>.</li>
+</ol>
+</li>
+</ol>
+
+<p>Now you're ready to build your layout with <code>ConstraintLayout</code>.</p>
+
+<h3 id="convert">Convert a layout</h3>
+
+<div class="figure" style="width:415px">
+<img src="/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png"
+  width="415" alt="" />
+<p class="img-caption">
+  <b>Figure 4.</b> The menu to convert a layout to <code>ConstraintLayout</code></p>
+</div>
+
+<p>To convert an existing layout to a constraint layout, follow these steps:</p>
+<ol>
+<li>Open your layout in Android Studio and click the <strong>Design</strong> tab
+at the bottom of the editor window.
+<li>In the <strong>Component Tree</strong> window, right-click the layout and
+click <strong>Convert <em>layout</em> to ConstraintLayout</strong>.</li>
+</ol>
+
+<h3 id="createNew">Create a new layout</h3>
+
+<p>To start a new constraint layout file, follow these steps:</p>
+<ol>
+<li>Click anywhere in the <strong>Project</strong> window and then select
+<strong>File > New > XML > Layout XML</strong>.
+<li>Enter a name for the layout file and enter
+"android.support.constraint.ConstraintLayout" for the <b>Root Tag</b>.
+<li>Click <strong>Finish</strong>.</li>
+</ol>
+
+
+<h2 id="add-a-constraint">Add a constraint</h2>
+
+<p>Start by dragging a view from the <b>Palette</b> window into the editor.
+When you add a view in a <code>ConstraintLayout</code>, it displays a bounding box with square
+resizing handles on each corner and circular constraint handles on each side.
+</p>
+
+
+<div class="figure" style="width:460px">
+<div class="video-wrapper">
+<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-first.png"
+  onclick="this.play()" width="460">
+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-first.mp4" type="video/mp4">
+  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-first" alt="" />
+</video>
+</div>
+<p class="img-caption">
+<strong>Video 1. </strong>The left side of a view is constrained to the left side of the parent
+</p>
+</div>
+
+<p>
+Click the view to select it. Then click-and-hold one of the
+constraint handles and drag the line to an available anchor point (the edge of
+another view, the edge of the layout, or a guideline). When you release, the
+constraint is made, with <a href="#adjust-the-view-margins">a default margin</a>
+separating the two views.
+</p>
+
+<p>When creating constraints, remember the following rules:</p>
+
+<ul>
+<li>Every view must have at least two constraints: one horizontal and one
+vertical.
+<li>You can create constraints only between a constraint handle and an anchor
+point that share the same plane. So a vertical plane (the left and right sides)
+of a view can be constrained only to another vertical plane; and baselines can
+constrain only to other baselines.
+<li>Each constraint handle can be used for just one constraint, but you can
+create multiple constraints (from different views) to the same anchor
+point.</li>
+</ul>
+
+
+
+<div class="figure" style="width:460px">
+<div class="video-wrapper">
+<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-second.png"
+  onclick="this.play()" width="460">
+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-second.mp4" type="video/mp4">
+  <img src="/training/constraint-layout/images/thumbnail-studio-constraint-second.png" alt="" />
+</video>
+</div>
+<p class="img-caption">
+<strong>Video 2. </strong>Adding a constraint that opposes an existing one
+</p>
+</div>
+
+
+
+<p>
+To remove a constraint, select the view and then click the constraint handle.
+</p>
+
+<p>If you add opposing constraints on a view, the constraint lines become squiggly
+like a spring to indicate the opposing forces, as shown in video 2. The effect
+is most visible when the view size is set to "fixed" or "wrap content," in which
+case the view is centered between the constraints. If you instead
+want the view to stretch its size to meet the constraints, <a
+href="#adjust-the-view-size">switch the size to "any size"</a>; or if you want
+to keep the current size but move the view so that it is not centered, <a
+href="#adjust-the-constraint-bias">adjust the constraint bias</a>.
+</p>
+
+
+
+<p>
+There are many ways to constrain a view, but the following constraint types
+provide the basic building blocks.
+</p>
+
+
+
+
+<h3>Parent constraint</h3>
+<div class="cols">
+<div class="col-2of3">
+  <p>
+  Connect the side of a view to the corresponding edge of the layout.
+  <p>
+  In figure 5, the left side of a view is connected to the left edge of the
+  parent layout.
+  <p>
+</div>
+<div class="col-1of3">
+  <img src="/training/constraint-layout/images/parent-constraint_2x.png" width="100%" alt="">
+  <p class="img-caption"><strong>Figure 5. </strong>A horizontal constraint to the parent</p>
+</div>
+</div>
+
+
+<h3>Position constraint</h3>
+<div class="cols">
+<div class="col-2of3">
+<p>Define the order of appearance for two views, either vertically or horizontally.</p>
+<p>In figure 6, a <code>Button</code> is constrained below an <code>ImageView</code> with a 24dp
+margin.</p>
+</div>
+<div class="col-1of3">
+  <img src="/training/constraint-layout/images/position-constraint_2x.png" width="100%" alt="">
+  <p class="img-caption"><strong>Figure 6.</strong> A vertical position constraint</p>
+</div>
+</div>
+
+
+
+<h3>Alignment constraint</h3>
+<div class="cols">
+<div class="col-1of3">
+<p>Align the edge of a view to the same edge of another view.<p>
+<p>In figure 7, the left side of a <code>Button</code> is aligned to the left side of an
+<code>ImageView</code>.</p>
+<p>You can offset the alignment by dragging the view
+inward from the constraint. For example, figure 8 shows the same
+<code>Button</code> with a 24dp offset alignment.
+The offset is defined by the constrained view's margin.</p>
+</div>
+<div class="col-1of3">
+  <img src="/training/constraint-layout/images/alignment-constraint_2x.png" width="100%" alt="">
+  <p class="img-caption"><strong>Figure 7.</strong> A horizontal alignment constraint</p>
+</div>
+<div class="col-1of3">
+  <img src="/training/constraint-layout/images/alignment-constraint-offset_2x.png" width="100%"
+    alt="">
+  <p class="img-caption"><strong>Figure 8.</strong> An offset horizontal alignment constraint</p>
+</div>
+</div>
+
+
+<h3>Baseline alignment constraint</h3>
+<div class="cols">
+<div class="col-2of3">
+<p>Align the text baseline of a view to the text baseline of another view.</p>
+<p>In figure 9, the first line of a <code>TextView</code> is aligned with the text in a
+<code>Button</code>.</p>
+<p>To create a baseline constraint, hover your mouse over the baseline handle for
+two seconds until the handle blinks white. Then click and drag the line to
+another baseline.</p>
+</div>
+<div class="col-1of3">
+  <img src="/training/constraint-layout/images/baseline-constraint_2x.png" width="100%" alt="">
+  <p class="img-caption"><strong>Figure 9.</strong> A baseline alignment constraint</p>
+</div>
+</div>
+
+
+
+
+
+<h3 id="constrain-to-a-guideline">Constrain to a guideline</h3>
+<div class="cols">
+<div class="col-1of2">
+
+<p>
+You can add a vertical or horizontal guideline to which you can attach
+constraints. You can position the guideline within the layout based on either dp
+units or percent, relative to the layout's edge.
+</p>
+
+<p>
+To create a guideline, click <strong>Guidelines</strong>
+<img src="/studio/images/buttons/layout-editor-guidelines.png" class="inline-icon" alt="" />
+in the toolbar, and then click either <strong>Add Vertical Guideline</strong>
+or <strong>Add Horizontal Guideline</strong>.
+</p>
+
+<p>
+Click the circle at the edge of the guideline to toggle the measurements used to
+position the guideline (either percent or dp units from the layout's edge).
+</p>
+
+<p>
+Guidelines are not visible to your users.
+</p>
+</div>
+
+<div class="col-1of2">
+  <div class="video-wrapper">
+  <video controls poster="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png"
+    onclick="this.play()" width="100%">
+    <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/add-layout-guideline_2-2.mp4" type="video/mp4">
+    <img src="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png" alt="" />
+  </video>
+  </div>
+  <p class="img-caption"><strong>Video 3.</strong> Adding a constraint to a guideline</p>
+</div>
+</div>
+
+
+<h2 id="use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</h2>
+
+<div class="figure" style="width:460px">
+<div class="video-wrapper">
+<video controls poster=""
+  onclick="this.play()" width="460">
+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/constraint-autoconnect_2-2.mp4" type="video/mp4">
+</video>
+</div>
+<p class="img-caption"><b>Video 4.</b> Adding a view with Autoconnect enabled</p>
+</div>
+
+<p>
+Autoconnect is a persistent mode that automatically creates two or more
+constraints for each view you add to the layout. Autoconnect is disabled by
+default. You can enable it by clicking <strong>Turn on Autoconnect</strong>
+<img src="/studio/images/buttons/layout-editor-autoconnect-on.png" class="inline-icon" alt="" />
+in the Layout Editor toolbar.
+</p>
+
+<p>While enabled, Autoconnect creates constraints for each view as you add them; it does not create
+constraints for existing views in the layout. If you drag a view once the constraints are made, the
+constraints do not change (though the margins do), so you must delete the constraints if you want to
+significantly reposition the view.</p>
+
+<p>Alternatively, you can click  <strong>Infer Constraints</strong>
+<img src="/studio/images/buttons/layout-editor-infer.png" class="inline-icon" alt="" />
+to create constraints for all views in the layout.
+</p>
+
+<p>Infer Constraints is a one-time action that scans the entire layout to determine the most
+effective set of constraints for all views, so it may create constraints between elements that are
+far from each other. Autoconnect, however, creates constraints only for the view you are adding, and
+it creates constraints to only the nearest elements. In either case, you can always modify a
+constraint by clicking the constraint handle to delete it, and then create a new constraint.</p>
+
+
+<h2 id="adjust-the-view-size">Adjust the view size</h2>
+
+<p>
+You can use the handles on each corner of the view to resize it, but doing so
+hard codes the width and height values, which you should avoid for most views
+because hard-coded view sizes cannot adapt to different content and screen
+sizes. To select from one of the dynamic sizing modes or to define more specific
+dimensions, click a view and open the <strong>Properties</strong>
+<img src="/studio/images/buttons/window-properties.png" class="inline-icon" alt="" />
+window on the right side of the editor. At the top of the window is the view
+inspector, as shown in figure 10.
+</p>
+<div class="figure" style="width:287px" >
+<img src="/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png" alt=""
+  width="287" />
+<p class="img-caption"><strong>Figure 10.</strong> The <b>Properties</b> window includes controls for
+<strong>(1)</strong> view size, <strong>(2)</strong> margins, and
+<strong>(3)</strong> constraint bias.</p>
+</div>
+
+<p>
+The grey square represents the selected view. The symbols inside the square
+represent the height and width settings as follows:
+</p>
+
+<ul>
+<li>
+<img src="/studio/images/buttons/layout-width-wrap.png" class="inline-icon" alt="" />
+ <strong>Wrap Content</strong>: The view expands exactly as needed to fit its
+contents.
+<li>
+<img src="/studio/images/buttons/layout-width-match.png" class="inline-icon" alt="" />
+ <strong>Any Size</strong>: The view expands exactly as needed to match the
+constraints. The actual value is 0dp because the view has no desired dimensions, but
+it resizes as needed to meet the constraints. However, if the given dimension
+has only one constraint, then the view expands to fit its contents. Another way
+to think of it is "match constraints" (instead of <code>match_parent</code>) because it
+expands the view as much as possible after accounting for the limits of each
+constraint and its margins.
+<li>
+<img src="/studio/images/buttons/layout-width-fixed.png" class="inline-icon" alt="" />
+ <strong>Fixed</strong>: You specify the dimension in the text box below or by
+resizing the view in the editor.</li>
+</ul>
+
+<p>To toggle between these settings, click the symbols.</p>
+
+<p class="note"><strong>Note</strong>: You should not use <code>match_parent</code> for any view
+in a <code>ConstraintLayout</code>. Instead use "Any Size" (<code>0dp</code>).
+</p>
+
+
+<h2 id="adjust-the-constraint-bias">Adjust the constraint bias</h2>
+
+<p>When you add a constraint to both sides of a view (and the view size for the same dimension is
+either "fixed" or "wrap content"), the view becomes centered between the two anchor points by
+default. When a view is centered, the bias is 50%. You can adjust the bias by dragging the bias
+slider in the <b>Properties</b> window or by dragging the view, as shown in video 5.</p>
+
+<div class="video-wrapper" style="max-width:740px">
+<video controls poster="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png"
+  onclick="this.play();$(this.parentElement).addClass('playing');">
+  <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/adjust-constraint-bias.mp4" type="video/mp4">
+  <img src="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png" alt="" />
+</video>
+</div>
+<p class="img-caption"><b>Video 5.</b> Adjusting the constraint bias</p>
+
+<p>If you instead want the view to stretch its size to meet the constraints, <a href="#adjust-the-
+view-size">switch the size to "any size"</a>.</p>
+
+
+<h2 id="adjust-the-view-margins">Adjust the view margins</h2>
+
+<p> To ensure that all your views are evenly spaced, click <strong>Margin</strong> <img
+src="/studio/images/buttons/layout-editor-margin.png" class="inline-icon" alt="" /> in the toolbar
+to select the default margin for each view that you add to the layout. The button changes to show
+your current margin selection. Any change you make to the default margin applies only to the views
+you add from then on. </p>
+
+
+<img src="/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png"
+ alt="" width="232"/>
+<p class="img-caption"><strong>Figure 11.</strong> The toolbar's <b>Margin</b> button.
+Click to adjust the default margin.
+</p>
+
+<p> You can control the margin for each view in the <strong>Properties</strong> window by clicking
+the number on the line that represents each constraint (in figure 10, the margins are each set to
+16dp). </p>
+
+<p> All margins offered by the tool are factors of 8dp to help your views align to Material Design's
+<a href="https://material.google.com/layout/metrics-keylines.html">8dp square grid
+recommendations</a>. </p>
+
+</body>
+</html>
diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
index d286440..6c9616b 100644
--- a/docs/html/training/contacts-provider/display-contact-badge.jd
+++ b/docs/html/training/contacts-provider/display-contact-badge.jd
@@ -113,10 +113,10 @@
 <p>
     For Android 3.0 (API level 11) and later, include the following columns in your projection:</p>
 <ul>
-    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
-    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
     <li>
-        {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI
+        {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI
         Contacts.PHOTO_THUMBNAIL_URI}
     </li>
 </ul>
@@ -124,8 +124,8 @@
     For Android 2.3.3 (API level 10) and earlier, use the following columns:
 </p>
 <ul>
-    <li>{@link android.provider.BaseColumns#_ID Contacts._ID}</li>
-    <li>{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
 </ul>
 <p>
     The remainder of this lesson assumes that you've already loaded a
@@ -187,14 +187,14 @@
 </p>
 <p class="note">
     <strong>Note:</strong> The
-    {@link android.provider.ContactsContract.ContactsColumns#PHOTO_THUMBNAIL_URI} column isn't available
+    {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI} column isn't available
     in platform versions prior to 3.0. For those versions, you must retrieve the URI
     from the {@link android.provider.ContactsContract.Contacts.Photo Contacts.Photo} subtable.
 </p>
 <p>
     First, set up variables for accessing the {@link android.database.Cursor} containing the
-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
     described previously:
 </p>
 <pre>
diff --git a/docs/html/training/contacts-provider/modify-data.jd b/docs/html/training/contacts-provider/modify-data.jd
index e993c56..64853ef 100644
--- a/docs/html/training/contacts-provider/modify-data.jd
+++ b/docs/html/training/contacts-provider/modify-data.jd
@@ -196,8 +196,8 @@
     Contacts.CONTENT_LOOKUP_URI}, call
     {@link android.provider.ContactsContract.Contacts#getLookupUri
     Contacts.getLookupUri(id, lookupkey)} with the contact's
-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
     arguments.
 </p>
 <p>
diff --git a/docs/html/training/contacts-provider/retrieve-details.jd b/docs/html/training/contacts-provider/retrieve-details.jd
index a463b75..0de3b67 100644
--- a/docs/html/training/contacts-provider/retrieve-details.jd
+++ b/docs/html/training/contacts-provider/retrieve-details.jd
@@ -55,11 +55,11 @@
 <p>
     To retrieve all the details for a contact, search the
     {@link android.provider.ContactsContract.Data} table for any rows that contain the contact's
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}. This column is available in
+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY}. This column is available in
     the {@link android.provider.ContactsContract.Data} table, because the Contacts
     Provider makes an implicit join between the {@link android.provider.ContactsContract.Contacts}
     table and the {@link android.provider.ContactsContract.Data} table. The
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} column is described
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} column is described
     in more detail in the <a href="retrieve-names.html">Retrieving Contact Names</a> lesson.
 </p>
 <p class="note">
@@ -85,9 +85,9 @@
     the data is in different columns depending on the data type.
     To ensure you get all the possible columns for all possible data types, you need to add all the
     column names to your projection. Always retrieve
-    {@link android.provider.BaseColumns#_ID Data._ID} if you're binding the result
+    {@link android.provider.ContactsContract.Data#_ID Data._ID} if you're binding the result
     {@link android.database.Cursor} to a {@link android.widget.ListView}; otherwise, the binding
-    won't work. Also retrieve {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}
+    won't work. Also retrieve {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}
     so you can identify the data type of each row you retrieve. For example:
 </p>
 <pre>
@@ -128,7 +128,7 @@
 <p>
     Define a constant for your selection clause, an array to hold selection arguments, and a
     variable to hold the selection value. Use
-    the {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
+    the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
     find the contact. For example:
 </p>
 <pre>
@@ -153,7 +153,7 @@
 <p>
     Define the sort order you want in the resulting {@link android.database.Cursor}. To
     keep all rows for a particular data type together, sort by
-    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}. This query argument
+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}. This query argument
     groups all email rows together, all phone rows together, and so forth. For example:
 </p>
 <pre>
@@ -299,7 +299,7 @@
     </dt>
     <dd>
         Modify the selection text to search for the
-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value that's specific to
+        {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value that's specific to
         your data type.
     </dd>
     <dt>
@@ -307,7 +307,7 @@
     </dt>
     <dd>
         Since you're only selecting a single detail type, don't group the returned
-        {@link android.database.Cursor} by {@link android.provider.ContactsContract.DataColumns#MIMETYPE
+        {@link android.database.Cursor} by {@link android.provider.ContactsContract.Data#MIMETYPE
         Data.MIMETYPE}.
     </dd>
 </dl>
@@ -344,9 +344,9 @@
 <h3>Define selection criteria</h3>
 <p>
     Define a search text expression that retrieves rows for a specific contact's
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} and the
-    {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE} of the details you
-    want. Enclose the {@link android.provider.ContactsContract.DataColumns#MIMETYPE MIMETYPE} value in
+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY} and the
+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE} of the details you
+    want. Enclose the {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value in
     single quotes by concatenating a "<code>'</code>" (single-quote) character to the start and end
     of the constant; otherwise, the provider interprets the constant as a variable name rather
     than as a string value. You don't need to use a placeholder for this value, because you're
@@ -368,10 +368,10 @@
 <h3>Define a sort order</h3>
 <p>
     Define a sort order for the returned {@link android.database.Cursor}. Since you're retrieving a
-    specific data type, omit the sort on {@link android.provider.ContactsContract.DataColumns#MIMETYPE}.
+    specific data type, omit the sort on {@link android.provider.ContactsContract.Data#MIMETYPE}.
     Instead, if the type of detail data you're searching includes a subtype, sort on it.
     For example, for email data you can sort on
-    {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE Email.TYPE}:
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#TYPE Email.TYPE}:
 </p>
 <pre>
     private static final String SORT_ORDER = Email.TYPE + " ASC ";
diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
index 7d70ceb..49d6e95 100755
--- a/docs/html/training/contacts-provider/retrieve-names.jd
+++ b/docs/html/training/contacts-provider/retrieve-names.jd
@@ -227,7 +227,7 @@
 </pre>
 <p class="note">
     <strong>Note:</strong> Since
-    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
     Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
     app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
     Android Studio. To turn off this warning, add the annotation
@@ -261,7 +261,7 @@
     that displays the contacts, you need to call {@link android.app.Activity#findViewById
     Activity.findViewById()} using the parent activity of the
     {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
-    parent activity when you call {@link android.widget.AdapterView#setAdapter setAdapter()}.
+    parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
     For example:
 </p>
 <pre>
@@ -293,7 +293,7 @@
 </p>
 <p>
     To continue setting up the listener, bind it to the {@link android.widget.ListView} by
-    calling the method {@link android.widget.AdapterView#setOnItemClickListener
+    calling the method {@link android.widget.ListView#setOnItemClickListener
     setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
     onActivityCreated()}. For example:
 </p>
@@ -318,15 +318,15 @@
     the {@link android.widget.ListView} displays the contact's display name,
     which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
     the name of this column is
-    {@link android.provider.ContactsContract.ContactNameColumns#DISPLAY_NAME_PRIMARY
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
     Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
-    {@link android.provider.ContactsContract.ContactsColumns#DISPLAY_NAME Contacts.DISPLAY_NAME}.
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
 </p>
 <p>
-    The column {@link android.provider.BaseColumns#_ID Contacts._ID} is used by the
+    The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
     {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
-    {@link android.provider.BaseColumns#_ID Contacts._ID} and
-    {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} are used together to
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
     construct a content URI for the contact the user selects.
 </p>
 <pre>
@@ -635,7 +635,7 @@
     </li>
     <li>
         The name of the column that contains the custom MIME type value. This name is always
-        {@link android.provider.ContactsContract.DataColumns#MIMETYPE Data.MIMETYPE}.
+        {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
     </li>
     <li>
         The custom MIME type value for the data type. As described previously, this is the constant
diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
index 6a961da..089ede7 100644
--- a/docs/html/training/graphics/opengl/touch.jd
+++ b/docs/html/training/graphics/opengl/touch.jd
@@ -36,7 +36,7 @@
 getting some attention, but what if you want to have users interact with your OpenGL ES graphics?
 The key to making your OpenGL ES application touch interactive is expanding your implementation of
 {@link android.opengl.GLSurfaceView} to override the {@link
-android.view.View#onTouchEvent onTouchEvent()} to listen for touch events.</p>
+android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} to listen for touch events.</p>
 
 <p>This lesson shows you how to listen for touch events to let users rotate an OpenGL ES object.</p>
 
@@ -44,7 +44,7 @@
 <h2 id="listener">Setup a Touch Listener</h2>
 
 <p>In order to make your OpenGL ES application respond to touch events, you must implement the
-{@link android.view.View#onTouchEvent onTouchEvent()} method in your
+{@link android.opengl.GLSurfaceView#onTouchEvent onTouchEvent()} method in your
 {@link android.opengl.GLSurfaceView} class. The example implementation below shows how to listen for
 {@link android.view.MotionEvent#ACTION_MOVE MotionEvent.ACTION_MOVE} events and translate them to
 an angle of rotation for a shape.</p>
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
index abc79b6..8aebd4b 100644
--- a/docs/html/training/implementing-navigation/nav-drawer.jd
+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
@@ -148,7 +148,7 @@
 }
 </pre>
 
-<p>This code also calls {@link android.widget.AdapterView#setOnItemClickListener
+<p>This code also calls {@link android.widget.ListView#setOnItemClickListener
 setOnItemClickListener()} to receive click events in the navigation drawer's list.
 The next section shows how to implement this interface
 and change the content view when the user selects an item.</p>
@@ -160,7 +160,7 @@
 <p>When the user selects an item in the drawer's list, the system calls {@link
 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
 {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
-{@link android.widget.AdapterView#setOnItemClickListener setOnItemClickListener()}.</p>
+{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
 
 <p>What you do in the {@link
 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
diff --git a/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png
new file mode 100644
index 0000000..d14ec32
--- /dev/null
+++ b/docs/html/training/material/images/palette-library-color-profiles_2-1_2x.png
Binary files differ
diff --git a/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png
new file mode 100644
index 0000000..883adba
--- /dev/null
+++ b/docs/html/training/material/images/palette-library-title-text-color_2-1_2x.png
Binary files differ
diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd
index 4001e6b..8baa065 100644
--- a/docs/html/training/material/index.jd
+++ b/docs/html/training/material/index.jd
@@ -3,7 +3,6 @@
 page.image=images/cards/material_2x.png
 page.metaDescription=Learn how to apply material design to your apps.
 
-
 @jd:body
 
 <div id="tb-wrapper">
@@ -58,6 +57,9 @@
 
   <dt><a href="{@docRoot}training/material/compatibility.html">Maintaining Compatibility</a></dt>
   <dd>Learn how to maintain compatibility with platform versions earlier than Android 5.0.</dd>
+
+  <dt><a href="{@docRoot}training/material/palette-colors.html">Selecting Colors with the Palette API</a></dt>
+  <dd>Learn how to select colors for your app using the v7 Palette library.</dd>
 </dl>
 
 <h2>Video Training</h2>
diff --git a/docs/html/training/material/palette-colors.html b/docs/html/training/material/palette-colors.html
new file mode 100644
index 0000000..27485d2
--- /dev/null
+++ b/docs/html/training/material/palette-colors.html
@@ -0,0 +1,310 @@
+<html devsite>
+<head>
+  <title>Selecting Colors with the Palette API</title>
+  <meta name="book_path" value="/training/_book.yaml" />
+  <meta name="top_category" value="develop" />
+  <meta name="subcategory" value="training" />
+</head>
+<body>
+
+<div id="tb-wrapper">
+  <div id="tb">
+    <h2>This lesson teaches you to</h2>
+    <ol>
+      <li><a href="#set-up-the-library">Set up the library</a></li>
+      <li><a href="#create-a-palette">Create a palette</a>
+        <ol>
+          <li><a href="#generate-a-palette-instance">Generate a Palette instance</a></li>
+          <li><a href="#customize-your-palette">Customize your palette</a></li>
+        </ol>
+      </li>
+      <li><a href="#extract-color-profiles">Extract color profiles</a>
+        <ol>
+          <li><a href="#use-swatches">Use swatches to create color schemes</a></li>
+        </ol>
+      </li>
+    </ol>
+    <h2>You should also read</h2>
+    <ul>
+      <li><a href="http://www.google.com/design/spec">Material design specification</a></li>
+      <li><a href="/design/material/index.html">Material design on Android</a></li>
+    </ul>
+  </div>
+</div>
+
+<p>Good visual design is essential for a successful app, and color schemes are a primary component of design. The palette library is a
+<a href="/topic/libraries/support-library/features.html#v7-palette">support library</a>
+that extracts prominent colors from images to help you create visually engaging apps.</p>
+
+<p>You can use the palette library to design layout
+<a href="/guide/topics/ui/themes.html">themes</a> and apply custom colors to visual elements in your app.
+For example, you can use a palette to create a color-coordinated title 
+card for a song based on its album cover or to adjust an app’s toolbar color when its 
+background image changes. The <code><a 
+href="/reference/android/support/v7/graphics/Palette.html">Palette</a></code> object gives 
+you access to the colors in a <code><a
+href="/reference/android/graphics/Bitmap.html">Bitmap</a></code> 
+image while also providing six main color profiles from the bitmap to help
+inform your <a href="http://material.google.com">design choices</a>.</p>
+
+<h2 id="set-up-the-library">Set up the library</h2>
+
+<p>To use the palette library, install or update the <a
+href="/topic/libraries/support-library/index.html">Android
+Support Library</a> to version 24.0.0 or higher and follow the instructions for <a
+href="/topic/libraries/support-library/setup.html#add-library">Adding
+Support Libraries</a> to add the palette library to your app development project.</p>
+
+<p>Make sure that the version specified in your dependency identifier matches your
+app’s <code>compileSdkVersion</code>, set in the <code>build.gradle</code>
+file:</p>
+
+<pre class="prettyprint">
+android {
+  compileSdkVersion 24
+  ...
+}
+
+dependencies {
+  ...
+  compile 'com.android.support:palette-v7:24.2.1'
+}
+</pre>
+
+<p>For more information about adding the palette dependency, read about the palette
+feature in the <a
+href="/topic/libraries/support-library/features.html#v7-palette">support
+library documentation</a>.</p>
+
+<h2 id="create-a-palette">Create a palette</h2>
+
+<p>A <code>Palette</code> object gives you access to the primary colors in an
+image, as well as the corresponding colors for overlaid text. Use palettes to design
+your app’s style and to dynamically change your app’s color scheme based on a
+given source image.</p>
+
+<p>To create a palette, first instantiate a <code><a
+href="https://developer.android.com/reference/android/support/v7/graphics/Palette.Builder.html">Palette.Builder</a></code>
+from a <code>Bitmap</code>. You can then use the
+<code>Palette.Builder</code> to customize the palette before generating it. This
+section will describe palette generation and customization from a bitmap
+image.</p>
+
+<h3 id="generate-a-palette-instance">Generate a Palette instance</h3>
+
+<p>Generate a <code>Palette</code> instance using <code>Palette</code>’s
+<code><a
+href="/reference/android/support/v7/graphics/Palette.html#from(android.graphics.Bitmap)">from(Bitmap
+bitmap)</a></code> method to first create a <code>Palette.Builder</code>
+from a <code>Bitmap</code>. The builder can then generate the palette either
+synchronously or asynchronously.</p>
+
+<p>Use synchronous palette generation if you want to create the palette on
+the same thread as the method being called. If you generate the palette
+asynchronously on a different thread, use the <code><a
+href="/reference/android/support/v7/graphics/Palette.PaletteAsyncListener.html#onGenerated(android.support.v7.graphics.Palette)">onGenerated()</a></code>
+method to access the palette immediately after it has been created.</p>
+
+<p>The following code snippet provides example methods for both types of palette generation:</p>
+
+<pre class="prettyprint">
+// Generate palette synchronously and return it
+public Palette createPaletteSync(Bitmap bitmap) {
+  Palette p = Palette.from(bitmap).generate();
+  return p;
+}
+
+// Generate palette asynchronously and use it on a different
+// thread using onGenerated()
+public void createPaletteAsync(Bitmap bitmap) {
+  Palette.from(bitmap).generate(new PaletteAsyncListener() {
+    public void onGenerated(Palette p) {
+      // Use generated instance
+    }
+  });
+}
+</pre>
+
+<p>If you need to continuously generate palettes for a sorted list of images
+or objects, consider <a
+href="/reference/android/util/LruCache.html">caching</a>
+the <code>Palette</code> instances to prevent slow UI performance. You also
+should not create the palettes on your <a href="/training/articles/perf-anr.html">main thread</a>.</p>
+
+<h3 id="customize-your-palette">Customize your palette</h3>
+
+<p>The <code>Palette.Builder</code> allows you to customize your palette by
+choosing how many colors are in the resulting palette, what area of your
+image the builder uses to generate the palette, and what colors are allowed in the
+palette. For example, you can filter out the color black or ensure that the
+builder only uses the top half of an image to generate your palette.</p>
+
+<p>Fine-tune your palette’s size and colors with the following methods from
+the <code>Palette.Builder</code> class:</p>
+
+<dl>
+
+  <dt><code><a 
+  href="/reference/android/support/v7/graphics/Palette.Builder.html#addFilter(android.support.v7.graphics.Palette.Filter)">addFilter()</a></code></dt>
+  <dd>This method adds a filter that indicates what colors are allowed in the
+  resulting palette. Pass in your own<code> <a
+  href="/reference/android/support/v7/graphics/Palette.Filter.html">Palette.Filter</a></code>
+  and modify its <code>isAllowed()</code> method to determine which colors are
+  filtered from the palette.</dd>
+
+  <dt><code><a
+  href="/reference/android/support/v7/graphics/Palette.Builder.html#maximumColorCount(int)">maximumColorCount()</a></code></dt>
+  <dd>This method sets the maximum number of colors in your palette. The
+  default value is 16, and the optimal value depends on the source image. 
+  For landscapes, optimal values range from 8-16 while pictures with faces 
+  usually have values that fall between 24-32. The
+  <code>Palette.Builder</code> takes longer to generate palettes with more
+  colors.</dd>
+
+  <dt><code><a 
+  href="/reference/android/support/v7/graphics/Palette.Builder.html#setRegion(int,%20int,%20int,%20int)">setRegion()</a></code></dt>
+  <dd>This method indicates what area of the bitmap the builder uses when
+  creating the palette. You can only use this method when generating the palette from
+  a bitmap, and it does not affect the original image.</dd>
+
+  <dt><code><a
+  href="/reference/android/support/v7/graphics/Palette.Builder.html#addTarget(android.support.v7.graphics.Target)">addTarget()</a></code></dt>
+  <dd>This method allows you to perform your own color matching by adding a
+  <code><a
+  href="/reference/android/support/v7/graphics/Target.html">Target</a></code>
+  color profile to the builder. If the default <code>Target</code>s are not
+  sufficient, advanced developers can create their own <code>Target</code>s
+  using a <code><a
+  href="/reference/android/support/v7/graphics/Target.Builder.html">Target.Builder</a></code>.</dd>
+
+</dl>
+
+<h2 id="extract-color-profiles">Extract color profiles</h2>
+
+<p>Based on the <a
+href="https://material.google.com/style/color.html#">standards
+of material design</a>, the palette library extracts commonly used color
+profiles from an image. Each profile is defined by a <code><a
+href="/reference/android/support/v7/graphics/Target.html">Target</a></code>,
+and colors extracted from the bitmap image are scored against each profile
+based on saturation, luminance, and population (number of pixels in the bitmap
+represented by the color). For each profile, the color with the best score
+defines that color profile for the given image.</p>
+
+<p>By default, a <code>Palette</code> object contains 16 primary colors from
+a given image. When generating your palette, you can <a
+href="#customize-your-palette">customize</a> its number of colors using the
+<code>Palette.Builder</code>. Extracting more colors provides more potential
+matches for each color profile but also causes <code>Palette.Builder</code> to
+take longer when generating the palette.</p>
+
+<p>The palette library attempts to extract the following six color
+profiles:</p>
+
+<ul>
+  <li>Light Vibrant</li>
+  <li>Vibrant</li>
+  <li>Dark Vibrant</li>
+  <li>Light Muted</li>
+  <li>Muted</li>
+  <li>Dark Muted</li>
+</ul>
+
+<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Color()</code>
+methods returns the color in the palette associated with that particular profile,
+where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
+color profiles. For example, the method to get the Dark Vibrant color profile is <code><a
+href="/reference/android/support/v7/graphics/Palette.html#getDarkVibrantColor(int)">getDarkVibrantColor()</a></code>.
+Since not all images will contain all color profiles, you must also provide
+a default color to return.</p>
+
+<p>Figure 1 displays a photo and its corresponding color
+profiles from the <code>get&lt;<em>Profile</em>&gt;Color()</code> methods.</p>
+
+<img src="/training/material/images/palette-library-color-profiles_2-1_2x.png" alt="" width="624"/>
+
+<p class="img-caption"><strong>Figure 1.</strong> An example image and its
+extracted color profiles given the default maximum color count (16) for the palette.</p>
+
+<h3 id="use-swatches">Use swatches to create color schemes</h3>
+
+<p>The <code>Palette</code> class also generates <code><a 
+href="/reference/android/support/v7/graphics/Palette.Swatch.html">Palette.Swatch</a></code>
+objects for each color profile. <code>Palette.Swatch</code>
+objects contain the associated color for that profile, as well as the
+color’s population in pixels.</p>
+
+<p>Swatches have additional methods for accessing more information about the color
+profile, such as HSL values and pixel population. You can use swatches to help
+create more comprehensive color schemes and app themes using the <code><a
+href="/reference/android/support/v7/graphics/Palette.Swatch.html#getBodyTextColor()">getBodyTextColor()</a></code>
+and <code><a
+href="/reference/android/support/v7/graphics/Palette.Swatch.html#getTitleTextColor()">getTitleTextColor()</a></code>
+methods. These methods return colors appropriate for use over the swatch’s
+color.</p>
+
+<p>Each of <code>Palette</code>’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code>
+methods returns the swatch associated with that particular profile,
+where <code>&lt;<em>Profile</em>&gt;</code> is replaced by the name of one of the six
+color profiles. Although the palette’s <code>get&lt;<em>Profile</em>&gt;Swatch()</code> methods
+do not require default value parameters, they return <code>null</code> if that
+particular profile does not exist in the image. Therefore, you should check that
+a swatch is not null before using it. For example, the following method 
+returns the Vibrant swatch from a palette if the swatch is not null:</p>
+
+<pre class="prettyprint">
+// Return a palette's vibrant swatch after checking that it exists
+private Palette.Swatch checkVibrantSwatch(Palette p) {
+  Palette.Swatch vibrant = p.getVibrantSwatch();
+  if (vibrant != null) {
+    return vibrant;
+  }
+  // Throw error
+}
+</pre>
+
+<p>To access all colors in a palette, the <code><a
+href="/reference/android/support/v7/graphics/Palette.html#getSwatches()">getSwatches()</a></code>
+method returns a list of all swatches generated from an
+image, including the standard six color profiles.</p>
+
+<p>The following snippet of code uses the methods from the above code snippets to
+synchronously generate a palette, get its vibrant swatch, and change the colors of a
+toolbar to match the bitmap image. Figure 2 displays the resulting image and toolbar.</p>
+
+<div class="cols">
+
+  <div class="col-2of3">
+
+<pre class="prettyprint">
+// Set the background and text colors of a toolbar given a
+// bitmap image to match
+public void setToolbarColor(Bitmap bitmap) {
+  // Generate the palette and get the vibrant swatch
+  // See the createPaletteSync() and checkVibrantSwatch() methods
+  // from the code snippets above
+  Palette p = createPaletteSync(bitmap);
+  Palette.Swatch vibrantSwatch = checkVibrantSwatch(p);
+  
+  // Set the toolbar background and text colors
+  Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+  toolbar.setBackgroundColor(vibrantSwatch.getRgb());
+  toolbar.setTitleTextColor(vibrantSwatch.getTitleTextColor());
+}
+</pre>
+
+  </div>
+
+  <div class="col-1of3">
+
+    <img src="/training/material/images/palette-library-title-text-color_2-1_2x.png" alt="" width="400"/>
+
+    <p class="img-caption"><strong>Figure 2.</strong> An example image with its
+    vibrant-colored toolbar and corresponding title text color.</p>
+
+  </div>
+
+</div>
+
+</body>
+</html>
diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
index db75aaf..bab9c9c 100644
--- a/docs/html/training/monitoring-device-state/battery-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
@@ -141,10 +141,11 @@
 condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link
 android.content.Intent#ACTION_BATTERY_OKAY}.</p>
 
-<pre>&lt;receiver android:name=".BatteryLevelReceiver">
-&lt;intent-filter>
-  &lt;action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
-  &lt;action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
+<pre>
+&lt;receiver android:name=".BatteryLevelReceiver">
+  &lt;intent-filter>
+    &lt;action android:name="android.intent.action.BATTERY_LOW"/>
+    &lt;action android:name="android.intent.action.BATTERY_OKAY"/>
   &lt;/intent-filter>
 &lt;/receiver></pre>
 
diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
index 2dd904f..c63822b 100644
--- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
@@ -33,7 +33,7 @@
 <p>Some of the most common uses for repeating alarms and background services is to schedule regular
 updates of application data from Internet resources, cache data, or execute long running downloads.
 But if you aren't connected to the Internet, or the connection is too slow to complete your
-download, why both waking the device to schedule the update at all?</p>
+download, why bother waking the device to schedule the update at all?</p>
 
 <p>You can use the {@link android.net.ConnectivityManager} to check that you're actually
 connected to the Internet, and if so, what type of connection is in place.</p>
diff --git a/docs/html/training/monitoring-device-state/manifest-receivers.jd b/docs/html/training/monitoring-device-state/manifest-receivers.jd
index 3e36dba..5efa2fa 100644
--- a/docs/html/training/monitoring-device-state/manifest-receivers.jd
+++ b/docs/html/training/monitoring-device-state/manifest-receivers.jd
@@ -21,7 +21,10 @@
 
 <h2>You should also read</h2>
 <ul>
-  <li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
+  <li><a href="/topic/performance/background-optimization.html">Background Optimizations</a>
+  <li><a href="/topic/performance/scheduling.html">Intelligent Job-Scheduling</a>
+  <li><a href="/training/articles/perf-anr.html">Keeping Your App Responsive</a>
+  <li><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a>
 </ul>
 
 </div>
@@ -32,13 +35,22 @@
 your application manifest. Then within each of these receivers you simply reschedule your recurring
 alarms based on the current device state.</p>
 
-<p>A side-effect of this approach is that your app will wake the device each time any of these
-receivers is triggered&mdash;potentially much more frequently than required.</p>
-
 <p>A better approach is to disable or enable the broadcast receivers at runtime. That way you can
 use the receivers you declared in the manifest as passive alarms that are triggered by system events
 only when necessary.</p>
 
+<p class="warning">
+    <strong>Warning:</strong> Limit how many broadcast
+    receivers you set in your app. Instead of using broadcast receivers,
+    consider using other APIs for
+    performing background work. For example, in Android 5.0 (API level 21) and
+    higher, you can use the {@link android.app.job.JobScheduler} class for
+    assigning work to be completed in the background.
+    For more information about APIs you can use instead of the
+    {@link android.content.BroadcastReceiver} class for scheduling background
+    work, see
+    <a href="{@docRoot}topic/performance/background-optimization.html">Background Optimizations</a>.
+</p>
 
 <h2 id="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve Efficiency </h2>
 
diff --git a/docs/html/training/multiple-threads/define-runnable.jd b/docs/html/training/multiple-threads/define-runnable.jd
index 40853d3..84c7bdf 100644
--- a/docs/html/training/multiple-threads/define-runnable.jd
+++ b/docs/html/training/multiple-threads/define-runnable.jd
@@ -23,11 +23,10 @@
 <div class="download-box">
     <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
     <p class="filename">ThreadSample.zip</p>
-</div>
-</div>
+</div> <!-- download-box -->
 
-</div>
-</div>
+</div> <!-- tb -->
+</div> <!-- tb-wrapper -->
 
 <p>
     This lesson shows you how to implement a {@link java.lang.Runnable} class, which runs the code
diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd
index 7df2787..baa1074 100644
--- a/docs/html/training/notify-user/build-notification.jd
+++ b/docs/html/training/notify-user/build-notification.jd
@@ -134,8 +134,8 @@
 <ul>
 <li>Get an instance of {@link android.app.NotificationManager}.</li>
 
-<li>Use the {@link android.app.NotificationManager#notify(String, int, Notification)} method to issue the
-notification. When you call {@link android.app.NotificationManager#notify(String, int, Notification)}, specify a notification ID.
+<li>Use the {@link android.app.NotificationManager#notify notify()} method to issue the
+notification. When you call {@link android.app.NotificationManager#notify notify()}, specify a notification ID.
 You can use this ID to update the notification later on. This is described in more detail in
 <a href="managing.html">Managing Notifications</a>.</li>
 
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/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
index d3d31de..3d2bca7 100644
--- a/docs/html/training/testing/ui-testing/espresso-testing.jd
+++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
@@ -24,17 +24,11 @@
         </h2>
 
         <ol>
-          <li>
-            <a href="#setup">Set Up Espresso</a>
-          </li>
+          <li><a href="#setup">Set Up Espresso</a></li>
 
-          <li>
-            <a href="#build">Create an Espresso Test Class</a>
-          </li>
+          <li><a href="#build">Create an Espresso Test Class</a></li>
 
-          <li>
-            <a href="#run">Run Espresso Tests on a Device or Emulator</a>
-          </li>
+          <li><a href="#run">Run Espresso Tests on a Device or Emulator</a></li>
         </ol>
 
         <h2>
@@ -59,31 +53,40 @@
             class="external-link">Android Testing Codelab</a></li>
         </ul>
       </div>
-    </div>
+</div>
 
     <p>
       Testing user interactions
       within a single app helps to ensure that users do not
-      encounter unexpected results or have a poor experience when interacting with your app.
-      You should get into the habit of creating user interface (UI) tests if you need to verify
+      encounter unexpected results or have a poor
+      experience when interacting with your app.
+      You should get into the habit of creating
+      user interface (UI) tests if you need to verify
       that the UI of your app is functioning correctly.
     </p>
 
     <p>
       The Espresso testing framework, provided by the
       <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>,
-      provides APIs for writing UI tests to simulate user interactions within a
-      single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and
-      higher. A key benefit of using Espresso is that it provides automatic synchronization of test
-      actions with the UI of the app you are testing. Espresso detects when the main thread is idle,
-      so it is able to run your test commands at the appropriate time, improving the reliability of
-      your tests. This capability also relieves you from having to adding any timing workarounds,
-      such as a sleep period, in your test code.
+      provides APIs for writing UI tests to simulate
+      user interactions within a
+      single target app. Espresso tests can run on
+      devices running Android 2.3.3 (API level 10) and
+      higher. A key benefit of using Espresso is
+      that it provides automatic synchronization of test
+      actions with the UI of the app you are testing.
+      Espresso detects when the main thread is idle,
+      so it is able to run your test commands
+      at the appropriate time, improving the reliability of
+      your tests. This capability also relieves you
+      from having to add any timing workarounds,
+      such as {@link java.lang.Thread#sleep(long) Thread.sleep()}
+      in your test code.
     </p>
 
     <p>
-      The Espresso testing framework is an instrumentation-based API and works
-      with the
+      The Espresso testing framework is
+      an instrumentation-based API and works with the
       <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
       AndroidJUnitRunner}</a> test runner.
     </p>
@@ -92,105 +95,139 @@
       Set Up Espresso
     </h2>
 
-<p>Before building your UI test with Espresso, make sure to configure your test source code
-location and project dependencies, as described in
-<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
-Getting Started with Testing</a>.</p>
+<p>
+  Before building your UI test with Espresso,
+  make sure to configure your test source code
+  location and project dependencies, as described in
+  <a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">Getting Started with Testing</a>.
+</p>
 
-<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
-  reference to the Espresso library:</p>
+<p>
+  In the {@code build.gradle} file of your Android app
+  module, you must set a dependency
+  reference to the Espresso library:
+</p>
 
 <pre>
 dependencies {
-    ...
-    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
+    // Other dependencies ...
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
 }
 </pre>
 
-<p>Turn off animations on your test device &mdash; leaving system animations turned on in the test
-device might cause unexpected results or may lead your test to fail. Turn off animations from
-<em>Settings</em> by opening <em>Developing Options</em> and turning all the following options off:
+<p>
+  Turn off animations on your test device &mdash;
+  leaving system animations turned on in the test
+  device might cause unexpected results or may
+  lead your test to fail. Turn off animations from
+  <em>Settings</em> by opening <em>Developer options</em>
+  and turning all the following options off:
 </p>
-        <ul>
-          <li>
-            <strong>Window animation scale</strong>
-          </li>
 
-          <li>
-            <strong>Transition animation scale</strong>
-          </li>
+<p>
+  <ul>
+    <li>
+      <strong>Window animation scale</strong>
+    </li>
 
-          <li>
-            <strong>Animator duration scale</strong>
-          </li>
-        </ul>
-      </li>
-    </ul>
-<p>If you want to set up your project to use Espresso features other than what the core API
+    <li>
+      <strong>Transition animation scale</strong>
+    </li>
+
+    <li>
+      <strong>Animator duration scale</strong>
+    </li>
+  </ul>
+</p>
+
+<p>
+  If you want to set up your project to use Espresso
+  features other than what the core API
   provides, see this
   <a href="https://google.github.io/android-testing-support-library/docs/espresso/index.html"
   class="external-link">resource</a>.</p>
 
-    <h2 id="build">
-      Create an Espresso Test Class
-    </h2>
+<!-- Section 2 -->
 
-    <p>
-      To create an Espresso test, create a Java class that follows this programming model:
-    </p>
+<h2 id="build">
+  Create an Espresso Test Class
+</h2>
 
-    <ol>
-      <li>Find the UI component you want to test in an {@link android.app.Activity} (for example, a
-      sign-in button in the app) by calling the
-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-        {@code onView()}</a> method, or the
-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
-      {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
-      </li>
+<p>
+  To create an Espresso test, create a Java
+  class that follows this programming model:
+</p>
 
-      <li>Simulate a specific user interaction to perform on that UI component, by calling the
-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
-      or
-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
-      method and passing in the user action (for example, click on the sign-in button). To sequence
-      multiple actions on the same UI component, chain them using a comma-separated list in your
-      method argument.
-      </li>
+<ol>
+  <li>
+    Find the UI component you want to test in
+    an {@link android.app.Activity} (for example, a
+    sign-in button in the app) by calling the
+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+    {@code onView()}</a> method, or the
+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
+    {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
+  </li>
 
-      <li>Repeat the steps above as necessary, to simulate a user flow across multiple
-      activities in the target app.
-      </li>
+  <li>
+    Simulate a specific user interaction to
+    perform on that UI component, by calling the
+    <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+    or
+    <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+    method and passing in the user action
+    (for example, click on the sign-in button). To sequence
+    multiple actions on the same UI component, chain them using a comma-separated list in your
+    method argument.
+  </li>
 
-      <li>Use the
+  <li>
+    Repeat the steps above as necessary, to simulate a user flow across multiple
+    activities in the target app.
+  </li>
+
+  <li>
+    Use the
     <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
-        methods to check that the UI reflects the expected
-      state or behavior, after these user interactions are performed.
-      </li>
-    </ol>
+    methods to check that the UI reflects the expected
+    state or behavior, after these user interactions are performed.
+  </li>
+</ol>
 
-    <p>
-      These steps are covered in more detail in the sections below.
-    </p>
+<p>
+  These steps are covered in more detail in the sections below.
+</p>
 
-    <p>
-      The following code snippet shows how your test class might invoke this basic workflow:
-    </p>
+<p>
+  The following code snippet shows how your test
+  class might invoke this basic workflow:
+</p>
 
 <pre>
 onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
         .perform(click())               // click() is a ViewAction
         .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
 </pre>
-<h3 id="espresso-atr">Using Espresso with ActivityTestRule</h3>
+
+<!-- Section 2.1 -->
+
+<h3 id="espresso-atr">
+  Using Espresso with ActivityTestRule
+</h3>
+
 <p>
-The following section describes how to create a new Espresso test in the JUnit 4 style and use
-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
-{@code ActivityTestRule}</a> to reduce the amount of boilerplate code you need to write. By using
-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
-{@code ActivityTestRule}</a>, the testing framework launches the activity under test
-before each test method annotated with <code>&#64;Test</code> and before any method annotated with
-<code>&#64;Before</code>. The framework handles shutting down the activity after the test finishes
-and all methods annotated with <code>&#64;After</code> are run.</p>
+  The following section describes how to create a
+  new Espresso test in the JUnit 4 style and use
+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>
+  to reduce the amount of boilerplate code you need to write. By using
+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">{@code ActivityTestRule}</a>,
+  the testing framework launches the activity under test
+  before each test method annotated with
+  <code>&#64;Test</code> and before any method annotated with
+  <code>&#64;Before</code>. The framework handles
+  shutting down the activity after the test finishes
+  and all methods annotated with <code>&#64;After</code> are run.
+</p>
 
 <pre>
 package com.example.android.testing.espresso.BasicSample;
@@ -234,103 +271,57 @@
 }
 </pre>
 
-    <h3 id="espresso-aitc2">
-      Using Espresso with ActivityInstrumentationTestCase2
-    </h3>
-<p>The following section describes how to migrate to Espresso if you have existing test classes
-subclassed from {@link android.test.ActivityInstrumentationTestCase2} and you don't want to rewrite
-them to use JUnit4.</p>
-<p class="note"><strong>Note:</strong> For new UI tests, we strongly recommend that you write your
-test in the JUnit 4 style and use the
-<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
-{@code ActivityTestRule}</a> class, instead of
-{@link android.test.ActivityInstrumentationTestCase2}.</p>
-    <p>
-      If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
-      to create your Espresso test class, you must inject an
-      {@link android.app.Instrumentation} instance into your test class. This step is required in
-      order for your Espresso test to run with the
-      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
-      test runner.
-    </p>
+<!-- Section 2.2 -->
 
-    <p>
-      To do this, call the
-      {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()}
-      method and pass in the result of
-      <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()">
-      {@code InstrumentationRegistry.getInstrumentation()}</a>, as shown in the following code
-      example:
-    </p>
+<h3 id="accessing-ui-components">
+  Accessing UI Components
+</h3>
 
-<pre>
-import android.support.test.InstrumentationRegistry;
+<p>
+  Before Espresso can interact with the app
+  under test, you must first specify the UI component
+  or <em>view</em>. Espresso supports the use of
+  <a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
+  for specifying views and adapters in your app.
+</p>
 
-public class MyEspressoTest
-        extends ActivityInstrumentationTestCase2&lt;MyActivity&gt; {
+<p>
+  To find the view, call the
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
+  method and pass in a view matcher that
+  specifies the view that you are targeting. This is
+  described in more detail in
+  <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
+  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
+  method returns a
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">{@code ViewInteraction}</a>
+  object that allows your test to interact with the view.
+  However, calling the
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+  {@code onView()}</a>
+  method may not work if you want to locate a view in
+  an {@link android.support.v7.widget.RecyclerView} layout.
+  In this case, follow the instructions in
+  <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a>
+  instead.
+</p>
 
-    private MyActivity mActivity;
+<p class="note">
+  <strong>Note</strong>:
+  The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
+  method does not check if the view you specified is
+  valid. Instead, Espresso searches only the
+  current view hierarchy, using the matcher provided.
+  If no match is found, the method throws a
+  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
+</p>
 
-    public MyEspressoTest() {
-        super(MyActivity.class);
-    }
-
-    &#64;Before
-    public void setUp() throws Exception {
-        super.setUp();
-        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
-        mActivity = getActivity();
-    }
-
-   ...
-}
-</pre>
-
-<p class="note"><strong>Note:</strong> Previously, {@link android.test.InstrumentationTestRunner}
-would inject the {@link android.app.Instrumentation} instance, but this test runner is being
-deprecated.</p>
-
-    <h3 id="accessing-ui-components">
-      Accessing UI Components
-    </h3>
-
-    <p>
-      Before Espresso can interact with the app under test, you must first specify the UI component
-      or <em>view</em>. Espresso supports the use of
-<a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
-      for specifying views and adapters in your app.
-    </p>
-
-    <p>
-      To find the view, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-      {@code onView()}</a>
-      method and pass in a view matcher that specifies the view that you are targeting. This is
-      described in more detail in <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
-      The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-      {@code onView()}</a> method returns a
-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">
-      {@code ViewInteraction}</a>
-      object that allows your test to interact with the view.
-      However, calling  the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-      {@code onView()}</a> method may not work if you want to locate a view in
-      an {@link android.widget.AdapterView} layout. In this case, follow the instructions in
-      <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a> instead.
-    </p>
-
-    <p class="note">
-      <strong>Note</strong>: The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-      {@code onView()}</a> method does not check if the view you specified is
-      valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided.
-      If no match is found, the method throws a
-      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
-      {@code NoMatchingViewException}</a>.
-    </p>
-
-    <p>
-      The following code snippet shows how you might write a test that accesses an
-      {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard,
-      and then performs a button click.
-    </p>
+<p>
+  The following code snippet shows how you might write a test that accesses an
+  {@link android.widget.EditText} field,
+  enters a string of text, closes the virtual keyboard,
+  and then performs a button click.
+</p>
 
 <pre>
 public void testChangeText_sameActivity() {
@@ -344,231 +335,464 @@
 }
 </pre>
 
-    <h4 id="specifying-view-matcher">
-      Specifying a View Matcher
-    </h4>
+<!-- Section 2.2.1 -->
+<h4 id="specifying-view-matcher">
+  Specifying a View Matcher
+</h4>
 
-    <p>
-      You can specify a view matcher by using these approaches:
-    </p>
+<p>
+  You can specify a view matcher by using these approaches:
+</p>
 
-    <ul>
-      <li>Calling methods in the
-        <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">
-        {@code ViewMatchers}</a> class. For example, to find a view by looking for a text string it
-        displays, you can call a method like this:
-        <pre>
+<ul>
+  <li>Calling methods in the
+    <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">{@code ViewMatchers}</a>
+    class. For example, to find a view by looking for a text string it
+    displays, you can call a method like this:
+<pre>
 onView(withText("Sign-in"));
 </pre>
 
-<p>Similarly you can call
-<a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">
-{@code withId()}</a> and providing the resource ID ({@code R.id}) of the view, as shown in the
-following example:</p>
+    <p>
+      Similarly you can call
+      <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">{@code withId()}</a>
+      and providing the resource ID ({@code R.id}) of the view,
+      as shown in the
+      following example:
+    </p>
 
 <pre>
 onView(withId(R.id.button_signin));
 </pre>
 
     <p>
-      Android resource IDs are not guaranteed to be unique. If your test attempts to match to a
+      Android resource IDs are not guaranteed to be unique.
+      If your test attempts to match to a
       resource ID used by more than one view, Espresso throws an
-<a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">
-  {@code AmbiguousViewMatcherException}</a>.
+      <a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">{@code AmbiguousViewMatcherException}</a>.
     </p>
-      </li>
-      <li>Using the Hamcrest
-      <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
-         class="external-link">{@code Matchers}</a> class. You can use the
-      {@code allOf()} methods to combine multiple matchers, such as
-      {@code containsString()} and {@code instanceOf()}. This approach allows you to
-      filter the match results more narrowly, as shown in the following example:
+  </li>
+
+  <li>
+    Using the Hamcrest
+    <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
+    class="external-link">{@code Matchers}</a> class. You can use the
+    {@code allOf()} methods to combine multiple matchers, such as
+    {@code containsString()} and {@code instanceOf()}.
+    This approach allows you to
+    filter the match results more narrowly, as shown in the following example:
+
 <pre>
 onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
 </pre>
-<p>You can use the {@code not} keyword to filter for views that don't correspond to the matcher, as
-shown in the following example:</p>
+
+    <p>
+      You can use the {@code not} keyword to filter
+      for views that don't correspond to the matcher, as
+      shown in the following example:
+    </p>
+
 <pre>
 onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
 </pre>
-<p>To use these methods in your test, import the {@code org.hamcrest.Matchers} package. To
-learn more about Hamcrest matching, see the
-<a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
+
+    <p>
+      To use these methods in your test,
+      import the {@code org.hamcrest.Matchers} package. To
+      learn more about Hamcrest matching, see the
+      <a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
+    </p>
+  </li>
+</ul>
+
+<p>
+  To improve the performance of your Espresso tests,
+  specify the minimum matching information
+  needed to find your target view. For example,
+  if a view is uniquely identifiable by its
+  descriptive text, you do not need to specify
+  that it is also assignable from the
+  {@link android.widget.TextView} instance.
 </p>
-      </li>
-    </ul>
 
-    <p>
-      To improve the performance of your Espresso tests, specify the minimum matching information
-      needed to find your target view. For example, if a view is uniquely identifiable by its
-      descriptive text, you do not need to specify that it is also assignable from the
-      {@link android.widget.TextView} instance.
-    </p>
+<!-- Section 2.2.2 -->
 
-    <h4 id="#locating-adpeterview-view">
-      Locating a view in an AdapterView
-    </h4>
+<h4 id="#locating-adpeterview-view">
+  Locating a view in an AdapterView
+</h4>
 
-    <p>
-      In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child
-      views at runtime. If the target view you want to test is inside an
-      {@link android.widget.AdapterView}
-      (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or
-      {@link android.widget.Spinner}), the
-<a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
-  {@code onView()}</a> method might not work because only a
-      subset of the views may be loaded in the current view hierarchy.
-    </p>
+<p>
+  In an {@link android.widget.AdapterView} widget,
+  the view is dynamically populated with child
+  views at runtime. If the target view you want to test is inside an
+  {@link android.widget.AdapterView}
+  (such as a {@link android.widget.ListView},
+  {@link android.widget.GridView}, or
+  {@link android.widget.Spinner}), the
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">{@code onView()}</a>
+  method might not work because only a
+  subset of the views may be loaded in the current view hierarchy.
+</p>
 
-    <p>
-      Instead, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
-      method to obtain a
-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">
-      {@code DataInteraction}</a>
-      object to access the target view element. Espresso handles loading the target view element
-      into the current view hierarchy. Espresso also takes care of scrolling to the target element,
-      and putting the element into focus.
-    </p>
-
-    <p class="note">
-      <strong>Note</strong>: The
+<p>
+  Instead, call the
   <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
-      method does not check if if the item you specified corresponds with a view. Espresso searches
-      only the current view hierarchy. If no match is found, the method throws a
-      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
-        {@code NoMatchingViewException}</a>.
-    </p>
+  method to obtain a
+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">{@code DataInteraction}</a>
+  object to access the target view element.
+  Espresso handles loading the target view element
+  into the current view hierarchy. Espresso
+  also takes care of scrolling to the target element,
+  and putting the element into focus.
+</p>
 
-    <p>
-      The following code snippet shows how you can use the
-      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
-      method together
-      with Hamcrest matching to search for a specific row in a list that contains a given string.
-      In this example, the {@code LongListActivity} class contains a list of strings exposed
-      through a {@link android.widget.SimpleAdapter}.
-    </p>
+<p class="note">
+  <strong>Note</strong>: The
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+  method does not check if the item you
+  specified corresponds with a view. Espresso searches
+  only the current view hierarchy. If no match is found, the method throws a
+  <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">{@code NoMatchingViewException}</a>.
+</p>
+
+<p>
+  The following code snippet shows how you can use the
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+  method together
+  with Hamcrest matching to search for a specific
+  row in a list that contains a given string.
+  In this example, the {@code LongListActivity} class
+  contains a list of strings exposed
+  through a {@link android.widget.SimpleAdapter}.
+</p>
 
 <pre>
 onData(allOf(is(instanceOf(Map.class)),
-        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
+        hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
 </pre>
 
-    <h3 id="perform-actions">
-      Performing Actions
-    </h3>
+<!-- Section 2.3 -->
 
-    <p>
-      Call the <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
-      or
-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
-      methods to
-      simulate user interactions on the UI component. You must pass in one or more
-      <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
-      objects as arguments. Espresso fires each action in sequence according to
-      the given order, and executes them in the main thread.
-    </p>
+<h3 id="perform-actions">Performing Actions</h3>
 
-    <p>
-      The
-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
-      class provides a list of helper methods for specifying common actions.
-      You can use these methods as convenient shortcuts instead of creating and configuring
-      individual <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
-      objects. You can specify such actions as:
-    </p>
+<p>
+  Call the
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+  or
+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+  methods to
+  simulate user interactions on the UI component. You must pass in one or more
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+  objects as arguments. Espresso fires each action in sequence according to
+  the given order, and executes them in the main thread.
+</p>
 
-    <ul>
-      <li>
-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
-       Clicks on the view.
-      </li>
+<p>
+  The
+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
+  class provides a list of helper methods for specifying common actions.
+  You can use these methods as convenient shortcuts
+  instead of creating and configuring individual
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+  objects. You can specify such actions as:
+</p>
 
-      <li>
-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
-       Clicks on a view and enters a specified string.
-      </li>
+<ul>
+  <li>
+   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
+   Clicks on the view.
+  </li>
 
-      <li>
-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
-       Scrolls to the view. The
-        target view must be subclassed from {@link android.widget.ScrollView}
-        and the value of its
-        <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
-        property must be {@link android.view.View#VISIBLE}. For views that extend
-        {@link android.widget.AdapterView} (for example,
-        {@link android.widget.ListView}),
-        the
-        <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
-        method takes care of scrolling for you.
-      </li>
+  <li>
+   <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
+   Clicks on a view and enters a specified string.
+  </li>
 
-      <li>
-       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
-       Performs a key press using a specified keycode.
-      </li>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
+    Scrolls to the view. The
+    target view must be subclassed from {@link android.widget.ScrollView}
+    and the value of its
+    <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
+    property must be {@link android.view.View#VISIBLE}. For views that extend
+    {@link android.widget.AdapterView} (for example,
+    {@link android.widget.ListView}), the
+    <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+    method takes care of scrolling for you.
+  </li>
 
-      <li>
-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
-      Clears the text in the target view.
-      </li>
-    </ul>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
+    Performs a key press using a specified keycode.
+  </li>
 
-    <p>
-      If the target view is inside a {@link android.widget.ScrollView}, perform the
-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
-      action first to display the view in the screen before other proceeding
-      with other actions. The
-      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
-      action will have no effect if the view is already displayed.
-    </p>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
+  Clears the text in the target view.
+  </li>
+</ul>
 
-    <h3 id="verify-results">
-      Verifying Results
-    </h3>
+<p>
+  If the target view is inside a {@link android.widget.ScrollView},
+  perform the
+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+  action first to display the view in the screen before other proceeding
+  with other actions. The
+  <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+  action will have no effect if the view is already displayed.
+</p>
 
-    <p>
-      Call the
-      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
-      or
-      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
-      method to assert
-      that the view in the UI matches some expected state. You must pass in a
-      <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">
-      {@code ViewAssertion}</a> object as the argument. If the assertion fails, Espresso throws
-      an {@link junit.framework.AssertionFailedError}.
-    </p>
+<!-- Section 2.4 -->
 
-    <p>
-      The
+<h3 id="intents">
+  Test your activities in isolation with Espresso Intents
+</h3>
+
+<p>
+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html" class="external-link">Espresso Intents</a>
+  enables validation and stubbing of intents sent out by an app.
+  With Espresso Intents, you can test an app, activity, or service in isolation
+  by intercepting outgoing intents, stubbing the result, and sending it back to
+  the component under test.
+</p>
+
+<p>
+  To begin testing with Espresso Intents, you need
+  to add the following line to your app's build.gradle file:
+</p>
+
+<pre>
+dependencies {
+  // Other dependencies ...
+  androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
+}
+</pre>
+
+<p>
+  To test an intent, you need to create an instance of the
+  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
+  class, which is very similar to the
+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
+  class.
+  The
+  <a href="{@docRoot}reference/android/support/test/espresso/intent/rule/IntentsTestRule.html">IntentsTestRule</a>
+  class initializes Espresso Intents before each test,
+  terminates the host activity,
+  and releases Espresso Intents after each test.
+</p>
+
+<p>
+  The test class shown in the following codes snippet provides a simple
+  test for an explicit intent. It tests the activities and intents created in the
+  <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>
+  tutorial.
+</p>
+
+<pre>
+&#64;Large
+&#64;RunWith(AndroidJUnit4.class)
+public class SimpleIntentTest {
+
+    private static final String MESSAGE = "This is a test";
+    private static final String PACKAGE_NAME = "com.example.myfirstapp";
+
+    /* Instantiate an IntentsTestRule object. */
+    &#64;Rule
+    public IntentsTestRule&lg;MainActivity&gt; mIntentsRule =
+      new IntentsTestRule&lg;&gt;(MainActivity.class);
+
+    &#64;Test
+    public void verifyMessageSentToMessageActivity() {
+
+        // Types a message into a EditText element.
+        onView(withId(R.id.edit_message))
+                .perform(typeText(MESSAGE), closeSoftKeyboard());
+
+        // Clicks a button to send the message to another
+        // activity through an explicit intent.
+        onView(withId(R.id.send_message)).perform(click());
+
+        // Verifies that the DisplayMessageActivity received an intent
+        // with the correct package name and message.
+        intended(allOf(
+                hasComponent(hasShortClassName(".DisplayMessageActivity")),
+                toPackage(PACKAGE_NAME),
+                hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));
+
+    }
+}
+</pre>
+
+<p>
+  For more information about Espresso Intents, see the
+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html"
+  class="external-link">Espresso Intents
+  documentation on the Android Testing Support Library site</a>.
+  You can also download the
+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsBasicSample"
+  class="external-link">IntentsBasicSample</a> and
+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsAdvancedSample"
+  class="external-link">IntentsAdvancedSample</a>
+  code samples.
+</p>
+
+<!-- Section 2.5 -->
+
+<h3 id="webviews">
+  Testing WebViews with Espresso Web
+</h3>
+
+<p>
+  Espresso Web allows you to test {@link android.webkit.WebView} components
+  contained within an activity. It uses the
+  <a href="http://docs.seleniumhq.org/docs/03_webdriver.jsp"
+  class="external-link">WebDriver API</a> to inspect and control the
+  behavior of a {@link android.webkit.WebView}.
+</p>
+
+<p>
+  To begin testing with Espresso Web, you need
+  to add the following line to your app's build.gradle file:
+</p>
+
+<pre>
+dependencies {
+  // Other dependencies ...
+  androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'
+}
+</pre>
+
+<p>
+  When creating a test using Espresso Web, you need to enable
+  JavaScript on the {@link android.webkit.WebView} when you instantiate the
+  <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">ActivityTestRule</a>
+  object to test the activity. In the tests, you can select
+  HTML elements displayed in the
+  {@link android.webkit.WebView} and simulate user interactions, like
+  entering text into a text box and then clicking a button. After the actions
+  are completed, you can then verify that the results on the
+  Web page match the results that you expect.
+</p>
+
+<p>
+  In the following code snippet, the class tests
+  a {@link android.webkit.WebView} component with the id value 'webview'
+  in the activity being tested.
+  The <code>verifyValidInputYieldsSuccesfulSubmission()</code> test selects an
+  <code>&lt;input&gt;</code> element on the
+  Web page, enters some text, and checks text that appears in
+  another element.
+</p>
+
+<pre>
+&#64;LargeTest
+&#64;RunWith(AndroidJUnit4.class)
+public class WebViewActivityTest {
+
+    private static final String MACCHIATO = "Macchiato";
+    private static final String DOPPIO = "Doppio";
+
+    &#64;Rule
+    public ActivityTestRule<WebViewActivity> mActivityRule =
+        new ActivityTestRule<WebViewActivity>(WebViewActivity.class,
+            false /* Initial touch mode */, false /*  launch activity */) {
+
+        &#64;Override
+        protected void afterActivityLaunched() {
+            // Enable JavaScript.
+            onWebView().forceJavascriptEnabled();
+        }
+    }
+
+    &#64;Test
+    public void typeTextInInput_clickButton_SubmitsForm() {
+       // Lazily launch the Activity with a custom start Intent per test
+       mActivityRule.launchActivity(withWebFormIntent());
+
+       // Selects the WebView in your layout.
+       // If you have multiple WebViews you can also use a
+       // matcher to select a given WebView, onWebView(withId(R.id.web_view)).
+       onWebView()
+           // Find the input element by ID
+           .withElement(findElement(Locator.ID, "text_input"))
+           // Clear previous input
+           .perform(clearElement())
+           // Enter text into the input element
+           .perform(DriverAtoms.webKeys(MACCHIATO))
+           // Find the submit button
+           .withElement(findElement(Locator.ID, "submitBtn"))
+           // Simulate a click via JavaScript
+           .perform(webClick())
+           // Find the response element by ID
+           .withElement(findElement(Locator.ID, "response"))
+           // Verify that the response page contains the entered text
+           .check(webMatches(getText(), containsString(MACCHIATO)));
+    }
+}
+</pre>
+
+<p>
+  For more information about Espresso Web, see the
+  <a href="https://google.github.io/android-testing-support-library/docs/espresso/web/index.html"
+  class="external-link">Espresso
+  Web documentation on the Android Testing Support Library site.</a>.
+  You can also download this code snippet as part of the
+  <a href="https://github.com/googlesamples/android-testing/tree/master/ui/espresso/WebBasicSample"
+  class="external-link">Espresso Web code sample</a>.
+</p>
+
+<!-- Section 2.6 -->
+
+<h3 id="verify-results">
+  Verifying Results
+</h3>
+
+<p>
+  Call the
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
+  or
+  <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
+  method to assert
+  that the view in the UI matches some expected state. You must pass in a
+  <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">{@code ViewAssertion}</a>
+  object as the argument. If the assertion fails, Espresso throws
+  an {@link junit.framework.AssertionFailedError}.
+</p>
+
+<p>
+  The
   <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
-      class provides a list of helper methods for specifying common
-      assertions. The assertions you can use include:
-    </p>
+  class provides a list of helper methods for specifying common
+  assertions. The assertions you can use include:
+</p>
 
-    <ul>
-      <li>
-        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
-Asserts that there is no view matching the specified criteria in the current view hierarchy.
-      </li>
+<ul>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
+    Asserts that there is no view matching the specified
+    criteria in the current view hierarchy.
+  </li>
 
-      <li>
-        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
-        Asserts that the specified view exists in the current view hierarchy
-        and its state matches some given Hamcrest matcher.
-      </li>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
+    Asserts that the specified view exists in the current view hierarchy
+    and its state matches some given Hamcrest matcher.
+  </li>
 
-      <li>
-       <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>
-       : Asserts that the specified children views for a
-        parent view exist, and their state matches some given Hamcrest matcher.
-      </li>
-    </ul>
+  <li>
+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>:
+    Asserts that the specified children views for a
+    parent view exist, and their state matches some given Hamcrest matcher.
+  </li>
+</ul>
 
-    <p>
-      The following code snippet shows how you might check that the text displayed in the UI has
-      the same value as the text previously entered in the
-      {@link android.widget.EditText} field.
-    </p>
+<p>
+  The following code snippet shows how you might
+  check that the text displayed in the UI has
+  the same value as the text previously entered in the
+  {@link android.widget.EditText} field.
+</p>
+
 <pre>
 public void testChangeText_sameActivity() {
     // Type text and then press the button.
@@ -580,14 +804,22 @@
 }
 </pre>
 
-<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
+<!-- Section 3 -->
+
+<h2 id="run">
+  Run Espresso Tests on a Device or Emulator
+</h2>
+
 <p>
-You can run Espresso tests from <a href="{@docRoot}studio/index.html">Android Studio</a> or
-from the command-line. Make sure to specify
-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
-  {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
+  You can run Espresso tests from
+  <a href="{@docRoot}studio/index.html">Android Studio</a> or
+  from the command-line. Make sure to specify
+  <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+  as the default instrumentation runner in your project.
 </p>
+
 <p>
-To run your Espresso test, follow the steps for running instrumented tests
-described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
-Getting Started with Testing</a>.</p>
+  To run your Espresso test, follow the steps for running instrumented tests
+  described in
+  <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">Getting Started with Testing</a>.
+</p>
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..dc94bdf 100644
--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
@@ -53,8 +53,9 @@
 
 <p>In your Android Studio project, you must store the source files for
 instrumented tests at
-<code><var>module-name</var>/src/androidTests/java/</code>. This directory
-already exists when you create a new project.</p>
+<code><var>module-name</var>/src/androidTest/java/</code>. This directory
+already exists when you create a new project and contains an example
+instrumented test.</p>
 
 <p>Before you begin, you should
   <a href="{@docRoot}tools/testing-support-library/index.html#setup">download
@@ -95,6 +96,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=
@@ -279,23 +293,21 @@
 of any app failures.</p>
 
 <p>
-  Before you can start using Firebase Test Lab, you need to:
+  Before you can start using Firebase Test Lab, you need to do the following
+unless you already have a Google account and a Firebase project with the Blaze
+billing plan enabled:
 </p>
 
 <ol>
-  <li>
-    <a href="https://console.developers.google.com/freetrial">Create a
-    Google Cloud Platform account</a> to use with active billing.
-  </li>
-
-  <li>
-    <a href="https://support.google.com/cloud/answer/6251787">Create a Google
-    Cloud project</a> for your app.
-  </li>
-
-  <li>
-    <a href="https://support.google.com/cloud/answer/6288653">Set up an active
-    billing account</a> and associate it with the project you just created.
+  <li><a href="https://accounts.google.com/">Create a Google account</a>,
+  if you don't have one already.</li>
+  <li>In the <a href="https://console.firebase.google.com/">Firebase
+  console</a>, click <b>Create New Project</b>.</li>
+  <li>In the Firebase console, click <b>Upgrade</b>, and then click <b>Select
+Plan</b> in the <b>Blaze</b> plan column.
+    <p class="note"><b>Note</b>: To learn about billing,
+see <a href="https://firebase.google.com/docs/test-lab/overview#billing">Test
+Lab billing</a>.</p>
   </li>
 </ol>
 
@@ -305,10 +317,10 @@
 </h4>
 
 <p>
-  Android Studio provides integrated tools that allow you to configure how you
- want to deploy your tests to Firebase Test Lab. After you have created a Google
-  Cloud project with active billing, you can create a test configuration and
-  run your tests:
+Android Studio provides integrated tools that allow you to configure how you
+want to deploy your tests to Firebase Test Lab. After you have created a
+Firebase project with Blaze plan billing, you can create a test configuration
+and run your tests:
 </p>
 
 <ol>
@@ -316,7 +328,8 @@
   the main menu.
   </li>
 
-  <li>Click <strong>Add New Configuration (+)</strong> and select
+  <li>Click <strong>Add New Configuration</strong> <img
+src="/studio/images/buttons/ic_plus.png" alt="" class="inline-icon"/> and select
   <strong>Android Tests</strong>.
   </li>
 
@@ -327,7 +340,7 @@
       </li>
 
       <li>From the <em>Target</em> drop-down menu under <em>Deployment Target
-      Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>.
+      Options</em>, select <strong>Firebase Test Lab Device Matrix</strong>.
       </li>
 
       <li>If you are not logged in, click <strong>Connect to Google Cloud
@@ -335,9 +348,9 @@
       </li>
 
       <li>Next to <em>Cloud Project</em>, click the <img src=
-      "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style=
-      "vertical-align:bottom;margin:0;"> button and select your Google Cloud
-      Platform project from the list.
+      "{@docRoot}images/tools/as-wrench.png" alt="" class="inline-icon"/>
+      button and select your Firebase
+      project from the list.
       </li>
     </ol>
   </li>
@@ -346,7 +359,7 @@
     <ol type="a">
       <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong>
         Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png"
-        alt="ellipses button" style="vertical-align:bottom;margin:0;">.
+        alt="" class="inline-icon">.
       </li>
 
       <li>Click <strong>Add New Configuration (+)</strong>.
@@ -372,8 +385,7 @@
   </li>
 
   <li>Run your tests by clicking <strong>Run</strong> <img src=
-  "{@docRoot}images/tools/as-run.png" alt="" style=
-  "vertical-align:bottom;margin:0;">.
+  "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon"/>.
   </li>
 </ol>
 
@@ -391,7 +403,7 @@
   When Firebase Test Lab completes running your tests, the <em>Run</em> window
   will open to show the results, as shown in figure 2. You may need to click
   <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt=
-  "" style="vertical-align:bottom;margin:0;"> to see all your executed tests.
+  "" class="inline-icon"/> to see all your executed tests.
 </p>
 
 <img src="{@docRoot}images/training/ctl-test-results.png" alt="">
@@ -403,15 +415,7 @@
 
 <p>
   You can also analyze your tests on the web by following the link displayed at
-  the beginning of the test execution log in the <em>Run</em> window, as shown
-  in figure 3.
-</p>
-
-<img src="{@docRoot}images/training/ctl-exec-log.png" alt="">
-
-<p class="img-caption">
-  <strong>Figure 3.</strong> Click the link to view detailed test results on
-  the web.
+  the beginning of the test execution log in the <em>Run</em> window.
 </p>
 
 <p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index d0dccba..d2bf881 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -649,25 +649,7 @@
           </li>
         </ul>
       </li>
-
       <li class="nav-section">
-        <div class="nav-section-header">
-          <a href="<?cs var:toroot ?>training/backup/index.html"
-             description=
-             "How to sync and back up app and user data to remote web services in the
-              cloud and how to restore the data back to multiple devices."
-            >Backing up App Data to the Cloud</a>
-        </div>
-        <ul>
-          <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html">
-            Configuring Auto Backup
-          </a>
-          </li>
-          <li><a href="<?cs var:toroot ?>training/backup/backupapi.html">
-            Using the Backup API
-          </a>
-          </li>
-        </ul>
         <li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html"
            description=
            "How to design a robust conflict resolution strategy for apps that save data to the cloud."
@@ -1888,6 +1870,12 @@
           >Managing Your App's Memory</a>
       </li>
       <li>
+        <a href="<?cs var:toroot ?>training/articles/memory-overview.html"
+          description=
+          "How Android manages app process and memory allocation."
+          >Overview of Android Memory Management</a>
+      </li>
+      <li>
         <a href="<?cs var:toroot ?>training/articles/perf-tips.html"
            description=
            "How to optimize your app's performance in various ways to improve its
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/docs/html/training/tv/playback/card.jd b/docs/html/training/tv/playback/card.jd
index a3a9872..2391185 100644
--- a/docs/html/training/tv/playback/card.jd
+++ b/docs/html/training/tv/playback/card.jd
@@ -43,7 +43,7 @@
 on demand. In the browse fragment where your app presents its content to the user, you create a
 {@link android.support.v17.leanback.widget.Presenter} for the content cards and pass it to the adapter
 that adds the content to the screen. In the following code, the <code>CardPresenter</code> is created
-in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android.support.v4.content.Loader, java.lang.Object) onLoadFinished()}
+in the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
 callback of the {@link android.support.v4.app.LoaderManager}.</p>
 
 <pre>
diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
index d5e4e67..34c6287 100644
--- a/docs/html/training/tv/playback/index.jd
+++ b/docs/html/training/tv/playback/index.jd
@@ -69,6 +69,10 @@
     <dd>Learn how to use the Leanback support library to guide a user through a series of
     decisions.</dd>
 
+  <dt><b><a href="onboarding.html">Introducing First-time Users to Your App</a></b></dt>
+    <dd>Learn how to use the Leanback support library to show first-time users
+    how to get the most out of your app.</dd>
+
   <dt><b><a href="options.html">Enabling Background Playback</a></b></dt>
     <dd>Learn how to continue playback when the user clicks on <strong>Home</strong>.</dd>
 </dl>
diff --git a/docs/html/training/tv/playback/onboarding.jd b/docs/html/training/tv/playback/onboarding.jd
new file mode 100644
index 0000000..bb41bec
--- /dev/null
+++ b/docs/html/training/tv/playback/onboarding.jd
@@ -0,0 +1,377 @@
+page.title=Introducing First-time Users to Your App
+page.tags=tv,onboarding,OnboardingFragment
+page.keywords=tv,onboarding,OnboardingFragment
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#addFragment">Add an OnboardingFragment</a></li>
+    <li><a href="#pageContent">Add OnboardingFragment Pages</a></li>
+    <li><a href="#logoScreen">Add an Initial Logo Screen</a></li>
+    <li><a href="#pageAnimations">Customize Page Animations</a></li>
+    <li><a href="#themes">Customize Themes</a></li>
+  </ol>
+  <h2>Try it out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
+    Leanback sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>
+To show a first-time user how to get the most from your app, present
+onboarding information at app startup. Here are some examples of onboarding
+information:
+</p>
+
+<ul>
+<li>Present detailed information on which channels are available when a user
+first accesses a channel app.</li>
+<li>Call attention to noteworthy features in your app.</li>
+<li>Illustrate any required or recommended steps that users should take when
+using the app for the first time.</li>
+</ul>
+
+<p>The <a href=
+"{@docRoot}tools/support-library/features.html#v17-leanback">v17 Leanback
+support library</a> provides the
+{@link android.support.v17.leanback.app.OnboardingFragment} class for
+presenting first-time user information. This lesson describes how to use the
+{@link android.support.v17.leanback.app.OnboardingFragment} class to present
+introductory information that is shown when the app launches for the first
+time. {@link android.support.v17.leanback.app.OnboardingFragment} uses TV UI
+best practices to present the information in a way that matches TV UI styles,
+and is easy to navigate on TV devices.</p>
+
+<img src="{@docRoot}images/training/tv/playback/onboarding-fragment.png"
+srcset="{@docRoot}images/training/tv/playback/onboarding-fragment.png 1x,
+{@docRoot}images/training/tv/playback/onboarding-fragment_2x.png 2x" />
+<p class="img-caption"><strong>Figure 1.</strong> An example
+OnboardingFragment.</p>
+
+<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} should
+not contain UI elements that require user input, such as buttons and fields.
+Similarly, it should not be used as a UI element for a task the user will do
+regularly. If you need to present a multi-page UI that requires
+user input, consider using a
+{@link android.support.v17.leanback.app.GuidedStepFragment}.</p>
+
+<h2 id="addFragment">Add an OnboardingFragment</h2>
+
+<p>To add an {@link android.support.v17.leanback.app.OnboardingFragment}
+to your app, implement a class that extends
+the {@link android.support.v17.leanback.app.OnboardingFragment} class. Add
+this fragment to an activity, either via the activity's layout XML, or
+programmatically. Make sure the activity or
+fragment is using a theme derived from
+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding},
+as described in <a href="#themes">Customize Themes</a>.</p>
+
+<p>In the {@link android.app.Activity#onCreate onCreate()} method of your
+app's main activity, call
+{@link android.app.Activity#startActivity startActivity()}
+with an {@link android.content.Intent} that points to your
+{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
+parent activity. This ensures that your
+{@link android.support.v17.leanback.app.OnboardingFragment} appears as
+soon as your app starts.<p>
+
+<p>To ensure that the
+{@link android.support.v17.leanback.app.OnboardingFragment} only appears the
+first time that the user starts your app, use a
+{@link android.content.SharedPreferences} object
+to track whether the user has already viewed the
+{@link android.support.v17.leanback.app.OnboardingFragment}. Define a boolean
+value that changes to true when the user finishes viewing the
+{@link android.support.v17.leanback.app.OnboardingFragment}. Check
+this value in your main activity’s
+{@link android.app.Activity#onCreate onCreate()}, and only start the
+{@link android.support.v17.leanback.app.OnboardingFragment} parent activity if
+the value is false. The following example shows an override of
+{@link android.app.Activity#onCreate onCreate()} that checks for a
+{@link android.content.SharedPreferences} value and, if not set to true, calls
+{@link android.app.Activity#startActivity startActivity()} to
+show the {@link android.support.v17.leanback.app.OnboardingFragment}:</p>
+
+<pre>
+&#64;Override
+protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_main);
+    SharedPreferences sharedPreferences =
+            PreferenceManager.getDefaultSharedPreferences(this);
+    // Check if we need to display our OnboardingFragment
+    if (!sharedPreferences.getBoolean(
+            MyOnboardingFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
+        // The user hasn't seen the OnboardingFragment yet, so show it
+        startActivity(new Intent(this, OnboardingActivity.class));
+    }
+}
+</pre>
+
+<p>After the user views the
+{@link android.support.v17.leanback.app.OnboardingFragment}, mark it as viewed
+using the {@link android.content.SharedPreferences} object. To do this, in your
+{@link android.support.v17.leanback.app.OnboardingFragment}, override
+{@link android.support.v17.leanback.app.OnboardingFragment#onFinishFragment
+onFinishFragment()} and set your {@link android.content.SharedPreferences} value
+to true, as shown in the following example:
+
+<pre>
+&#64;Override
+protected void onFinishFragment() {
+    super.onFinishFragment();
+    // User has seen OnboardingFragment, so mark our SharedPreferences
+    // flag as completed so that we don't show our OnboardingFragment
+    // the next time the user launches the app.
+    SharedPreferences.Editor sharedPreferencesEditor =
+            PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
+    sharedPreferencesEditor.putBoolean(
+            COMPLETED_ONBOARDING_PREF_NAME, true);
+    sharedPreferencesEditor.apply();
+}
+</pre>
+
+<h2 id="pageContent">Add OnboardingFragment Pages</h2>
+
+<p>After you add your
+{@link android.support.v17.leanback.app.OnboardingFragment}, you need to define
+the onboarding pages. An
+{@link android.support.v17.leanback.app.OnboardingFragment} displays content
+in a series of ordered pages. Each page can have a title, description, and
+several sub-views that can contain images or animations.</p>
+
+<img src="{@docRoot}images/training/tv/playback/onboarding-fragment-diagram.png"
+/><p class="img-caption"><strong>Figure 2.</strong> OnboardingFragment
+page elements.
+</p>
+
+<p>Figure 2 shows an example page with callouts marking customizable page
+elements that your {@link android.support.v17.leanback.app.OnboardingFragment}
+can provide. The page elements are:</p>
+
+<ol>
+<li>The page title.</li>
+<li>The page description.</li>
+<li>The page content view, in this case a simple green checkmark in a grey box.
+This view is optional. Use this view to illustrate page details such as a
+screenshot that highlights the app feature that the page describes.</li>
+<li>The page background view, in this case a simple blue gradient. This view
+always renders behind other views on the page. This view is optional.</li>
+<li>The page foreground view, in this case a logo. This view always renders
+in front of all other views on the page. This view is optional.</li>
+</ol>
+
+<p>Initialize page information when your
+{@link android.support.v17.leanback.app.OnboardingFragment} is first created
+or attached to the parent activity, as the system requests page
+information when it creates the fragment's view. You can initialize page
+information in your class constructor or in an override of
+{@link android.app.Fragment#onAttach onAttach()}.</p>
+
+<p>Override each of the following methods that provide page information
+to the system:</p>
+
+<ul>
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageCount
+getPageCount()} returns the number of pages in your
+{@link android.support.v17.leanback.app.OnboardingFragment}.</li>
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageTitle
+getPageTitle()} returns the title for the requested page number.</li>
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#getPageDescription
+getPagedescription()} returns the description for the requested page
+number.</li>
+</ul>
+
+<p>Override each of the following methods to provide optional sub-views used
+to display images or animations:</p>
+
+<ul>
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateBackgroundView
+onCreateBackgroundView()} returns a {@link android.view.View} that you
+create to act as the background view, or null if no background view is needed.
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
+onCreateContentView()} returns a {@link android.view.View} that you
+create to act as the content view, or null if no content view is needed.
+<li>{@link android.support.v17.leanback.app.OnboardingFragment#onCreateForegroundView
+onCreateForegroundView()} returns a {@link android.view.View} that you
+create to act as the foreground view, or null if no foreground view is needed.
+</ul>
+
+<p>The system adds the {@link android.view.View} that you create to the page
+layout. The following example overrides
+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateContentView
+onCreateContentView()} and returns an {@link android.widget.ImageView}:</p>
+
+<pre>
+private ImageView mContentView;
+...
+&#64;Override
+protected View onCreateContentView(LayoutInflater inflater, ViewGroup container) {
+    mContentView = new ImageView(getContext());
+    mContentView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+    mContentView.setImageResource(R.drawable.onboarding_content_view);
+    mContentView.setPadding(0, 32, 0, 32);
+    return mContentView;
+}
+</pre>
+
+<h2 id="logoScreen">Add an Initial Logo Screen</h2>
+
+<p>Your {@link android.support.v17.leanback.app.OnboardingFragment} can start
+with an optional logo screen that introduces your app. If you want to display
+a {@link android.graphics.drawable.Drawable} as your logo screen, in your
+{@link android.support.v17.leanback.app.OnboardingFragment OnboardingFragment's}
+{@link android.app.Fragment#onCreate onCreate()} method, call
+{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
+setLogoResourceId()} with the ID of your
+{@link android.graphics.drawable.Drawable}. The
+system will fade in and briefly display this
+{@link android.graphics.drawable.Drawable}, and then fade out the
+{@link android.graphics.drawable.Drawable}
+before displaying the first page of your
+{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
+
+<p>If you want to provide a custom animation for your logo screen, instead of
+calling
+{@link android.support.v17.leanback.app.OnboardingFragment#setLogoResourceId
+setLogoResourceId()}, override
+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateLogoAnimation
+onCreateLogoAnimation()} and return an {@link android.animation.Animator}
+object that renders your custom animation, as shown in the following example:
+</p>
+
+<pre>
+&#64;Override
+public Animator onCreateLogoAnimation() {
+    return AnimatorInflater.loadAnimator(mContext,
+            R.animator.onboarding_logo_screen_animation);
+}
+</pre>
+
+<h2 id="pageAnimations">Customize Page Animations</h2>
+
+<p>The system uses default animations when displaying the first page of your
+{@link android.support.v17.leanback.app.OnboardingFragment} and when the user
+navigates to a different page. You can customize these animations by
+overriding methods in your
+{@link android.support.v17.leanback.app.OnboardingFragment}.</p>
+
+<p>To customize the animation that appears on your first page,
+override
+{@link android.support.v17.leanback.app.OnboardingFragment#onCreateEnterAnimation
+onCreateEnterAnimation()} and return an {@link android.animation.Animator}.
+The following example creates an
+{@link android.animation.Animator} that scales the content view
+horizontally:</p>
+
+<pre>
+&#64;Override
+protected Animator onCreateEnterAnimation() {
+    Animator startAnimator = ObjectAnimator.ofFloat(mContentView,
+            View.SCALE_X, 0.2f, 1.0f).setDuration(ANIMATION_DURATION);
+    return startAnimator;
+}
+</pre>
+
+<p>To customize the animation used when the user navigates to a different page,
+override
+{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
+onPageChanged()}. In your
+{@link android.support.v17.leanback.app.OnboardingFragment#onPageChanged
+onPageChanged()} method, create {@link android.animation.Animator Animators}
+that remove the previous page and display the next page, add these to an
+{@link android.animation.AnimatorSet}, and play the set. The following
+example uses a fade-out animation to remove the previous page, updates the
+content view image, and uses a fade-in animation to display the next page:</p>
+
+<pre>
+&#64;Override
+protected void onPageChanged(final int newPage, int previousPage) {
+    // Create a fade-out animation used to fade out previousPage and, once
+    // done, swaps the contentView image with the next page's image.
+    Animator fadeOut = ObjectAnimator.ofFloat(mContentView,
+            View.ALPHA, 1.0f, 0.0f).setDuration(ANIMATION_DURATION);
+    fadeOut.addListener(new AnimatorListenerAdapter() {
+        &#64;Override
+        public void onAnimationEnd(Animator animation) {
+            mContentView.setImageResource(pageImages[newPage]);
+        }
+    });
+    // Create a fade-in animation used to fade in nextPage
+    Animator fadeIn = ObjectAnimator.ofFloat(mContentView,
+            View.ALPHA, 0.0f, 1.0f).setDuration(ANIMATION_DURATION);
+    // Create AnimatorSet with our fade-out and fade-in animators, and start it
+    AnimatorSet set = new AnimatorSet();
+    set.playSequentially(fadeOut, fadeIn);
+    set.start();
+}
+</pre>
+
+<p>For more details about how to create
+{@link android.animation.Animator Animators} and
+{@link android.animation.AnimatorSet AnimatorSets}, see
+<a href="https://developer.android.com/guide/topics/graphics/prop-animation.html">
+Property Animations</a>.</p>
+
+<h2 id="themes">Customize Themes</h2>
+
+<p>Any {@link android.support.v17.leanback.app.OnboardingFragment}
+implementation must use either the
+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} theme
+or a theme that inherits from
+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}. Set the
+theme for your {@link android.support.v17.leanback.app.OnboardingFragment} by
+doing one of the following:</p>
+
+<ul>
+<li>Set the {@link android.support.v17.leanback.app.OnboardingFragment
+OnboardingFragment's} parent activity to use the desired theme. The following
+example shows how to set an activity to use
+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding} in the
+app manifest:
+<pre>
+&lt;activity
+   android:name=".OnboardingActivity"
+   android:enabled="true"
+   android:exported="true"
+   android:theme="&#64;style/Theme.Leanback.Onboarding"&gt;
+&lt;/activity&gt;
+</pre>
+</li>
+<li>
+Set the theme in the parent activity by using the
+{@link android.support.v17.leanback.R.styleable#LeanbackOnboardingTheme_onboardingTheme}
+attribute in a custom activity theme. Point this attribute to another
+custom theme that only the
+{@link android.support.v17.leanback.app.OnboardingFragment}
+objects in your activity use. Use this approach if your activity already uses
+a custom theme and you don't want to apply
+{@link android.support.v17.leanback.app.OnboardingFragment} styles to other
+views in the activity.
+</li>
+<li>Override
+{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
+onProvideTheme()} and return the desired theme. Use this approach if
+multiple activities use your
+{@link android.support.v17.leanback.app.OnboardingFragment}
+or if the parent activity can't use the desired theme.
+The following example overrides
+{@link android.support.v17.leanback.app.OnboardingFragment#onProvideTheme
+onProvideTheme()} and returns
+{@link android.support.v17.leanback.R.style#Theme_Leanback_Onboarding}:
+<pre>
+&#64;Override
+public int onProvideTheme() {
+   return R.style.Theme_Leanback_Onboarding;
+}
+</pre>
+</li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd
index 97cf7ff..0639871 100644
--- a/docs/html/training/tv/start/hardware.jd
+++ b/docs/html/training/tv/start/hardware.jd
@@ -227,13 +227,19 @@
   </tr>
   <tr>
     <td>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</td>
-    <td>{@code android.hardware.location} <em>and</em> <br>
-      {@code android.hardware.location.network}</td>
+    <td>
+      <p>{@code android.hardware.location}</p>
+      <p>{@code android.hardware.location.network} (Target API level 20 or lower
+      only.)</p>
+    </td>
   </tr>
   <tr>
     <td>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</td>
-    <td>{@code android.hardware.location} <em>and</em> <br>
-      {@code android.hardware.location.gps}</td>
+    <td>
+      <p>{@code android.hardware.location}</p>
+      <p>{@code android.hardware.location.gps} (Target API level 20 or lower
+      only.)</p>
+    </td>
   </tr>
 </table>
 
@@ -246,6 +252,13 @@
   required ({@code android:required="false"}).
 </p>
 
+<p class="note">
+  <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or
+  higher and uses the <code>ACCESS_COARSE_LOCATION</code> or
+  <code>ACCESS_FINE_LOCATION</code> permission, users can still install your
+  app on a TV device, even if the TV device doesn't have a network card or a GPS
+  receiver.
+</p>
 
 <h3 id="check-features">Checking for hardware features</h2>
 
diff --git a/docs/html/training/volley/index.jd b/docs/html/training/volley/index.jd
index a8c4b84..d3645d9 100755
--- a/docs/html/training/volley/index.jd
+++ b/docs/html/training/volley/index.jd
@@ -42,7 +42,7 @@
 <li>Automatic scheduling of network requests.</li>
 <li>Multiple concurrent network connections.</li>
 <li>Transparent disk and memory response caching with standard HTTP
-<a href=http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
+<a href="http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
 <li>Support for request prioritization.</li>
 <li>Cancellation request API. You can cancel a single request, or you can set blocks or
 scopes of requests to cancel.</li>
@@ -66,13 +66,22 @@
 <a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a>
 repository at {@code frameworks/volley} and contains the main request dispatch pipeline
 as well as a set of commonly applicable utilities, available in the Volley "toolbox." The
-easiest way to add Volley to your project is to clone the Volley repository and set it as
-a library project:</p>
+easiest way to add Volley to your project is to add the following dependency to your app's
+build.gradle file:
+
+<pre class="no-pretty-print">
+dependencies {
+    ...
+    compile 'com.android.volley:volley:1.0.0'
+}
+</pre>
+
+You can also clone the Volley repository and set it as a library project:</p>
 
 <ol>
 <li>Git clone the repository by typing the following at the command line:
 
-<pre>
+<pre class="no-pretty-print">
 git clone https://android.googlesource.com/platform/frameworks/volley
 </pre>
 </li>
diff --git a/docs/html/training/wearables/notifications/creating.jd b/docs/html/training/wearables/notifications/creating.jd
index 35bb2bd..5663b58 100644
--- a/docs/html/training/wearables/notifications/creating.jd
+++ b/docs/html/training/wearables/notifications/creating.jd
@@ -58,7 +58,7 @@
 
 <p>To create a notification with the support library, you create an instance of
 {@link android.support.v4.app.NotificationCompat.Builder} and issue the notification by
-passing it to {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}. For example:
+passing it to {@link android.support.v4.app.NotificationManagerCompat#notify notify()}. For example:
 </p>
 
 <pre>
diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd
index c3f43a7..8056fc8 100644
--- a/docs/html/training/wearables/notifications/stacks.jd
+++ b/docs/html/training/wearables/notifications/stacks.jd
@@ -37,7 +37,7 @@
 
 <p>To create a stack, call {@link android.support.v4.app.NotificationCompat.Builder#setGroup setGroup()}
 for each notification you want in the stack and specify a
-group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()}
+group key. Then call {@link android.support.v4.app.NotificationManagerCompat#notify notify()}
 to send it to the wearable.</p>
 
 <pre style="clear:right">
@@ -59,7 +59,7 @@
 
 <p>Later on, when you create another notification, specify
 the same group key. When you call
-{@link android.support.v4.app.NotificationManagerCompat#notify(int, android.app.Notification) notify()},
+{@link android.support.v4.app.NotificationManagerCompat#notify notify()},
 this notification appears in the same stack as the previous notification,
 instead of as a new card:</p>
 
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
index 7c958c0..6ecc1ea 100644
--- a/docs/html/tv/index.jd
+++ b/docs/html/tv/index.jd
@@ -13,7 +13,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 </style>
diff --git a/docs/html/wear/images/partners/mkors.png b/docs/html/wear/images/partners/mkors.png
new file mode 100644
index 0000000..2f1e8ec
--- /dev/null
+++ b/docs/html/wear/images/partners/mkors.png
Binary files differ
diff --git a/docs/html/wear/images/partners/nixon.png b/docs/html/wear/images/partners/nixon.png
new file mode 100644
index 0000000..8674da2
--- /dev/null
+++ b/docs/html/wear/images/partners/nixon.png
Binary files differ
diff --git a/docs/html/wear/images/partners/polar.png b/docs/html/wear/images/partners/polar.png
new file mode 100644
index 0000000..2faeb06
--- /dev/null
+++ b/docs/html/wear/images/partners/polar.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index f5e9e87..1eb08be 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -9,7 +9,7 @@
 
 <style>
 .fullpage>#footer,
-#jd-content>.content-footer.wrap {
+#body-content>.content-footer.wrap {
   display:none;
 }
 </style>
@@ -267,6 +267,9 @@
             <div class="col-4">
               <img src="/wear/images/partners/mips.png" alt="MIPS">
             </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/mkors.png" alt=Michael Kors">
+            </div>
              <div class="col-4">
               <img src="/wear/images/partners/mobvoi.png" alt="Mobvoi">
             </div>
@@ -277,6 +280,12 @@
               <img src="/wear/images/partners/nb.png" alt="New Balance">
             </div>
             <div class="col-4">
+              <img src="/wear/images/partners/nixon.png" alt="Nixon">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/polar.png" alt="Polar">
+            </div>
+            <div class="col-4">
               <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
             </div>
             <div class="col-4">
diff --git a/docs/html/wear/preview/_book.yaml b/docs/html/wear/preview/_book.yaml
index a231fb5..54d5442 100644
--- a/docs/html/wear/preview/_book.yaml
+++ b/docs/html/wear/preview/_book.yaml
@@ -8,18 +8,24 @@
 - title: API Overview
   path: /wear/preview/api-overview.html
   section:
-  - title: Notification Improvements
-    path: /wear/preview/features/notifications.html
-  - title: Input Method Framework
-    path: /wear/preview/features/ime.html
   - title: Complications
     path: /wear/preview/features/complications.html
   - title: Navigation and Actions
     path: /wear/preview/features/ui-nav-actions.html
+  - title: Curved Layout
+    path: /wear/preview/features/wearable-recycler-view.html
+  - title: Notification Improvements
+    path: /wear/preview/features/notifications.html
   - title: Bridging for Notifications
     path: /wear/preview/features/bridger.html
+  - title: Input Method Framework
+    path: /wear/preview/features/ime.html
   - title: Wrist Gestures
     path: /wear/preview/features/gestures.html
+  - title: Standalone apps
+    path: /wear/preview/features/standalone-apps.html
+  - title: App Distribution
+    path: /wear/preview/features/app-distribution.html
 
 - title: Get Started
   path: /wear/preview/start.html
diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd
index 0b3ac6b..f4612a2 100644
--- a/docs/html/wear/preview/api-overview.jd
+++ b/docs/html/wear/preview/api-overview.jd
@@ -13,15 +13,16 @@
           <ol>
             <li><a href="#complications">Complications</a></li>
             <li><a href="#drawers">Navigation and Action Drawers</a></li>
+            <li><a href="#wrv">Curved Layout</a></li>
           </ol>
         </li>
 
         <li><a href="#notify">Notifications and Input</a>
           <ol>
-            <li><a href="#expanded">Expanded Notification</a></li>
-            <li><a href="#messaging">Messaging Style Notification</a></li>
+            <li><a href="#expanded">Expanded Notifications</a></li>
+            <li><a href="#messaging">Messaging Style Notifications</a></li>
+            <li><a href="#inline-action">Inline Action</a></li>
             <li><a href="#smart-replies">Smart Reply</a></li>
-            <li><a href="#content-action">Notification Content Action</a>
             <li><a href="#remote-input">Remote Input</a></li>
             <li><a href="#bridging">Bridging Mode</a></li>
             <li><a href="#imf">Input Method Framework</a></li>
@@ -40,308 +41,447 @@
 </div>
 </div>
 
+    <p>
+      Wear 2.0 is still in active development, but you can try it as part of
+      the Wear 2.0 Developer Preview. The sections below highlight some of the
+      new features for developers.
+    </p>
 
+    <h2 id="ui">
+      User Interface Improvements
+    </h2>
 
-<p>
-  The Android Wear Preview API is still in active development, but you can try
-  it now as part of the Wear 2.0 Developer Preview. The sections below
-  highlight some of the new features for Android Wear developers.
-</p>
+    <p>
+      The preview introduces powerful additions to the user interface, opening
+      up exciting possibilities to developers.
+    </p>
 
+    <h3 id="complications">
+      Complications
+    </h3>
 
-<h2 id="ui">User Interface Improvements</h2>
+    <img src="{@docRoot}wear/preview/images/complications-main-image.png"
+    height="320" style="float:right;margin:10px 0 0 40px">
+    <p>
+      A <a href=
+      "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a>
+      is a feature of a watch face that displays more than hours and minutes,
+      such as a battery indicator or a step counter. The Complications API thus
+      helps watch face developers create visual features and the data
+      connections they require.
+    </p>
 
-<p>
-  The preview introduces powerful additions to the user interface, opening up
-  exciting possibilities to developers. A complication
-  is any feature in a watch face that displays more than hours and
-  minutes. With the Complications API, watch faces can display extra information
-  and separate apps can expose complication data. The navigation and action
-  drawers provide users with new ways to interact with apps.
-</p>
+    <p>
+      Watch faces that use this API can display extra information without
+      needing code for getting the underlying data. Data providers can supply
+      data to any watch face using the API.
+    </p>
 
+    <p>
+      For information about this API, see <a href=
+      "{@docRoot}wear/preview/features/complications.html">Watch Face
+      Complications</a>.
+    </p>
 
-<h3 id="complications">Complications</h3>
-<img src="{@docRoot}wear/preview/images/complications-main-image.png"
-  height="320" style="float:right;margin:10px 0 0 40px" />
+    <h3 id="drawers">
+      Navigation and Action Drawers
+    </h3>
 
-<p>
-  A <a href=
-  "https://en.wikipedia.org/wiki/Complication_(horology)">complication</a> is a
-  feature of a watch face that displays more than hours and minutes, such as a
-  battery indicator or a step counter. The Complications API thus helps watch face
-  developers create visual features and the data connections they
-  require.
-</p>
+    <p>
+      Wear 2.0 introduces two new widgets, navigation drawer and action drawer.
+      These widgets give your users new ways to interact with your app. The
+      navigation drawer appears at the top of the screen and allows users to
+      navigate between app views. The action drawer appears at the bottom of
+      the screen and allows users to choose from a list of actions associated
+      with the current usage context. These drawers are accessible to users
+      when they edge swipe from the top or bottom of the screen; they peek when
+      users scroll in an opposite direction.
+    </p>
 
-<p>
-  Watch faces that use this API can display extra information without needing
-  code for getting the underlying data. Data providers can supply data to any
-  watch face using the API.
-</p>
+    <div class="cols">
+      <div class="col-2of6">
+        <img src="{@docRoot}wear/preview/images/nav_drawer.gif" height="240"
+        alt="" style="padding:.5em">
+      </div>
 
-<p>For information about this API,
-see <a href="{@docRoot}wear/preview/features/complications.html">
- Watch Face Complications</a>.
-</p>
+      <div class="col-2of6">
+        <img src="{@docRoot}wear/preview/images/action_drawer.gif" height="240"
+        alt="" style="padding:.5em;">
+      </div>
+    </div>
 
-<h3 id="drawers">Navigation and Action drawers</h3>
+    <p>
+      To learn how to add these widgets to your app, see <a href=
+      "{@docRoot}wear/preview/features/ui-nav-actions.html">Wear Navigation and
+      Actions</a>.
+    </p>
 
-<p>Wear 2.0 introduces two new widgets, navigation drawer and action drawer. These
- widgets give your users new ways to interact with your app. The navigation drawer
-  appears at the top of the screen and allows users to navigate between app views.
-   The  action drawer appears at the bottom of the screen and allows users to choose
-    from a list of actions associated with the current usage context.  These drawers
-     are accessible to users when they edge swipe from the top or bottom of the
-     screen; they peek when users scroll in an opposite direction.
-</p>
+    <h3 id="wrv">
+      Curved Layout
+    </h3>
 
-<div class="cols">
-  <div class="col-2of6">
-    <img src="{@docRoot}wear/preview/images/nav_drawer.gif"
-      height="240" alt="" style="padding:.5em">
-  </div>
-  <div class="col-2of6">
-    <img src="{@docRoot}wear/preview/images/action_drawer.gif"
-      height="240" alt="" style="padding:.5em;">
-  </div>
-</div>
+    <p>
+      Wear 2.0 introduces the <code>WearableRecyclerView</code> class for
+      displaying and manipulating a vertical list of items,
+      optimized for round displays.
+    </p>
 
-<p>
-  To learn how to add these widgets to your app, see
-  <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">
-  Wear Navigation and Actions</a>.
-</p>
+    <p>
+      The key features include the following:
+    </p>
 
+    <ul>
+      <li>A curved layout on round devices
+      </li>
 
-<h2 id="notify">Notifications and Input</h2>
+      <li>A circular scrolling gesture, which can be toggled on and off
+      </li>
+    </ul>
 
-<p>In Wear 2.0, we’ve redesigned the key experiences on the watch to be even more
- intuitive and provide users new ways to respond to messages. Some of the highlights
-  are below; for a complete list of changes, see
-  <a href="{@docRoot}wear/preview/features/notifications.html">Notification Changes in Wear 2.0</a>.
+    <p>
+      To learn how to create a curved layout optimized for round devices, see
+      <a href=
+      "https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
+      Curved Layout</a>.
+    </p>
 
+    <h2 id="notify">
+      Notifications and Input
+    </h2>
 
-<img src="{@docRoot}wear/preview/images/expanded_diagram.png" height="340"
-  style="float:left;margin:10px 20px 0 0" />
-<h3 id="expanded">Expanded notifications</h3>
+    <p>
+      In Wear 2.0, we’ve redesigned the key experiences on the watch to be even
+      more intuitive and provide users new ways to respond to messages. Some of
+      the highlights are below; for a complete list of changes, see <a href=
+      "{@docRoot}wear/preview/features/notifications.html">Notification Changes
+      in Wear 2.0</a>. <img src=
+      "{@docRoot}wear/preview/images/expanded_diagram.png" height="340" style=
+      "float:left;margin:10px 20px 0 0">
+    </p>
 
-<p>
-  When a user taps on a notification that is bridged from the phone to the
-  watch or that lacks a
-  <a href="{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
-  {@code contentIntent}</a>, the user will be taken to the expanded view of
-  that notification. When you <a href=
-  "{@docRoot}training/wearables/notifications/pages.html">specify additional
-  content pages</a> and actions for a notification, those are available to the
-  user within the expanded notification. Each expanded notification follows
-  <a href="https://google.com/design/spec-wear">Material Design for Android
-  Wear</a>, so the user gets an app-like experience.
-</p>
+    <h3 id="expanded">
+      Expanded Notifications
+    </h3>
 
+    <p>
+      When a user taps on a notification that is bridged from the phone to the
+      watch or that lacks a <a href=
+      "{@docRoot}reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">
+      {@code contentIntent}</a>, the user will be taken to the expanded view of
+      that notification. When you <a href=
+      "{@docRoot}training/wearables/notifications/pages.html">specify
+      additional content pages</a> and actions for a notification, those are
+      available to the user within the expanded notification. Each expanded
+      notification follows <a href=
+      "https://google.com/design/spec-wear">Material Design for Android
+      Wear</a>, so the user gets an app-like experience.
+    </p>
 
-<h3 id="messaging">Messaging Style notification</h3>
-<p> If you have a chat messaging app, your notifications should use
-{@code Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
-the chat messages included in a
-<a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
- notification
-(see {@code addMessage()}) to provide a rich chat app-like experience in the
-expanded notification.
-</p>
+    <h3 id="messaging">
+      Messaging Style Notifications
+    </h3>
 
+    <p>
+      If you have a chat messaging app, your notifications should use {@code
+      Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
+      the chat messages included in a <a href=
+      "{@docRoot}preview/features/notification-updates.html#style">{@code
+      MessagingStyle}</a> notification (see {@code addMessage()}) to provide a
+      rich chat, app-like experience in the expanded notification.
+    </p>
 
-<h3 id="smart-replies">Smart Reply</h3>
+    <h3 id="inline-action">
+      Inline Action
+    </h3>
 
-<p>Android Wear 2.0 introduces support for Smart Reply in
-<a href="{@docRoot}wear/preview/features/notifications.html#messaging">{@code MessagingStyle}</a>
- notifications. Smart Reply provides the user with contextually relevant,
- touchable choices in the expanded notification and in
- <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>.
-</p>
+    <p>
+      Wear 2.0 enables you to add an inline action within the notification
+      stream so that users can quickly take an action on a notification.
+      Examples of good use cases for an inline action within a notification stream
+      include replying to a text message, stopping a fitness activity, or
+      archiving an email message.
+    </p>
 
-<p>By enabling Smart Reply for your {@code MessagingStyle} notifications, you provide
-users a fast (single tap), discreet (no speaking aloud), and reliable way to respond
- to chat messages they receive.
- </p>
+    <p>
+      To learn how to add an inline action to your notification stream, see
+      <a href=
+      "https://developer.android.com/wear/preview/features/notifications.html#inline">
+      Inline Action</a>.
+    </p>
 
+    <h3 id="smart-replies">
+      Smart Reply
+    </h3>
 
-<img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
-  style="float:right;margin:10px 0 0 40px" />
+    <p>
+      Android Wear 2.0 introduces support for Smart Reply in <a href=
+      "{@docRoot}wear/preview/features/notifications.html#messaging">{@code
+      MessagingStyle}</a> notifications. Smart Reply provides the user with
+      contextually relevant, touchable choices in the expanded notification and
+      in <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code
+      RemoteInput}</a>.
+    </p>
 
-<h3 id="remote-input">Remote Input</h3>
+    <p>
+      By enabling Smart Reply for your {@code MessagingStyle} notifications,
+      you provide users a fast (single tap), discreet (no speaking aloud), and
+      reliable way to respond to chat messages they receive.
+    </p>
 
-<p>Wear 2.0 users can choose between various input options from
-<a href="{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
- These options include:
-</p>
-<ul>
-<li>Dictation</li>
-<li>Emoji</li>
-<li>Canned responses</li>
-<li>Smart Reply</i>
-<li>Default IME </i>
-</ul>
+    <img src="{@docRoot}wear/preview/images/remoteinput.png" height="350"
+    style="float:right;margin:10px 0 0 40px">
 
-<p>
-For messaging notifications with Smart Reply, the system-generated Smart Reply
- appears within <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
-  above the developer-provided list of canned responses.
-  You can also use the
-  <a href="{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">setChoices()</a>
-   method in the {@code RemoteInput} API to enable users to select from a list
-   of canned responses.
-</p>
+    <h3 id="remote-input">
+      Remote Input
+    </h3>
 
-<h3 id="bridging"> Bridging Mode </h3>
-<p>By default, notifications are
-<a href="{@docRoot}training/wearables/notifications/index.html">
-bridged</a> (shared) from an app on a companion phone
-to the watch. Since a phone app and a standalone watch app may be sources of the
- same notifications, the Android Wear 2.0 Preview includes a Bridging mode feature.
-  Developers can begin planning to change the behavior of notifications with the
-  following:
-</p>
+    <p>
+      Wear 2.0 users can choose between various input options from <a href=
+      "{@docRoot}reference/android/app/RemoteInput.html">Remote Input</a>.
+      These options include:
+    </p>
 
-<ul>
-<li>Specifying in the standalone app's Android manifest file that notifications from
- the corresponding phone app should not be bridged to the watch. </li>
-<li>Setting a dismissal ID so notification dismissals (by users) are synced across
-devices.</li>
-</ul>
+    <ul>
+      <li>Dictation
+      </li>
 
-<p>For an example of how to use this feature, see <a href="{@docRoot}wear/preview/features/bridger.html">
-Bridging Mode for Notifications</a>.</p>
+      <li>Emoji
+      </li>
 
-<h3 id="imf">Input Method Framework</h3>
+      <li>Canned responses
+      </li>
 
-<p>Wear 2.0 extends the Android input method framework (IMF) to Android Wear.
-This allows users to enter text on Wear using the system default IME or third party
- IMEs.  The Wear IME lets the user enter text via gesture typing as well as tapping
-  individual keys. The IMF APIs used for Wear devices are the same as other form
-  factors, though usage is slightly different due to limited screen real estate.
-</p>
+      <li>Smart Reply
+      </li>
 
-<p>Wear provides user settings on the watch that let the user:</p>
-<ul>
-<li>Enable multiple IMEs from the list of installed IMEs.</li>
-<li>Set a single default IME from the list of enabled IMEs.</li>
-<li>Change languages for various IMEs.</li>
-</ul>
+      <li>Default IME
+      </li>
+    </ul>
 
-<p>To learn how to create an IME for Wear, see <a href="{@docRoot}wear/preview/features/ime.html">
-Input Method Framework</a>.
-</p>
+    <p>
+      For messaging notifications with Smart Reply, the system-generated Smart
+      Reply appears within <a href=
+      "{@docRoot}reference/android/app/RemoteInput.html">{@code
+      RemoteInput}</a> above the developer-provided list of canned responses.
+      You can also use the <a href=
+      "{@docRoot}reference/android/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">
+      setChoices()</a> method in the {@code RemoteInput} API to enable users to
+      select from a list of canned responses.
+    </p>
 
-<h3 id="wrist-gestures">Wrist Gestures</h3>
+    <h3 id="bridging">
+      Bridging Mode
+    </h3>
 
-<p>
-  Wrist gestures can enable quick, one-handed interactions with your app
-  when use of a touch screen is inconvenient. The following
-  <a href="https://support.google.com/androidwear/answer/6312406">wrist gestures</a>
-  are available for use by apps:
-</p>
+    <p>
+      By default, notifications are <a href=
+      "{@docRoot}training/wearables/notifications/index.html">bridged</a>
+      (shared) from an app on a companion phone to the watch. Since a phone app
+      and a standalone watch app may be sources of the same notifications, the
+      Android Wear 2.0 Preview includes a Bridging mode feature.
+    </p>
 
-<ul>
-  <li>Flick wrist out</li>
-  <li>Flick wrist in</li>
-</ul>
+    <p>
+      For information about this feature, see <a href=
+      "{@docRoot}wear/preview/features/bridger.html">Bridging Mode for
+      Notifications</a>.
+    </p>
 
-<p>For more information, see
-<a href="{@docRoot}wear/preview/features/gestures.html">
- Wrist Gestures</a>.
-</p>
+    <h3 id="imf">
+      Input Method Framework
+    </h3>
 
-<h2 id="stand-alone">Standalone Devices</h2>
+    <p>
+      Wear 2.0 extends the Android input method framework (IMF) to Android
+      Wear. This allows users to enter text on Wear using the system default
+      IME or third party IMEs. The Wear IME lets the user enter text via
+      gesture typing as well as tapping individual keys. The IMF APIs used for
+      Wear devices are the same as other form factors, though usage is slightly
+      different due to limited screen real estate.
+    </p>
 
-<p>Standalone watches will enable Android Wear apps to work independently of phone
- apps. This means your app can continue to offer full functionality even if the
- paired phone is far away or turned off. </p>
+    <p>
+      Wear provides user settings on the watch that let the user:
+    </p>
 
-<h3 id="wear-apk">Wear-Specific APKs</h3>
+    <ul>
+      <li>Enable multiple IMEs from the list of installed IMEs.
+      </li>
 
-<p>For delivery to a watch, an Android Wear app is currently embedded in its corresponding
-phone app. This delivery method can result in an increased download size for users,
- regardless of whether they have an Android Wear device.
-</p>
+      <li>Set a single default IME from the list of enabled IMEs.
+      </li>
 
-<p>With standalone devices, the
-<a href ="{@docRoot}google/play/publishing/multiple-apks.html">Multi-APK</a>
- delivery method will be used. Developers will have the ability to release Android
-  Wear apps independently of the corresponding phone apps. Please stay tuned for
-   more information about this change.
-</p>
+      <li>Change languages for various IMEs.
+      </li>
+    </ul>
 
-<h3 id="network">Network Access</h3>
+    <p>
+      To learn how to create an IME for Wear, see <a href=
+      "{@docRoot}wear/preview/features/ime.html">Input Method Framework</a>.
+    </p>
 
-<p>Since Android Wear apps will work independently of phone apps, Android Wear's
- network access will no longer require the
- <a href="{@docRoot}training/wearables/data-layer/index.html">
- Wearable Data Layer API</a>. Android Wear apps will have the ability to make
- their own network requests. Additionally, they will be able to directly use
- Google Cloud Messaging.
-</p>
+    <h3 id="wrist-gestures">
+      Wrist Gestures
+    </h3>
 
-<p>No APIs for network access or GCM are specific to Android Wear; refer to the
-existing documentation about
-<a href="{@docRoot}training/basics/network-ops/connecting.html">
-Connecting to the Network</a> and
-<a href="https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
-</p>
+    <p>
+      Wrist gestures can enable quick, one-handed interactions with your app
+      when use of a touch screen is inconvenient. The following <a href=
+      "https://support.google.com/androidwear/answer/6312406">wrist
+      gestures</a> are available for use by apps:
+    </p>
 
-<p>We recommend using the following libraries:</p>
-<ul>
-<li><a href="{@docRoot}reference/android/app/job/JobScheduler.html">
-JobScheduler</a> for asynchronous jobs, including polling at regular intervals
-</li>
-<li>Multi-networking APIs if you need to connect to specific network types; see
-the <a href="{@docRoot}about/versions/android-5.0.html#Wireless">
-Multiple Network Connections</a>
-</li>
-</ul>
+    <ul>
+      <li>Flick wrist out
+      </li>
 
-<p>You will still be able to use the
-<a href="{@docRoot}training/wearables/data-layer/index.html">
- Wearable Data Layer API</a> to communicate with a phone app.
- However, use of this API to connect to a network will be discouraged.
- </p>
+      <li>Flick wrist in
+      </li>
+    </ul>
 
+    <p>
+      For more information, see <a href=
+      "{@docRoot}wear/preview/features/gestures.html">Wrist Gestures</a>.
+    </p>
 
-<h3 id="auth">Authentication</h3>
+    <h2 id="stand-alone">
+      Standalone Devices
+    </h2>
 
-<p>Since Android Wear apps will work independently of phone apps, Android Wear's
- authentication capabilities will be more powerful; apps will have new ways to
- authenticate.</p>
+    <p>
+      Standalone watches enable Android Wear apps to work independently of
+      phone apps. This means your app can continue to offer full functionality
+      even if the paired phone is far away or turned off.
+    </p>
 
-<h4>Users can enter a username and password on a watch</h4>
+    <h3 id="wear-apk">
+      Wear-Specific APKs
+    </h3>
 
-<p>Google Keyboard will be standard on Android Wear, allowing for direct text
-entry. This feature will work as expected with standard
-<a href="{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
-For passwords, the {@code textPassword} attribute will be used.</p>
+    <p>
+      For delivery to a watch, an Android Wear app is currently embedded in its
+      corresponding phone app. This delivery method can result in an increased
+      download size for users, regardless of whether they have an Android Wear
+      device.
+    </p>
 
-<h4>Utilizing Account Manager</h4>
+    <p>
+      For information about planning and building your standalone app
+      for Wear 2.0, see <a href=
+      "https://developer.android.com/wear/preview/features/standalone-apps.html">
+      Standalone Apps</a>.
+    </p>
 
-<p>Android Wear will include the
-<a href="{@docRoot}reference/android/accounts/AccountManager.html">
-AccountManager</a>, which will be accessible for syncing and storing account
-data, as it is on an Android phone.</p>
+    <p>
+      For information about distributing your app, see <a href=
+      "https://developer.android.com/wear/preview/features/app-distribution.html">
+      App Distribution</a>.
+    </p>
 
-<h4>Authentication tokens can be passed over the Wearable Data Layer</h4>
+    <h3 id="network">
+      Network Access
+    </h3>
 
-<p>For Android-paired watches (only), a phone securely
-transfers authentication credentials to a watch app via the
-<a href="{@docRoot}training/wearables/data-layer/index.html">
-Wearable Data Layer API</a>. The credentials can be transferred as
-messages or data items.</p>
+    <p>
+      Since Android Wear apps will work independently of phone apps, Android
+      Wear's network access will no longer require the <a href=
+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
+      API</a>. Android Wear apps will have the ability to make their own
+      network requests. Additionally, they will be able to directly use Google
+      Cloud Messaging. For more information, see
+      <a href=
+      "https://developer.android.com/wear/preview/features/standalone-apps.html#network_access">
+      Network Access and Cloud Messaging</a>.
+    </p>
 
-<p>If your watch app needs to determine if your phone app is installed, you can
-advertise a capability on the phone app and retrieve the capability on the
-watch. For more information, see the following sections of
-<a href="{@docRoot}training/wearables/data-layer/messages.html">
-Sending and Receiving Messages</a>:</p>
+    <p>
+      No APIs for network access or GCM are specific to Android Wear; refer to
+      the existing documentation about <a href=
+      "{@docRoot}training/basics/network-ops/connecting.html">Connecting to the
+      Network</a> and <a href=
+      "https://developers.google.com/cloud-messaging/">Cloud Messaging</a>.
+    </p>
 
-<ul>
-  <li>Advertise Capabilities</li>
-  <li>Retrieve the Nodes with the Required Capabilities</li>
-</ul>
+    <p>
+      We recommend using the following libraries:
+    </p>
+
+    <ul>
+      <li>
+        <a href=
+        "{@docRoot}reference/android/app/job/JobScheduler.html">JobScheduler</a>
+        for asynchronous jobs, including polling at regular intervals
+      </li>
+
+      <li>Multi-networking APIs, to connect to specific network
+      types; see <a href=
+      "{@docRoot}about/versions/android-5.0.html#Wireless">Multiple Network
+      Connections</a>
+      </li>
+    </ul>
+
+    <p>
+      The <a href=
+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
+      API</a> is available to communicate with a phone app.
+      However, use of this API to connect to a network will be discouraged.
+    </p>
+
+    <h3 id="auth">
+      Authentication
+    </h3>
+
+    <p>
+      Since Android Wear apps will work independently of phone apps, Android
+      Wear's authentication capabilities will be more powerful; apps will have
+      new ways to authenticate.
+    </p>
+
+    <h4>
+      Users can enter a username and password on a watch
+    </h4>
+
+    <p>
+      Google Keyboard will be standard on Android Wear, allowing for direct
+      text entry. This feature will work as expected with standard <a href=
+      "{@docRoot}reference/android/widget/EditText.html">EditText widgets</a>.
+      For passwords, the {@code textPassword} attribute will be used.
+    </p>
+
+    <h4>
+      Utilizing Account Manager
+    </h4>
+
+    <p>
+      Android Wear will include the <a href=
+      "{@docRoot}reference/android/accounts/AccountManager.html">AccountManager</a>,
+      which will be accessible for syncing and storing account data, as it is
+      on an Android phone.
+    </p>
+
+    <h4>
+      Authentication tokens can be passed over the Wearable Data Layer
+    </h4>
+
+    <p>
+      For Android-paired watches (only), a phone securely transfers
+      authentication credentials to a watch app via the <a href=
+      "{@docRoot}training/wearables/data-layer/index.html">Wearable Data Layer
+      API</a>. The credentials can be transferred as messages or data items.
+    </p>
+
+    <p>
+      If your watch app needs to determine if your phone app is installed, you
+      can advertise a capability on the phone app and retrieve the capability
+      on the watch. For more information, see the following sections of
+      <a href="{@docRoot}training/wearables/data-layer/messages.html">Sending
+      and Receiving Messages</a>:
+    </p>
+
+    <ul>
+      <li>Advertise Capabilities
+      </li>
+
+      <li>Retrieve the Nodes with the Required Capabilities
+      </li>
+    </ul>
diff --git a/docs/html/wear/preview/behavior-changes.jd b/docs/html/wear/preview/behavior-changes.jd
index 0214622..c93d337 100644
--- a/docs/html/wear/preview/behavior-changes.jd
+++ b/docs/html/wear/preview/behavior-changes.jd
@@ -22,6 +22,8 @@
 
 <ul>
   <li><a href="#activity-dismissal">Activity Dismissal</a></li>
+  <li><a href="#invalid-fields">Invalid Fields for a Complication Type</a></li>
+  <li><a href="#empty">Complication Types for Empty Data</a></li>
 </ul>
 
 </div>
@@ -61,3 +63,44 @@
   <a href="{@docRoot}wear/preview/features/ui-nav-actions.html">navigation
   drawers</a>.
 </p>
+
+<h2 id="invalid-fields">Invalid Fields for a Complication Type</h2>
+
+<p>
+  When a watch face uses the <a href="{@docRoot}wear/preview/features/complications.html">
+  Complications API</a>, the watch face requests data from a chosen provider.
+  A <code>ComplicationData</code> object, which contains
+  complication types, is returned.
+</p>
+
+<p>
+  A complication type determines the
+  kinds of data that a watch face can render. This section describes
+  a behavior change related to the <code>ComplicationData</code> object.
+</p>
+
+<p>
+  Starting with
+  <a href="https://developer.android.com/wear/preview/support.html#dp3">
+  Developer Preview 3</a>, when a watch face requests a field that is invalid
+  for a complication type, a default value for the field is returned.
+  For example, if a watch face tries to access a <code>Long text</code>
+  field in a <code>SHORT_TEXT</code> type, the default value for the
+  <code>Long text</code> field is returned.
+  In previous releases, such a request for an invalid field
+  (for a type) resulted in an exception.
+</p>
+
+<h2 id="empty">Complication Types for Empty Data</h2>
+
+<p>
+  Starting with
+  <a href="https://developer.android.com/wear/preview/support.html#dp3">
+  Developer Preview 3</a>, the complication types used for "empty" data are
+  changed. Apps that use the Complications API
+  may need to be updated to use
+  <code>TYPE_NO_DATA</code>. See the information
+  about <code>TYPE_NO_DATA</code> in the
+  <a href="{@docRoot}wear/preview/features/complications.html#types_and_fields">
+  Types and fields</a> section.
+</p>
diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd
index 4bc401b..da6a06d 100644
--- a/docs/html/wear/preview/downloads.jd
+++ b/docs/html/wear/preview/downloads.jd
@@ -171,7 +171,9 @@
           <li>
             <a href="#set_up_a_watch">Set Up a Watch</a>
           </li>
-
+          <li>
+            <a href="#set_up_a_phone">Set Up a Phone</a>
+          </li>
           <li>
             <a href="#set_up_an_emulator">Set Up an Emulator</a>
           </li>
@@ -180,7 +182,7 @@
     </div>
 
     <p>
-      You can run and test your app with the Android Wear 2.0 Developer Preview
+      You can run and test your app with the Android Wear 2.0 Preview
       in either of these ways:
     </p>
 
@@ -237,6 +239,13 @@
       following tables and flash it to the corresponding device.
     </p>
 
+    <p class="caution"><strong>Caution:</strong>
+      After you flash an image to a watch, follow the steps for
+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
+      the Android Wear companion app. To use a Wear 2.0 image on a watch,
+      you must have the beta companion app on a paired phone.
+    </p>
+
     <p>
       To restore your device to its original state during the preview,
       you can flash the appropriate retail system image, below, to the device.
@@ -266,9 +275,9 @@
         <td>
           Preview image for testing
         </td>
-        <td><a href="#top" onclick="onDownload(this)">nemo-nvd83h-factory-48ac950c.tgz</a><br>
-          MD5: dd351884cce9fb5bf1bdec0a8e5f56e3<br>
-          SHA-1: 48ac950c48faef96a7770e3c1acb56d23a28d859
+        <td><a href="#top" onclick="onDownload(this)">nemo-nve68j-factory-302a33ea.tgz</a><br>
+          MD5: ddfccc3e050c7e2db8d657c82f7d6291<br>
+          SHA-1: 302a33eac348c401fcb165bad4b9aaa40c7beb2b
         </td>
       </tr>
 
@@ -276,9 +285,9 @@
         <td>
           Non-preview image (for after testing)
         </td>
-        <td><a href="#top" onclick="onDownload(this)">nemo-mnc40x-factory-fa528bec.tgz</a><br>
-          MD5: 0b8ba3653d5a93cb854f4d7409d7b6c9<br>
-          SHA-1: fa528bec8aba3bf6c7d901ba63cd6ea0a08dbeb0
+        <td><a href="#top" onclick="onDownload(this)">nemo-mfd18l-factory-3faf6f2d.tgz</a><br>
+          MD5: f3a0090c0e99da82ad095b5d2a9acc6d<br>
+          SHA-1: 3faf6f2d7f422a17a5f6c54cf5e1d2c5622689b0
         </td>
       </tr>
 
@@ -307,18 +316,18 @@
         <td>
           Preview image for testing
         </td>
-        <td><a href="#top" onclick="onDownload(this)">sturgeon-nvd83h-factory-cb5a11ab.tgz</a><br>
-          MD5: 38c1047992b1d28f6833d9f6c8470cdc<br>
-          SHA-1: cb5a11ab0260ea3ca7da5894e73e41f70357da6b
+        <td><a href="#top" onclick="onDownload(this)">sturgeon-nve68j-factory-6607cd31.tgz</a><br>
+          MD5: f78ac6ba8bb84038d163cc2d7ca85040<br>
+          SHA-1: 6607cd31858af1bfd50b905c68f7cf1f0b6e570e
         </td>
       </tr>
       <tr id="sturgeon-non-preview">
         <td>
           Non-preview image (for after testing)
         </td>
-        <td><a href="#top" onclick="onDownload(this)">sturgeon-mec23l-factory-48003078.tgz</a><br>
-          MD5: 417b5cbddb29a2262bce133e283d2732<br>
-          SHA-1: 4800307843580f818557dd7c43d8ba2161e289b2
+        <td><a href="#top" onclick="onDownload(this)">sturgeon-m6e69f-factory-e659286a.tgz</a><br>
+          MD5: 12ce6cb0b0e43b67ea46a886eae052ae<br>
+          SHA-1: e659286aa9004f4555a476ede4e8b690f56cfefd
         </td>
       </tr>
     </table>
@@ -437,13 +446,14 @@
 
 
     <h4 id="set_up_watch">
-      Set up the watch and begin testing
+      Set up the watch
     </h4>
 
       <p>
         After the <code>flash-all</code> script finishes, your watch reboots.
-        Pair the watch with a phone or tablet. The preview now is available
-        for testing on the watch. Before installing an app, perform the
+        Only pair the watch with a phone (so you can begin testing the preview)
+        by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
+        Additionally, before installing an app, perform the
         following steps on the watch to re-secure the watch's bootloader:
     </p>
 
@@ -483,7 +493,9 @@
     </ol>
 
     <p>
-      Your watch is ready for you to <a href=
+      After you follow the instructions in
+      <a href="#set_up_a_phone">Set Up a Phone</a>,
+      your watch will be ready for you to <a href=
       "{@docRoot}training/wearables/apps/creating.html#Install">install and run
       your app</a>:
     </p>
@@ -539,13 +551,115 @@
       device reset and removes all user data on the device.
     </p>
 
+    <h2 id="set_up_a_phone">
+      Set Up a Phone
+    </h2>
+
+    <p>
+      On a phone, follow the instructions in this section to install the beta
+      version of the Android Wear companion app. The beta version cannot be run
+      on a phone at the same time as the non-beta version. Additionally, the
+      beta version is English-only.
+    </p>
+
+    <p>
+      <p class="caution"><strong>Caution:</strong> If you have an existing
+      pairing of the phone to a Wear 1.x
+      watch, installation of the beta companion app will cause a loss of that
+      pairing.
+    </p>
+
+    <h3 id="join-the-wear-2-0-preview-group">
+      Join the Wear 2.0 preview group
+    </h3>
+
+    <p>
+      To access the beta companion app, you must <a href=
+      "https://groups.google.com/forum/#!forum/android-wear-developer-preview">join
+      the preview group in Google Groups</a>.
+    </p>
+
+    <h3>
+      Opt in for beta testing
+    </h3>
+
+    <p>
+      On the <a href=
+      "https://play.google.com/apps/testing/com.google.android.wearable.app">Testing
+      Opt-in</a> page, select <strong>Become a Tester</strong>.
+    </p>
+
+    <h3 id="download-and-install-the-beta-version-of-the-companion-app">
+      Download and install the beta version of the companion app
+    </h3>
+
+    <p>
+      On the Play Store on your phone, go to the <a href=
+      "https://play.google.com/store/apps/details?id=com.google.android.wearable.app">
+      Android Wear app listing</a>. Tap <strong>Update</strong> to download and
+      install the beta version of the app. After installation, confirm that
+      <strong>Auto-update</strong> is selected for the app (see
+      the "Set up automatic updates for specific apps" section of <a href=
+      "https://support.google.com/googleplay/answer/113412">Update downloaded
+      apps</a>). Tap <strong>Open</strong> to start the app.
+    </p>
+
+    <h3 id="pairing">
+      Pair the phone to the watch
+    </h3>
+
+    <p>
+      After you install the beta version of the companion app on a phone,
+      you can pair the phone to the watch:
+    </p>
+
+    <ol>
+      <li>On the phone, select your device name from the list of devices.
+      A pairing code is displayed on the phone and on the watch.
+      Ensure that the codes match.
+      </li>
+
+      <li>Tap <strong>Pair</strong> to
+      continue the pairing process. When the watch is connected to
+      the phone, a confirmation message is displayed.
+      On the phone, a screen is displayed that lists
+      the accounts on the phone.
+      </li>
+
+      <li>Choose a Google Account to add and sync to your watch.
+      </li>
+
+      <li>Confirm the screen lock and enter the password to start the copying of
+      the account from the phone to the watch.
+      </li>
+
+      <li>Follow the instructions in the wizard to finish the
+      pairing process.
+      </li>
+    </ol>
+
+    <p>
+      You can begin testing your app with the preview.
+    </p>
+
     <h2 id="set_up_an_emulator">
       Set Up an Emulator
     </h2>
 
     <p>
-      To test with the Android Emulator, create a virtual device in Android
-      Studio as follows:
+      To test with the Android Emulator,
+      confirm that you have the latest version of the <strong>Android SDK
+      Platform-tools</strong> from the <a href=
+      "{@docRoot}studio/intro/update.html#sdk-manager">SDK Manager</a>.
+    </p>
+
+    <p>
+      After you create a virtual device as described below, follow the steps for
+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
+      the Android Wear companion app.
+    </p>
+
+    <p>Create a new virtual device in Android Studio as follows:
     </p>
 
     <ol>
@@ -556,19 +670,19 @@
       <li>Click <strong>Create Virtual Device</strong>.
       </li>
 
-      <li>In the <strong>Category</strong> pane, select Wear and
-       choose a hardware profile.
+      <li>In the <strong>Category</strong> pane, select <strong>Wear</strong>
+       and choose a hardware profile.
        The Android Wear 2.0 Developer Preview
        is only optimized for round devices currently, so we recommend not
        using the square or chin profiles for now.
        Click <strong>Next</strong>.
       </li>
 
-      <li>Select an <strong>N</strong> image to download. The images may be on
+      <li>Select a <strong>Nougat</strong> image to download. The images may be on
       the <strong>x86</strong> tab instead of the <strong>Recommended</strong>
       tab, until installed. For example, select the image with the
-      <strong>Release Name</strong> of N, the <strong>API Level</strong> of N,
-      and the <strong>Target</strong> of "Android 6.X (with Android Wear)".
+      <strong>Release Name</strong> of Nougat, the <strong>API Level</strong> of 24,
+      and the <strong>Target</strong> of "Android 7.0 (with Android Wear)".
       When the download and installation are complete, click
       <strong>Finish</strong> and then click <strong>Next</strong>.
       </li>
@@ -576,16 +690,68 @@
       <li>Verify the configuration of the Android Virtual Device (AVD) and
       click <strong>Finish</strong>.
       </li>
+
+      <li>Start the emulator by selecting the new virtual device, clicking the
+      <strong>Play</strong> button, and waiting until
+      the emulator initializes and shows the Android Wear home screen.
+      </li>
     </ol>
 
     <p>
-      You can now test an application with a virtual preview device
+      Pair the phone with the emulator, and sync a Google Account, as follows:
+    </p>
+
+    <ol>
+      <li>Follow the steps for
+      <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
+      the Android Wear companion app.
+      </li>
+
+      <li>On the phone, enable Developer Options and USB Debugging.
+      </li>
+
+      <li>Connect the phone to your computer through USB.
+      </li>
+
+      <li>Forward the AVD's communication port to the connected handheld device
+      (each time the phone is connected):<br>
+      <code>adb -d forward tcp:5601 tcp:5601</code>
+      </li>
+
+      <li>On the phone, in the Android Wear app, begin the standard pairing
+      process. For example, on the Welcome screen, tap the
+      <strong>Set It Up</strong> button.
+      Alternatively, if an existing watch already is paired, in the upper-left
+      drop-down, tap <strong>Add a New Watch</strong>.
+      </li>
+
+      <li>On the phone, in the Android Wear app, tap the
+      Overflow button, and then tap
+      <strong>Pair with Emulator</strong>.
+      </li>
+
+      <li>Tap the Settings icon.
+      </li>
+
+      <li>Under Device Settings, tap <strong>Emulator</strong>.
+      </li>
+
+      <li>Tap <strong>Accounts</strong> and select a Google Account,
+      and follow the steps in the wizard to
+      sync the account with the emulator. If necessary, type the screen-lock
+      device password, and Google Account password, to start the account sync.
+      </li>
+    </ol>
+
+    <p>
+      You can now test an app with a virtual preview device
       in the <a href=
       "{@docRoot}tools/devices/emulator.html">Android Emulator</a>. For more
       information about using virtual devices, see <a href=
-      "{@docRoot}tools/devices/managing-avds.html">Managing AVDs with the AVD
-      Manager</a>.
+      "{@docRoot}studio/run/managing-avds.html">
+      Create and Manage Virtual Devices</a>.
     </p>
+
  </div><!-- landing -->
 
 </div><!-- relative wrapper -->
diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd
new file mode 100644
index 0000000..afc9516
--- /dev/null
+++ b/docs/html/wear/preview/features/app-distribution.jd
@@ -0,0 +1,329 @@
+page.title=App Distribution
+meta.keywords="wear-preview"
+page.tags="wear-preview"
+page.image=images/cards/card-n-sdk_2x.png
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+  <ul>
+    <li><a href="#publish">Publish Your APKs</a></li>
+    <li><a href="#targeting">Setting Up Targeting for a Watch</a></li>
+    <li><a href="#console">Using the Play Developer Console</a></li>
+  </ul>
+
+</div>
+</div>
+
+    <p>
+      With Android Wear 2.0, a user can visit the Play Store on a watch and
+      download a Wear app directly to the watch.
+    </p>
+
+    <p>
+      Generally, a Wear 2.0 app in the Play Store needs
+      a minimum and target API level of 24 or higher in
+      the Android manifest file. The minimum SDK level can be 23
+      only if you are using the same APK
+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
+    </p>
+
+    <h2 id="publish">
+      Publish Your APKs
+    </h2>
+
+    <p>
+      To make your app appear in the on-watch Play Store, upload
+      the watch APK in the Play Developer Console just as you would any other
+      APK. If you only have a watch APK and no phone APK, no other steps
+      are required.
+    </p>
+
+    <p>
+      If you have a phone APK in addition to a watch APK, you must use the
+      <a href="https://developer.android.com/google/play/publishing/multiple-apks.html">Multi-APK delivery method</a>.
+    </p>
+
+    <p>
+      <a href=
+      "https://developer.android.com/training/permissions/requesting.html">Run-time
+      permissions</a> are required.
+    </p>
+
+    <p>
+      Also see
+      <a href="{@docRoot}wear/preview/features/standalone-apps.html">
+      Standalone Apps</a>.
+    </p>
+
+    <h3>
+      Distribution to Wear 2.0 watches
+    </h3>
+
+    <p>
+      If you only want your app to be distributed to Wear 2.0 watches,
+      it is unnecessary to embed the watch APK inside the the phone APK.
+    </p>
+
+    <p>
+      If you want your app to
+      be distributed to Wear 1.0 watches, you need to embed the
+      watch APK inside the phone APK, as described directly below.
+    </p>
+
+    <h3>
+      Distribution to Wear 1.0 and 2.0 watches
+    </h3>
+
+    <p>
+      If you are already distributing your app to Wear 1.0 watches,
+      follow these steps:
+    </p>
+
+    <ol>
+      <li>Provide a Wear 2.0 (standalone) version of your watch APK that can be made
+      available in the Play Store on Wear.
+      </li>
+
+      <li>Continue embedding a Wear 1.0 APK in your phone APK,
+      for use by watches that do not have Wear 2.0.
+      </li>
+    </ol>
+
+    <h3>
+      Specifying a version code
+    </h3>
+
+    <p>
+      To ensure that a standalone APK acts as an upgrade to an embedded Wear APK, the
+      standalone Wear APK's <a href=
+      "https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes">
+      version code</a> generally should be higher than the embedded Wear APK's version code.
+      (A phone APK's version code scheme can be independent from that of a watch
+      APK, although they must be unique.) However, the version codes
+      of the standalone APK and the embedded Wear APK can be the same if
+      the APKs are equivalent. If the APKs are not equivalent,
+      but the version code is the same, then when a watch updates from Wear 1.0
+      to 2.0, the watch may get the new APK only after waiting for a
+      longer-than-expected period of time.
+    </p>
+
+    <p>
+      Note that it currently is not possible to create a single APK that works
+      on a phone and watch.
+    </p>
+
+    <h3>
+      Support in the Gradle file
+    </h3>
+
+    <p>
+      If you have a Wear app that is intended for both Wear 1.0 and Wear 2.0,
+      consider using <a href=
+      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
+      product flavors</a>. For example,
+      if you want to target both SDK version 23 and version 24,
+      update your Wear module's <code>build.gradle</code> file to include
+      the following if an existing embedded app has a minimum SDK version of 23:
+    </p>
+
+<pre>
+android {
+    // Allows you to reference product flavors in your
+    // phone module's build.gradle file
+    publishNonDefault true
+    ...
+    defaultConfig
+    {
+       // This is the minSdkVersion of the Wear 1.0 embedded app
+       minSdkVersion 23
+       ...
+    }
+    buildTypes {...}
+    productFlavors {
+        wear1 {
+          // Use the defaultConfig value
+        }
+        wear2 {
+            minSdkVersion 24
+        }
+    }
+}
+</pre>
+
+    <p>
+      Then update your phone module’s <code>build.gradle</code> file, replacing
+      <code>wearApp</code> as follows:
+    </p>
+
+<pre>
+dependencies {
+    ...
+    wearApp project(path: ':wear', configuration: 'wear1Release')
+}
+</pre>
+
+    <p>
+      A <a href=
+      "https://developer.android.com/studio/build/build-variants.html#product-flavors">
+      build variant</a> is a combination of the product flavor and build type.
+      In Android Studio, select the appropriate build variant when
+      debugging or publishing your app. For example, if <code>wear2</code> is a
+      product flavor, select <strong>wear2Release</strong> as the
+      release build variant.
+    </p>
+
+    <p>
+      For purposes of code that is Wear 2.0-specific or Wear 1.0-specific,
+      consider <a href=
+      "https://developer.android.com/studio/build/build-variants.html#sourcesets">
+      source sets for build variants</a>.
+    </p>
+
+
+    <h2 id="targeting">
+      Setting Up Targeting for a Watch
+    </h2>
+
+    <p>
+      In your Android Manifest file, you must specify the following feature
+      restriction: the <code>uses-feature</code> element is set to
+      <code>android.hardware.type.watch</code>. Do not set
+      the <code>required</code> attribute to <code>false</code>.
+      A single APK for Wear and non-Wear devices presently is not supported.
+    </p>
+
+    <p>
+      Thus, if an APK has the following setting, Google Play provides the APK
+      to watches only:
+    </p>
+
+<pre>
+&lt;manifest package=&quot;com.example.standalone&quot;
+    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
+    &lt;uses-feature
+        android:name=&quot;android.hardware.type.watch&quot;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+    <p>
+      The <code>android.hardware.type.watch</code> setting above can be
+      combined with other criteria such as SDK version, screen resolution, and
+      CPU architecture. Thus, different Wear APKs can target different hardware
+      configurations.
+    </p>
+
+    <h2 id="console">
+      Using the Play Developer Console
+    </h2>
+
+    <p>
+      Below is an introduction to <a href=
+      "https://support.google.com/googleplay/android-developer/answer/113469">uploading</a>
+      a standalone Wear APK to an application listing using the Play Developer
+      Console.
+    </p>
+
+    <p>
+      If your app supports both Wear 1.0 and Wear 2.0, continue embedding the
+      Wear 1.0 APK (minimum SDK version of 20, 21, or 22, or 23) in the phone
+      APK and upload the phone APK. In addition, upload your standalone Wear
+      2.0 APK (which has a minimum SDK version of 24).
+    </p>
+
+    <p>
+      Also see <a href=
+      "https://developer.android.com/google/play/publishing/multiple-apks.html">
+      Multiple APK Support</a> and <a href=
+      "https://developer.android.com/distribute/googleplay/developer-console.html#manage">
+      Manage Your App</a>.
+      Before uploading an APK as described below, the APK
+      must be <a href=
+      "https://developer.android.com/studio/publish/app-signing.html#release-mode">
+      signed</a>.
+    </p>
+
+     <h3  id="uploading-apk">
+      Uploading your APK
+    </h3>
+
+    <p>
+      Go to the <a href="https://play.google.com/apps/publish">Play Developer
+      Console</a>, navigate to your application listing, and select
+      <strong>APK</strong> in the left-navigation panel. An APK screen similar to
+      the following is displayed:
+    </p>
+    <img src="../images/apk-tabs.png" width="" alt="alt_text">
+
+    <p>
+      You may need to use advanced mode for uploads, as follows:
+    </p>
+
+    <ul>
+      <li>Advanced mode is unnecessary if you only have a Wear 2.0 app and no
+      phone app. Instead of advanced mode, use simple mode.</li>
+
+      <li>Use advanced mode if you support Wear 1.0 or have a phone app.</li>
+    </ul>
+
+    <p>
+      Therefore, on the above APK screen, to determine whether to click
+      the <strong>Switch to advanced mode</strong>
+      button, consider the following:
+    </p>
+
+    <ul>
+      <li>If your app does not support Wear 1.0, and only has a watch APK,
+      upload it using simple mode.
+      </li>
+
+      <li>If your app does not support Wear 1.0 and has both a watch APK and a
+      phone APK, click <strong>Switch to advanced mode</strong>
+      to upload the watch and phone APKs.
+      </li>
+    </ul>
+
+    <p>
+      See <a href=
+      "https://developer.android.com/google/play/publishing/multiple-apks.html#SimpleAndAdvanced">
+      Simple mode and advanced mode</a> for more information about toggling
+      between modes.
+    </p>
+
+    <p>
+      Select the appropriate tab (<strong>Production</strong>, <strong>Beta
+      Testing</strong>, or <strong>Alpha Testing</strong>) for your upload.
+      Then click
+      the <strong>Upload New APK</strong> button and select your standalone
+      Wear APK for upload.
+    </p>
+
+    <h3>
+      Reviewing and publishing
+    </h3>
+
+    <p>
+      After you upload your standalone Wear APK and scroll down the resulting
+      page, the APK is shown in the <strong>Current APK</strong> table, with a
+      version number, in a similar way to the following:
+    </p>
+    <img src="../images/current-apk.png" width="" alt="alt_text">
+
+    <p>
+      Finally, in the <strong>Current APK</strong> table above, click the line
+      with the <strong>Version</strong> to review the APK. The <strong>APK
+      Details</strong> panel is displayed. You can verify, for example, that
+      the number in the <strong>Supported Android Devices</strong> line is far
+      fewer than the number would be for a typical phone APK:
+    </p>
+    <img src="../images/apk-details.png" width="" alt="alt_text">
+
+    <p>
+      When you are ready, <a href=
+      "https://support.google.com/googleplay/android-developer/answer/6334282">publish</a>
+      your app.
+    </p>
diff --git a/docs/html/wear/preview/features/bridger.jd b/docs/html/wear/preview/features/bridger.jd
index b7be093..2d879ca 100644
--- a/docs/html/wear/preview/features/bridger.jd
+++ b/docs/html/wear/preview/features/bridger.jd
@@ -6,19 +6,26 @@
 
     <div id="qv-wrapper">
       <div id="qv">
-        <ol>
+        <ul>
           <li>
             <a href=
-            "#preventing_bridging_with_the_bridging_mode_feature">Preventing
-            Bridging with the Bridging Mode Feature</a>
+            "#using-an-entry-in-the-manifest-file">Specifying a Bridging Configuration in the Manifest File</a>
           </li>
 
           <li>
             <a href=
-            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a
-            Dismissal ID to Sync Notification Dismissals</a>
+            "#specifying-a-bridging-configuration-at-runtime">Specifying a Bridging Configuration at Runtime</a>
           </li>
-        </ol>
+          <li>
+            <a href=
+            "#existing-method-of-preventing-bridging">Existing Method of Preventing Bridging</a>
+          </li>
+
+          <li>
+            <a href=
+            "#using_a_dismissal_id_to_sync_notification_dismissals">Using a Dismissal ID to Sync Notification Dismissals</a>
+          </li>
+        </ul>
       </div>
     </div>
 
@@ -27,19 +34,20 @@
       "{@docRoot}training/wearables/notifications/index.html">are bridged
       (shared)</a> from an app on a companion phone to the watch. If you build
       a standalone watch app and have a companion phone app, they may duplicate
-      notifications. The Android Wear 2.0 Preview includes a Bridging mode
-      feature to handle this problem of repeated notifications.
+      notifications. The Android Wear 2.0 Preview includes
+      features to handle this problem of repeated notifications.
     </p>
 
     <p>
-      With the Android Wear 2.0 Preview, developers can change the
-      behavior of notifications with the following:
+      With the Android Wear 2.0 Preview, developers can change the behavior of
+      notifications with one or more of the following:
     </p>
 
     <ul>
-      <li>Specifying in the standalone app's Android manifest file that
-      notifications from the corresponding phone app should not be
-      bridged to the watch
+      <li>Specifying a bridging configuration in the manifest file
+      </li>
+
+      <li>Specifying a bridging configuration at runtime
       </li>
 
       <li>Setting a dismissal ID so notification dismissals are synced across
@@ -47,43 +55,201 @@
       </li>
     </ul>
 
-    <h2 id="preventing_bridging_with_the_bridging_mode_feature">
-      Preventing Bridging with the Bridging Mode Feature
+    <h2 id="using-an-entry-in-the-manifest-file">
+      Specifying a Bridging Configuration in the Manifest File
     </h2>
 
     <p>
-      To prevent bridging of notifications from a phone app, you can use an
+      An app's Android manifest file can indicate that notifications from the
+      corresponding phone app should not be bridged to the watch. Specifically,
+      to prevent bridging of notifications from a phone app, you can use a
+      <code>&lt;meta-data&gt;</code>
       entry in the manifest file of the watch app (e.g. the standalone watch
       app), as follows:
     </p>
 
-    <pre>
+<pre>
 com.google.android.wearable.notificationBridgeMode
-    </pre>
+</pre>
 
     <p>
       Setting that entry to <code>NO_BRIDGING</code> will prevent bridging:
     </p>
 
-    <pre>
-&lt;meta-data android:name="com.google.android.wearable.notificationBridgeMode"
-                   android:value="NO_BRIDGING" /&gt;
+<pre>
+&lt;meta-data android:name=&quot;com.google.android.wearable.notificationBridgeMode&quot;
+                   android:value=&quot;NO_BRIDGING&quot; /&gt;
 </pre>
+
     <p>
-      The default bridging behavior occurs if you do not include the entry or
+      The default bridging behavior occurs if you do not
+      include the <code>&lt;meta-data&gt;</code> entry or
       if you specify a value of <code>BRIDGING</code> instead of
       <code>NO_BRIDGING</code>.
     </p>
 
-    <h3 id="existing_method_of_preventing_bridging">
-      Existing method of preventing bridging
+    <p>
+      For an existing app, if you are using
+      Google Cloud Messaging (GCM) or Firebase Cloud
+      Messaging (FCM) to send notification alerts to devices,
+      you may already have disabled bridging in case a phone is not
+      connected at the time of receiving an alert.
+      In this case, you may still want to dismiss the notification
+      across other devices when it is dismissed in a watch app.
+    </p>
+
+    <p>
+      The bridging configuration that is set in the manifest takes effect as
+      soon as a watch app is installed.
+    </p>
+
+    <h2 id="specifying-a-bridging-configuration-at-runtime">
+      Specifying a Bridging Configuration at Runtime
+    </h2>
+
+    <p>
+      This section describes how to specify a bridging configuration at runtime
+      using the <code>BridgingManager</code> class
+      <code>(android.support.wearable.notifications.BridgingManager)</code>.
+    </p>
+
+    <p>
+      You can set a bridging mode, and optionally set tags for notifications
+      that are exempt from the bridging mode, using a
+      <code>BridgingManager</code> object. Specifically, create a
+      <code>BridgingConfig</code> object and set it as shown in this section,
+      optionally using the <code>setBridgingEnabled</code> method. If you
+      specify a bridging configuration at runtime, then if the
+      <code>setBridgingEnabled</code> method is not set, bridging is enabled by
+      default.
+    </p>
+
+    <p>
+      Specifying a bridging configuration at runtime overrides a
+      bridging-related setting in the Android manifest file.
+    </p>
+
+    <h3 id="disable-bridging-for-all-notifications">
+      Disable bridging for all notifications
     </h3>
 
     <p>
+      You can use the <code>setBridgingEnabled</code> method, as follows:
+    </p>
+
+<pre>
+BridgingManager.setConfig(context,
+  new BridgingConfig.Builder(context)
+    .setBridgingEnabled(false)
+    .build());
+</pre>
+    <p>
+      If the above setter is not called, the bridging mode defaults to true.
+      Here is an example of setting tags without using the
+      <code>setBridgingEnabled</code> method, excluding notifications with a
+      tag of <code>foo</code> or <code>bar</code>:
+    </p>
+
+<pre>
+BridgingManager.setConfig(context,
+  new BridgingConfig.Builder(context)
+    .addExcludedTag("foo")
+    .addExcludedTag("bar")
+    .build());
+</pre>
+    <h3 id="exempt-notifications-that-are-tagged">
+      Exempt notifications that are tagged
+    </h3>
+
+    <p>
+      You can disable bridging for all notifications except those with certain
+      tags.
+    </p>
+
+    <p>
+      For example, you can disable bridging, except for notifications tagged as
+      <code>foo</code> or <code>bar,</code> with the following:
+    </p>
+
+<pre>
+BridgingManager.setConfig(context,
+  new BridgingConfig.Builder(context)
+    .setBridgingEnabled(false)
+    .addExcludedTag("foo")
+    .addExcludedTag("bar")
+    .build());
+</pre>
+
+    <p>
+      As another example, you can disable bridging for all notifications except
+      for notifications tagged as <code>foo</code>, <code>bar</code> or
+      <code>baz</code>.
+    </p>
+
+    <pre>
+BridgingManager.setConfig(context,
+  new BridgingConfig.Builder(context)
+    .setBridgingEnabled(false)
+    .addExcludedTags(Arrays.asList("foo", "bar", "baz"))
+    .build());
+</pre>
+    <h3 id="enable-bridging-except-for-notifications-with-certain-tags">
+      Enable bridging except for notifications with certain tags
+    </h3>
+
+    <p>
+      You can enable bridging for all notifications except those with certain
+      tags.
+    </p>
+
+    <p>
+      For example, you can enable bridging for all notifications, except for
+      notifications tagged as <code>foo</code> or <code>bar</code>, with the
+      following:
+    </p>
+
+<pre>
+BridgingManager.setConfig(context,
+  new BridgingConfig.Builder(context)
+    .setBridgingEnabled(true)
+    .addExcludedTag("foo")
+    .addExcludedTag("bar")
+    .build());
+</pre>
+
+    <h3 id="setting-a-bridge-tag">
+      Setting a bridge tag
+    </h3>
+
+    <p>
+      A bridge tag can be set on a notification by calling the
+      <code>setNotificationBridgeTag</code> method as follows:
+    </p>
+
+<pre>
+BridgingManager.setNotificationBridgeTag(&lt;NotificationCompat.Builder&gt;, &lt;String&gt;);
+</pre>
+
+    <p>
+      For example:
+    </p>
+
+<pre>
+NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
+&lt;set other fields&gt;;
+BridgingManager.setNotificationBridgeTag(builder, &quot;foo&quot;);
+Notification notification =  builder.build();
+</pre>
+
+    <h2 id="existing-method-of-preventing-bridging">
+      Existing Method of Preventing Bridging
+    </h2>
+
+    <p>
       An existing way to prevent bridging is with the
       <code>Notification.Builder</code> class; specify <code>true</code> in the
       <a href=
-      "{@docRoot}reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
+      "http://developer.android.com/reference/android/app/Notification.Builder.html#setLocalOnly(boolean)">
       setLocalOnly</a> method.
     </p>
 
@@ -95,12 +261,6 @@
       the watch app may not be installed on all of them.
     </p>
 
-    <p>
-      Thus, if bridging should be prevented when the watch app
-      is installed, use the <a href=
-      "#preventing_bridging_with_the_bridging_mode_feature">Bridging mode
-      feature</a>.
-    </p>
 
     <h2 id="using_a_dismissal_id_to_sync_notification_dismissals">
       Using a Dismissal ID to Sync Notification Dismissals
@@ -110,7 +270,7 @@
       If you prevent bridging with the Bridging mode feature, dismissals
       (cancellations) of notifications are not synced across a user's devices.
       However, the following methods of the <a href=
-      "{@docRoot}reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
+      "http://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html">
       NotificationCompat.WearableExtender</a> class enable you to use dismissal
       IDs:
     </p>
@@ -118,7 +278,7 @@
     <pre>
 public WearableExtender setDismissalId(String dismissalId)
 public String getDismissalId()
-    </pre>
+</pre>
     <p>
       To enable a dismissal to be synced, use the <code>setDismissalId()</code>
       method. For each notification, pass a globally unique ID, as a string,
@@ -135,12 +295,12 @@
 
     <pre>
 NotificationCompat.WearableExtender wearableExtender =
-new NotificationCompat.WearableExtender().setDismissalId(“abc123”);
+new NotificationCompat.WearableExtender().setDismissalId("abc123");
 Notification notification = new NotificationCompat.Builder(context)
 &lt;set other fields&gt;
 .extend(wearableExtender)
 .build();
-    </pre>
+</pre>
     <p>
       Dismissal IDs work if a watch is paired to an Android phone, but not if a
       watch is paired to an iPhone.
diff --git a/docs/html/wear/preview/features/complications.jd b/docs/html/wear/preview/features/complications.jd
index 3334cb7..c866118 100644
--- a/docs/html/wear/preview/features/complications.jd
+++ b/docs/html/wear/preview/features/complications.jd
@@ -13,6 +13,13 @@
             Complications to a Watch Face</a>
           </li>
           <li>
+            <a href="#permissions-for-complication-data">Permissions
+            for Complication Data</a>
+          </li>
+          <li>
+            <a href="#default-providers">Default Providers for Watch Faces</a>
+          </li>
+          <li>
             <a href="#exposing_data_to_complications">Exposing Data to
             Complications</a>
           </li>
@@ -27,12 +34,14 @@
             <a href="#api_additions">API Additions</a>
           </li>
       </ol>
+
     <h2>See Also</h2>
       <ol>
         <li><a class="external-link"
           href="https://github.com/googlesamples/android-WatchFace">Watch
           Face sample app with complications</a></li>
       </ol>
+
       </div>
     </div>
 
@@ -56,9 +65,12 @@
     </p>
 
     <p>
-      Along with reviewing this page, download the Android Wear 2.0 Preview
-      Reference (see the Complications API <a href=
-      "#api_additions">additions</a>) and review the Javadoc for complications.
+      You can review the Javadoc for complications by downloading
+      the Android Wear 2.0 Preview
+      Reference. Also see the <a href="#api_additions">API additions for
+      complications</a> and the
+      <a href="https://developer.android.com/wear/preview/behavior-changes.html">
+      behavior changes</a> for Wear 2.0.
     </p>
 
     <p>
@@ -117,8 +129,8 @@
       <code>WatchFaceService.Engine</code> class, with a list of watch face
       complication IDs. A watch face creates these IDs to uniquely identify
       slots on the watch face where complications can appear, and passes them
-      to the <code>createProviderChooserIntent</code> method (of the
-      <code>ProviderChooserIntent</code> class) to allow the user to decide
+      to the <code>createProviderChooserIntent</code> method
+      to allow the user to decide
       which complication should go in which slot.
     </p>
 
@@ -186,6 +198,406 @@
       where possible.
     </p>
 
+    <h2 id="permissions-for-complication-data">
+      Permissions for Complication Data
+    </h2>
+
+    <p>
+      A watch face must have the following <a href=
+      "https://developer.android.com/training/permissions/requesting.html">permission</a>
+      to receive complication data and open the provider chooser:
+    </p>
+
+<pre>
+com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA
+</pre>
+
+    <h3 id="opening-the-provider-chooser">
+      Opening the provider chooser
+    </h3>
+
+    <p>
+      A watch face that was not granted the above permission will be unable to
+      start the provider chooser.
+    </p>
+
+    <p>
+      To make it easier to request the permission and start the chooser, the
+      <code>ComplicationHelperActivity</code> class is available in the
+      wearable support library. This class should be used instead of
+      <code>ProviderChooserIntent</code> to start the chooser in almost all
+      cases.
+    </p>
+
+    <h4 id="requesting-the-necessary-permission">
+      Requesting the necessary permission
+    </h4>
+
+    <p>
+      To use <code>ComplicationHelperActivity</code>, add it to the watch face
+      in the <a href=
+      "https://developer.android.com/guide/topics/manifest/manifest-intro.html">
+      manifest file</a>:
+    </p>
+
+<pre>
+&lt;activity android:name=&quot;android.support.wearable.complications.ComplicationHelperActivity&quot;/&gt;
+</pre>
+
+    <p>
+      To start the provider chooser, call the
+      <code>ComplicationHelperActivity.createProviderChooserHelperIntent</code>
+      method, to obtain an intent.
+    </p>
+
+    <p>
+      The new intent can be used with either <code>startActivity</code> or
+      <code>startActivityForResult</code> to launch the chooser.
+    </p>
+
+    <p>
+      Here is an example of using the new intent with
+      <code>startActivityForResult</code>:
+    </p>
+
+    <pre>
+startActivityForResult(
+  ComplicationHelperActivity.createProviderChooserHelperIntent(
+     getActivity(),
+     watchFace,
+     complicationId,
+     ComplicationData.TYPE_LARGE_IMAGE),
+  PROVIDER_CHOOSER_REQUEST_CODE);
+</pre>
+    <p>
+      When the helper activity is started, the helper activity checks if the
+      permission was granted. If the permission was not granted, the helper
+      activity makes a runtime permission request. If the permission request is
+      accepted (or is unneeded), the provider chooser is shown.
+    </p>
+
+    <p>
+      If <code>startActivityForResult</code> was used with the intent, the
+      result delivered back to the calling Activity will have a result code of
+      <code>RESULT_OK</code> if a provider was successfully set, or a result
+      code of <code>RESULT_CANCELLED</code> if no provider was set.
+    </p>
+
+    <p>
+      In the case where a provider was set,
+      <code>ComplicationProviderInfo</code> for the chosen provider will be
+      included in the data intent of the result, as an extra with the key
+      <code>ProviderChooserIntent#EXTRA_PROVIDER_INFO</code>.
+    </p>
+
+    <h3 id="receiving-complication-data">
+      Receiving complication data
+    </h3>
+
+    <p>
+      In general, watch faces need the above permission in order to receive
+      complication data, but there are some exceptions. Specifically, a watch
+      face can only receive data from a provider if one of the following is
+      true:
+    </p>
+
+    <ul>
+      <li>The provider is a "safe" system provider,
+      </li>
+
+      <li>The provider and watch face are from the same app,
+      </li>
+
+      <li>The provider whitelists the watch face as a "safe" watch face, or
+      </li>
+
+      <li>The watch face has the permission
+      </li>
+    </ul>
+
+    <h4 id="lack-of-appropriate-permission">
+      Lack of appropriate permission
+    </h4>
+
+    <p>
+      If none of the above is true, then when <code>ComplicationData</code>
+      normally would be sent by a provider to a watch face, the system instead
+      sends data of the type <code>TYPE_NO_PERMISSION</code>. This type
+      includes an icon (an exclamation mark) and short text ("--") to allow it
+      to be rendered as if it were of the short text type or icon type, for
+      convenience.
+    </p>
+
+    <p>
+      When a watch face receives data of <code>TYPE_NO_PERMISSION</code>, the
+      watch face should render this appropriately, so the user can see that
+      action is needed for the complication to work. If possible, a tap on a
+      complication in this state should launch a permission request. This can
+      be done using
+      <code>ComplicationHelperActivity.createPermissionRequestHelperIntent</code>,
+      if the helper activity was added to the watch face app.
+    </p>
+
+    <p>
+      If a user accepts the permission request created by the helper activity,
+      updates are requested for all the active complications on the watch face
+      automatically, allowing the <code>TYPE_NO_PERMISSION</code> data to be
+      replaced by real data.
+    </p>
+
+    <h4 id="safe-providers">
+      Safe providers
+    </h4>
+
+    <p>
+      Some system providers are considered "safe", because they only supply
+      information that the watch face already could obtain itself.
+    </p>
+
+    <p>
+      These providers are listed in the new <code>SystemProviders</code> class
+      in the wearable support library. Whether a system provider is safe is
+      stated in the Javadoc (in the Android Wear 2.0 Preview Reference). Also
+      see <a href="#system-providers">System providers</a> for a list.
+    </p>
+
+    <h4 id="provider-specified-safe-watch-faces">
+      Provider-specified safe watch faces
+    </h4>
+
+    <p>
+      Providers can specify certain watch faces as "safe" to receive their
+      data. This is intended to be used only when the watch face will attempt
+      to use the provider as a default (see below),
+      and the provider trusts the watch face app.
+    </p>
+
+    <p>
+      To declare watch faces as safe, the provider adds metadata with a key of
+      <code>android.support.wearable.complications.SAFE_WATCH_FACES</code>. The
+      metadata value should be a comma-separated list (whitespace is ignored).
+      Entries in the list can be component names (of
+      <code>WatchFaceServices</code>, given as if
+      <code>ComponentName.flattenToString()</code> had been called), or they
+      can be package names (of apps, in which case every watch face within a
+      specified app is considered safe).
+    </p>
+
+    <p>
+      For example:
+    </p>
+
+<pre>
+&lt;meta-data
+       android:name=&quot;android.support.wearable.complications.SAFE_WATCH_FACES&quot;
+        android:value=&quot;
+          com.app.watchface/com.app.watchface.MyWatchFaceService,
+          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
+          com.something.text
+        &quot;/&gt;
+</pre>
+
+  <h2 id="default-providers">
+      Default Providers for Watch Faces
+  </h2>
+
+    <p>
+      Watch faces can specify default providers that are used until a user
+      selects a provider.
+    </p>
+
+    <h3 id="setting-default-providers">
+      Setting default providers
+    </h3>
+
+    <p>
+      Set default providers using the
+      <code>setDefaultComplicationProvider</code> method in
+      <code>WatchFaceService.Engine</code>. This method may be called at any
+      time, but it does nothing if the user already chose a provider for the
+      given complication.
+    </p>
+
+    <h3 id="safe-providers2">
+      Safe providers
+    </h3>
+
+    <p>
+      For most providers, the <code>RECEIVE_COMPLICATION_DATA</code> permission
+      must be granted to a watch face before data can flow to it. However, some
+      system providers are considered "safe", and do not require the watch face
+      to have the permission for data to be sent (see <a href=
+      "#safe-providers">Safe Providers</a> and <a href=
+      "#system-providers">System providers</a>). These providers may be
+      preferable to use as defaults, as they can supply data immediately.
+    </p>
+
+    <p>
+      Alternatively, if a watch face has a partnership with a certain provider
+      and wishes to use it as a default, it can request that the provider list
+      it as a safe watch face (see <a href=
+      "#provider-specified-safe-watch-faces">Provider-specified safe watch
+      faces</a>).
+    </p>
+
+    <h3 id="system-providers">
+      System providers
+    </h3>
+
+    <p>
+      The system includes providers that can be used as defaults. These are
+      listed in the <code>SystemProviders</code> class in the wearable support
+      library.
+    </p>
+
+    <p>
+      The following table has details about providers that are considered safe:
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          Method name in the SystemProviders class
+        </th>
+        <th>
+          Safety
+        </th>
+        <th>
+          Can be the default
+        </th>
+        <th>
+          Notes
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          <code>dateProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          The standard system date provider. Tapping opens the standard Agenda
+          app.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>currentTimeProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          The standard system "time and date" provider. No tap action.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>batteryProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          The standard system battery provider. No tap action.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>stepCountProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Shows a daily total of steps, as reported by
+          <code>readDailyTotal</code>.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>unreadCountProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Shows the number of unread notifications in the stream.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>worldClockProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Will default to London or New York. Can be tapped to change the time
+          zone.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>appsProvider()</code>
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Yes
+        </td>
+        <td>
+          Will show an "apps" icon at first, which can be tapped to choose an
+          app.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>nextEventProvider()</code>
+        </td>
+        <td>
+          No
+        </td>
+        <td>
+          Yes (but not a safe provider)
+        </td>
+        <td>
+          The standard system "next event" provider. Tapping opens
+            the standard Agenda app.
+          </p>
+        </td>
+      </tr>
+    </table>
+
+
     <h2 id="exposing_data_to_complications">
       Exposing Data to Complications
     </h2>
@@ -203,6 +615,11 @@
       be used to send data back to the system.
     </p>
 
+    <p class="note"><strong>Note:</strong> When you provide data as a
+    complication data provider, the watch face receives the raw values
+    you send so it can draw them on the watch face.
+    </p>
+
     <p>
       In your app's manifest, declare the service and add an intent filter for
       the following:
@@ -210,7 +627,8 @@
 
     <pre>
 android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST
-</pre>
+    </pre>
+
     <p>
       The service's manifest entry should also include an
       <code>android:icon</code> attribute. The provided icon should be a
@@ -227,6 +645,21 @@
       <a href="#api_additions">API Additions</a>).
     </p>
 
+    <p>
+      Additionally, a permission for provider services ensures that only the Android Wear system
+      can bind to provider services. Only the Android Wear system can have this
+      permission.
+    </p>
+
+    <p>
+      Provider services should add the following to their service declarations
+      in the manifest:
+    </p>
+
+<pre>
+android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER"
+</pre>
+
     <h3 id="update_period">
       Update period
     </h3>
@@ -371,6 +804,11 @@
     <p>
       The following table describes the types and fields of the
       <code>ComplicationData</code> object.
+      If a watch face requests a field that is invalid for a complication type,
+      a default value for the field is returned.
+      For example, if a watch face tries to access a <code>Long text</code>
+      field in a <code>SHORT_TEXT</code> type, the default value for the
+      <code>Long text</code> field is returned.
     </p>
 
     <table>
@@ -489,56 +927,80 @@
     </table>
 
     <p>
-      In addition, the following two types have no fields. These two types may
-      be sent for any complication slot and do not need to be included in a
-      list of supported types:
+      In addition, the types in the table below are for empty data and
+      may be sent for any complication slot. These types have no fields
+      and do not need to be included in a
+      list of supported types. These types enable watch
+      faces to differentiate among the following three cases:
+    </p>
+
+    <ul>
+      <li>No provider was chosen
+      </li>
+
+      <li>The user has selected "empty" for a slot
+      </li>
+
+      <li>A provider has no data to send
+      </li>
+    </ul>
+
+    <p>
+      Providers should not send <code>TYPE_EMPTY</code> in response to
+      update requests. Providers should send <code>TYPE_NO_DATA</code> instead.
+    </p>
+
+    <p>
+      Details on the complication types for "empty" data are in the
+      following table:
     </p>
 
     <table>
       <tr>
-        <th style="width:175px">
-          Type
+        <th>Complication type
         </th>
-        <th style="width:175px">
-          Required fields
-        </th>
-        <th style="width:175px">
-          Optional fields
-        </th>
-        <th>
-          Notes
+        <th>Description
         </th>
       </tr>
 
       <tr>
         <td>
-          NOT_CONFIGURED
+          <code>TYPE_NOT_CONFIGURED</code>
         </td>
         <td>
-          None
-        </td>
-        <td>
-          None
-        </td>
-        <td>
-          Sent when a provider has not yet been chosen for a complication.
+          Sent by the system when a complication is activated but the user has
+          not selected a provider, and no default was set.
+          <p>
+            Cannot be sent by providers.
+          </p>
         </td>
       </tr>
 
       <tr>
         <td>
-          EMPTY
+          <code>TYPE_EMPTY</code>
         </td>
         <td>
-          None
+          Sent by the system when a complication is activated and the user has
+          chosen "empty" instead of a provider, or when the watch face has
+          chosen no provider, and this type, as the default.
+          <p>
+            Cannot be sent by providers.
+          </p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>TYPE_NO_DATA</code>
         </td>
         <td>
-          None
-        </td>
-        <td>
-          Sent by a provider when there is no data to display in a
-          complication, or sent by the system when nothing should be shown in a
-          complication.
+          Sent by the system when a complication (that has a provider) is
+          activated, to clear the complication before actual data is received
+          from the provider.
+          <p>
+            Should be sent by providers if they have no actual data to send.
+          </p>
         </td>
       </tr>
     </table>
@@ -700,8 +1162,8 @@
     </h2>
 
     <p>
-      The Complications API includes new classes in the Wearable Support
-      Library. For more information, download the <a href=
+      The Complications API includes new classes in the wearable support
+      library. For more information, download the <a href=
       "{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation">
       Android Wear 2.0 Preview Reference</a>.
     </p>
@@ -722,26 +1184,14 @@
       </li>
 
       <li>
-        <code>ComplicationText</code>
+        <code>ComplicationHelperActivity</code>
         <ul>
-          <li>Used to supply text-based values in a
-          <code>ComplicationData</code> object
+          <li>Used to request the following permission: <br>
+<code>com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA</code>
           </li>
 
-          <li>Includes options for time-dependent values, whose text value
-          depends on the current time
-          </li>
-        </ul>
-      </li>
-
-      <li>
-        <code>ComplicationProviderService</code>
-        <ul>
-          <li>Extends <code>Service</code> and includes callback methods to
-          respond to the complication system
-          </li>
-
-          <li>Callback methods are all called on the main thread
+          <li>Used instead of <code>ProviderChooserIntent</code>
+          to start the chooser in almost all cases
           </li>
         </ul>
       </li>
@@ -759,13 +1209,35 @@
       </li>
 
       <li>
-        <code>ProviderChooserIntent</code>
+        <code>ComplicationProviderService</code>
         <ul>
-          <li>Non-instantiable utility class
+          <li>Extends <code>Service</code> and includes callback methods to
+          respond to the complication system
           </li>
 
-          <li>Includes a method that a watch face can call for starting a
-          provider chooser (to allow a user to configure complications)
+          <li>Callback methods are all called on the main thread
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <code>ComplicationText</code>
+        <ul>
+          <li>Used to supply text-based values in a
+          <code>ComplicationData</code> object
+          </li>
+
+          <li>Includes options for time-dependent values, whose text value
+          depends on the current time
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <code>ProviderChooserIntent</code>
+        <ul>
+          <li>Non-instantiable utility class that is not commonly used; use
+          <code>ComplicationHelperActivity</code> instead
           </li>
         </ul>
       </li>
@@ -789,6 +1261,16 @@
           </li>
         </ul>
       </li>
+
+      <li>
+        <code>SystemProviders</code>
+        <ul>
+          <li>Lists system providers that are considered "safe",
+          because they only supply information that the watch face
+          already could obtain itself
+          </li>
+        </ul>
+      </li>
     </ul>
 
     <p>
diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd
index dcc0970..b546978 100644
--- a/docs/html/wear/preview/features/notifications.jd
+++ b/docs/html/wear/preview/features/notifications.jd
@@ -1,6 +1,5 @@
 page.title=Notification Changes in Android Wear 2.0
-meta.tags="wear", "wear-preview", "notifications"
-page.tags="wear"
+meta.tags="wear", "wear-preview", "notifications" page.tags="wear"
 page.image=/wear/preview/images/expanded_diagram.png
 
 
@@ -12,6 +11,7 @@
     <h2>This document includes</h2>
     <ol>
       <li><a href="#visual">Visual Updates</a></li>
+      <li><a href="#inline">Inline Action</a></li>
       <li><a href="#expanded">Expanded Notifications</a></li>
       <li><a href="#messaging">MessagingStyle</a></li>
     </ol>
@@ -67,7 +67,8 @@
   We recommended that you don't set color for bridged notifications.
 
   When Wear apps post local notifications, you can work around this by checking
-  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a> they're running on and using an appropriate color
+  <a href="{@docRoot}training/basics/supporting-devices/platforms.html#version-codes">the API level of the device</a>
+   they're running on and using an appropriate color
   for Wear 1.x and a different color for Wear 2.0.
 </li>
 
@@ -77,6 +78,85 @@
   you must update the text of your notification.
 </li>
 </ul>
+
+<h2 id="inline">Inline Action</h3>
+
+<img src="{@docRoot}wear/preview/images/inline_action.png" style="float:right;margin:10px 20px 0 0">
+<p>
+  Wear 2.0 now supports inline action, which allows users to take actions on a
+  notification from within the notification stream card.  On Wear, the inline
+  action appears as an additional button displayed at the bottom of the notification.
+</p>
+<p>
+  Inline actions are optional but recommended for cases in which users are likely
+  to take an action on a notification after viewing the contents in the
+  notification stream card (without going to the
+  <a href= "{@docRoot}wear/preview/features/notifications.html#expanded">expanded notification</a>).
+  Examples of good use cases for inline action on a notification include: replying to a
+  text message, stopping a fitness activity, and archiving an email message.
+</p>
+
+<p>
+  A notification can provide only one inline action.
+  To display the inline action as an additional button in the notification, set
+  the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">{@code setHintDisplayActionInline()}</a>
+  method to true. When a user taps the inline action, the system invokes
+  the intent that you specified in the notification action.
+</p>
+
+<h3>Adding an inline action</h3>
+<p>
+  The following code example shows how to create a notification with an inline
+  reply action:
+</p>
+
+<ol>
+  <li>Create an instance of
+    <a href="https://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html">{@code RemoteInput.Builder}</a></code>
+    that you can add to your notification action. This class's constructor accepts a
+    string that the system uses as the key for the text input. Later, your app
+    uses that key to retrieve the text of the input.
+
+<pre>
+String[] choices = context.getResources().getStringArray(R.array.notification_reply_choices);
+    choices = WearUtil.addEmojisToCannedResponse(choices);
+  RemoteInput remoteInput = new RemoteInput.Builder(Intent.EXTRA_TEXT)
+        .setLabel(context.getString(R.string.notification_prompt_reply))
+        .setChoices(choices)
+        .build();
+</pre>
+
+  </li>
+
+  <li>
+    Use the <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#addRemoteInput(android.support.v4.app.RemoteInput)">{@code addRemoteInput()}</a>
+    method to attach the <ahref="https://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
+    object to an action.
+
+<pre>
+NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder(
+        R.drawable.ic_full_reply, R.string.notification_reply, replyPendingIntent);
+    actionBuilder.addRemoteInput(remoteInput);
+    actionBuilder.setAllowGeneratedReplies(true);
+</pre>
+  </li>
+
+  <li>
+    Add a hint to display the reply action inline, and use the
+    <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.WearableExtender.html#addAction(android.support.v4.app.NotificationCompat.Action)">{@code addAction}</a>
+    method to add this action to the notification.
+
+<pre>
+// Android Wear 2.0 requires a hint to display the reply action inline.
+    Action.WearableExtender actionExtender =
+        new Action.WearableExtender()
+            .setHintLaunchesActivity(true)
+            .setHintDisplayActionInline(true);
+    wearableExtender.addAction(actionBuilder.extend(actionExtender).build());
+</pre>
+  </li>
+</ol>
+
 <h2 id="expanded">Expanded Notifications</h2>
 <p>Android Wear 2.0 introduces <i>expanded notifications</i>, which provide
   substantial additional content and actions for each notification.
@@ -152,51 +232,52 @@
 </p>
 <h2 id="messaging">MessagingStyle</h2>
 
-<p>If you have a chat messaging app, your notifications should use
-<a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>,
- which is new in Android N. Wear 2.0 uses the chat messages included
-  in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification
-
-  (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide
-  a rich chat app-like experience in the expanded notification.
+<p>
+  If you have a chat messaging app, your notifications should use
+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>,
+  which is new in Android 7.0. Wear 2.0 uses the chat messages included in a
+  {@code MessagingStyle} notification
+  (see <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html#addMessage(android.support.v4.app.NotificationCompat.MessagingStyle.Message)">{@code addMessage()}</a>)
+  to provide a rich chat app-like experience in the expanded notification.
 </p>
 
-<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
+<p class="note">Note: <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a>
 expanded notifications require that you have at least version 1.5.0.2861804 of the
   <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a>
-  on your paired Android phone. That version will be available within the next
-  few weeks in the Play Store.
+  on your paired Android phone.
 </p>
 
 <h3 id="smart-reply">Smart Reply</h3>
 <img src="{@docRoot}wear/preview/images/messaging_style.png" height="420"
   style="float:right;margin:10px 20px 0 0" />
-<p>Wear 2.0 also introduces <i>Smart Reply</i>
-for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications.
+<p>Wear 2.0 also introduces <i>Smart Reply</i> for
+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code MessagingStyle}</a> notifications.
   Smart Reply provides the user with contextually relevant, touchable choices in
   the expanded notification and in {@code RemoteInput}. These augment the fixed
   list of choices that the developer provides in
-   <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
-    using the
-    <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
-</p>
-<p>By enabling Smart Reply for your MessagingStyle notifications,
-  you provide users with a fast (single tap), discreet (no speaking aloud), and
-  reliable way to respond to chat messages.
-</p>
-
-<p>Responses generated by Smart Reply are shown in addition to those set using the
+  <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
+  using the
   <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
 </p>
+<p> Smart Reply provides users with a fast (single tap), discreet (no speaking aloud),
+  private (messages received by a user never leave the watch), and reliable (no
+  internet connection needed) way to respond to chat messages.
+</p>
+
+<p>
+  Smart Reply responses are generated by an entirely on-watch machine learning
+  model using the context provided by the MessagingStyle notification. No user
+  notification data is sent to Google servers to generate Smart Reply responses.
+</p>
+
 <p>To enable Smart Reply for your notification action, you need to do the
 following:
 </p>
 <ol>
-  <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>.
+  <li>Use <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.html">{@code NotificationCompat.MessagingStyle}</a>.
   </li>
-  <li>Call the method {@code setAllowGeneratedReplies()} for the notification action.
-  For more information, see the downloadable
-  <a href="{@docRoot}preview/setup-sdk.html#docs-dl">API reference</a>.
+  <li>Call the method <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">{@code setAllowGeneratedReplies(true)}</a>
+   for the notification action.
   </li>
   <li>Ensure that the notification action has a
     <a href="{@docRoot}reference/android/app/RemoteInput.html">{@code RemoteInput}</a>
@@ -236,3 +317,29 @@
 // 3) add an action with RemoteInput
 .extend(new WearableExtender().addAction(action)).build();
 </pre>
+
+<h3 id="images">Adding images to a MessagingStyle notification</h3>
+<p>
+  You can add images to a notification message  by setting the appropriate MIME
+  type and placing the URI to the image in {@code NotificationCompat.MessagingStyle.Message.}
+  <a href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html#setData(java.lang.String, android.net.Uri)">{@code setData()}</a> method.
+</p>
+<p>
+  Here is the code snippet to set data of type image in a notification:
+</p>
+<pre>
+NotificationCompat.MessagingStyle.Message message = new Message("sticker", 1, "Jeff")
+                      .setData("image/png", stickerUri);
+
+  NotificationCompat notification = new NotificationCompat.Builder()
+             .setStyle(new NotificationComapt.MessagingStyle("Me")
+             .addMessage(message)
+             .build());
+
+</pre>
+<p>
+  In the above code snippet the variable <code>stickerUri </code>is a Uri that
+  points to a publicly-accessible location, as described <a
+  href="https://developer.android.com/reference/android/support/v4/app/NotificationCompat.MessagingStyle.Message.html">here
+  </a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/wear/preview/features/standalone-apps.jd b/docs/html/wear/preview/features/standalone-apps.jd
new file mode 100644
index 0000000..5c1930d
--- /dev/null
+++ b/docs/html/wear/preview/features/standalone-apps.jd
@@ -0,0 +1,499 @@
+page.title=Standalone Apps
+meta.keywords="wear-preview"
+page.tags="wear-preview"
+page.image=images/cards/card-n-sdk_2x.png
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+  <ul>
+    <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li>
+    <li><a href="#network_access">Network Access and Cloud Messaging</a></li>
+    <li><a href="#background_services">Using Background Services</a></li>
+    <li><a href="#fcm">Cloud Notifications Using FCM</a></li>
+    <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li>
+  </ul>
+
+</div>
+</div>
+
+    <p>
+      In Android Wear 2.0, apps can work independently of a phone. Users can
+      complete more tasks on a watch, without access to an Android or iOS
+      phone.
+    </p>
+
+    <h2 id="planning_apps">
+      Planning Your Phone and Watch Apps
+    </h2>
+
+    <p>
+      A watch APK targeting Wear 2.0 should not be embedded in a phone APK.
+      For more information, see
+      <a href="{@docRoot}wear/preview/features/app-distribution.html">
+      App Distribution</a>.
+    </p>
+
+    <p>
+      Generally, the minimum and target API level for a standalone app, and
+      for Wear 2.0, is level 24. The minimum SDK level can be 23
+      only if you are using the same APK
+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
+    </p>
+
+    <p>
+      If you build a standalone Wear 2.0 APK and will continue to have a
+      Wear 1.0 APK, please do both of the following:
+    </p>
+
+    <ul>
+      <li>Provide a standalone version of the Wear APK, and
+      </li>
+
+      <li>Continue embedding a version of the Wear APK in your phone APK
+      </li>
+    </ul>
+
+    <p>
+      <strong>Caution</strong>: For the Wear 2.0 Developer Preview, if you
+      publish an update to your production phone APK that has removed an embedded
+      Wear APK, production users who update the phone APK before installing
+      your standalone Wear APK will lose their existing Wear app and its data.
+      Therefore, it's important that you continue to embed
+      your watch APK into your phone APK.
+    </p>
+
+    <p>
+      <a href=
+      "https://developer.android.com/training/articles/wear-permissions.html">
+      Run-time permissions</a> are required for standalone apps.
+    </p>
+
+    <h3>
+      Shared code and data storage
+    </h3>
+
+    <p>
+      Code can be shared between a Wear app and a phone app. Optionally, code
+      that is specific to a form factor can be in a separate module.
+    </p>
+
+    <p>
+      For example, common code for networking can be in a shared library.
+    </p>
+
+    <p>
+      You can use standard Android storage APIs to store data locally.
+      For example, you can use
+      the <a href=
+      "https://developer.android.com/reference/android/content/SharedPreferences.html">
+      SharedPreferences APIs</a>, SQLite, or internal storage (as you would in
+      the case of a phone).
+    </p>
+
+    <h3>
+      Detecting your phone app or watch app
+    </h3>
+
+    <p>
+      If a user of your watch app needs your phone app, your watch app can
+      detect if the phone app is available. Using the <a href=
+      "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi">
+      CapabilityApi</a>, your phone app or watch app can advertise its presence
+      to a paired device. It can do so statically and dynamically. When an app
+      is on a node in a user's Wear network (i.e., on a phone, paired watch, or
+      in the cloud), the <code>CapabilityApi</code> enables another
+      app to detect if it is installed. For more information, see <a href=
+      "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities">
+      Advertise capabilities</a>.
+    </p>
+
+    <p>
+      If your phone app is unavailable, your can check if the Play Store is
+      available on the phone, as described below, before directing the user to
+      go to the Play Store (to install your phone app).
+    </p>
+
+    <h4>
+      Checking for Play Store availability on a phone
+    </h4>
+
+    <p>
+      iPhones and some Android phones lack the Play Store. A standalone Wear
+      app can check if the paired phone has the Play Store, before directing a
+      user to go there to install your phone app. The
+      <code>PlayStoreAvailability</code> class contains a
+      <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your
+      Wear app to check if a companion phone has the Play Store.
+    </p>
+
+    <p>
+      More information about the <code>PlayStoreAvailability</code> class is
+      available when you <a href=
+      "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation">
+      download the Android Wear 2.0 Preview Reference</a>. Here is a snippet
+      that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to
+      determine if the paired phone has the Play Store:
+    </p>
+
+<pre>
+int playStoreAvailabilityOnPhone =
+PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context);
+</pre>
+
+    <p>
+      The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code>
+      method is one of the following:
+    </p>
+
+    <table>
+      <tr>
+        <th>
+          <strong>Return value</strong>
+        </th>
+        <th>
+          <strong>Description</strong>
+        </th>
+      </tr>
+
+      <tr>
+        <td>
+          <code>PLAY_STORE_ON_PHONE_AVAILABLE</code>
+        </td>
+        <td>
+          The Play Store is available on the companion phone.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code>
+        </td>
+        <td>
+          The Play Store is not available on the companion phone.
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code>
+        </td>
+        <td>
+          An error occurred in the check for the Play Store; another check
+          should be made later.
+        </td>
+      </tr>
+    </table>
+
+    <h2 id="network_access">
+      Network Access and Cloud Messaging
+    </h2>
+
+    <p>
+      Android Wear apps can make their own network requests. When a watch has a
+      Bluetooth connection to a phone, the watch's network traffic is proxied
+      through the phone. When a phone is unavailable, Wi-Fi and cellular
+      networks are used, depending on the hardware. The Wear platform handles
+      transitions between networks. A watch's network access thus does not
+      require the <a href=
+      "https://developer.android.com/training/wearables/data-layer/index.html">
+      Wearable Data Layer API</a>.
+    </p>
+
+    <p>
+      For sending notifications, apps can directly use Firebase Cloud Messaging
+      (FCM), which replaces Google Cloud Messaging, or continue to use GCM.
+    </p>
+
+    <p>
+      No APIs for network access or FCM are specific to Android Wear.
+      Refer to the existing documentation about <a href=
+      "https://developer.android.com/training/basics/network-ops/connecting.html">
+      connecting to a network</a> and <a href=
+      "https://developers.google.com/cloud-messaging/">cloud messaging</a>.
+    </p>
+
+    <p>
+      You can use protocols such as HTTP, TCP, and UDP. However,
+      the <a href="https://developer.android.com/reference/android/webkit/package-summary.html">
+      android.webkit</a> APIs are not available. Therefore,
+      use of cookies is available by reading and writing headers on
+      requests and responses, but the <a href=
+      "https://developer.androidcom/reference/android/webkit/CookieManager.html">
+      CookieManager</a> class is not available.
+    </p>
+
+    <p>
+      FCM works well with
+      <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html">
+      Doze</a>.
+    </p>
+
+    <p>
+      Additionally, we recommend using the following:
+    </p>
+
+    <ul>
+      <li>The <a href=
+      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
+        JobScheduler</a> API for asynchronous jobs, including polling at
+        regular intervals (described below)
+      </li>
+
+      <li>Multi-networking APIs if you need to connect to specific network
+      types; see <a href=
+      "https://developer.android.com/about/versions/android-5.0.html#Wireless">
+        Multiple Network Connections</a>
+      </li>
+    </ul>
+
+    <p>
+      For foreground use cases, we currently recommend that you make a
+      request for an unmetered network. Here is an example of using
+      the multi-networking APIs to request an unmetered network:
+    </p>
+
+<pre>
+ConnectivityManager.NetworkCallback networkCallback =
+  new ConnectivityManager.NetworkCallback() {
+    &#64;Override
+    public void onAvailable(Network network) {
+      // access network
+      }
+    };
+ConnectivityManager connectivityManager =
+  (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+connectivityManager.requestNetwork(new NetworkRequest.Builder()
+  .addCapability(NET_CAPABILITY_NOT_METERED)
+  .build(), networkCallback);
+</pre>
+
+    <p>
+      We also recommend setting a timer for frontend scenarios
+      to prevent a user from potentially waiting for a long time.
+      When the network is no longer needed, or if the timer fires,
+      the network callback needs to be unregistered:
+    </p>
+
+<pre>
+connectivityManager.unregisterNetworkCallback(networkCallback):
+</pre>
+
+    <p>
+      A Wear app can communicate with a phone app using the <a href=
+      "https://developer.android.com/training/wearables/data-layer/index.html">Wearable
+      Data Layer API</a>, but connecting to a network using that API is
+      discouraged.
+    </p>
+
+    <h3 id="necessary_data">
+      Obtaining only the necessary data
+    </h3>
+
+    <p>
+      When obtaining data from the cloud, get only the necessary data.
+      Otherwise, you may introduce unnecessary latency, memory use, and battery
+      use.
+    </p>
+
+    <p>
+      When a watch is connected over a Bluetooth LE connection, your app may
+      have access to a bandwidth of only 10 kilobytes per second. Therefore,
+      the following steps are recommended:
+    </p>
+
+    <ul>
+      <li>Audit your network requests and responses for extra data that only is
+      for a phone app
+      </li>
+
+      <li>Shrink large images before sending them over a network to a watch
+      </li>
+    </ul>
+
+    <h2 id="background_services">
+      Using Background Services
+    </h2>
+
+    <p>
+      To ensure that background tasks are correctly executed, they must account
+      for <a href=
+      "https://developer.android.com/training/monitoring-device-state/doze-standby.html">
+      Doze</a>. In Android 6.0, Doze and App Standby resulted in significant
+      improvements to battery life by allowing devices to enter deep sleep when
+      idle and stationary.
+    </p>
+
+    <p>
+      Doze is <a href=
+      "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a>
+      in Android Nougat and Android Wear 2.0. When a screen turns off or enters
+      ambient mode for a long enough time, a subset of Doze can occur and
+      background tasks may be deferred for certain periods. Later, when a
+      device is stationary for an extended time, regular Doze occurs.
+    </p>
+
+    <p>
+      You should schedule jobs with the <a href=
+      "https://developer.android.com/reference/android/app/job/JobScheduler.html">
+      JobScheduler</a> API, which enables your app to register for Doze-safe
+      code execution. When scheduling jobs, you can select constraints such as
+      periodic execution and the need for connectivity or device charging.
+      It is important to configure jobs in a way that does not adversely
+      impact battery life. Jobs should use a
+      <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html">
+      JobInfo.Builder</a> object to provide constraints and metadata, e.g. with
+      one or more of the following methods for a task:
+    </p>
+
+    <ul>
+      <li>To schedule a task that requires networking, use
+      <code>setRequiredNetworkType(int networkType)</code>, specifying
+      <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>;
+      note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers
+      while <code>NETWORK_TYPE_ANY</code> is for small transfers
+      </li>
+
+      <li>To schedule a task while charging, use
+      <code>setRequiresCharging(boolean requiresCharging)</code>
+      </li>
+
+      <li>For specifying that a device is idle for a task, use
+      <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this
+      method can be useful for lower-priority background work or
+      synchronization, especially when used with
+      <code>setRequiresCharging</code>
+      </li>
+    </ul>
+
+    <p>
+      Note that some low-bandwidth networks, such as Bluetooth LE, are
+      considered metered.
+    </p>
+
+    <h3>
+      Scheduling with constraints
+    </h3>
+
+    <p>
+      You can schedule a task that requires constraints. In the example below,
+      a <code>JobScheduler</code> object activates <code>MyJobService</code>
+      when the following constraints are met:
+    </p>
+
+    <ul>
+      <li>Unmetered networking
+      </li>
+
+      <li>Device charging
+      </li>
+    </ul>
+
+    <p>
+      You can use the builder method <code>setExtras</code> to attach a bundle
+      of app-specific metadata to the job request. When your job executes, this
+      bundle is provided to your job service. Note the <code>MY_JOB_ID</code>
+      value passed to the <code>JobInfo.Builder</code> constructor. This
+      <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent
+      calls to cancel, and subsequent jobs created with that same value, will
+      update the existing job:
+    </p>
+
+<pre>
+JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID,
+        new ComponentName(this, MyJobService.class))
+        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+        .setRequiresCharging(true)
+        .setExtras(extras)
+        .build();
+((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE))
+        .schedule(jobInfo);
+</pre>
+
+    <p>
+      Below is an implementation of <a href=
+      "https://developer.android.com/reference/android/app/job/JobService.html">
+      JobService</a> to handle the job above. When the job executes, a
+      <code>JobParameters</code> object is passed into the
+      <code>onStartJob</code> method. The <code>JobParameters</code> object
+      enables you to get the job ID value along with any extras bundle provided
+      when scheduling the job. The <code>onStartJob</code> method is called on
+      the main application thread, and therefore any expensive logic should be
+      run from a separate thread. In the example, an <code>AsyncTask</code> is
+      used to run code in the background. When work is complete, you would call
+      the <code>jobFinished</code> method to notify <code>JobScheduler</code>
+      that the task is done:
+    </p>
+
+<pre>
+public class MyJobService extends JobService {
+    &#64;Override public boolean onStartJob(JobParameters params) {
+        new JobAsyncTask().execute(params);
+        return true;
+    }
+
+    private class JobAsyncTask extends AsyncTask
+</pre>
+
+    <h2 id="fcm">
+      Cloud Notifications Using FCM
+    </h2>
+
+    <p>
+      FCM is the recommended way to send notifications to a watch.
+    </p>
+
+    <p>
+      Provide for messages from FCM by collecting a registration token for a
+      device when your Wear app runs. Then include the token as part of the
+      destination when your server sends messages to the FCM REST endpoint. FCM
+      sends messages to the device identified by the token.
+    </p>
+
+    <p>
+      An FCM message is in JSON format and can include one or both of the
+      following payloads:
+    </p>
+
+    <ul>
+      <li>
+        <strong>Notification payload.</strong> When a notification payload is
+        received by a watch, the data is displayed to a user directly in the
+        notification stream. When the user taps the notification, your app is
+        launched.
+      </li>
+
+      <li>
+        <strong>Data payload</strong>. The payload has a set of custom
+        key/value pairs. The payload and is delivered as data to your Wear app.
+      </li>
+    </ul>
+
+    <p>
+      For more information and examples of payloads, see <a href=
+      "https://firebase.google.com/docs/cloud-messaging/concept-options">About
+      FCM Messages</a>.
+    </p>
+
+    <h2 id="fcm-phone">
+      Notifications from a Companion Phone
+    </h2>
+
+    <p>
+      By default, notifications are bridged (shared) from a phone app to a
+      watch. If you have a standalone Wear app and a corresponding phone app,
+      duplicate notifications can occur. For example, the same notification
+      from FCM, received by both a phone and a watch, could be
+      displayed by both devices independently.
+    </p>
+
+    <p>
+      For information about preventing duplicate notifications, see <a href=
+      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
+      Mode for Notifications</a>.
+    </p>
diff --git a/docs/html/wear/preview/features/wearable-recycler-view.jd b/docs/html/wear/preview/features/wearable-recycler-view.jd
new file mode 100644
index 0000000..f28a472
--- /dev/null
+++ b/docs/html/wear/preview/features/wearable-recycler-view.jd
@@ -0,0 +1,223 @@
+
+page.title=Curved Layout
+meta.tags="wear", "wear-preview", "RecyclerView"
+page.tags="wear"
+
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#creating">Creating a Curved Layout</a></li>
+      <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li>
+      <li><a href="#aligning">Anchoring Children to the Curve</a></li>
+    </ol>
+
+</div>
+</div>
+
+
+<p>
+  Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying
+  and manipulating a vertical list of items optimized for round displays.
+  {@code WearableRecyclerView} extends the existing
+  <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a>
+  class to provide a curved layout and a circular scrolling gesture in wearable apps.
+</p>
+<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png"
+      style="float:right;margin:10px 20px 0 0">
+
+<p>
+  You can adapt to this interface in your wearable app by creating a new
+  {@code WearableRecyclerView} container.
+</p>
+
+<p>
+  You should decide whether to use a {@code WearableRecyclerView}, based on
+  the kind of user experience you want to provide. We recommend using the
+  {@code WearableRecyclerView} for a simple, long list of items, such as an
+  application launcher, or a list contacts. Each item might have a short string
+  and an associated icon. Alternatively, each item might have only a string or
+  an icon. We do not recommend using a {@code WearableRecyclerView} for short
+  or complex lists.
+</p>
+
+<p>
+  This document describes how to create a curved layout for your scrollable items
+  and properly align them along the curve.
+</p>
+
+
+<h2 id="creating">Creating a Curved Layout</h2>
+<p>To create a curved layout for scrollable items in your wearable app:
+</p>
+<ul>
+  <li>Use {@code WearableRecyclerView} as your main container in the relevant
+      xml layout.
+  </li>
+
+  <li>By default, {@code WearableRecyclerView} uses the {@code
+    DefaultOffsettingHelper} class to offset items in a curved layout on round
+    devices. If you wish to implement your own offsetting logic, you can extend the
+    abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to
+    the {@code WearableRecyclerView} using {@code
+    WearableRecyclerView.setOffsettingHelper} method.
+
+    <pre>
+      CircularOffsettingHelper circularHelper = new CircularOffsettingHelper();
+      mRecyclerView.setOffsettingHelper(circularHelper);
+    </pre>
+
+    <pre>
+      public class CircularOffsettingHelper extends OffsettingHelper {
+
+        &#64;Override
+        public void updateChild(View child, WearableRecyclerView parent) {
+          int progress = child.getTop() / parent.getHeight();
+          child.setTranslationX(-child.getHeight() * progress);
+         }
+      }
+    </pre>
+
+  </li>
+
+</ul>
+
+<p class="note">
+  <strong>Note:</strong> {@code DefaultOffsettingHelper} class
+  offsets the child items
+  along a predefined UX curve, but the operation can cut off part of the child
+  view if it is not scaled down accordingly. This is because the default curve
+  attempts to fit 5 items on the screen, regardless of their size.
+  If you do not wish to scale your items, you should consider additional padding.
+</p>
+
+<h3>Examples</h3>
+<p>
+  The following code example demonstrates how to add {@code WearableRecyclerView}
+   to a layout:
+</p>
+<pre>
+&lt;android.support.wearable.view.WearableRecyclerView
+   xmlns:android="http://schemas.android.com/apk/res/android"
+   xmlns:tools="http://schemas.android.com/tools"
+   android:id="&#64;+id/recycler_launcher_view"
+   android:layout_width="match_parent"
+   android:layout_height="match_parent"
+   android:scrollbars="vertical" /&gt;
+ </pre>
+
+
+<p>
+  To customize the appearance of the children while scrolling (for example,
+  scale the icons and text while the items scroll away from the center),  extend
+  the  {@code DefaultOffsettingHelper} and override the {@code updateChild }
+  method. It is important to call the {@code super.updateChild(child, parent)} to
+  offset the children along the curve. However, if for any particular child you do
+  not wish them to follow a curve, you can chose not to call the super method for
+  that particular child.
+</p>
+
+<pre>
+
+public class MyOffsettingHelper extends DefaultOffsettingHelper {
+
+   /** How much should we scale the icon at most. */
+   private static final float MAX_ICON_PROGRESS = 0.65f;
+
+   private float mProgressToCenter;
+
+   public OffsettingHelper() {}
+
+   &#64;Override
+
+   public void updateChild(View child,  WearableRecyclerView parent) {
+       super.updateChild(child, parent);
+
+
+       // Figure out % progress from top to bottom
+       float centerOffset = ((float) child.getHeight() / 2.0f) /  (float) mParentView.getHeight();
+       float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset;
+
+       // Normalize for center
+       mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset);
+       // Adjust to the maximum scale
+       mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS);
+
+       child.setScaleX(1 - mProgressToCenter);
+       child.setScaleY(1 - mProgressToCenter);
+   }
+}
+
+
+</pre>
+
+
+<h2 id="adding">Adding a Circular Scrolling Gesture</h2>
+
+<p>
+  By default, circular scrolling is disabled in the {@code
+  WearableRecyclerView}. If you want to enable circular scrolling gesture
+  in your child view, use the  {@code WearavleRecyclerView}’s {@code
+  setCircularScrollingGestureEnabled()} method.  You can also customize the
+  circular scrolling gesture by defining one or both of the following:
+</p>
+
+<ul>
+  <li>How many degrees the user has to rotate by to scroll through one screen height.
+    This effectively influences the speed of the scolling -
+    {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees.
+  </li>
+
+  <li>
+    The width of a virtual ‘bezel’ near the the edge of the screen in which the
+    gesture will be recognized - {@code setBezelWidth} - the default value is set
+    at 1. This is expressed as a fraction of the radius of the view.
+</ul>
+
+
+<p>The following code snippet shows how to set these methods:</p>
+
+<pre>
+  setCircularScrollingGestureEnabled(true);
+  setBezelWidth(0.5f);
+  setScrollDegreesPerScreen(90);
+</pre>
+
+<h2 id="aligning"> Anchoring Children to the Curve </h2>
+
+<p>
+  To ensure that the layout for WearableRecyclerView is adaptable to different
+  types of child views, the WearableRecyclerView class, by default, chooses the
+  middle left edge (X=0, Y=Half the child height) as the anchor coordinates for
+  the child item. Using the default anchor coordinates can result in offsetting
+  the child items from the left edge of the watch face. To customize the anchor
+  coordinates of your child view along the curve, you can overwrite the
+  {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal)
+  and Y (vertical) offset of the child item, and set it using the
+  {@code adjustAnchorOffsetXY()} method to properly align items
+  along the curve. The coordinates should be with relation to the child view.
+</p>
+
+<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p>
+<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p>
+
+<p>
+  The code snippet below, calculates the X offset for a child item in which the
+  width of the icon is same as the height of the child item. In this case, the
+  anchor coordinates for the child item are at the center of the icon.
+
+</p>
+<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/>
+
+<pre>
+ &#64;Override
+  protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
+    anchorOffsetXY[0] = child.getHeight() / 2.0f;
+  }
+</pre>
+
+
diff --git a/docs/html/wear/preview/images/alignment.png b/docs/html/wear/preview/images/alignment.png
new file mode 100644
index 0000000..525b334
--- /dev/null
+++ b/docs/html/wear/preview/images/alignment.png
Binary files differ
diff --git a/docs/html/wear/preview/images/apk-details.png b/docs/html/wear/preview/images/apk-details.png
new file mode 100644
index 0000000..eb3b859
--- /dev/null
+++ b/docs/html/wear/preview/images/apk-details.png
Binary files differ
diff --git a/docs/html/wear/preview/images/apk-tabs.png b/docs/html/wear/preview/images/apk-tabs.png
new file mode 100644
index 0000000..949b98f
--- /dev/null
+++ b/docs/html/wear/preview/images/apk-tabs.png
Binary files differ
diff --git a/docs/html/wear/preview/images/center_align.png b/docs/html/wear/preview/images/center_align.png
new file mode 100644
index 0000000..ca88ad7
--- /dev/null
+++ b/docs/html/wear/preview/images/center_align.png
Binary files differ
diff --git a/docs/html/wear/preview/images/current-apk.png b/docs/html/wear/preview/images/current-apk.png
new file mode 100644
index 0000000..2545f92
--- /dev/null
+++ b/docs/html/wear/preview/images/current-apk.png
Binary files differ
diff --git a/docs/html/wear/preview/images/inline_action.png b/docs/html/wear/preview/images/inline_action.png
new file mode 100644
index 0000000..7ecaafe
--- /dev/null
+++ b/docs/html/wear/preview/images/inline_action.png
Binary files differ
diff --git a/docs/html/wear/preview/images/wrv_new.png b/docs/html/wear/preview/images/wrv_new.png
new file mode 100644
index 0000000..c413c59
--- /dev/null
+++ b/docs/html/wear/preview/images/wrv_new.png
Binary files differ
diff --git a/docs/html/wear/preview/index.jd b/docs/html/wear/preview/index.jd
index 4b3c1f2..6292577 100644
--- a/docs/html/wear/preview/index.jd
+++ b/docs/html/wear/preview/index.jd
@@ -7,16 +7,6 @@
 footer.hide=1
 @jd:body
 
-<script>
-  $(document).ready(function() {
-    if (useUpdatedTemplates) {
-      $("#useUpdatedTemplates").css("display","block");
-    } else {
-      $("#useOldTemplates").css("display","block");
-    }
-  })
-</script>
-
 <section class="dac-expand dac-hero dac-light" style="background-color:#FFFFFF">
   <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
@@ -55,7 +45,7 @@
   </div>
 </section>
 
-<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
+<div 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">
       <i class="dac-sprite dac-arrow-down-gray"></i>
@@ -77,22 +67,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="{@docRoot}wear/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Report an issue
-      </a></div>
-      <div><a href="http://g.co/androidweardev">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Join developer community
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light"><div class="wrap">
   <h1 class="dac-section-title">Resources</h1>
   <div class="dac-section-subtitle">
diff --git a/docs/html/wear/preview/program.jd b/docs/html/wear/preview/program.jd
index e2bf92f..4f2fb5c 100644
--- a/docs/html/wear/preview/program.jd
+++ b/docs/html/wear/preview/program.jd
@@ -143,8 +143,9 @@
     <p>
       At milestone 4, you'll have access to the final Android Wear 2.0
       APIs and SDK to develop with, as well as near-final system images to test
-      system behaviors and features. Android Wear 2.0 will use the Android N
-      API level at this time. You can begin final compatibility testing of your
+      system behaviors and features. Android Wear 2.0 will use the
+      Android 7.0 API level at this time.
+      You can begin final compatibility testing of your
       legacy apps and refine any new code that is using the Android Wear 2.0
       APIs or features.
     </p>
diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
index 8fccdc8..c9720dc 100644
--- a/docs/html/wear/preview/start.jd
+++ b/docs/html/wear/preview/start.jd
@@ -29,7 +29,7 @@
 
     <p>
       If you want an environment for basic compatibility
-      testing of your app, you can use your current APK and a
+      testing, you can use your current APK and a
       supported watch or an emulator. You don't necessarily need to update your
       full development environment to do basic testing. To simply test your
       app's compatibility with a preview system image, see <a href=
@@ -48,10 +48,8 @@
     </h2>
 
     <p>
-      1. For compatibility with the <a href="{@docRoot}preview/overview.html">N
-      Developer Preview</a>, follow the <a href=
-      "{@docRoot}preview/setup-sdk.html">setup instructions</a> for installing
-      the latest version of Android Studio.
+      1. For compatibility with Android 7.0, install the latest version of
+      <a href="https://developer.android.com/studio/index.html">Android Studio</a>.
     </p>
 
     <p>
@@ -63,7 +61,7 @@
     <ul>
       <li>Under the <strong>SDK Platforms tab</strong>:
         <ul>
-          <li>Android N Preview
+          <li>Android 7.0 (Nougat)
           </li>
         </ul>
       </li>
@@ -107,10 +105,10 @@
 
       <tr>
         <td>
-          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-2-docs.zip">wearable-support-preview-2-docs.zip</a>
+          <a href="http://storage.googleapis.com/androiddevelopers/shareables/wear-preview/wearable-support-preview-3-docs.zip">wearable-support-preview-3-docs.zip</a>
         </td>
-        <td>MD5: afb770c9c5c0431bbcbdde186f1eae06<br>
-            SHA-1: 81d681e61cee01f222ea82e83297d23c4e55b8f3
+        <td>MD5: 22bae00e473e39e320aae8ea09a001a5<br>
+            SHA-1: 474502cc7092bcf0bd671441b8654aa8d6c155ed
         </td>
       </tr>
     </table>
@@ -163,7 +161,7 @@
       following, which requires that your the Google Repository <a href=
       "#install_android_studio_and_the_latest_packages">is the latest
       version</a>:
-      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
+      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
         </li>
       </ul>
       </li>
@@ -190,12 +188,12 @@
       </li>
 
       <li>Optionally, select the <strong>Phone and Tablet</strong> option. If
-      you plan to use N Preview APIs in a phone app, then the Minimum SDK
-      option list, select <strong>API N: Android 6.x (N Preview)</strong>.
+      you plan to use Android 7.0 APIs in a phone app, then the Minimum SDK
+      option list, select <strong>API 24: Android 7.0 (Nougat)</strong>.
       </li>
 
       <li>Select the <strong>Wear</strong> option, and in the Minimum SDK
-      option list, select the latest available (<strong>N Preview</strong>)
+      option list, select the latest available (<strong>API Nougat</strong>)
       option. Click <strong>Next</strong> until you exit the Create New Project
       wizard.
       </li>
@@ -215,7 +213,7 @@
       following, which requires that your the Google Repository <a href=
       "#install_android_studio_and_the_latest_packages">is the latest
       version</a>:
-      <code>compile 'com.google.android.support:wearable:2.0.0-alpha2'</code>
+      <code>compile 'com.google.android.support:wearable:2.0.0-alpha3'</code>
         </li>
       </ul>
       </li>
diff --git a/docs/html/wear/preview/support.jd b/docs/html/wear/preview/support.jd
index 78b4e4b..6006627 100644
--- a/docs/html/wear/preview/support.jd
+++ b/docs/html/wear/preview/support.jd
@@ -23,7 +23,9 @@
 
 <ul>
   <li><a href="#general">General Advisories</a></li>
+  <li><a href="#platform-version">Platform API Version</a></li>
   <li><a href="#deprecations">Deprecations</a></li>
+  <li><a href="#dp3">Developer Preview 3</a></li>
   <li><a href="#dp2">Developer Preview 2</a></li>
   <li><a href="#dp1">Developer Preview 1</a></li>
 </ul>
@@ -46,10 +48,25 @@
     panics and crashes.
   </li>
   <li>Some apps <strong>may not function as expected</strong> on the new
-  platform version. This includes Google’s apps and other apps.
+  platform version. This includes Google's apps and other apps.
   </li>
 </ul>
 
+<h2 id="platform-version">
+  Platform API Version
+</h2>
+
+<p>
+  The Android Platform API version is incremented to 24 to match Android 7.0.
+  You can update the following in your Android Wear 2.0 Preview project
+  to <strong>24</strong>:
+</p>
+
+<ul>
+  <li><code>compileSdkVersion</code></li>
+  <li><code>targetSdkVersion</code></li>
+</ul>
+
 <h2 id="deprecations">Deprecations</h2>
 
 <p>The following fields are deprecated in the preview:</p>
@@ -64,6 +81,291 @@
   </li>
 </ul>
 
+<h2 id="dp3">Developer Preview 3</h2>
+
+<div class="wrap">
+  <div class="cols">
+    <div class="col-6of12">
+      <p><em>Date: September 2016<br />
+      Builds: Wearable Support 2.0.0-alpha3, NVE68J<br/>
+      Emulator support: x86 & ARM (32-bit)<br/>
+      </em></p>
+    </div>
+  </div>
+</div>
+
+<h3 id="new-in-fdp3">
+  New in Preview 3
+</h3>
+
+    <p>
+      For access to system images and the companion app for Preview 3, see
+      <a href="https://developer.android.com/wear/preview/downloads.html">
+      Download and Test with a Device</a>.
+    </p>
+
+    <h4>
+      Additions for standalone apps and the Play Store on Wear
+    </h4>
+
+    <p>
+      For information about planning your Wear 2.0 app, see <a href=
+      "https://developer.android.com/wear/preview/features/standalone-apps.html">
+      Standalone Apps</a>.
+    </p>
+
+    <p>
+      Generally, the minimum and target SDK level for Wear 2.0, and for a
+      standalone APK, is level 24. The minimum SDK level can be 23
+      only if you are using the same APK
+      for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).
+    </p>
+
+    <p>
+      Run-time permissions are required.
+    </p>
+
+    <p>
+      For information about distributing your Wear 2.0 app, see <a href=
+      "https://developer.android.com/wear/preview/features/app-distribution.html">
+      App Distribution</a>.
+    </p>
+
+    <h4 id="additions-to-the-complications-api">
+      Complications API additions
+    </h4>
+
+    <p>
+      For Preview 3, additions and changes have been made to the Complications
+      API. The <a href=
+      "https://developer.android.com/wear/preview/features/complications.html">documentation</a>
+      includes information about the following additions and changes:
+    </p>
+
+    <ul>
+      <li>To receive complication data and open the provider chooser, a watch
+      face must have the <code>RECEIVE_COMPLICATION_DATA</code> permission.
+      </li>
+
+      <li>To ease a request for the new permission and the starting of the
+      chooser, the <code>ComplicationHelperActivity</code> class is available
+      in the wearable support library. This class should be used instead of
+      <code>ProviderChooserIntent</code> to start the chooser in almost all
+      cases.
+      </li>
+
+      <li>Watch faces can specify default providers that are used until a user
+      selects a provider.
+      </li>
+
+      <li>The complication types used for "empty" data are changed.
+      </li>
+
+      <li>A new permission was added to ensure that only the Android Wear
+      system can bind to provider services.
+      </li>
+    </ul>
+
+    <p>
+      For changes related to the <code>ComplicationData</code> object, see
+      <a href=
+      "https://developer.android.com/wear/preview/behavior-changes.html">Behavior
+      Changes</a>.
+    </p>
+
+    <h4 id="wearable-recycler-view-api">
+      Curved Layout
+    </h4>
+
+    <p>
+      For information about creating a curved layout using
+      the <code>WearableRecyclerView</code> API in your Wear 2.0 app, see
+      <a href="https://developer.android.com/wear/preview/features/wearable-recycler-view.html">
+      Curved Layout</a>.
+    </p>
+
+    <h4 id="notifications-features-fdp3">
+      Notifications features
+    </h4>
+
+    <p>
+      To learn about adding an inline action to a notification,
+      see <a href="https://developer.android.com/wear/preview/notifications.html#inline">Inline
+      Action</a>.
+    </p>
+
+    <p>
+      To learn about adding images to a notification, see
+      <a href=
+      "https://developer.android.com/wear/preview/notifications.html#images">Adding
+      images to a notification</a>.
+    </p>
+
+    <p>
+      For additions related to the bridging of notifications from a companion
+      app to a watch, see <a href=
+      "https://developer.android.com/wear/preview/features/bridger.html">Bridging
+      Mode for Notifications</a>.
+    </p>
+
+    <h4 id="additions-for-smart-reply">
+      Smart Reply additions
+    </h4>
+
+    <p>
+      Smart Reply responses are generated by an entirely on-watch,
+      machine-learning model using the context provided by <a href=
+      "https://developer.android.com/wear/preview/features/notifications.html#messaging">
+      MessagingStyle</a> notifications. Use the <a href=
+      "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.Builder.html#setAllowGeneratedReplies(boolean)">
+      setAllowGeneratedReplies(boolean)</a> method to enable Smart Reply for
+      your <code>MessagingStyle</code> notification.
+    </p>
+
+    <h3 id="known-issues-3">
+      Known Issues
+    </h3>
+
+    <h4 id="notifications">
+      Notifications
+    </h4>
+
+    <ul>
+      <li>The <code>MessagingStyle</code> <a href=
+      "https://developer.android.com/wear/preview/features/notifications.html#images">
+        notifications with images</a> posted by standalone apps don't show
+        images in the notification (i.e., bridged notifications show images,
+        but standalone notifications don't).
+      </li>
+
+      <li>This preview release does not include support for notification
+      groups.
+      </li>
+
+      <li>With Wear 2.0, a watch can receive notifications directly from
+      Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging
+      (GCM). However, in Preview 3 of Wear 2.0, FCM does not function with
+      iOS-paired watches.
+      </li>
+
+      <li>Smart Reply responses are only shown in <code>RemoteInput</code> when
+      <code>RemoteInput</code> is called from a <code>MessagingStyle</code>
+      expanded notification. Smart Reply responses are not shown in
+      <code>RemoteInput</code> when <code>RemoteInput</code> is called from an
+      <a href=
+      "https://developer.android.com/wear/preview/features/notifications.html#inline">
+        inline action</a> within the stream&#8212;an action set with the <a href=
+        "https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Action.WearableExtender.html#setHintDisplayActionInline(boolean)">
+        setHintDisplayActionInline(true)</a> method.
+      </li>
+    </ul>
+
+    <h4 id="companion-app">
+      Companion app
+    </h4>
+
+    <ul>
+      <li>The preview companion app is not compatible with Android 4.3
+      (Jelly Bean MR2), which has an SDK build version code of:
+      <code>JELLY_BEAN_MR2</code></li>
+    </ul>
+
+    <ul>
+      <li>In permission screens in the preview companion app:
+      If you deny a permission, you cannot
+      proceed. Instead of denying a permission, tap <strong>Skip</strong>.
+      </li>
+    </ul>
+
+
+    <h4 id="developer-console">
+      Developer Console
+    </h4>
+
+    <ul>
+      <li>If you set a minimum SDK version of 24, the Play Developer Console
+      states that there are few supported devices.
+      </li>
+    </ul>
+
+    <h4 id="system-user-interface">
+      System user interface and apps
+    </h4>
+
+    <ul>
+      <li>Dismissing multiple notifications can cause an app to forcibly close.
+      </li>
+
+      <li>The "Ok Google" detection and voice transcription may not work
+      reliably.
+      </li>
+
+      <li>Google Fit is not available with Preview 3.
+      </li>
+
+      <li>Syncing for embedded apps is not enabled for the preview. Therefore,
+      to test an app on a device, add it to the Play Store or side-load it
+      onto a watch. Some existing Wear apps, e.g. Google Maps, are only
+      using the embedded apps mechanism currently, and are therefore not
+      installable on the preview (and therefore do not appear on the watch).
+      </li>
+
+      <li>In Play Store search results on the watch,
+      results other than apps sometimes appear.
+      </li>
+
+      <li>Media controls/notifications are not bridged
+      to the watch from an Android KitKat phone.
+      </li>
+    </ul>
+
+    <h4 id="account">
+      Account sync
+    </h4>
+
+    <ul>
+      <li>Account sync initiated from watch settings may not work reliably.
+      Instead, add accounts from the setup flow of the Android Wear app, or using
+      the Accounts settings for a device from the Android Wear app.
+      </li>
+
+      <li>The list of accounts that can be synced is the same as the list of accounts
+      on the phone. So to add a new account, use the Android settings on the phone,
+      and then proceed to Android Wear app to sync that account.
+      </li>
+    </ul>
+
+    <h4 id="devices">
+      Devices
+    </h4>
+
+    <ul>
+      <li>In Android Wear emulators, the Play Store app requires that an
+      account is synced to the device before the app can be opened.
+      </li>
+
+      <li>On the Huawei Watch, selecting the language, followed by multiple
+      acknowledgement dialogues, results in a black screen.
+      </li>
+
+      <li>On the LG Watch Urbane 2nd Edition, when answering a call from the
+      watch, the watch does not provide audio from the caller.
+      </li>
+    </ul>
+
+    <h4 id="smart-reply">
+      Smart Reply
+    </h4>
+
+    <ul>
+      <li>Smart Reply is only available if your watch's system language is
+      English.
+      </li>
+
+      <li>Smart Reply responses are not generated for all messages.
+      </li>
+    </ul>
+
 <h2 id="dp2">Developer Preview 2</h2>
 
 <div class="wrap">
@@ -78,24 +380,9 @@
 </div>
 
 <h3 id="new-in-fdp2">
-  <strong>New in Preview 2</strong>
+  New in Preview 2
 </h3>
 
-<h4 id="platform-version-24">
-  Platform API Version
-</h4>
-
-<p>
-  The Android Platform API version is incremented to 24 to match Android Nougat.
-  You can update the following in your Android Wear 2.0 Preview project
-  to <strong>24</strong>:
-</p>
-
-<ul>
-  <li><code>compileSdkVersion</code></li>
-  <li><code>targetSdkVersion</code></li>
-</ul>
-
 <h4 id="wearable-drawers">
   Wearable drawers
 </h4>
@@ -174,7 +461,7 @@
 </p>
 
 <h3 id="known-issues-2">
-  <strong>Known Issues</strong>
+  Known Issues
 </h3>
 
 <h4 id="notifications-2">
@@ -239,6 +526,10 @@
 
   <li>Unable to turn off the Wi-Fi on a wearable.
   </li>
+
+  <li>After music is played on a companion phone,
+  music card notifications are not mirrored to the watch.
+  </li>
 </ul>
 
 <h4 id="companion-app-2">
diff --git a/docs/html/work/guide.jd b/docs/html/work/guide.jd
index 30b895b..b2be949 100644
--- a/docs/html/work/guide.jd
+++ b/docs/html/work/guide.jd
@@ -412,6 +412,17 @@
   </li>
 </ol>
 
+<p class="caution"><b>Caution</b>: When running your app with Instant Run in
+Android Studio, attempting to open your app with a Work profile or secondary
+profile will crash your app. To use your app with the Work profile, we
+recommend you create a new <a href="/studio/run/rundebugconfig.html">run
+configuration</a> that includes the <code>--user <var>user_id</var></code> flag,
+specifying the Work profile user ID. You can find the user ID by executing
+<code>adb shell pm list users</code> from command line. For more information,
+see the <a href="/studio/run/index.html#ir-work-profile">Instant Run
+documentation</a>.</p>
+
+
 <h3>Provision a device owner</h3>
 
 <p>
diff --git a/docs/html/work/managed-configurations.jd b/docs/html/work/managed-configurations.jd
index 76ca82f..6de4d8b 100644
--- a/docs/html/work/managed-configurations.jd
+++ b/docs/html/work/managed-configurations.jd
@@ -349,7 +349,7 @@
 <p>
   To get a {@link android.content.RestrictionsManager} object, get the current
   activity with {@link android.app.Fragment#getActivity getActivity()}, then
-  call that activity's {@link android.app.Activity#getSystemService(java.lang.String)
+  call that activity's {@link android.app.Activity#getSystemService
   Activity.getSystemService()} method:
 </p>
 
@@ -399,9 +399,9 @@
   <code>String</code>, and <code>String[]</code>. Once you have the
   managed configurations {@link android.os.Bundle}, you can check the current
   configuration settings with the standard {@link android.os.Bundle} methods for
-  those data types, such as {@link android.os.BaseBundle#getBoolean getBoolean()}
+  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
   or
-  {@link android.os.BaseBundle#getString getString()}.
+  {@link android.os.Bundle#getString getString()}.
 </p>
 
 <p class="note">
diff --git a/docs/image_sources/brand/android_logo_no.graffle/data.plist b/docs/image_sources/brand/android_logo_no.graffle/data.plist
new file mode 100644
index 0000000..1132a59
--- /dev/null
+++ b/docs/image_sources/brand/android_logo_no.graffle/data.plist
Binary files differ
diff --git a/docs/image_sources/brand/android_logo_no.graffle/image1.jpg b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg
new file mode 100644
index 0000000..ff29599
--- /dev/null
+++ b/docs/image_sources/brand/android_logo_no.graffle/image1.jpg
Binary files differ
diff --git a/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip
new file mode 100644
index 0000000..89a799b
--- /dev/null
+++ b/docs/image_sources/training/tv/playback/onboarding-fragment-diagram.graffle.zip
Binary files differ
diff --git a/docs/source.properties b/docs/source.properties
new file mode 100644
index 0000000..77a760b
--- /dev/null
+++ b/docs/source.properties
@@ -0,0 +1,3 @@
+Pkg.Revision=24.0
+Pkg.Desc=Android offline API reference
+Pkg.Path=docs
\ No newline at end of file
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index 08c7b95..d0797a9 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -37,7 +37,6 @@
     $(TOP)/frameworks/av/drm/libdrmframework/include \
     $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include \
     $(TOP)/frameworks/av/include \
-    $(TOP)/libcore/include
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 49721cf..7ce750d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -48,11 +48,6 @@
     // pixel data.
     private static final long NATIVE_ALLOCATION_SIZE = 32;
 
-    /**
-     * Backing buffer for the Bitmap.
-     */
-    private byte[] mBuffer;
-
     // Convenience for JNI access
     private final long mNativePtr;
 
@@ -108,7 +103,7 @@
      * int (pointer).
      */
     // called from JNI
-    Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
+    Bitmap(long nativeBitmap, int width, int height, int density,
             boolean isMutable, boolean requestPremultiplied,
             byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
         if (nativeBitmap == 0) {
@@ -119,7 +114,6 @@
         mHeight = height;
         mIsMutable = isMutable;
         mRequestPremultiplied = requestPremultiplied;
-        mBuffer = buffer;
 
         mNinePatchChunk = ninePatchChunk;
         mNinePatchInsets = ninePatchInsets;
@@ -128,10 +122,7 @@
         }
 
         mNativePtr = nativeBitmap;
-        long nativeSize = NATIVE_ALLOCATION_SIZE;
-        if (buffer == null) {
-            nativeSize += getByteCount();
-        }
+        long nativeSize = NATIVE_ALLOCATION_SIZE + getAllocationByteCount();
         NativeAllocationRegistry registry = new NativeAllocationRegistry(
             Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);
         registry.registerNativeAllocation(this, nativeBitmap);
@@ -256,12 +247,8 @@
         if (!isMutable()) {
             throw new IllegalStateException("only mutable bitmaps may be reconfigured");
         }
-        if (mBuffer == null) {
-            throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
-        }
 
-        nativeReconfigure(mNativePtr, width, height, config.nativeInt,
-                mBuffer.length, mRequestPremultiplied);
+        nativeReconfigure(mNativePtr, width, height, config.nativeInt, mRequestPremultiplied);
         mWidth = width;
         mHeight = height;
     }
@@ -343,7 +330,6 @@
                 // false indicates that it is still in use at the native level and these
                 // objects should not be collected now. They will be collected later when the
                 // Bitmap itself is collected.
-                mBuffer = null;
                 mNinePatchChunk = null;
             }
             mRecycled = true;
@@ -1273,12 +1259,7 @@
      * @see #reconfigure(int, int, Config)
      */
     public final int getAllocationByteCount() {
-        if (mBuffer == null) {
-            // native backed bitmaps don't support reconfiguration,
-            // so alloc size is always content size
-            return getByteCount();
-        }
-        return mBuffer.length;
+        return nativeGetAllocationByteCount(mNativePtr);
     }
 
     /**
@@ -1695,8 +1676,7 @@
     private static native long nativeGetNativeFinalizer();
     private static native boolean nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
-                                                 int config, int allocSize,
-                                                 boolean isPremultiplied);
+                                                 int config, boolean isPremultiplied);
 
     private static native boolean nativeCompress(long nativeBitmap, int format,
                                             int quality, OutputStream stream,
@@ -1742,4 +1722,5 @@
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
     private static native long nativeRefPixelRef(long nativeBitmap);
     private static native void nativePrepareToDraw(long nativeBitmap);
+    private static native int nativeGetAllocationByteCount(long nativeBitmap);
 }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 4257904..d29005c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -857,6 +857,15 @@
         nativeSetDrawFilter(mNativeCanvasWrapper, nativeFilter);
     }
 
+    /**
+     * Constant values used as parameters to {@code quickReject()} calls. These values
+     * specify how much space around the shape should be accounted for, depending on whether
+     * the shaped area is antialiased or not.
+     *
+     * @see #quickReject(float, float, float, float, EdgeType)
+     * @see #quickReject(Path, EdgeType)
+     * @see #quickReject(RectF, EdgeType)
+     */
     public enum EdgeType {
 
         /**
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index b2adcf6..08a68f4 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -21,23 +21,8 @@
 */
 public class ComposeShader extends Shader {
 
-    private static final int TYPE_XFERMODE = 1;
-    private static final int TYPE_PORTERDUFFMODE = 2;
-
-    /**
-     * Type of the ComposeShader: can be either TYPE_XFERMODE or TYPE_PORTERDUFFMODE
-     */
-    private int mType;
-
-    private Xfermode mXferMode;
-    private PorterDuff.Mode mPorterDuffMode;
-
-    /**
-     * Hold onto the shaders to avoid GC.
-     */
-    @SuppressWarnings({"UnusedDeclaration"})
+    private int mPorterDuffMode;
     private final Shader mShaderA;
-    @SuppressWarnings({"UnusedDeclaration"})
     private final Shader mShaderB;
 
     /** Create a new compose shader, given shaders A, B, and a combining mode.
@@ -49,12 +34,7 @@
                         is null, then SRC_OVER is assumed.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
-        mType = TYPE_XFERMODE;
-        mShaderA = shaderA;
-        mShaderB = shaderB;
-        mXferMode = mode;
-        init(nativeCreate1(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
-                (mode != null) ? mode.native_instance : 0));
+        this(shaderA, shaderB, mode.porterDuffMode);
     }
 
     /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@@ -65,12 +45,15 @@
         @param mode     The PorterDuff mode that combines the colors from the two shaders.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
-        mType = TYPE_PORTERDUFFMODE;
+        this(shaderA, shaderB, mode.nativeInt);
+    }
+
+    private ComposeShader(Shader shaderA, Shader shaderB, int nativeMode) {
         mShaderA = shaderA;
         mShaderB = shaderB;
-        mPorterDuffMode = mode;
-        init(nativeCreate2(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
-                mode.nativeInt));
+        mPorterDuffMode = nativeMode;
+        init(nativeCreate(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
+                nativeMode));
     }
 
     /**
@@ -78,24 +61,12 @@
      */
     @Override
     protected Shader copy() {
-        final ComposeShader copy;
-        switch (mType) {
-            case TYPE_XFERMODE:
-                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mXferMode);
-                break;
-            case TYPE_PORTERDUFFMODE:
-                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mPorterDuffMode);
-                break;
-            default:
-                throw new IllegalArgumentException(
-                        "ComposeShader should be created with either Xfermode or PorterDuffMode");
-        }
+        final ComposeShader copy = new ComposeShader(
+                mShaderA.copy(), mShaderB.copy(), mPorterDuffMode);
         copyLocalMatrix(copy);
         return copy;
     }
 
-    private static native long nativeCreate1(long native_shaderA, long native_shaderB,
-            long native_mode);
-    private static native long nativeCreate2(long native_shaderA, long native_shaderB,
+    private static native long nativeCreate(long native_shaderA, long native_shaderB,
             int porterDuffMode);
 }
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 1e8f11b..35cedae 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -16,8 +16,12 @@
 
 package android.graphics;
 
-import java.io.PrintWriter;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
 
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.PrintWriter;
 
 /**
  * The Matrix class holds a 3x3 matrix for transforming coordinates.
@@ -216,352 +220,345 @@
         }
     };
 
+    // sizeof(SkMatrix) is 9 * sizeof(float) + uint32_t
+    private static final long NATIVE_ALLOCATION_SIZE = 40;
+
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                Matrix.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+    }
+
     /**
      * @hide
      */
-    public long native_instance;
+    public final long native_instance;
 
     /**
      * Create an identity matrix
      */
     public Matrix() {
-        native_instance = native_create(0);
+        native_instance = nCreate(0);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
     }
 
     /**
      * Create a matrix that is a (deep) copy of src
+     *
      * @param src The matrix to copy into this matrix
      */
     public Matrix(Matrix src) {
-        native_instance = native_create(src != null ? src.native_instance : 0);
+        native_instance = nCreate(src != null ? src.native_instance : 0);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
     }
 
     /**
-     * Returns true if the matrix is identity.
-     * This maybe faster than testing if (getType() == 0)
+     * Returns true if the matrix is identity. This maybe faster than testing if (getType() == 0)
      */
     public boolean isIdentity() {
-        return native_isIdentity(native_instance);
+        return nIsIdentity(native_instance);
     }
 
     /**
-     * Gets whether this matrix is affine. An affine matrix preserves
-     * straight lines and has no perspective.
+     * Gets whether this matrix is affine. An affine matrix preserves straight lines and has no
+     * perspective.
      *
      * @return Whether the matrix is affine.
      */
     public boolean isAffine() {
-        return native_isAffine(native_instance);
+        return nIsAffine(native_instance);
     }
 
     /**
-     * Returns true if will map a rectangle to another rectangle. This can be
-     * true if the matrix is identity, scale-only, or rotates a multiple of 90
-     * degrees.
+     * Returns true if will map a rectangle to another rectangle. This can be true if the matrix is
+     * identity, scale-only, or rotates a multiple of 90 degrees.
      */
     public boolean rectStaysRect() {
-        return native_rectStaysRect(native_instance);
+        return nRectStaysRect(native_instance);
     }
 
     /**
-     * (deep) copy the src matrix into this matrix. If src is null, reset this
-     * matrix to the identity matrix.
+     * (deep) copy the src matrix into this matrix. If src is null, reset this matrix to the
+     * identity matrix.
      */
     public void set(Matrix src) {
         if (src == null) {
             reset();
         } else {
-            native_set(native_instance, src.native_instance);
+            nSet(native_instance, src.native_instance);
         }
     }
 
-    /** Returns true iff obj is a Matrix and its values equal our values.
-    */
+    /**
+     * Returns true iff obj is a Matrix and its values equal our values.
+     */
     @Override
     public boolean equals(Object obj) {
-        //if (obj == this) return true;     -- NaN value would mean matrix != itself
-        if (!(obj instanceof Matrix)) return false;
-        return native_equals(native_instance, ((Matrix)obj).native_instance);
+        // if (obj == this) return true; -- NaN value would mean matrix != itself
+        if (!(obj instanceof Matrix)) {
+            return false;
+        }
+        return nEquals(native_instance, ((Matrix) obj).native_instance);
     }
 
     @Override
     public int hashCode() {
         // This should generate the hash code by performing some arithmetic operation on all
         // the matrix elements -- our equals() does an element-by-element comparison, and we
-        // need to ensure that the hash code for two equal objects is the same.  We're not
+        // need to ensure that the hash code for two equal objects is the same. We're not
         // really using this at the moment, so we take the easy way out.
         return 44;
     }
 
     /** Set the matrix to identity */
     public void reset() {
-        native_reset(native_instance);
+        nReset(native_instance);
     }
 
     /** Set the matrix to translate by (dx, dy). */
     public void setTranslate(float dx, float dy) {
-        native_setTranslate(native_instance, dx, dy);
+        nSetTranslate(native_instance, dx, dy);
     }
 
     /**
-     * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
-     * The pivot point is the coordinate that should remain unchanged by the
-     * specified transformation.
+     * Set the matrix to scale by sx and sy, with a pivot point at (px, py). The pivot point is the
+     * coordinate that should remain unchanged by the specified transformation.
      */
     public void setScale(float sx, float sy, float px, float py) {
-        native_setScale(native_instance, sx, sy, px, py);
+        nSetScale(native_instance, sx, sy, px, py);
     }
 
     /** Set the matrix to scale by sx and sy. */
     public void setScale(float sx, float sy) {
-        native_setScale(native_instance, sx, sy);
+        nSetScale(native_instance, sx, sy);
     }
 
     /**
-     * Set the matrix to rotate by the specified number of degrees, with a pivot
-     * point at (px, py). The pivot point is the coordinate that should remain
-     * unchanged by the specified transformation.
+     * Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py).
+     * The pivot point is the coordinate that should remain unchanged by the specified
+     * transformation.
      */
     public void setRotate(float degrees, float px, float py) {
-        native_setRotate(native_instance, degrees, px, py);
+        nSetRotate(native_instance, degrees, px, py);
     }
 
     /**
      * Set the matrix to rotate about (0,0) by the specified number of degrees.
      */
     public void setRotate(float degrees) {
-        native_setRotate(native_instance, degrees);
+        nSetRotate(native_instance, degrees);
     }
 
     /**
-     * Set the matrix to rotate by the specified sine and cosine values, with a
-     * pivot point at (px, py). The pivot point is the coordinate that should
-     * remain unchanged by the specified transformation.
+     * Set the matrix to rotate by the specified sine and cosine values, with a pivot point at (px,
+     * py). The pivot point is the coordinate that should remain unchanged by the specified
+     * transformation.
      */
     public void setSinCos(float sinValue, float cosValue, float px, float py) {
-        native_setSinCos(native_instance, sinValue, cosValue, px, py);
+        nSetSinCos(native_instance, sinValue, cosValue, px, py);
     }
 
     /** Set the matrix to rotate by the specified sine and cosine values. */
     public void setSinCos(float sinValue, float cosValue) {
-        native_setSinCos(native_instance, sinValue, cosValue);
+        nSetSinCos(native_instance, sinValue, cosValue);
     }
 
     /**
-     * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
-     * The pivot point is the coordinate that should remain unchanged by the
-     * specified transformation.
+     * Set the matrix to skew by sx and sy, with a pivot point at (px, py). The pivot point is the
+     * coordinate that should remain unchanged by the specified transformation.
      */
     public void setSkew(float kx, float ky, float px, float py) {
-        native_setSkew(native_instance, kx, ky, px, py);
+        nSetSkew(native_instance, kx, ky, px, py);
     }
 
     /** Set the matrix to skew by sx and sy. */
     public void setSkew(float kx, float ky) {
-        native_setSkew(native_instance, kx, ky);
+        nSetSkew(native_instance, kx, ky);
     }
 
     /**
-     * Set the matrix to the concatenation of the two specified matrices and
-     * return true.
-     *
-     * <p>Either of the two matrices may also be the target matrix, that is
-     * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.</p>
-     *
-     * <p class="note">In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this
-     * function returns true only if the result can be represented. In
-     * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.</p>
+     * Set the matrix to the concatenation of the two specified matrices and return true.
+     * <p>
+     * Either of the two matrices may also be the target matrix, that is
+     * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.
+     * </p>
+     * <p class="note">
+     * In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this function returns
+     * true only if the result can be represented. In
+     * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.
+     * </p>
      */
     public boolean setConcat(Matrix a, Matrix b) {
-        native_setConcat(native_instance, a.native_instance, b.native_instance);
+        nSetConcat(native_instance, a.native_instance, b.native_instance);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified translation.
-     * M' = M * T(dx, dy)
+     * Preconcats the matrix with the specified translation. M' = M * T(dx, dy)
      */
     public boolean preTranslate(float dx, float dy) {
-        native_preTranslate(native_instance, dx, dy);
+        nPreTranslate(native_instance, dx, dy);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified scale.
-     * M' = M * S(sx, sy, px, py)
+     * Preconcats the matrix with the specified scale. M' = M * S(sx, sy, px, py)
      */
     public boolean preScale(float sx, float sy, float px, float py) {
-        native_preScale(native_instance, sx, sy, px, py);
+        nPreScale(native_instance, sx, sy, px, py);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified scale.
-     * M' = M * S(sx, sy)
+     * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
      */
     public boolean preScale(float sx, float sy) {
-        native_preScale(native_instance, sx, sy);
+        nPreScale(native_instance, sx, sy);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified rotation.
-     * M' = M * R(degrees, px, py)
+     * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
      */
     public boolean preRotate(float degrees, float px, float py) {
-        native_preRotate(native_instance, degrees, px, py);
+        nPreRotate(native_instance, degrees, px, py);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified rotation.
-     * M' = M * R(degrees)
+     * Preconcats the matrix with the specified rotation. M' = M * R(degrees)
      */
     public boolean preRotate(float degrees) {
-        native_preRotate(native_instance, degrees);
+        nPreRotate(native_instance, degrees);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified skew.
-     * M' = M * K(kx, ky, px, py)
+     * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
      */
     public boolean preSkew(float kx, float ky, float px, float py) {
-        native_preSkew(native_instance, kx, ky, px, py);
+        nPreSkew(native_instance, kx, ky, px, py);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified skew.
-     * M' = M * K(kx, ky)
+     * Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
      */
     public boolean preSkew(float kx, float ky) {
-        native_preSkew(native_instance, kx, ky);
+        nPreSkew(native_instance, kx, ky);
         return true;
     }
 
     /**
-     * Preconcats the matrix with the specified matrix.
-     * M' = M * other
+     * Preconcats the matrix with the specified matrix. M' = M * other
      */
     public boolean preConcat(Matrix other) {
-        native_preConcat(native_instance, other.native_instance);
+        nPreConcat(native_instance, other.native_instance);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified translation.
-     * M' = T(dx, dy) * M
+     * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
      */
     public boolean postTranslate(float dx, float dy) {
-        native_postTranslate(native_instance, dx, dy);
+        nPostTranslate(native_instance, dx, dy);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified scale.
-     * M' = S(sx, sy, px, py) * M
+     * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
      */
     public boolean postScale(float sx, float sy, float px, float py) {
-        native_postScale(native_instance, sx, sy, px, py);
+        nPostScale(native_instance, sx, sy, px, py);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified scale.
-     * M' = S(sx, sy) * M
+     * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
      */
     public boolean postScale(float sx, float sy) {
-        native_postScale(native_instance, sx, sy);
+        nPostScale(native_instance, sx, sy);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified rotation.
-     * M' = R(degrees, px, py) * M
+     * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
      */
     public boolean postRotate(float degrees, float px, float py) {
-        native_postRotate(native_instance, degrees, px, py);
+        nPostRotate(native_instance, degrees, px, py);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified rotation.
-     * M' = R(degrees) * M
+     * Postconcats the matrix with the specified rotation. M' = R(degrees) * M
      */
     public boolean postRotate(float degrees) {
-        native_postRotate(native_instance, degrees);
+        nPostRotate(native_instance, degrees);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified skew.
-     * M' = K(kx, ky, px, py) * M
+     * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
      */
     public boolean postSkew(float kx, float ky, float px, float py) {
-        native_postSkew(native_instance, kx, ky, px, py);
+        nPostSkew(native_instance, kx, ky, px, py);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified skew.
-     * M' = K(kx, ky) * M
+     * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
      */
     public boolean postSkew(float kx, float ky) {
-        native_postSkew(native_instance, kx, ky);
+        nPostSkew(native_instance, kx, ky);
         return true;
     }
 
     /**
-     * Postconcats the matrix with the specified matrix.
-     * M' = other * M
+     * Postconcats the matrix with the specified matrix. M' = other * M
      */
     public boolean postConcat(Matrix other) {
-        native_postConcat(native_instance, other.native_instance);
+        nPostConcat(native_instance, other.native_instance);
         return true;
     }
 
-    /** Controlls how the src rect should align into the dst rect for
-        setRectToRect().
-    */
+    /**
+     * Controlls how the src rect should align into the dst rect for setRectToRect().
+     */
     public enum ScaleToFit {
         /**
-         * Scale in X and Y independently, so that src matches dst exactly.
-         * This may change the aspect ratio of the src.
+         * Scale in X and Y independently, so that src matches dst exactly. This may change the
+         * aspect ratio of the src.
          */
-        FILL    (0),
+        FILL(0),
         /**
-         * Compute a scale that will maintain the original src aspect ratio,
-         * but will also ensure that src fits entirely inside dst. At least one
-         * axis (X or Y) will fit exactly. START aligns the result to the
-         * left and top edges of dst.
+         * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+         * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START
+         * aligns the result to the left and top edges of dst.
          */
-        START   (1),
+        START(1),
         /**
-         * Compute a scale that will maintain the original src aspect ratio,
-         * but will also ensure that src fits entirely inside dst. At least one
-         * axis (X or Y) will fit exactly. The result is centered inside dst.
+         * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+         * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The
+         * result is centered inside dst.
          */
-        CENTER  (2),
+        CENTER(2),
         /**
-         * Compute a scale that will maintain the original src aspect ratio,
-         * but will also ensure that src fits entirely inside dst. At least one
-         * axis (X or Y) will fit exactly. END aligns the result to the
-         * right and bottom edges of dst.
+         * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+         * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END
+         * aligns the result to the right and bottom edges of dst.
          */
-        END     (3);
+        END(3);
 
         // the native values must match those in SkMatrix.h
         ScaleToFit(int nativeInt) {
             this.nativeInt = nativeInt;
         }
+
         final int nativeInt;
     }
 
     /**
-     * Set the matrix to the scale and translate values that map the source
-     * rectangle to the destination rectangle, returning true if the the result
-     * can be represented.
+     * Set the matrix to the scale and translate values that map the source rectangle to the
+     * destination rectangle, returning true if the the result can be represented.
      *
      * @param src the source rectangle to map from.
      * @param dst the destination rectangle to map to.
@@ -572,13 +569,13 @@
         if (dst == null || src == null) {
             throw new NullPointerException();
         }
-        return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
+        return nSetRectToRect(native_instance, src, dst, stf.nativeInt);
     }
 
     // private helper to perform range checks on arrays of "points"
     private static void checkPointArrays(float[] src, int srcIndex,
-                                         float[] dst, int dstIndex,
-                                         int pointCount) {
+            float[] dst, int dstIndex,
+            int pointCount) {
         // check for too-small and too-big indices
         int srcStop = srcIndex + (pointCount << 1);
         int dstStop = dstIndex + (pointCount << 1);
@@ -589,84 +586,81 @@
     }
 
     /**
-     * Set the matrix such that the specified src points would map to the
-     * specified dst points. The "points" are represented as an array of floats,
-     * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
+     * Set the matrix such that the specified src points would map to the specified dst points. The
+     * "points" are represented as an array of floats, order [x0, y0, x1, y1, ...], where each
+     * "point" is 2 float values.
      *
-     * @param src   The array of src [x,y] pairs (points)
+     * @param src The array of src [x,y] pairs (points)
      * @param srcIndex Index of the first pair of src values
-     * @param dst   The array of dst [x,y] pairs (points)
+     * @param dst The array of dst [x,y] pairs (points)
      * @param dstIndex Index of the first pair of dst values
      * @param pointCount The number of pairs/points to be used. Must be [0..4]
      * @return true if the matrix was set to the specified transformation
      */
     public boolean setPolyToPoly(float[] src, int srcIndex,
-                                 float[] dst, int dstIndex,
-                                 int pointCount) {
+            float[] dst, int dstIndex,
+            int pointCount) {
         if (pointCount > 4) {
             throw new IllegalArgumentException();
         }
         checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
-        return native_setPolyToPoly(native_instance, src, srcIndex,
-                                    dst, dstIndex, pointCount);
+        return nSetPolyToPoly(native_instance, src, srcIndex,
+                dst, dstIndex, pointCount);
     }
 
     /**
-     * If this matrix can be inverted, return true and if inverse is not null,
-     * set inverse to be the inverse of this matrix. If this matrix cannot be
-     * inverted, ignore inverse and return false.
+     * If this matrix can be inverted, return true and if inverse is not null, set inverse to be the
+     * inverse of this matrix. If this matrix cannot be inverted, ignore inverse and return false.
      */
     public boolean invert(Matrix inverse) {
-        return native_invert(native_instance, inverse.native_instance);
+        return nInvert(native_instance, inverse.native_instance);
     }
 
     /**
-    * Apply this matrix to the array of 2D points specified by src, and write
-     * the transformed points into the array of points specified by dst. The
-     * two arrays represent their "points" as pairs of floats [x, y].
+     * Apply this matrix to the array of 2D points specified by src, and write the transformed
+     * points into the array of points specified by dst. The two arrays represent their "points" as
+     * pairs of floats [x, y].
      *
-     * @param dst   The array of dst points (x,y pairs)
+     * @param dst The array of dst points (x,y pairs)
      * @param dstIndex The index of the first [x,y] pair of dst floats
-     * @param src   The array of src points (x,y pairs)
+     * @param src The array of src points (x,y pairs)
      * @param srcIndex The index of the first [x,y] pair of src floats
      * @param pointCount The number of points (x,y pairs) to transform
      */
     public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
-                          int pointCount) {
+            int pointCount) {
         checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
-        native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
-                         pointCount, true);
+        nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
+                pointCount, true);
     }
 
     /**
-    * Apply this matrix to the array of 2D vectors specified by src, and write
-     * the transformed vectors into the array of vectors specified by dst. The
-     * two arrays represent their "vectors" as pairs of floats [x, y].
+     * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
+     * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
+     * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
+     * the matrix. Use {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the
+     * translation to be applied.
      *
-     * Note: this method does not apply the translation associated with the matrix. Use
-     * {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the translation
-     * to be applied.
-     *
-     * @param dst   The array of dst vectors (x,y pairs)
+     * @param dst The array of dst vectors (x,y pairs)
      * @param dstIndex The index of the first [x,y] pair of dst floats
-     * @param src   The array of src vectors (x,y pairs)
+     * @param src The array of src vectors (x,y pairs)
      * @param srcIndex The index of the first [x,y] pair of src floats
      * @param vectorCount The number of vectors (x,y pairs) to transform
      */
     public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
-                          int vectorCount) {
+            int vectorCount) {
         checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
-        native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
-                         vectorCount, false);
+        nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
+                vectorCount, false);
     }
 
     /**
-     * Apply this matrix to the array of 2D points specified by src, and write
-     * the transformed points into the array of points specified by dst. The
-     * two arrays represent their "points" as pairs of floats [x, y].
+     * Apply this matrix to the array of 2D points specified by src, and write the transformed
+     * points into the array of points specified by dst. The two arrays represent their "points" as
+     * pairs of floats [x, y].
      *
-     * @param dst   The array of dst points (x,y pairs)
-     * @param src   The array of src points (x,y pairs)
+     * @param dst The array of dst points (x,y pairs)
+     * @param src The array of src points (x,y pairs)
      */
     public void mapPoints(float[] dst, float[] src) {
         if (dst.length != src.length) {
@@ -676,15 +670,14 @@
     }
 
     /**
-     * Apply this matrix to the array of 2D vectors specified by src, and write
-     * the transformed vectors into the array of vectors specified by dst. The
-     * two arrays represent their "vectors" as pairs of floats [x, y].
+     * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
+     * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
+     * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
+     * the matrix. Use {@link Matrix#mapPoints(float[], float[])} if you want the translation to be
+     * applied.
      *
-     * Note: this method does not apply the translation associated with the matrix. Use
-     * {@link Matrix#mapPoints(float[], float[])} if you want the translation to be applied.
-     *
-     * @param dst   The array of dst vectors (x,y pairs)
-     * @param src   The array of src vectors (x,y pairs)
+     * @param dst The array of dst vectors (x,y pairs)
+     * @param src The array of src vectors (x,y pairs)
      */
     public void mapVectors(float[] dst, float[] src) {
         if (dst.length != src.length) {
@@ -694,8 +687,8 @@
     }
 
     /**
-     * Apply this matrix to the array of 2D points, and write the transformed
-     * points back into the array
+     * Apply this matrix to the array of 2D points, and write the transformed points back into the
+     * array
      *
      * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
      */
@@ -704,10 +697,8 @@
     }
 
     /**
-     * Apply this matrix to the array of 2D vectors, and write the transformed
-     * vectors back into the array.
-     *
-     * Note: this method does not apply the translation associated with the matrix. Use
+     * Apply this matrix to the array of 2D vectors, and write the transformed vectors back into the
+     * array. Note: this method does not apply the translation associated with the matrix. Use
      * {@link Matrix#mapPoints(float[])} if you want the translation to be applied.
      *
      * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
@@ -717,9 +708,9 @@
     }
 
     /**
-     * Apply this matrix to the src rectangle, and write the transformed
-     * rectangle into dst. This is accomplished by transforming the 4 corners of
-     * src, and then setting dst to the bounds of those points.
+     * Apply this matrix to the src rectangle, and write the transformed rectangle into dst. This is
+     * accomplished by transforming the 4 corners of src, and then setting dst to the bounds of
+     * those points.
      *
      * @param dst Where the transformed rectangle is written.
      * @param src The original rectangle to be transformed.
@@ -729,13 +720,13 @@
         if (dst == null || src == null) {
             throw new NullPointerException();
         }
-        return native_mapRect(native_instance, dst, src);
+        return nMapRect(native_instance, dst, src);
     }
 
     /**
-     * Apply this matrix to the rectangle, and write the transformed rectangle
-     * back into it. This is accomplished by transforming the 4 corners of rect,
-     * and then setting it to the bounds of those points
+     * Apply this matrix to the rectangle, and write the transformed rectangle back into it. This is
+     * accomplished by transforming the 4 corners of rect, and then setting it to the bounds of
+     * those points
      *
      * @param rect The rectangle to transform.
      * @return the result of calling rectStaysRect()
@@ -745,34 +736,33 @@
     }
 
     /**
-     * Return the mean radius of a circle after it has been mapped by
-     * this matrix. NOTE: in perspective this value assumes the circle
-     * has its center at the origin.
+     * Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in
+     * perspective this value assumes the circle has its center at the origin.
      */
     public float mapRadius(float radius) {
-        return native_mapRadius(native_instance, radius);
+        return nMapRadius(native_instance, radius);
     }
 
-    /** Copy 9 values from the matrix into the array.
-    */
+    /**
+     * Copy 9 values from the matrix into the array.
+     */
     public void getValues(float[] values) {
         if (values.length < 9) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getValues(native_instance, values);
+        nGetValues(native_instance, values);
     }
 
-    /** Copy 9 values from the array into the matrix.
-        Depending on the implementation of Matrix, these may be
-        transformed into 16.16 integers in the Matrix, such that
-        a subsequent call to getValues() will not yield exactly
-        the same values.
-    */
+    /**
+     * Copy 9 values from the array into the matrix. Depending on the implementation of Matrix,
+     * these may be transformed into 16.16 integers in the Matrix, such that a subsequent call to
+     * getValues() will not yield exactly the same values.
+     */
     public void setValues(float[] values) {
         if (values.length < 9) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_setValues(native_instance, values);
+        nSetValues(native_instance, values);
     }
 
     @Override
@@ -798,122 +788,155 @@
         float[] values = new float[9];
         getValues(values);
         sb.append('[');
-        sb.append(values[0]); sb.append(", "); sb.append(values[1]); sb.append(", ");
-        sb.append(values[2]); sb.append("][");
-        sb.append(values[3]); sb.append(", "); sb.append(values[4]); sb.append(", ");
-        sb.append(values[5]); sb.append("][");
-        sb.append(values[6]); sb.append(", "); sb.append(values[7]); sb.append(", ");
-        sb.append(values[8]); sb.append(']');
+        sb.append(values[0]);
+        sb.append(", ");
+        sb.append(values[1]);
+        sb.append(", ");
+        sb.append(values[2]);
+        sb.append("][");
+        sb.append(values[3]);
+        sb.append(", ");
+        sb.append(values[4]);
+        sb.append(", ");
+        sb.append(values[5]);
+        sb.append("][");
+        sb.append(values[6]);
+        sb.append(", ");
+        sb.append(values[7]);
+        sb.append(", ");
+        sb.append(values[8]);
+        sb.append(']');
     }
 
     /**
      * Print short string, to optimize dumping.
+     *
      * @hide
      */
     public void printShortString(PrintWriter pw) {
         float[] values = new float[9];
         getValues(values);
         pw.print('[');
-        pw.print(values[0]); pw.print(", "); pw.print(values[1]); pw.print(", ");
-                pw.print(values[2]); pw.print("][");
-        pw.print(values[3]); pw.print(", "); pw.print(values[4]); pw.print(", ");
-                pw.print(values[5]); pw.print("][");
-        pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", ");
-                pw.print(values[8]); pw.print(']');
+        pw.print(values[0]);
+        pw.print(", ");
+        pw.print(values[1]);
+        pw.print(", ");
+        pw.print(values[2]);
+        pw.print("][");
+        pw.print(values[3]);
+        pw.print(", ");
+        pw.print(values[4]);
+        pw.print(", ");
+        pw.print(values[5]);
+        pw.print("][");
+        pw.print(values[6]);
+        pw.print(", ");
+        pw.print(values[7]);
+        pw.print(", ");
+        pw.print(values[8]);
+        pw.print(']');
 
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            finalizer(native_instance);
-            native_instance = 0;  // Other finalizers can still call us.
-        } finally {
-            super.finalize();
-        }
-    }
-
-    /*package*/ final long ni() {
+    /* package */ final long ni() {
         return native_instance;
     }
 
-    private static native long native_create(long native_src_or_zero);
-    private static native boolean native_isIdentity(long native_object);
-    private static native boolean native_isAffine(long native_object);
-    private static native boolean native_rectStaysRect(long native_object);
-    private static native void native_reset(long native_object);
-    private static native void native_set(long native_object,
-                                          long native_other);
-    private static native void native_setTranslate(long native_object,
-                                                   float dx, float dy);
-    private static native void native_setScale(long native_object,
-                                        float sx, float sy, float px, float py);
-    private static native void native_setScale(long native_object,
-                                               float sx, float sy);
-    private static native void native_setRotate(long native_object,
-                                            float degrees, float px, float py);
-    private static native void native_setRotate(long native_object,
-                                                float degrees);
-    private static native void native_setSinCos(long native_object,
-                            float sinValue, float cosValue, float px, float py);
-    private static native void native_setSinCos(long native_object,
-                                                float sinValue, float cosValue);
-    private static native void native_setSkew(long native_object,
-                                        float kx, float ky, float px, float py);
-    private static native void native_setSkew(long native_object,
-                                              float kx, float ky);
-    private static native void native_setConcat(long native_object,
-                                                long native_a,
-                                                long native_b);
-    private static native void native_preTranslate(long native_object,
-                                                   float dx, float dy);
-    private static native void native_preScale(long native_object,
-                                               float sx, float sy, float px, float py);
-    private static native void native_preScale(long native_object,
-                                               float sx, float sy);
-    private static native void native_preRotate(long native_object,
-                                                float degrees, float px, float py);
-    private static native void native_preRotate(long native_object,
-                                                float degrees);
-    private static native void native_preSkew(long native_object,
-                                              float kx, float ky, float px, float py);
-    private static native void native_preSkew(long native_object,
-                                              float kx, float ky);
-    private static native void native_preConcat(long native_object,
-                                                long native_other_matrix);
-    private static native void native_postTranslate(long native_object,
-                                                    float dx, float dy);
-    private static native void native_postScale(long native_object,
-                                                float sx, float sy, float px, float py);
-    private static native void native_postScale(long native_object,
-                                                float sx, float sy);
-    private static native void native_postRotate(long native_object,
-                                                 float degrees, float px, float py);
-    private static native void native_postRotate(long native_object,
-                                                 float degrees);
-    private static native void native_postSkew(long native_object,
-                                               float kx, float ky, float px, float py);
-    private static native void native_postSkew(long native_object,
-                                               float kx, float ky);
-    private static native void native_postConcat(long native_object,
-                                                 long native_other_matrix);
-    private static native boolean native_setRectToRect(long native_object,
-                                                RectF src, RectF dst, int stf);
-    private static native boolean native_setPolyToPoly(long native_object,
-        float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
-    private static native boolean native_invert(long native_object,
-                                                long native_inverse);
-    private static native void native_mapPoints(long native_object,
-                        float[] dst, int dstIndex, float[] src, int srcIndex,
-                        int ptCount, boolean isPts);
-    private static native boolean native_mapRect(long native_object,
-                                                 RectF dst, RectF src);
-    private static native float native_mapRadius(long native_object,
-                                                 float radius);
-    private static native void native_getValues(long native_object,
-                                                float[] values);
-    private static native void native_setValues(long native_object,
-                                                float[] values);
-    private static native boolean native_equals(long native_a, long native_b);
-    private static native void finalizer(long native_instance);
+    // ------------------ Regular JNI ------------------------
+
+    private static native long nCreate(long nSrc_or_zero);
+    private static native long nGetNativeFinalizer();
+
+
+    // ------------------ Fast JNI ------------------------
+
+    @FastNative
+    private static native boolean nSetRectToRect(long nObject,
+            RectF src, RectF dst, int stf);
+    @FastNative
+    private static native boolean nSetPolyToPoly(long nObject,
+            float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
+    @FastNative
+    private static native void nMapPoints(long nObject,
+            float[] dst, int dstIndex, float[] src, int srcIndex,
+            int ptCount, boolean isPts);
+    @FastNative
+    private static native boolean nMapRect(long nObject, RectF dst, RectF src);
+    @FastNative
+    private static native void nGetValues(long nObject, float[] values);
+    @FastNative
+    private static native void nSetValues(long nObject, float[] values);
+
+
+    // ------------------ Critical JNI ------------------------
+
+    @CriticalNative
+    private static native boolean nIsIdentity(long nObject);
+    @CriticalNative
+    private static native boolean nIsAffine(long nObject);
+    @CriticalNative
+    private static native boolean nRectStaysRect(long nObject);
+    @CriticalNative
+    private static native void nReset(long nObject);
+    @CriticalNative
+    private static native void nSet(long nObject, long nOther);
+    @CriticalNative
+    private static native void nSetTranslate(long nObject, float dx, float dy);
+    @CriticalNative
+    private static native void nSetScale(long nObject, float sx, float sy, float px, float py);
+    @CriticalNative
+    private static native void nSetScale(long nObject, float sx, float sy);
+    @CriticalNative
+    private static native void nSetRotate(long nObject, float degrees, float px, float py);
+    @CriticalNative
+    private static native void nSetRotate(long nObject, float degrees);
+    @CriticalNative
+    private static native void nSetSinCos(long nObject, float sinValue, float cosValue,
+            float px, float py);
+    @CriticalNative
+    private static native void nSetSinCos(long nObject, float sinValue, float cosValue);
+    @CriticalNative
+    private static native void nSetSkew(long nObject, float kx, float ky, float px, float py);
+    @CriticalNative
+    private static native void nSetSkew(long nObject, float kx, float ky);
+    @CriticalNative
+    private static native void nSetConcat(long nObject, long nA, long nB);
+    @CriticalNative
+    private static native void nPreTranslate(long nObject, float dx, float dy);
+    @CriticalNative
+    private static native void nPreScale(long nObject, float sx, float sy, float px, float py);
+    @CriticalNative
+    private static native void nPreScale(long nObject, float sx, float sy);
+    @CriticalNative
+    private static native void nPreRotate(long nObject, float degrees, float px, float py);
+    @CriticalNative
+    private static native void nPreRotate(long nObject, float degrees);
+    @CriticalNative
+    private static native void nPreSkew(long nObject, float kx, float ky, float px, float py);
+    @CriticalNative
+    private static native void nPreSkew(long nObject, float kx, float ky);
+    @CriticalNative
+    private static native void nPreConcat(long nObject, long nOther_matrix);
+    @CriticalNative
+    private static native void nPostTranslate(long nObject, float dx, float dy);
+    @CriticalNative
+    private static native void nPostScale(long nObject, float sx, float sy, float px, float py);
+    @CriticalNative
+    private static native void nPostScale(long nObject, float sx, float sy);
+    @CriticalNative
+    private static native void nPostRotate(long nObject, float degrees, float px, float py);
+    @CriticalNative
+    private static native void nPostRotate(long nObject, float degrees);
+    @CriticalNative
+    private static native void nPostSkew(long nObject, float kx, float ky, float px, float py);
+    @CriticalNative
+    private static native void nPostSkew(long nObject, float kx, float ky);
+    @CriticalNative
+    private static native void nPostConcat(long nObject, long nOther_matrix);
+    @CriticalNative
+    private static native boolean nInvert(long nObject, long nInverse);
+    @CriticalNative
+    private static native float nMapRadius(long nObject, float radius);
+    @CriticalNative
+    private static native boolean nEquals(long nA, long nB);
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 888bbc2..98d45dc 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -27,6 +27,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 import java.util.HashMap;
 import java.util.Locale;
 
@@ -604,8 +607,6 @@
         return nGetFlags(mNativePaint);
     }
 
-    private native int nGetFlags(long paintPtr);
-
     /**
      * Set the paint's flags. Use the Flag enum to specific flag values.
      *
@@ -615,8 +616,6 @@
         nSetFlags(mNativePaint, flags);
     }
 
-    private native void nSetFlags(long paintPtr, int flags);
-
     /**
      * Return the paint's hinting mode.  Returns either
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
@@ -625,8 +624,6 @@
         return nGetHinting(mNativePaint);
     }
 
-    private native int nGetHinting(long paintPtr);
-
     /**
      * Set the paint's hinting mode.  May be either
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
@@ -635,8 +632,6 @@
         nSetHinting(mNativePaint, mode);
     }
 
-    private native void nSetHinting(long paintPtr, int mode);
-
     /**
      * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
      * AntiAliasing smooths out the edges of what is being drawn, but is has
@@ -661,8 +656,6 @@
         nSetAntiAlias(mNativePaint, aa);
     }
 
-    private native void nSetAntiAlias(long paintPtr, boolean aa);
-
     /**
      * Helper for getFlags(), returning true if DITHER_FLAG bit is set
      * Dithering affects how colors that are higher precision than the device
@@ -691,8 +684,6 @@
         nSetDither(mNativePaint, dither);
     }
 
-    private native void nSetDither(long paintPtr, boolean dither);
-
     /**
      * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
      *
@@ -712,8 +703,6 @@
         nSetLinearText(mNativePaint, linearText);
     }
 
-    private native void nSetLinearText(long paintPtr, boolean linearText);
-
     /**
      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
      *
@@ -733,8 +722,6 @@
         nSetSubpixelText(mNativePaint, subpixelText);
     }
 
-    private native void nSetSubpixelText(long paintPtr, boolean subpixelText);
-
     /**
      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
      *
@@ -754,8 +741,6 @@
         nSetUnderlineText(mNativePaint, underlineText);
     }
 
-    private native void nSetUnderlineText(long paintPtr, boolean underlineText);
-
     /**
      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
      *
@@ -775,8 +760,6 @@
         nSetStrikeThruText(mNativePaint, strikeThruText);
     }
 
-    private native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
-
     /**
      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
      *
@@ -796,8 +779,6 @@
         nSetFakeBoldText(mNativePaint, fakeBoldText);
     }
 
-    private native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
-
     /**
      * Whether or not the bitmap filter is activated.
      * Filtering affects the sampling of bitmaps when they are transformed.
@@ -823,8 +804,6 @@
         nSetFilterBitmap(mNativePaint, filter);
     }
 
-    private native void nSetFilterBitmap(long paintPtr, boolean filter);
-
     /**
      * Return the paint's style, used for controlling how primitives'
      * geometries are interpreted (except for drawBitmap, which always assumes
@@ -860,8 +839,6 @@
         return nGetColor(mNativePaint);
     }
 
-    private native int nGetColor(long paintPtr);
-
     /**
      * Set the paint's color. Note that the color is an int containing alpha
      * as well as r,g,b. This 32bit value is not premultiplied, meaning that
@@ -874,8 +851,6 @@
         nSetColor(mNativePaint, color);
     }
 
-    private native void nSetColor(long paintPtr, @ColorInt int color);
-
     /**
      * Helper to getColor() that just returns the color's alpha value. This is
      * the same as calling getColor() >>> 24. It always returns a value between
@@ -887,8 +862,6 @@
         return nGetAlpha(mNativePaint);
     }
 
-    private native int nGetAlpha(long paintPtr);
-
     /**
      * Helper to setColor(), that only assigns the color's alpha value,
      * leaving its r,g,b values unchanged. Results are undefined if the alpha
@@ -900,8 +873,6 @@
         nSetAlpha(mNativePaint, a);
     }
 
-    private native void nSetAlpha(long paintPtr, int a);
-
     /**
      * Helper to setColor(), that takes a,r,g,b and constructs the color int
      *
@@ -927,8 +898,6 @@
         return nGetStrokeWidth(mNativePaint);
     }
 
-    private native float nGetStrokeWidth(long paintPtr);
-
     /**
      * Set the width for stroking.
      * Pass 0 to stroke in hairline mode.
@@ -941,8 +910,6 @@
         nSetStrokeWidth(mNativePaint, width);
     }
 
-    private native void nSetStrokeWidth(long paintPtr, float width);
-
     /**
      * Return the paint's stroke miter value. Used to control the behavior
      * of miter joins when the joins angle is sharp.
@@ -954,8 +921,6 @@
         return nGetStrokeMiter(mNativePaint);
     }
 
-    private native float nGetStrokeMiter(long paintPtr);
-
     /**
      * Set the paint's stroke miter value. This is used to control the behavior
      * of miter joins when the joins angle is sharp. This value must be >= 0.
@@ -967,8 +932,6 @@
         nSetStrokeMiter(mNativePaint, miter);
     }
 
-    private native void nSetStrokeMiter(long paintPtr, float miter);
-
     /**
      * Return the paint's Cap, controlling how the start and end of stroked
      * lines and paths are treated.
@@ -1096,10 +1059,11 @@
      * @return         xfermode
      */
     public Xfermode setXfermode(Xfermode xfermode) {
-        long xfermodeNative = 0;
-        if (xfermode != null)
-            xfermodeNative = xfermode.native_instance;
-        nSetXfermode(mNativePaint, xfermodeNative);
+        int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
+        int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
+        if (newMode != curMode) {
+            nSetXfermode(mNativePaint, newMode);
+        }
         mXfermode = xfermode;
         return xfermode;
     }
@@ -1386,8 +1350,6 @@
         return nIsElegantTextHeight(mNativePaint);
     }
 
-    private native boolean nIsElegantTextHeight(long paintPtr);
-
     /**
      * Set the paint's elegant height metrics flag. This setting selects font
      * variants that have not been compacted to fit Latin-based vertical
@@ -1399,8 +1361,6 @@
         nSetElegantTextHeight(mNativePaint, elegant);
     }
 
-    private native void nSetElegantTextHeight(long paintPtr, boolean elegant);
-
     /**
      * Return the paint's text size.
      *
@@ -1410,8 +1370,6 @@
         return nGetTextSize(mNativePaint);
     }
 
-    private native float nGetTextSize(long paintPtr);
-
     /**
      * Set the paint's text size. This value must be > 0
      *
@@ -1421,8 +1379,6 @@
         nSetTextSize(mNativePaint, textSize);
     }
 
-    private native void nSetTextSize(long paintPtr, float textSize);
-
     /**
      * Return the paint's horizontal scale factor for text. The default value
      * is 1.0.
@@ -1433,8 +1389,6 @@
         return nGetTextScaleX(mNativePaint);
     }
 
-    private native float nGetTextScaleX(long paintPtr);
-
     /**
      * Set the paint's horizontal scale factor for text. The default value
      * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
@@ -1446,8 +1400,6 @@
         nSetTextScaleX(mNativePaint, scaleX);
     }
 
-    private native void nSetTextScaleX(long paintPtr, float scaleX);
-
     /**
      * Return the paint's horizontal skew factor for text. The default value
      * is 0.
@@ -1458,8 +1410,6 @@
         return nGetTextSkewX(mNativePaint);
     }
 
-    private native float nGetTextSkewX(long paintPtr);
-
     /**
      * Set the paint's horizontal skew factor for text. The default value
      * is 0. For approximating oblique text, use values around -0.25.
@@ -1470,8 +1420,6 @@
         nSetTextSkewX(mNativePaint, skewX);
     }
 
-    private native void nSetTextSkewX(long paintPtr, float skewX);
-
     /**
      * Return the paint's letter-spacing for text. The default value
      * is 0.
@@ -1564,8 +1512,6 @@
         return nAscent(mNativePaint, mNativeTypeface);
     }
 
-    private native float nAscent(long paintPtr, long typefacePtr);
-
     /**
      * Return the distance below (positive) the baseline (descent) based on the
      * current typeface and text size.
@@ -1577,8 +1523,6 @@
         return nDescent(mNativePaint, mNativeTypeface);
     }
 
-    private native float nDescent(long paintPtr, long typefacePtr);
-
     /**
      * Class that describes the various metrics for a font at a given text size.
      * Remember, Y values increase going down, so those values will be positive,
@@ -1623,9 +1567,6 @@
         return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics);
     }
 
-    private native float nGetFontMetrics(long paintPtr,
-            long typefacePtr, FontMetrics metrics);
-
     /**
      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
      * with it, returning the object.
@@ -1641,10 +1582,27 @@
      * integers.
      */
     public static class FontMetricsInt {
+        /**
+         * The maximum distance above the baseline for the tallest glyph in
+         * the font at a given text size.
+         */
         public int   top;
+        /**
+         * The recommended distance above the baseline for singled spaced text.
+         */
         public int   ascent;
+        /**
+         * The recommended distance below the baseline for singled spaced text.
+         */
         public int   descent;
+        /**
+         * The maximum distance below the baseline for the lowest glyph in
+         * the font at a given text size.
+         */
         public int   bottom;
+        /**
+         * The recommended additional space to add between lines of text.
+         */
         public int   leading;
 
         @Override public String toString() {
@@ -1668,9 +1626,6 @@
         return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi);
     }
 
-    private native int nGetFontMetricsInt(long paintPtr,
-            long typefacePtr, FontMetricsInt fmi);
-
     public FontMetricsInt getFontMetricsInt() {
         FontMetricsInt fm = new FontMetricsInt();
         getFontMetricsInt(fm);
@@ -1842,10 +1797,6 @@
         return res;
     }
 
-    private static native int nBreakText(long nObject, long nTypeface,
-                                               char[] text, int index, int count,
-                                               float maxWidth, int bidiFlags, float[] measuredWidth);
-
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
      * Return the number of chars that were measured, and if measuredWidth is
@@ -1934,10 +1885,6 @@
         return res;
     }
 
-    private static native int nBreakText(long nObject, long nTypeface,
-                                        String text, boolean measureForwards,
-                                        float maxWidth, int bidiFlags, float[] measuredWidth);
-
     /**
      * Return the advance widths for the characters in the string.
      *
@@ -2380,13 +2327,12 @@
      * Note: just like Canvas.drawText, this will respect the Align setting in
      * the paint.
      *
-     * @param text     The text to retrieve the path from
-     * @param index    The index of the first character in text
-     * @param count    The number of characterss starting with index
-     * @param x        The x coordinate of the text's origin
-     * @param y        The y coordinate of the text's origin
-     * @param path     The path to receive the data describing the text. Must
-     *                 be allocated by the caller.
+     * @param text the text to retrieve the path from
+     * @param index the index of the first character in text
+     * @param count the number of characters starting with index
+     * @param x the x coordinate of the text's origin
+     * @param y the y coordinate of the text's origin
+     * @param path the path to receive the data describing the text. Must be allocated by the caller
      */
     public void getTextPath(char[] text, int index, int count,
                             float x, float y, Path path) {
@@ -2402,13 +2348,12 @@
      * Note: just like Canvas.drawText, this will respect the Align setting
      * in the paint.
      *
-     * @param text  The text to retrieve the path from
-     * @param start The first character in the text
-     * @param end   1 past the last charcter in the text
-     * @param x     The x coordinate of the text's origin
-     * @param y     The y coordinate of the text's origin
-     * @param path  The path to receive the data describing the text. Must
-     *              be allocated by the caller.
+     * @param text the text to retrieve the path from
+     * @param start the first character in the text
+     * @param end 1 past the last character in the text
+     * @param x the x coordinate of the text's origin
+     * @param y the y coordinate of the text's origin
+     * @param path the path to receive the data describing the text. Must be allocated by the caller
      */
     public void getTextPath(String text, int start, int end,
                             float x, float y, Path path) {
@@ -2423,11 +2368,10 @@
      * Return in bounds (allocated by the caller) the smallest rectangle that
      * encloses all of the characters, with an implied origin at (0,0).
      *
-     * @param text  String to measure and return its bounds
-     * @param start Index of the first char in the string to measure
-     * @param end   1 past the last char in the string measure
-     * @param bounds Returns the unioned bounds of all the text. Must be
-     *               allocated by the caller.
+     * @param text string to measure and return its bounds
+     * @param start index of the first char in the string to measure
+     * @param end 1 past the last char in the string to measure
+     * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
      */
     public void getTextBounds(String text, int start, int end, Rect bounds) {
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
@@ -2443,11 +2387,33 @@
      * Return in bounds (allocated by the caller) the smallest rectangle that
      * encloses all of the characters, with an implied origin at (0,0).
      *
-     * @param text  Array of chars to measure and return their unioned bounds
-     * @param index Index of the first char in the array to measure
-     * @param count The number of chars, beginning at index, to measure
-     * @param bounds Returns the unioned bounds of all the text. Must be
-     *               allocated by the caller.
+     * @param text text to measure and return its bounds
+     * @param start index of the first char in the text to measure
+     * @param end 1 past the last char in the text to measure
+     * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
+     * @hide
+     */
+    public void getTextBounds(CharSequence text, int start, int end, Rect bounds) {
+        if ((start | end | (end - start) | (text.length() - end)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (bounds == null) {
+            throw new NullPointerException("need bounds Rect");
+        }
+        char[] buf = TemporaryBuffer.obtain(end - start);
+        TextUtils.getChars(text, start, end, buf, 0);
+        getTextBounds(buf, 0, end - start, bounds);
+        TemporaryBuffer.recycle(buf);
+    }
+
+    /**
+     * Return in bounds (allocated by the caller) the smallest rectangle that
+     * encloses all of the characters, with an implied origin at (0,0).
+     *
+     * @param text  array of chars to measure and return their unioned bounds
+     * @param index index of the first char in the array to measure
+     * @param count the number of chars, beginning at index, to measure
+     * @param bounds returns the unioned bounds of all the text. Must be allocated by the caller
      */
     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
         if ((index | count) < 0 || index + count > text.length) {
@@ -2642,74 +2608,34 @@
         return result;
     }
 
+    // regular JNI
+    private static native long nGetNativeFinalizer();
     private static native long nInit();
     private static native long nInitWithPaint(long paint);
-    private static native void nReset(long paintPtr);
-    private static native void nSet(long paintPtrDest, long paintPtrSrc);
-    private static native int nGetStyle(long paintPtr);
-    private static native void nSetStyle(long paintPtr, int style);
-    private static native int nGetStrokeCap(long paintPtr);
-    private static native void nSetStrokeCap(long paintPtr, int cap);
-    private static native int nGetStrokeJoin(long paintPtr);
-    private static native void nSetStrokeJoin(long paintPtr,
-                                                    int join);
-    private static native boolean nGetFillPath(long paintPtr,
-                                                     long src, long dst);
-    private static native long nSetShader(long paintPtr, long shader);
-    private static native long nSetColorFilter(long paintPtr,
-                                                    long filter);
-    private static native long nSetXfermode(long paintPtr,
-                                                  long xfermode);
-    private static native long nSetPathEffect(long paintPtr,
-                                                    long effect);
-    private static native long nSetMaskFilter(long paintPtr,
-                                                    long maskfilter);
-    private static native long nSetTypeface(long paintPtr,
-                                                  long typeface);
-    private static native long nSetRasterizer(long paintPtr,
-                                                   long rasterizer);
-
-    private static native int nGetTextAlign(long paintPtr);
-    private static native void nSetTextAlign(long paintPtr,
-                                                   int align);
-
-    private static native int nSetTextLocales(long paintPtr, String locales);
-    private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
-            int mMinikinLangListId);
-
+    private static native int nBreakText(long nObject, long nTypeface,
+            char[] text, int index, int count,
+            float maxWidth, int bidiFlags, float[] measuredWidth);
+    private static native int nBreakText(long nObject, long nTypeface,
+            String text, boolean measureForwards,
+            float maxWidth, int bidiFlags, float[] measuredWidth);
     private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int bidiFlags, float[] advances, int advancesIndex);
     private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
             String text, int start, int end, int contextStart, int contextEnd,
             int bidiFlags, float[] advances, int advancesIndex);
-
     private native int nGetTextRunCursor(long paintPtr, char[] text,
             int contextStart, int contextLength, int dir, int offset, int cursorOpt);
     private native int nGetTextRunCursor(long paintPtr, String text,
             int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
-
     private static native void nGetTextPath(long paintPtr, long typefacePtr,
             int bidiFlags, char[] text, int index, int count, float x, float y, long path);
     private static native void nGetTextPath(long paintPtr, long typefacePtr,
             int bidiFlags, String text, int start, int end, float x, float y, long path);
     private static native void nGetStringBounds(long nativePaint, long typefacePtr,
-                                String text, int start, int end, int bidiFlags, Rect bounds);
+            String text, int start, int end, int bidiFlags, Rect bounds);
     private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr,
-                                char[] text, int index, int count, int bidiFlags, Rect bounds);
-    private static native long nGetNativeFinalizer();
-
-    private static native void nSetShadowLayer(long paintPtr,
-            float radius, float dx, float dy, int color);
-    private static native boolean nHasShadowLayer(long paintPtr);
-
-    private static native float nGetLetterSpacing(long paintPtr);
-    private static native void nSetLetterSpacing(long paintPtr,
-                                                       float letterSpacing);
-    private static native void nSetFontFeatureSettings(long paintPtr,
-                                                             String settings);
-    private static native int nGetHyphenEdit(long paintPtr);
-    private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+            char[] text, int index, int count, int bidiFlags, Rect bounds);
     private static native boolean nHasGlyph(long paintPtr, long typefacePtr,
             int bidiFlags, String string);
     private static native float nGetRunAdvance(long paintPtr, long typefacePtr,
@@ -2718,4 +2644,134 @@
     private static native int nGetOffsetForAdvance(long paintPtr,
             long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd,
             boolean isRtl, float advance);
+
+
+    // ---------------- @FastNative ------------------------
+
+    @FastNative
+    private static native int nSetTextLocales(long paintPtr, String locales);
+    @FastNative
+    private static native void nSetFontFeatureSettings(long paintPtr, String settings);
+    @FastNative
+    private static native float nGetFontMetrics(long paintPtr,
+            long typefacePtr, FontMetrics metrics);
+    @FastNative
+    private static native int nGetFontMetricsInt(long paintPtr,
+            long typefacePtr, FontMetricsInt fmi);
+
+    
+    // ---------------- @CriticalNative ------------------------
+
+    @CriticalNative
+    private static native void nReset(long paintPtr);
+    @CriticalNative
+    private static native void nSet(long paintPtrDest, long paintPtrSrc);
+    @CriticalNative
+    private static native int nGetStyle(long paintPtr);
+    @CriticalNative
+    private static native void nSetStyle(long paintPtr, int style);
+    @CriticalNative
+    private static native int nGetStrokeCap(long paintPtr);
+    @CriticalNative
+    private static native void nSetStrokeCap(long paintPtr, int cap);
+    @CriticalNative
+    private static native int nGetStrokeJoin(long paintPtr);
+    @CriticalNative
+    private static native void nSetStrokeJoin(long paintPtr, int join);
+    @CriticalNative
+    private static native boolean nGetFillPath(long paintPtr, long src, long dst);
+    @CriticalNative
+    private static native long nSetShader(long paintPtr, long shader);
+    @CriticalNative
+    private static native long nSetColorFilter(long paintPtr, long filter);
+    @CriticalNative
+    private static native void nSetXfermode(long paintPtr, int xfermode);
+    @CriticalNative
+    private static native long nSetPathEffect(long paintPtr, long effect);
+    @CriticalNative
+    private static native long nSetMaskFilter(long paintPtr, long maskfilter);
+    @CriticalNative
+    private static native long nSetTypeface(long paintPtr, long typeface);
+    @CriticalNative
+    private static native long nSetRasterizer(long paintPtr, long rasterizer);
+    @CriticalNative
+    private static native int nGetTextAlign(long paintPtr);
+    @CriticalNative
+    private static native void nSetTextAlign(long paintPtr, int align);
+    @CriticalNative
+    private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
+            int mMinikinLangListId);
+    @CriticalNative
+    private static native void nSetShadowLayer(long paintPtr,
+            float radius, float dx, float dy, int color);
+    @CriticalNative
+    private static native boolean nHasShadowLayer(long paintPtr);
+    @CriticalNative
+    private static native float nGetLetterSpacing(long paintPtr);
+    @CriticalNative
+    private static native void nSetLetterSpacing(long paintPtr, float letterSpacing);
+    @CriticalNative
+    private static native int nGetHyphenEdit(long paintPtr);
+    @CriticalNative
+    private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+    @CriticalNative
+    private static native void nSetStrokeMiter(long paintPtr, float miter);
+    @CriticalNative
+    private static native float nGetStrokeMiter(long paintPtr);
+    @CriticalNative
+    private static native void nSetStrokeWidth(long paintPtr, float width);
+    @CriticalNative
+    private static native float nGetStrokeWidth(long paintPtr);
+    @CriticalNative
+    private static native void nSetAlpha(long paintPtr, int a);
+    @CriticalNative
+    private static native void nSetDither(long paintPtr, boolean dither);
+    @CriticalNative
+    private static native int nGetFlags(long paintPtr);
+    @CriticalNative
+    private static native void nSetFlags(long paintPtr, int flags);
+    @CriticalNative
+    private static native int nGetHinting(long paintPtr);
+    @CriticalNative
+    private static native void nSetHinting(long paintPtr, int mode);
+    @CriticalNative
+    private static native void nSetAntiAlias(long paintPtr, boolean aa);
+    @CriticalNative
+    private static native void nSetLinearText(long paintPtr, boolean linearText);
+    @CriticalNative
+    private static native void nSetSubpixelText(long paintPtr, boolean subpixelText);
+    @CriticalNative
+    private static native void nSetUnderlineText(long paintPtr, boolean underlineText);
+    @CriticalNative
+    private static native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
+    @CriticalNative
+    private static native void nSetFilterBitmap(long paintPtr, boolean filter);
+    @CriticalNative
+    private static native int nGetColor(long paintPtr);
+    @CriticalNative
+    private static native void nSetColor(long paintPtr, @ColorInt int color);
+    @CriticalNative
+    private static native int nGetAlpha(long paintPtr);
+    @CriticalNative
+    private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
+    @CriticalNative
+    private static native boolean nIsElegantTextHeight(long paintPtr);
+    @CriticalNative
+    private static native void nSetElegantTextHeight(long paintPtr, boolean elegant);
+    @CriticalNative
+    private static native float nGetTextSize(long paintPtr);
+    @CriticalNative
+    private static native float nGetTextScaleX(long paintPtr);
+    @CriticalNative
+    private static native void nSetTextScaleX(long paintPtr, float scaleX);
+    @CriticalNative
+    private static native float nGetTextSkewX(long paintPtr);
+    @CriticalNative
+    private static native void nSetTextSkewX(long paintPtr, float skewX);
+    @CriticalNative
+    private static native float nAscent(long paintPtr, long typefacePtr);
+    @CriticalNative
+    private static native float nDescent(long paintPtr, long typefacePtr);
+    @CriticalNative
+    private static native void nSetTextSize(long paintPtr, float textSize);
 }
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
index 78d892e..bf79656 100644
--- a/graphics/java/android/graphics/PathMeasure.java
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -79,7 +79,7 @@
      * are unchanged.
      *
      * @param distance The distance along the current contour to sample
-     * @param pos If not null, eturns the sampled position (x==[0], y==[1])
+     * @param pos If not null, returns the sampled position (x==[0], y==[1])
      * @param tan If not null, returns the sampled tangent (x==[0], y==[1])
      * @return false if there was no path associated with this measure object
     */
diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java
index d9d7689..5104410 100644
--- a/graphics/java/android/graphics/PorterDuffXfermode.java
+++ b/graphics/java/android/graphics/PorterDuffXfermode.java
@@ -18,19 +18,11 @@
 
 public class PorterDuffXfermode extends Xfermode {
     /**
-     * @hide
-     */
-    public final PorterDuff.Mode mode;
-
-    /**
      * Create an xfermode that uses the specified porter-duff mode.
      *
      * @param mode           The porter-duff mode that is applied
      */
     public PorterDuffXfermode(PorterDuff.Mode mode) {
-        this.mode = mode;
-        native_instance = nativeCreateXfermode(mode.nativeInt);
+        porterDuffMode = mode.nativeInt;
     }
-    
-    private static native long nativeCreateXfermode(int mode);
 }
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 5c54324..efb46b90 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -77,6 +77,8 @@
     private long mProducer;
     private long mFrameAvailableListener;
 
+    private boolean mIsSingleBuffered;
+
     /**
      * Callback interface for being notified that a new stream frame is available.
      */
@@ -130,6 +132,7 @@
      */
     public SurfaceTexture(int texName, boolean singleBufferMode) {
         mCreatorLooper = Looper.myLooper();
+        mIsSingleBuffered = singleBufferMode;
         nativeInit(false, texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
@@ -153,10 +156,10 @@
      * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
      *
      * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
-     * @hide
      */
     public SurfaceTexture(boolean singleBufferMode) {
         mCreatorLooper = Looper.myLooper();
+        mIsSingleBuffered = singleBufferMode;
         nativeInit(true, 0, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
@@ -378,6 +381,14 @@
         }
     }
 
+    /**
+     * Returns true if the SurfaceTexture is single-buffered
+     * @hide
+     */
+    public boolean isSingleBuffered() {
+        return mIsSingleBuffered;
+    }
+
     private native void nativeInit(boolean isDetached, int texName,
             boolean singleBufferMode, WeakReference<SurfaceTexture> weakSelf)
             throws Surface.OutOfResourcesException;
diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java
index c049e41..a5da5d0 100644
--- a/graphics/java/android/graphics/Xfermode.java
+++ b/graphics/java/android/graphics/Xfermode.java
@@ -29,17 +29,6 @@
  * objects drawn with that paint have the xfermode applied.
  */
 public class Xfermode {
-
-    protected void finalize() throws Throwable {
-        try {
-            finalizer(native_instance);
-            native_instance = 0;
-        } finally {
-            super.finalize();
-        }
-    }
-
-    private static native void finalizer(long native_instance);
-
-    long native_instance;
+    static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
+    int porterDuffMode = DEFAULT;
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e10445a..dcca431 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -65,19 +65,36 @@
 import java.util.ArrayList;
 
 /**
- * This class uses {@link android.animation.ObjectAnimator} and
- * {@link android.animation.AnimatorSet} to animate the properties of a
- * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable.
+ * This class animates properties of a {@link android.graphics.drawable.VectorDrawable} with
+ * animations defined using {@link android.animation.ObjectAnimator} or
+ * {@link android.animation.AnimatorSet}.
  * <p>
- * AnimatedVectorDrawable are normally defined as 3 separate XML files.
+ * Starting from API 25, AnimatedVectorDrawable runs on RenderThread (as opposed to on UI thread for
+ * earlier APIs). This means animations in AnimatedVectorDrawable can remain smooth even when there
+ * is heavy workload on the UI thread. Note: If the UI thread is unresponsive, RenderThread may
+ * continue animating until the UI thread is capable of pushing another frame. Therefore, it is not
+ * possible to precisely coordinate a RenderThread-enabled AnimatedVectorDrawable with UI thread
+ * animations. Additionally,
+ * {@link android.graphics.drawable.Animatable2.AnimationCallback#onAnimationEnd(Drawable)} will be
+ * called the frame after the AnimatedVectorDrawable finishes on the RenderThread.
  * </p>
  * <p>
- * First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
- * Note that we allow the animation to happen on the group's attributes and path's
- * attributes, which requires they are uniquely named in this XML file. Groups
- * and paths without animations do not need names.
+ * AnimatedVectorDrawable can be defined in either <a href="#ThreeXML">three separate XML files</a>,
+ * or <a href="#OneXML">one XML</a>.
  * </p>
- * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <a name="ThreeXML"></a>
+ * <h3>Define an AnimatedVectorDrawable in three separate XML files</h3>
+ * <ul>
+ * <a name="VDExample"></a>
+ * <li><h4>XML for the VectorDrawable containing properties to be animated</h4>
+ * <p>
+ * Animations can be performed on both group and path attributes, which requires groups and paths to
+ * have unique names in the same VectorDrawable. Groups and paths without animations do not need to
+ * be named.
+ * </p>
+ * Below is an example of a VectorDrawable defined in vectordrawable.xml. This VectorDrawable is
+ * referred to by its file name (not including file suffix) in the
+ * <a href="AVDExample">AnimatedVectorDrawable XML example</a>.
  * <pre>
  * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
  *     android:height=&quot;64dp&quot;
@@ -96,17 +113,20 @@
  *     &lt;/group&gt;
  * &lt;/vector&gt;
  * </pre></li>
+ *
+ * <a name="AVDExample"></a>
+ * <li><h4>XML for AnimatedVectorDrawable</h4>
  * <p>
- * Second is the AnimatedVectorDrawable's XML file, which defines the target
- * VectorDrawable, the target paths and groups to animate, the properties of the
- * path and group to animate and the animations defined as the ObjectAnimators
- * or AnimatorSets.
+ * An AnimatedVectorDrawable element has a VectorDrawable attribute, and one or more target
+ * element(s). The target elements can be the path or group to be animated. Each target element
+ * contains a name attribute that references a property (of a path or a group) to animate, and an
+ * animation attribute that points to an ObjectAnimator or an AnimatorSet.
  * </p>
- * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
- * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
+ * The following code sample defines an AnimatedVectorDrawable. Note that the names refer to the
+ * groups and paths in the <a href="#VDExample">VectorDrawable XML above</a>.
  * <pre>
  * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
- *   android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
+ *     android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
  *     &lt;target
  *         android:name=&quot;rotationGroup&quot;
  *         android:animation=&quot;@anim/rotation&quot; /&gt;
@@ -114,39 +134,43 @@
  *         android:name=&quot;v&quot;
  *         android:animation=&quot;@anim/path_morph&quot; /&gt;
  * &lt;/animated-vector&gt;
- * </pre></li>
+ * </pre>
+ * </li>
+ *
+ * <li><h4>XML for Animations defined using ObjectAnimator or AnimatorSet</h4>
  * <p>
- * Last is the Animator XML file, which is the same as a normal ObjectAnimator
- * or AnimatorSet.
- * To complete this example, here are the 2 animator files used in avd.xml:
- * rotation.xml and path_morph.xml.
+ * From the previous <a href="#AVDExample">example of AnimatedVectorDrawable</a>, two animations
+ * were used: rotation.xml and path_morph.xml.
  * </p>
- * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
+ * rotation.xml rotates the target group from 0 degree to 360 degrees over 6000ms:
  * <pre>
  * &lt;objectAnimator
  *     android:duration=&quot;6000&quot;
  *     android:propertyName=&quot;rotation&quot;
  *     android:valueFrom=&quot;0&quot;
  *     android:valueTo=&quot;360&quot; /&gt;
- * </pre></li>
- * <li>Here is the path_morph.xml, which will morph the path from one shape to
- * the other. Note that the paths must be compatible for morphing.
- * In more details, the paths should have exact same length of commands , and
- * exact same length of parameters for each commands.
- * Note that the path strings are better stored in strings.xml for reusing.
+ * </pre>
+ *
+ * path_morph.xml morphs the path from one shape into the other. Note that the paths must be
+ * compatible for morphing. Specifically, the paths must have the same commands, in the same order,
+ * and must have the same number of parameters for each command. It is recommended to store path
+ * strings as string resources for reuse.
  * <pre>
  * &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
  *     &lt;objectAnimator
  *         android:duration=&quot;3000&quot;
  *         android:propertyName=&quot;pathData&quot;
- *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
+ *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
  *         android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
  *         android:valueType=&quot;pathType&quot;/&gt;
  * &lt;/set&gt;
- * </pre></li>
+ * </pre>
+ * </ul>
+ * <a name="OneXML"></a>
+ * <h3>Define an AnimatedVectorDrawable all in one XML file</h3>
  * <p>
- * Since AAPT tool is now supporting a new format which can bundle several related XML files into
- * one, we can merge the previous example into one XML file, like this:
+ * Since the AAPT tool supports a new format that bundles several related XML files together, we can
+ * merge the XML files from the previous examples into one XML file:
  * </p>
  * <pre>
  * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
@@ -185,7 +209,7 @@
  *                 &lt;objectAnimator
  *                     android:duration=&quot;3000&quot;
  *                     android:propertyName=&quot;pathData&quot;
- *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
+ *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
  *                     android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
  *                     android:valueType=&quot;pathType&quot;/&gt;
  *             &lt;/set&gt;
@@ -286,6 +310,17 @@
         return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations();
     }
 
+    /**
+     * Draws the AnimatedVectorDrawable into the given canvas.
+     * <p>
+     * <strong>Note:</strong> Calling this method with a software canvas when the
+     * AnimatedVectorDrawable is being animated on RenderThread (for API 25 and later) may yield
+     * outdated result, as the UI thread is not guaranteed to be in sync with RenderThread on
+     * VectorDrawable's property changes during RenderThread animations.
+     * </p>
+     *
+     * @param canvas The canvas to draw into
+     */
     @Override
     public void draw(Canvas canvas) {
         if (!canvas.isHardwareAccelerated() && mAnimatorSet instanceof VectorDrawableAnimatorRT) {
@@ -293,10 +328,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);
@@ -324,9 +356,9 @@
     }
 
     /**
-     * AnimatedVectorDrawable is running on render thread now. Therefore, if the root alpha is being
-     * animated, then the root alpha value we get from this call could be out of sync with alpha
-     * value used in the render thread. Otherwise, the root alpha should be always the same value.
+     * For API 25 and later, AnimatedVectorDrawable runs on RenderThread. Therefore, when the
+     * root alpha is being animated, this getter does not guarantee to return an up-to-date alpha
+     * value.
      *
      * @return the containing vector drawable's root alpha value.
      */
@@ -539,10 +571,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);
         }
     }
 
@@ -1486,7 +1530,6 @@
             } else {
                 addPendingAction(START_ANIMATION);
             }
-
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 7f3a437..10f0dda 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -109,6 +109,9 @@
  *     <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
  *     specify information about how to stretch it and place things inside of
  *     it.
+ *     <li><b>Vector</b>: a drawable defined in an XML file as a set of points,
+ *     lines, and curves along with its associated color information. This type
+ *     of drawable can be scaled without loss of display quality.
  *     <li> <b>Shape</b>: contains simple drawing commands instead of a raw
  *     bitmap, allowing it to resize better in some cases.
  *     <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
@@ -573,6 +576,12 @@
      * </p>
      */
     public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
+        if (getColorFilter() instanceof PorterDuffColorFilter) {
+            PorterDuffColorFilter existing = (PorterDuffColorFilter) getColorFilter();
+            if (existing.getColor() == color && existing.getMode() == mode) {
+                return;
+            }
+        }
         setColorFilter(new PorterDuffColorFilter(color, mode));
     }
 
@@ -1422,9 +1431,10 @@
     /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
+     * @hide
      */
-    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
-            @NonNull AttributeSet set, @NonNull int[] attrs) {
+    protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
+            @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
         if (theme == null) {
             return res.obtainAttributes(set, attrs);
         }
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index cc7f5c7..c7a3c75 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -27,8 +27,8 @@
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
@@ -601,8 +601,9 @@
      * during inflation.
      *
      * @param res the resources used to inflate density-dependent values
+     * @hide
      */
-    final void updateDensity(Resources res) {
+    protected final void updateDensity(Resources res) {
         mDrawableContainerState.updateDensity(res);
     }
 
@@ -711,7 +712,10 @@
         boolean mHasTintList;
         boolean mHasTintMode;
 
-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+        /**
+         * @hide
+         */
+        protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
             mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 7ea466e..7aad7df 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -476,16 +476,17 @@
     }
 
     /**
-     * Sets the center location in pixels of the gradient. The radius is
-     * honored only when the gradient type is set to {@link #RADIAL_GRADIENT}
-     * or {@link #SWEEP_GRADIENT}.
+     * Sets the position of the center of the gradient as a fraction of the
+     * width and height.
+     * <p>
+     * The default value is (0.5, 0.5).
      * <p>
      * <strong>Note</strong>: changing this property will affect all instances
      * of a drawable loaded from a resource. It is recommended to invoke
      * {@link #mutate()} before changing this property.
      *
-     * @param x the x coordinate of the gradient's center in pixels
-     * @param y the y coordinate of the gradient's center in pixels
+     * @param x the X-position of the center of the gradient
+     * @param y the Y-position of the center of the gradient
      *
      * @see #mutate()
      * @see #setGradientType(int)
@@ -499,9 +500,10 @@
     }
 
     /**
-     * Returns the center X location of this gradient in pixels.
+     * Returns the X-position of the center of the gradient as a fraction of
+     * the width.
      *
-     * @return the center X location of this gradient in pixels
+     * @return the X-position of the center of the gradient
      * @see #setGradientCenter(float, float)
      */
     public float getGradientCenterX() {
@@ -509,9 +511,10 @@
     }
 
     /**
-     * Returns the center Y location of this gradient in pixels.
+     * Returns the Y-position of the center of this gradient as a fraction of
+     * the height.
      *
-     * @return the center Y location of this gradient in pixels
+     * @return the Y-position of the center of the gradient
      * @see #setGradientCenter(float, float)
      */
     public float getGradientCenterY() {
@@ -555,19 +558,43 @@
     }
 
     /**
-     * Sets whether or not this drawable will honor its {@code level} property.
+     * Sets whether this drawable's {@code level} property will be used to
+     * scale the gradient. If a gradient is not used, this property has no
+     * effect.
      * <p>
-     * <strong>Note</strong>: changing this property will affect all instances
+     * Scaling behavior varies based on gradient type:
+     * <ul>
+     *     <li>{@link #LINEAR_GRADIENT} adjusts the ending position along the
+     *         gradient's axis of orientation (see {@link #getOrientation()})
+     *     <li>{@link #RADIAL_GRADIENT} adjusts the outer radius
+     *     <li>{@link #SWEEP_GRADIENT} adjusts the ending angle
+     * <ul>
+     * <p>
+     * The default value for this property is {@code false}.
+     * <p>
+     * <strong>Note</strong>: This property corresponds to the
+     * {@code android:useLevel} attribute on the inner {@code &lt;gradient&gt;}
+     * tag, NOT the {@code android:useLevel} attribute on the outer
+     * {@code &lt;shape&gt;} tag. For example,
+     * <pre>{@code
+     * <shape ...>
+     *     <gradient
+     *         ...
+     *         android:useLevel="true" />
+     * </shape>
+     * }</pre><p>
+     * <strong>Note</strong>: Changing this property will affect all instances
      * of a drawable loaded from a resource. It is recommended to invoke
      * {@link #mutate()} before changing this property.
      *
-     * @param useLevel {@code true} if this drawable should honor its level,
-     *                 {@code false} otherwise
+     * @param useLevel {@code true} if the gradient should be scaled based on
+     *                 level, {@code false} otherwise
      *
      * @see #mutate()
      * @see #setLevel(int)
      * @see #getLevel()
      * @see #getUseLevel()
+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
      */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
@@ -576,12 +603,13 @@
     }
 
     /**
-     * Returns whether or not this drawable will honor its {@code level}
-     * property.
+     * Returns whether this drawable's {@code level} property will be used to
+     * scale the gradient.
      *
-     * @return {@code true} if this drawable should honor its level,
+     * @return {@code true} if the gradient should be scaled based on level,
      *         {@code false} otherwise
      * @see #setUseLevel(boolean)
+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
      */
     public boolean getUseLevel() {
         return mGradientState.mUseLevel;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 1864206..c30c4c2 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -269,7 +269,8 @@
 
             // If the layer doesn't have a drawable or unresolved theme
             // attribute for a drawable, attempt to parse one from the child
-            // element.
+            // element. If multiple child elements exist, we'll only use the
+            // first one.
             if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
                     layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
                 while ((type = parser.next()) == XmlPullParser.TEXT) {
@@ -279,13 +280,12 @@
                             + ": <item> tag requires a 'drawable' attribute or "
                             + "child tag defining a drawable");
                 }
-                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            }
 
-            if (layer.mDrawable != null) {
+                // We found a child drawable. Take ownership.
+                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
+                layer.mDrawable.setCallback(this);
                 state.mChildrenChangingConfigurations |=
                         layer.mDrawable.getChangingConfigurations();
-                layer.mDrawable.setCallback(this);
             }
 
             addLayer(layer);
@@ -387,7 +387,19 @@
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
         if (dr != null) {
+            if (layer.mDrawable != null) {
+                // It's possible that a drawable was already set, in which case
+                // we should clear the callback. We may have also integrated the
+                // drawable's changing configurations, but we don't have enough
+                // information to revert that change.
+                layer.mDrawable.setCallback(null);
+            }
+
+            // Take ownership of the new drawable.
             layer.mDrawable = dr;
+            layer.mDrawable.setCallback(this);
+            state.mChildrenChangingConfigurations |=
+                    layer.mDrawable.getChangingConfigurations();
         }
     }
 
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index 29bf963..a14609f 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -18,8 +18,11 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.os.Handler;
+import android.view.ViewTreeObserver.OnDrawListener;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -105,6 +108,32 @@
     }
 
     /**
+     * Requests for the display content of a {@link SurfaceView} to be copied
+     * into a provided {@link Bitmap}.
+     *
+     * The contents of the source will be scaled to fit exactly inside the bitmap.
+     * The pixel format of the source buffer will be converted, as part of the copy,
+     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * in the SurfaceView's Surface will be used as the source of the copy.
+     *
+     * @param source The source from which to copy
+     * @param srcRect The area of the source to copy from. If this is null
+     * the copy area will be the entire surface. The rect will be clamped to
+     * the bounds of the Surface.
+     * @param dest The destination of the copy. The source will be scaled to
+     * match the width, height, and format of this bitmap.
+     * @param listener Callback for when the pixel copy request completes
+     * @param listenerThread The callback will be invoked on this Handler when
+     * the copy is finished.
+     */
+    public static void request(@NonNull SurfaceView source, @Nullable Rect srcRect,
+            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
+            @NonNull Handler listenerThread) {
+        request(source.getHolder().getSurface(), srcRect,
+                dest, listener, listenerThread);
+    }
+
+    /**
      * Requests a copy of the pixels from a {@link Surface} to be copied into
      * a provided {@link Bitmap}.
      *
@@ -122,12 +151,40 @@
      */
     public static void request(@NonNull Surface source, @NonNull Bitmap dest,
             @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
+        request(source, null, dest, listener, listenerThread);
+    }
+
+    /**
+     * Requests a copy of the pixels at the provided {@link Rect} from
+     * a {@link Surface} to be copied into a provided {@link Bitmap}.
+     *
+     * The contents of the source rect will be scaled to fit exactly inside the bitmap.
+     * The pixel format of the source buffer will be converted, as part of the copy,
+     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * in the Surface will be used as the source of the copy.
+     *
+     * @param source The source from which to copy
+     * @param srcRect The area of the source to copy from. If this is null
+     * the copy area will be the entire surface. The rect will be clamped to
+     * the bounds of the Surface.
+     * @param dest The destination of the copy. The source will be scaled to
+     * match the width, height, and format of this bitmap.
+     * @param listener Callback for when the pixel copy request completes
+     * @param listenerThread The callback will be invoked on this Handler when
+     * the copy is finished.
+     */
+    public static void request(@NonNull Surface source, @Nullable Rect srcRect,
+            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
+            @NonNull Handler listenerThread) {
         validateBitmapDest(dest);
         if (!source.isValid()) {
             throw new IllegalArgumentException("Surface isn't valid, source.isValid() == false");
         }
+        if (srcRect != null && srcRect.isEmpty()) {
+            throw new IllegalArgumentException("sourceRect is empty");
+        }
         // TODO: Make this actually async and fast and cool and stuff
-        int result = ThreadedRenderer.copySurfaceInto(source, dest);
+        int result = ThreadedRenderer.copySurfaceInto(source, srcRect, dest);
         listenerThread.post(new Runnable() {
             @Override
             public void run() {
@@ -136,6 +193,86 @@
         });
     }
 
+    /**
+     * Requests a copy of the pixels from a {@link Window} to be copied into
+     * a provided {@link Bitmap}.
+     *
+     * The contents of the source will be scaled to fit exactly inside the bitmap.
+     * The pixel format of the source buffer will be converted, as part of the copy,
+     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * in the Window's Surface will be used as the source of the copy.
+     *
+     * Note: This is limited to being able to copy from Window's with a non-null
+     * DecorView. If {@link Window#peekDecorView()} is null this throws an
+     * {@link IllegalArgumentException}. It will similarly throw an exception
+     * if the DecorView has not yet acquired a backing surface. It is recommended
+     * that {@link OnDrawListener} is used to ensure that at least one draw
+     * has happened before trying to copy from the window, otherwise either
+     * an {@link IllegalArgumentException} will be thrown or an error will
+     * be returned to the {@link OnPixelCopyFinishedListener}.
+     *
+     * @param source The source from which to copy
+     * @param dest The destination of the copy. The source will be scaled to
+     * match the width, height, and format of this bitmap.
+     * @param listener Callback for when the pixel copy request completes
+     * @param listenerThread The callback will be invoked on this Handler when
+     * the copy is finished.
+     */
+    public static void request(@NonNull Window source, @NonNull Bitmap dest,
+            @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
+        request(source, null, dest, listener, listenerThread);
+    }
+
+    /**
+     * Requests a copy of the pixels at the provided {@link Rect} from
+     * a {@link Window} to be copied into a provided {@link Bitmap}.
+     *
+     * The contents of the source rect will be scaled to fit exactly inside the bitmap.
+     * The pixel format of the source buffer will be converted, as part of the copy,
+     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * in the Window's Surface will be used as the source of the copy.
+     *
+     * Note: This is limited to being able to copy from Window's with a non-null
+     * DecorView. If {@link Window#peekDecorView()} is null this throws an
+     * {@link IllegalArgumentException}. It will similarly throw an exception
+     * if the DecorView has not yet acquired a backing surface. It is recommended
+     * that {@link OnDrawListener} is used to ensure that at least one draw
+     * has happened before trying to copy from the window, otherwise either
+     * an {@link IllegalArgumentException} will be thrown or an error will
+     * be returned to the {@link OnPixelCopyFinishedListener}.
+     *
+     * @param source The source from which to copy
+     * @param srcRect The area of the source to copy from. If this is null
+     * the copy area will be the entire surface. The rect will be clamped to
+     * the bounds of the Surface.
+     * @param dest The destination of the copy. The source will be scaled to
+     * match the width, height, and format of this bitmap.
+     * @param listener Callback for when the pixel copy request completes
+     * @param listenerThread The callback will be invoked on this Handler when
+     * the copy is finished.
+     */
+    public static void request(@NonNull Window source, @Nullable Rect srcRect,
+            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
+            @NonNull Handler listenerThread) {
+        validateBitmapDest(dest);
+        if (source == null) {
+            throw new IllegalArgumentException("source is null");
+        }
+        if (source.peekDecorView() == null) {
+            throw new IllegalArgumentException(
+                    "Only able to copy windows with decor views");
+        }
+        Surface surface = null;
+        if (source.peekDecorView().getViewRootImpl() != null) {
+            surface = source.peekDecorView().getViewRootImpl().mSurface;
+        }
+        if (surface == null || !surface.isValid()) {
+            throw new IllegalArgumentException(
+                    "Window doesn't have a backing surface!");
+        }
+        request(surface, srcRect, dest, listener, listenerThread);
+    }
+
     private static void validateBitmapDest(Bitmap bitmap) {
         // TODO: Pre-check max texture dimens if we can
         if (bitmap == null) {
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 914ac3d..3b5cdce 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -59,10 +59,7 @@
  * single instance may be shared across multiple threads, and a single
  * thread may have more than one instance (the latter is discouraged).
  *
- * The purpose of the AssetManager is to create Asset objects.  To do
- * this efficiently it may cache information about the locations of
- * files it has seen.  This can be controlled with the "cacheMode"
- * argument.
+ * The purpose of the AssetManager is to create Asset objects.
  *
  * The asset hierarchy may be examined like a filesystem, using
  * AssetDir objects to peruse a single directory.
@@ -72,18 +69,17 @@
     static const char* RESOURCES_FILENAME;
     static const char* IDMAP_BIN;
     static const char* OVERLAY_DIR;
+    /*
+     * If OVERLAY_SKU_DIR_PROPERTY is set, search for runtime resource overlay
+     * APKs in OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> rather than in
+     * OVERLAY_DIR.
+     */
+    static const char* OVERLAY_SKU_DIR_PROPERTY;
     static const char* TARGET_PACKAGE_NAME;
     static const char* TARGET_APK_PATH;
     static const char* IDMAP_DIR;
 
-    typedef enum CacheMode {
-        CACHE_UNKNOWN = 0,
-        CACHE_OFF,          // don't try to cache file locations
-        CACHE_DEFER,        // construct cache as pieces are needed
-        //CACHE_SCAN,         // scan full(!) asset hierarchy at init() time
-    } CacheMode;
-
-    AssetManager(CacheMode cacheMode = CACHE_OFF);
+    AssetManager();
     virtual ~AssetManager(void);
 
     static int32_t getGlobalCount();
@@ -120,23 +116,16 @@
     int32_t nextAssetPath(const int32_t cookie) const;
 
     /*
-     * Return an asset path in the manager.  'which' must be between 0 and
-     * countAssetPaths().
+     * Return an asset path in the manager.  'cookie' must be a non-negative value
+     * previously returned from addAssetPath() or nextAssetPath().
      */
     String8 getAssetPath(const int32_t cookie) const;
 
     /*
-     * Set the current locale and vendor.  The locale can change during
-     * the lifetime of an AssetManager if the user updates the device's
-     * language setting.  The vendor is less likely to change.
-     *
-     * Pass in NULL to indicate no preference.
-     */
-    void setLocale(const char* locale);
-    void setVendor(const char* vendor);
-
-    /*
-     * Choose screen orientation for resources values returned.
+     * Sets various device configuration parameters, like screen orientation, layout,
+     * size, locale, etc.
+     * The optional 'locale' string takes precedence over the locale within 'config'
+     * and must be in bcp47 format.
      */
     void setConfiguration(const ResTable_config& config, const char* locale = NULL);
 
@@ -147,9 +136,6 @@
     /*
      * Open an asset.
      *
-     * This will search through locale-specific and vendor-specific
-     * directories and packages to find the file.
-     *
      * The object returned does not depend on the AssetManager.  It should
      * be freed by calling Asset::close().
      */
@@ -159,9 +145,8 @@
      * Open a non-asset file as an asset.
      *
      * This is for opening files that are included in an asset package
-     * but aren't assets.  These sit outside the usual "locale/vendor"
-     * path hierarchy, and will not be seen by "AssetDir" or included
-     * in our filename cache.
+     * but aren't assets.  These sit outside the usual "assets/"
+     * path hierarchy, and will not be seen by "AssetDir".
      */
     Asset* openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie = NULL);
 
@@ -174,11 +159,6 @@
     /*
      * Open a directory within the asset hierarchy.
      *
-     * The contents of the directory are an amalgam of vendor-specific,
-     * locale-specific, and generic assets stored loosely or in asset
-     * packages.  Depending on the cache setting and previous accesses,
-     * this call may incur significant disk overhead.
-     *
      * To open the top-level directory, pass in "".
      */
     AssetDir* openDir(const char* dirName);
@@ -186,11 +166,6 @@
     /*
      * Open a directory within a particular path of the asset manager.
      *
-     * The contents of the directory are an amalgam of vendor-specific,
-     * locale-specific, and generic assets stored loosely or in asset
-     * packages.  Depending on the cache setting and previous accesses,
-     * this call may incur significant disk overhead.
-     *
      * To open the top-level directory, pass in "".
      */
     AssetDir* openNonAssetDir(const int32_t cookie, const char* dirName);
@@ -209,13 +184,6 @@
     const ResTable& getResources(bool required = true) const;
 
     /*
-     * Discard cached filename information.  This only needs to be called
-     * if somebody has updated the set of "loose" files, and we want to
-     * discard our cached notion of what's where.
-     */
-    void purge(void) { purgeFileNameCacheLocked(); }
-
-    /*
      * Return true if the files this AssetManager references are all
      * up-to-date (have not been changed since it was created).  If false
      * is returned, you will need to create a new AssetManager to get
@@ -247,14 +215,8 @@
         bool isSystemAsset;
     };
 
-    Asset* openInPathLocked(const char* fileName, AccessMode mode,
-        const asset_path& path);
     Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
         const asset_path& path);
-    Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
-        const asset_path& path, const char* locale, const char* vendor);
-    String8 createPathNameLocked(const asset_path& path, const char* locale,
-        const char* vendor);
     String8 createPathNameLocked(const asset_path& path, const char* rootDir);
     String8 createZipSourceNameLocked(const String8& zipFileName,
         const String8& dirName, const String8& fileName);
@@ -272,15 +234,6 @@
     void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
         const SortedVector<AssetDir::FileInfo>* pContents);
 
-    void loadFileNameCacheLocked(void);
-    void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
-        const char* dirName);
-    bool fncScanAndMergeDirLocked(
-        SortedVector<AssetDir::FileInfo>* pMergedInfo,
-        const asset_path& path, const char* locale, const char* vendor,
-        const char* dirName);
-    void purgeFileNameCacheLocked(void);
-
     const ResTable* getResTable(bool required = true) const;
     void setLocaleLocked(const char* locale);
     void updateResourceParamsLocked() const;
@@ -337,8 +290,8 @@
      */
     class ZipSet {
     public:
-        ZipSet(void);
-        ~ZipSet(void);
+        ZipSet() = default;
+        ~ZipSet();
 
         /*
          * Return a ZipFileRO structure for a ZipFileRO with the specified
@@ -375,23 +328,9 @@
 
     Vector<asset_path> mAssetPaths;
     char*           mLocale;
-    char*           mVendor;
 
     mutable ResTable* mResources;
     ResTable_config* mConfig;
-
-    /*
-     * Cached data for "loose" files.  This lets us avoid poking at the
-     * filesystem when searching for loose assets.  Each entry is the
-     * "extended partial" path, e.g. "default/default/foo/bar.txt".  The
-     * full set of files is present, including ".EXCLUDE" entries.
-     *
-     * We do not cache directory names.  We don't retain the ".gz",
-     * because to our clients "foo" and "foo.gz" both look like "foo".
-     */
-    CacheMode       mCacheMode;         // is the cache enabled?
-    bool            mCacheValid;        // clear when locale or vendor changes
-    SortedVector<AssetDir::FileInfo> mCache;
 };
 
 }; // namespace android
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/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index d849317..d023866 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -251,8 +251,9 @@
     /**
      * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
-     * This will build a parameter spec for use with the <a href="{@docRoot}
-     * training/articles/keystore.html">Android KeyStore facility</a>.
+     * This will build a parameter spec for use with the
+     * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
+     * facility</a>.
      * <p>
      * The required fields must be filled in with the builder.
      * <p>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 641a7ff..796cb36 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -56,12 +56,6 @@
 
 static const bool kIsDebug = false;
 
-/*
- * Names for default app, locale, and vendor.  We might want to change
- * these to be an actual locale, e.g. always use en-US as the default.
- */
-static const char* kDefaultLocale = "default";
-static const char* kDefaultVendor = "default";
 static const char* kAssetsRoot = "assets";
 static const char* kAppZipName = NULL; //"classes.jar";
 static const char* kSystemAssets = "framework/framework-res.apk";
@@ -76,73 +70,70 @@
 const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
+const char* AssetManager::OVERLAY_SKU_DIR_PROPERTY = "ro.boot.vendor.overlay.sku";
 const char* AssetManager::TARGET_PACKAGE_NAME = "android";
 const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
 const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
 
 namespace {
-    String8 idmapPathForPackagePath(const String8& pkgPath)
-    {
-        const char* root = getenv("ANDROID_DATA");
-        LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
-        String8 path(root);
-        path.appendPath(kResourceCache);
 
-        char buf[256]; // 256 chars should be enough for anyone...
-        strncpy(buf, pkgPath.string(), 255);
-        buf[255] = '\0';
-        char* filename = buf;
-        while (*filename && *filename == '/') {
-            ++filename;
-        }
-        char* p = filename;
-        while (*p) {
-            if (*p == '/') {
-                *p = '@';
-            }
-            ++p;
-        }
-        path.appendPath(filename);
-        path.append("@idmap");
+String8 idmapPathForPackagePath(const String8& pkgPath) {
+    const char* root = getenv("ANDROID_DATA");
+    LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
+    String8 path(root);
+    path.appendPath(kResourceCache);
 
-        return path;
+    char buf[256]; // 256 chars should be enough for anyone...
+    strncpy(buf, pkgPath.string(), 255);
+    buf[255] = '\0';
+    char* filename = buf;
+    while (*filename && *filename == '/') {
+        ++filename;
     }
-
-    /*
-     * Like strdup(), but uses C++ "new" operator instead of malloc.
-     */
-    static char* strdupNew(const char* str)
-    {
-        char* newStr;
-        int len;
-
-        if (str == NULL)
-            return NULL;
-
-        len = strlen(str);
-        newStr = new char[len+1];
-        memcpy(newStr, str, len+1);
-
-        return newStr;
+    char* p = filename;
+    while (*p) {
+        if (*p == '/') {
+            *p = '@';
+        }
+        ++p;
     }
+    path.appendPath(filename);
+    path.append("@idmap");
+
+    return path;
 }
 
 /*
+ * Like strdup(), but uses C++ "new" operator instead of malloc.
+ */
+static char* strdupNew(const char* str) {
+    char* newStr;
+    int len;
+
+    if (str == NULL)
+        return NULL;
+
+    len = strlen(str);
+    newStr = new char[len+1];
+    memcpy(newStr, str, len+1);
+
+    return newStr;
+}
+
+} // namespace
+
+/*
  * ===========================================================================
  *      AssetManager
  * ===========================================================================
  */
 
-int32_t AssetManager::getGlobalCount()
-{
+int32_t AssetManager::getGlobalCount() {
     return gCount;
 }
 
-AssetManager::AssetManager(CacheMode cacheMode)
-    : mLocale(NULL), mVendor(NULL),
-      mResources(NULL), mConfig(new ResTable_config),
-      mCacheMode(cacheMode), mCacheValid(false)
-{
+AssetManager::AssetManager() :
+        mLocale(NULL), mResources(NULL), mConfig(new ResTable_config) {
     int count = android_atomic_inc(&gCount) + 1;
     if (kIsDebug) {
         ALOGI("Creating AssetManager %p #%d\n", this, count);
@@ -150,8 +141,7 @@
     memset(mConfig, 0, sizeof(ResTable_config));
 }
 
-AssetManager::~AssetManager(void)
-{
+AssetManager::~AssetManager() {
     int count = android_atomic_dec(&gCount);
     if (kIsDebug) {
         ALOGI("Destroying AssetManager in %p #%d\n", this, count);
@@ -162,12 +152,10 @@
 
     // don't have a String class yet, so make sure we clean up
     delete[] mLocale;
-    delete[] mVendor;
 }
 
 bool AssetManager::addAssetPath(
-        const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
-{
+        const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset) {
     AutoMutex _l(mLock);
 
     asset_path ap;
@@ -342,25 +330,9 @@
     return String8();
 }
 
-/*
- * Set the current locale.  Use NULL to indicate no locale.
- *
- * Close and reopen Zip archives as appropriate, and reset cached
- * information in the locale-specific sections of the tree.
- */
-void AssetManager::setLocale(const char* locale)
-{
-    AutoMutex _l(mLock);
-    setLocaleLocked(locale);
-}
-
-
 void AssetManager::setLocaleLocked(const char* locale)
 {
     if (mLocale != NULL) {
-        /* previously set, purge cached data */
-        purgeFileNameCacheLocked();
-        //mZipSet.purgeLocale();
         delete[] mLocale;
     }
 
@@ -368,25 +340,6 @@
     updateResourceParamsLocked();
 }
 
-/*
- * Set the current vendor.  Use NULL to indicate no vendor.
- *
- * Close and reopen Zip archives as appropriate, and reset cached
- * information in the vendor-specific sections of the tree.
- */
-void AssetManager::setVendor(const char* vendor)
-{
-    AutoMutex _l(mLock);
-
-    if (mVendor != NULL) {
-        /* previously set, purge cached data */
-        purgeFileNameCacheLocked();
-        //mZipSet.purgeVendor();
-        delete[] mVendor;
-    }
-    mVendor = strdupNew(vendor);
-}
-
 void AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
 {
     AutoMutex _l(mLock);
@@ -411,23 +364,11 @@
 /*
  * Open an asset.
  *
- * The data could be;
- *  - In a file on disk (assetBase + fileName).
- *  - In a compressed file on disk (assetBase + fileName.gz).
- *  - In a Zip archive, uncompressed or compressed.
+ * The data could be in any asset path. Each asset path could be:
+ *  - A directory on disk.
+ *  - A Zip archive, uncompressed or compressed.
  *
- * It can be in a number of different directories and Zip archives.
- * The search order is:
- *  - [appname]
- *    - locale + vendor
- *    - "default" + vendor
- *    - locale + "default"
- *    - "default + "default"
- *  - "common"
- *    - (same as above)
- *
- * To find a particular file, we have to try up to eight paths with
- * all three forms of data.
+ * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
  *
  * We should probably reject requests for "illegal" filenames, e.g. those
  * with illegal characters or "../" backward relative paths.
@@ -438,10 +379,6 @@
 
     LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
 
-
-    if (mCacheMode != CACHE_OFF && !mCacheValid)
-        loadFileNameCacheLocked();
-
     String8 assetName(kAssetsRoot);
     assetName.appendPath(fileName);
 
@@ -466,8 +403,7 @@
 /*
  * Open a non-asset file as if it were an asset.
  *
- * The "fileName" is the partial path starting from the application
- * name.
+ * The "fileName" is the partial path starting from the application name.
  */
 Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie)
 {
@@ -475,10 +411,6 @@
 
     LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
 
-
-    if (mCacheMode != CACHE_OFF && !mCacheValid)
-        loadFileNameCacheLocked();
-
     /*
      * For each top-level asset path, search for the asset.
      */
@@ -506,9 +438,6 @@
 
     LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
 
-    if (mCacheMode != CACHE_OFF && !mCacheValid)
-        loadFileNameCacheLocked();
-
     if (which < mAssetPaths.size()) {
         ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
                 mAssetPaths.itemAt(which).path.string());
@@ -540,10 +469,11 @@
     pAsset = open(fileName, Asset::ACCESS_STREAMING);
     delete pAsset;
 
-    if (pAsset == NULL)
+    if (pAsset == NULL) {
         return kFileTypeNonexistent;
-    else
+    } else {
         return kFileTypeRegular;
+    }
 }
 
 bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
@@ -658,10 +588,6 @@
         LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
     }
 
-    if (mCacheMode != CACHE_OFF && !mCacheValid) {
-        const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
-    }
-
     mResources = new ResTable();
     updateResourceParamsLocked();
 
@@ -832,158 +758,6 @@
 }
 
 /*
- * Open an asset, searching for it in the directory hierarchy for the
- * specified app.
- *
- * Pass in a NULL values for "appName" if the common app directory should
- * be used.
- */
-Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode,
-    const asset_path& ap)
-{
-    Asset* pAsset = NULL;
-
-    /*
-     * Try various combinations of locale and vendor.
-     */
-    if (mLocale != NULL && mVendor != NULL)
-        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor);
-    if (pAsset == NULL && mVendor != NULL)
-        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor);
-    if (pAsset == NULL && mLocale != NULL)
-        pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL);
-    if (pAsset == NULL)
-        pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL);
-
-    return pAsset;
-}
-
-/*
- * Open an asset, searching for it in the directory hierarchy for the
- * specified locale and vendor.
- *
- * We also search in "app.jar".
- *
- * Pass in NULL values for "appName", "locale", and "vendor" if the
- * defaults should be used.
- */
-Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode,
-    const asset_path& ap, const char* locale, const char* vendor)
-{
-    Asset* pAsset = NULL;
-
-    if (ap.type == kFileTypeDirectory) {
-        if (mCacheMode == CACHE_OFF) {
-            /* look at the filesystem on disk */
-            String8 path(createPathNameLocked(ap, locale, vendor));
-            path.appendPath(fileName);
-    
-            String8 excludeName(path);
-            excludeName.append(kExcludeExtension);
-            if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
-                /* say no more */
-                //printf("+++ excluding '%s'\n", (const char*) excludeName);
-                return kExcludedAsset;
-            }
-    
-            pAsset = openAssetFromFileLocked(path, mode);
-    
-            if (pAsset == NULL) {
-                /* try again, this time with ".gz" */
-                path.append(".gz");
-                pAsset = openAssetFromFileLocked(path, mode);
-            }
-    
-            if (pAsset != NULL)
-                pAsset->setAssetSource(path);
-        } else {
-            /* find in cache */
-            String8 path(createPathNameLocked(ap, locale, vendor));
-            path.appendPath(fileName);
-    
-            AssetDir::FileInfo tmpInfo;
-            bool found = false;
-    
-            String8 excludeName(path);
-            excludeName.append(kExcludeExtension);
-    
-            if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
-                /* go no farther */
-                //printf("+++ Excluding '%s'\n", (const char*) excludeName);
-                return kExcludedAsset;
-            }
-
-            /*
-             * File compression extensions (".gz") don't get stored in the
-             * name cache, so we have to try both here.
-             */
-            if (mCache.indexOf(path) != NAME_NOT_FOUND) {
-                found = true;
-                pAsset = openAssetFromFileLocked(path, mode);
-                if (pAsset == NULL) {
-                    /* try again, this time with ".gz" */
-                    path.append(".gz");
-                    pAsset = openAssetFromFileLocked(path, mode);
-                }
-            }
-
-            if (pAsset != NULL)
-                pAsset->setAssetSource(path);
-
-            /*
-             * Don't continue the search into the Zip files.  Our cached info
-             * said it was a file on disk; to be consistent with openDir()
-             * we want to return the loose asset.  If the cached file gets
-             * removed, we fail.
-             *
-             * The alternative is to update our cache when files get deleted,
-             * or make some sort of "best effort" promise, but for now I'm
-             * taking the hard line.
-             */
-            if (found) {
-                if (pAsset == NULL)
-                    ALOGD("Expected file not found: '%s'\n", path.string());
-                return pAsset;
-            }
-        }
-    }
-
-    /*
-     * Either it wasn't found on disk or on the cached view of the disk.
-     * Dig through the currently-opened set of Zip files.  If caching
-     * is disabled, the Zip file may get reopened.
-     */
-    if (pAsset == NULL && ap.type == kFileTypeRegular) {
-        String8 path;
-
-        path.appendPath((locale != NULL) ? locale : kDefaultLocale);
-        path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
-        path.appendPath(fileName);
-
-        /* check the appropriate Zip file */
-        ZipFileRO* pZip = getZipFileLocked(ap);
-        if (pZip != NULL) {
-            //printf("GOT zip, checking '%s'\n", (const char*) path);
-            ZipEntryRO entry = pZip->findEntryByName(path.string());
-            if (entry != NULL) {
-                //printf("FOUND in Zip file for %s/%s-%s\n",
-                //    appName, locale, vendor);
-                pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
-                pZip->releaseEntry(entry);
-            }
-        }
-
-        if (pAsset != NULL) {
-            /* create a "source" name, for debug/display */
-            pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()),
-                                                             String8(""), String8(fileName)));
-        }
-    }
-
-    return pAsset;
-}
-
-/*
  * Create a "source name" for a file from a Zip archive.
  */
 String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
@@ -1000,18 +774,6 @@
 }
 
 /*
- * Create a path to a loose asset (asset-base/app/locale/vendor).
- */
-String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale,
-    const char* vendor)
-{
-    String8 path(ap.path);
-    path.appendPath((locale != NULL) ? locale : kDefaultLocale);
-    path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
-    return path;
-}
-
-/*
  * Create a path to a loose asset (asset-base/app/rootDir).
  */
 String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
@@ -1024,15 +786,6 @@
 /*
  * Return a pointer to one of our open Zip archives.  Returns NULL if no
  * matching Zip file exists.
- *
- * Right now we have 2 possible Zip files (1 each in app/"common").
- *
- * If caching is set to CACHE_OFF, to get the expected behavior we
- * need to reopen the Zip file on every request.  That would be silly
- * and expensive, so instead we just check the file modification date.
- *
- * Pass in NULL values for "appName", "locale", and "vendor" if the
- * generics should be used.
  */
 ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
 {
@@ -1117,14 +870,10 @@
     return pAsset;
 }
 
-
-
 /*
  * Open a directory in the asset namespace.
  *
- * An "asset directory" is simply the combination of all files in all
- * locations, with ".gz" stripped for loose files.  With app, locale, and
- * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
  *
  * Pass in "" for the root dir.
  */
@@ -1140,9 +889,6 @@
 
     //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
 
-    if (mCacheMode != CACHE_OFF && !mCacheValid)
-        loadFileNameCacheLocked();
-
     pDir = new AssetDir;
 
     /*
@@ -1185,9 +931,7 @@
 /*
  * Open a directory in the non-asset namespace.
  *
- * An "asset directory" is simply the combination of all files in all
- * locations, with ".gz" stripped for loose files.  With app, locale, and
- * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
  *
  * Pass in "" for the root dir.
  */
@@ -1203,9 +947,6 @@
 
     //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
 
-    if (mCacheMode != CACHE_OFF && !mCacheValid)
-        loadFileNameCacheLocked();
-
     pDir = new AssetDir;
 
     pMergedInfo = new SortedVector<AssetDir::FileInfo>;
@@ -1246,74 +987,17 @@
 bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
     const asset_path& ap, const char* rootDir, const char* dirName)
 {
-    SortedVector<AssetDir::FileInfo>* pContents;
-    String8 path;
-
     assert(pMergedInfo != NULL);
 
-    //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName);
+    //printf("scanAndMergeDir: %s %s %s\n", ap.path.string(), rootDir, dirName);
 
-    if (mCacheValid) {
-        int i, start, count;
+    String8 path = createPathNameLocked(ap, rootDir);
+    if (dirName[0] != '\0')
+        path.appendPath(dirName);
 
-        pContents = new SortedVector<AssetDir::FileInfo>;
-
-        /*
-         * Get the basic partial path and find it in the cache.  That's
-         * the start point for the search.
-         */
-        path = createPathNameLocked(ap, rootDir);
-        if (dirName[0] != '\0')
-            path.appendPath(dirName);
-
-        start = mCache.indexOf(path);
-        if (start == NAME_NOT_FOUND) {
-            //printf("+++ not found in cache: dir '%s'\n", (const char*) path);
-            delete pContents;
-            return false;
-        }
-
-        /*
-         * The match string looks like "common/default/default/foo/bar/".
-         * The '/' on the end ensures that we don't match on the directory
-         * itself or on ".../foo/barfy/".
-         */
-        path.append("/");
-
-        count = mCache.size();
-
-        /*
-         * Pick out the stuff in the current dir by examining the pathname.
-         * It needs to match the partial pathname prefix, and not have a '/'
-         * (fssep) anywhere after the prefix.
-         */
-        for (i = start+1; i < count; i++) {
-            if (mCache[i].getFileName().length() > path.length() &&
-                strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0)
-            {
-                const char* name = mCache[i].getFileName().string();
-                // XXX THIS IS BROKEN!  Looks like we need to store the full
-                // path prefix separately from the file path.
-                if (strchr(name + path.length(), '/') == NULL) {
-                    /* grab it, reducing path to just the filename component */
-                    AssetDir::FileInfo tmp = mCache[i];
-                    tmp.setFileName(tmp.getFileName().getPathLeaf());
-                    pContents->add(tmp);
-                }
-            } else {
-                /* no longer in the dir or its subdirs */
-                break;
-            }
-
-        }
-    } else {
-        path = createPathNameLocked(ap, rootDir);
-        if (dirName[0] != '\0')
-            path.appendPath(dirName);
-        pContents = scanDirLocked(path);
-        if (pContents == NULL)
-            return false;
-    }
+    SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
+    if (pContents == NULL)
+        return false;
 
     // if we wanted to do an incremental cache fill, we would do it here
 
@@ -1640,153 +1324,6 @@
 #endif
 }
 
-
-/*
- * Load all files into the file name cache.  We want to do this across
- * all combinations of { appname, locale, vendor }, performing a recursive
- * directory traversal.
- *
- * This is not the most efficient data structure.  Also, gathering the
- * information as we needed it (file-by-file or directory-by-directory)
- * would be faster.  However, on the actual device, 99% of the files will
- * live in Zip archives, so this list will be very small.  The trouble
- * is that we have to check the "loose" files first, so it's important
- * that we don't beat the filesystem silly looking for files that aren't
- * there.
- *
- * Note on thread safety: this is the only function that causes updates
- * to mCache, and anybody who tries to use it will call here if !mCacheValid,
- * so we need to employ a mutex here.
- */
-void AssetManager::loadFileNameCacheLocked(void)
-{
-    assert(!mCacheValid);
-    assert(mCache.size() == 0);
-
-#ifdef DO_TIMINGS   // need to link against -lrt for this now
-    DurationTimer timer;
-    timer.start();
-#endif
-
-    fncScanLocked(&mCache, "");
-
-#ifdef DO_TIMINGS
-    timer.stop();
-    ALOGD("Cache scan took %.3fms\n",
-        timer.durationUsecs() / 1000.0);
-#endif
-
-#if 0
-    int i;
-    printf("CACHED FILE LIST (%d entries):\n", mCache.size());
-    for (i = 0; i < (int) mCache.size(); i++) {
-        printf(" %d: (%d) '%s'\n", i,
-            mCache.itemAt(i).getFileType(),
-            (const char*) mCache.itemAt(i).getFileName());
-    }
-#endif
-
-    mCacheValid = true;
-}
-
-/*
- * Scan up to 8 versions of the specified directory.
- */
-void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
-    const char* dirName)
-{
-    size_t i = mAssetPaths.size();
-    while (i > 0) {
-        i--;
-        const asset_path& ap = mAssetPaths.itemAt(i);
-        fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
-        if (mLocale != NULL)
-            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
-        if (mVendor != NULL)
-            fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName);
-        if (mLocale != NULL && mVendor != NULL)
-            fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName);
-    }
-}
-
-/*
- * Recursively scan this directory and all subdirs.
- *
- * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE
- * files, and we prepend the extended partial path to the filenames.
- */
-bool AssetManager::fncScanAndMergeDirLocked(
-    SortedVector<AssetDir::FileInfo>* pMergedInfo,
-    const asset_path& ap, const char* locale, const char* vendor,
-    const char* dirName)
-{
-    SortedVector<AssetDir::FileInfo>* pContents;
-    String8 partialPath;
-    String8 fullPath;
-
-    // XXX This is broken -- the filename cache needs to hold the base
-    // asset path separately from its filename.
-    
-    partialPath = createPathNameLocked(ap, locale, vendor);
-    if (dirName[0] != '\0') {
-        partialPath.appendPath(dirName);
-    }
-
-    fullPath = partialPath;
-    pContents = scanDirLocked(fullPath);
-    if (pContents == NULL) {
-        return false;       // directory did not exist
-    }
-
-    /*
-     * Scan all subdirectories of the current dir, merging what we find
-     * into "pMergedInfo".
-     */
-    for (int i = 0; i < (int) pContents->size(); i++) {
-        if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) {
-            String8 subdir(dirName);
-            subdir.appendPath(pContents->itemAt(i).getFileName());
-
-            fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string());
-        }
-    }
-
-    /*
-     * To be consistent, we want entries for the root directory.  If
-     * we're the root, add one now.
-     */
-    if (dirName[0] == '\0') {
-        AssetDir::FileInfo tmpInfo;
-
-        tmpInfo.set(String8(""), kFileTypeDirectory);
-        tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor));
-        pContents->add(tmpInfo);
-    }
-
-    /*
-     * We want to prepend the extended partial path to every entry in
-     * "pContents".  It's the same value for each entry, so this will
-     * not change the sorting order of the vector contents.
-     */
-    for (int i = 0; i < (int) pContents->size(); i++) {
-        const AssetDir::FileInfo& info = pContents->itemAt(i);
-        pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName()));
-    }
-
-    mergeInfoLocked(pMergedInfo, pContents);
-    delete pContents;
-    return true;
-}
-
-/*
- * Trash the cache.
- */
-void AssetManager::purgeFileNameCacheLocked(void)
-{
-    mCacheValid = false;
-    mCache.clear();
-}
-
 /*
  * ===========================================================================
  *      AssetManager::SharedZip
@@ -1836,6 +1373,7 @@
 
 Asset* AssetManager::SharedZip::getResourceTableAsset()
 {
+    AutoMutex _l(gLock);
     ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
     return mResourceTableAsset;
 }
@@ -1845,10 +1383,10 @@
     {
         AutoMutex _l(gLock);
         if (mResourceTableAsset == NULL) {
-            mResourceTableAsset = asset;
             // This is not thread safe the first time it is called, so
             // do it here with the global lock held.
             asset->getBuffer(true);
+            mResourceTableAsset = asset;
             return asset;
         }
     }
@@ -1919,13 +1457,6 @@
  */
 
 /*
- * Constructor.
- */
-AssetManager::ZipSet::ZipSet(void)
-{
-}
-
-/*
  * Destructor.  Close any open archives.
  */
 AssetManager::ZipSet::~ZipSet(void)
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/Android.mk b/libs/hwui/Android.mk
index 513e376..81a1831 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,6 +2,8 @@
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
+BUGREPORT_FONT_CACHE_USAGE := true
+
 # Enables fine-grained GLES error checking
 # If set to true, every GLES call is wrapped & error checked
 # Has moderate overhead
@@ -135,6 +137,13 @@
 # clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629
 hwui_cflags += -Wno-missing-braces
 
+ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE))
+    hwui_src_files += \
+        font/FontCacheHistoryTracker.cpp
+    hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE
+endif
+
+
 ifndef HWUI_COMPILE_SYMBOLS
     hwui_cflags += -fvisibility=hidden
 endif
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index fe3d859..741cdcc 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -21,6 +21,9 @@
 #include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "ShadowTessellator.h"
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+#include "font/FontCacheHistoryTracker.h"
+#endif
 #include "utils/GLUtils.h"
 
 #include <cutils/properties.h>
@@ -191,12 +194,7 @@
     log.appendFormat("  PatchCache           %8d / %8d\n",
             patchCache.getSize(), patchCache.getMaxSize());
 
-    const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA);
-    const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA);
-    log.appendFormat("  FontRenderer A8    %8d / %8d\n", sizeA8, sizeA8);
-    log.appendFormat("  FontRenderer RGBA  %8d / %8d\n", sizeRGBA, sizeRGBA);
-    log.appendFormat("  FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA,
-            sizeA8 + sizeRGBA);
+    fontRenderer.dumpMemoryUsage(log);
 
     log.appendFormat("Other:\n");
     log.appendFormat("  FboCache             %8d / %8d\n",
@@ -209,11 +207,14 @@
     total += tessellationCache.getSize();
     total += dropShadowCache.getSize();
     total += patchCache.getSize();
-    total += fontRenderer.getFontRendererSize(GL_ALPHA);
-    total += fontRenderer.getFontRendererSize(GL_RGBA);
+    total += fontRenderer.getSize();
 
     log.appendFormat("Total memory usage:\n");
     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
+
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+    fontRenderer.getFontRenderer().historyTracker().dump(log);
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 53d9d03..2e56160 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -97,9 +97,9 @@
 };
 
 struct ClipBase {
-    ClipBase(ClipMode mode)
+    explicit ClipBase(ClipMode mode)
             : mode(mode) {}
-    ClipBase(const Rect& rect)
+    explicit ClipBase(const Rect& rect)
             : mode(ClipMode::Rectangle)
             , rect(rect) {}
     const ClipMode mode;
@@ -112,19 +112,19 @@
 };
 
 struct ClipRect : ClipBase {
-    ClipRect(const Rect& rect)
+    explicit ClipRect(const Rect& rect)
             : ClipBase(rect) {}
 };
 
 struct ClipRectList : ClipBase {
-    ClipRectList(const RectangleList& rectList)
+    explicit ClipRectList(const RectangleList& rectList)
             : ClipBase(ClipMode::RectangleList)
             , rectList(rectList) {}
     RectangleList rectList;
 };
 
 struct ClipRegion : ClipBase {
-    ClipRegion(const SkRegion& region)
+    explicit ClipRegion(const SkRegion& region)
             : ClipBase(ClipMode::Region)
             , region(region) {}
     ClipRegion()
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 2376295..7420112 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -35,7 +35,7 @@
 public:
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
-    ANDROID_API DeferredLayerUpdater(Layer* layer);
+    ANDROID_API explicit DeferredLayerUpdater(Layer* layer);
     ANDROID_API ~DeferredLayerUpdater();
 
     ANDROID_API bool setSize(int width, int height) {
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 25dc92c..9b60dfc 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -151,10 +151,17 @@
 
     for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
         mACacheTextures[i]->init();
+
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+        mHistoryTracker.glyphsCleared(mACacheTextures[i]);
+#endif
     }
 
     for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
         mRGBACacheTextures[i]->init();
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+        mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
+#endif
     }
 
     mDrawn = false;
@@ -166,6 +173,9 @@
         CacheTexture* cacheTexture = cacheTextures[i];
         if (cacheTexture->getPixelBuffer()) {
             cacheTexture->init();
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+            mHistoryTracker.glyphsCleared(cacheTexture);
+#endif
             LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
             while (it.next()) {
                 it.value()->invalidateTextureCache(cacheTexture);
@@ -368,6 +378,10 @@
     }
 
     cachedGlyph->mIsValid = true;
+
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+    mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
+#endif
 }
 
 CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
@@ -730,18 +744,67 @@
     return size;
 }
 
-uint32_t FontRenderer::getCacheSize(GLenum format) const {
-    switch (format) {
-        case GL_ALPHA: {
-            return calculateCacheSize(mACacheTextures);
-        }
-        case GL_RGBA: {
-            return calculateCacheSize(mRGBACacheTextures);
-        }
-        default: {
-            return 0;
+static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
+    uint32_t size = 0;
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
+            size += cacheTexture->calculateFreeMemory();
         }
     }
+    return size;
+}
+
+const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
+    switch (format) {
+        case GL_ALPHA: {
+            return mACacheTextures;
+        }
+        case GL_RGBA: {
+            return mRGBACacheTextures;
+        }
+        default: {
+            LOG_ALWAYS_FATAL("Unsupported format: %d", format);
+            // Impossible to hit this, but the compiler doesn't know that
+            return *(new std::vector<CacheTexture*>());
+        }
+    }
+}
+
+static void dumpTextures(String8& log, const char* tag,
+        const std::vector<CacheTexture*>& cacheTextures) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture && cacheTexture->getPixelBuffer()) {
+            uint32_t free = cacheTexture->calculateFreeMemory();
+            uint32_t total = cacheTexture->getPixelBuffer()->getSize();
+            log.appendFormat("    %-4s texture %d     %8d / %8d\n", tag, i, total - free, total);
+        }
+    }
+}
+
+void FontRenderer::dumpMemoryUsage(String8& log) const {
+    const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
+    const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
+    const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
+    const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
+    log.appendFormat("  FontRenderer A8      %8d / %8d\n", usedA8, sizeA8);
+    dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
+    log.appendFormat("  FontRenderer RGBA    %8d / %8d\n", usedRGBA, sizeRGBA);
+    dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
+    log.appendFormat("  FontRenderer total   %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
+}
+
+uint32_t FontRenderer::getCacheSize(GLenum format) const {
+    return calculateCacheSize(cacheTexturesForFormat(format));
+}
+
+uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
+    return calculateFreeCacheSize(cacheTexturesForFormat(format));
+}
+
+uint32_t FontRenderer::getSize() const {
+    return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index dedc494..e836c20 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -20,8 +20,12 @@
 #include "font/CacheTexture.h"
 #include "font/CachedGlyphInfo.h"
 #include "font/Font.h"
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+#include "font/FontCacheHistoryTracker.h"
+#endif
 
 #include <utils/LruCache.h>
+#include <utils/String8.h>
 #include <utils/StrongPointer.h>
 
 #include <SkPaint.h>
@@ -81,7 +85,7 @@
 
 class FontRenderer {
 public:
-    FontRenderer(const uint8_t* gammaTable);
+    explicit FontRenderer(const uint8_t* gammaTable);
     ~FontRenderer();
 
     void flushLargeCaches(std::vector<CacheTexture*>& cacheTextures);
@@ -117,7 +121,12 @@
         mLinearFiltering = linearFiltering;
     }
 
-    uint32_t getCacheSize(GLenum format) const;
+    uint32_t getSize() const;
+    void dumpMemoryUsage(String8& log) const;
+
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+    FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; }
+#endif
 
 private:
     friend class Font;
@@ -160,6 +169,10 @@
         mUploadTexture = true;
     }
 
+    const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
+    uint32_t getCacheSize(GLenum format) const;
+    uint32_t getFreeCacheSize(GLenum format) const;
+
     uint32_t mSmallCacheWidth;
     uint32_t mSmallCacheHeight;
     uint32_t mLargeCacheWidth;
@@ -184,6 +197,10 @@
 
     bool mLinearFiltering;
 
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+    FontCacheHistoryTracker mHistoryTracker;
+#endif
+
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
     // RS constructs
     RSC::sp<RSC::RS> mRs;
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 5813e7f..bd27a1a 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -22,6 +22,8 @@
 
 #include <SkPaint.h>
 
+#include <utils/String8.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -46,8 +48,16 @@
         return *mRenderer;
     }
 
-    uint32_t getFontRendererSize(GLenum format) const {
-        return mRenderer ? mRenderer->getCacheSize(format) : 0;
+    void dumpMemoryUsage(String8& log) const {
+        if (mRenderer) {
+            mRenderer->dumpMemoryUsage(log);
+        } else {
+            log.appendFormat("FontRenderer doesn't exist.\n");
+        }
+    }
+
+    uint32_t getSize() const {
+        return mRenderer ? mRenderer->getSize() : 0;
     }
 
     void endPrecaching();
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
index 851aeae..bfb1bf1 100644
--- a/libs/hwui/GpuMemoryTracker.h
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -52,7 +52,7 @@
     static void onFrameCompleted();
 
 protected:
-    GpuMemoryTracker(GpuObjectType type) : mType(type) {
+    explicit GpuMemoryTracker(GpuObjectType type) : mType(type) {
         ASSERT_GPU_THREAD();
         startTrackingObject();
     }
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..eedc9e7 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -148,7 +148,7 @@
  * This will disable the use of EGL_EXT_buffer_age and BUFFER_PRESERVED.
  * Default is "true"
  */
-#define PROPERTY_ENABLE_PARTIAL_UPDATES "debug.hwui.enable_partial_updates"
+#define PROPERTY_ENABLE_PARTIAL_UPDATES "debug.hwui.use_partial_updates"
 
 #define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead"
 
@@ -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/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index e208b08..a5d9e86 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -89,7 +89,7 @@
 
 class PropertyAnimatorSetListener : public AnimationListener {
 public:
-    PropertyAnimatorSetListener(PropertyValuesAnimatorSet* set) : mSet(set) {}
+    explicit PropertyAnimatorSetListener(PropertyValuesAnimatorSet* set) : mSet(set) {}
     virtual void onAnimationFinished(BaseRenderNodeAnimator* animator) override;
 
 private:
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 60eadff..ddca122 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -32,7 +32,8 @@
 namespace uirenderer {
 
 static CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
-        Texture& sourceTexture, Matrix4& texTransform, SkBitmap* bitmap) {
+        Texture& sourceTexture, Matrix4& texTransform, const Rect& srcRect,
+        SkBitmap* bitmap) {
     int destWidth = bitmap->width();
     int destHeight = bitmap->height();
     if (destWidth > caches.maxTextureSize
@@ -100,11 +101,19 @@
         renderState.blend().syncEnabled();
         renderState.stencil().disable();
 
+        Matrix4 croppedTexTransform(texTransform);
+        if (!srcRect.isEmpty()) {
+            croppedTexTransform.loadTranslate(srcRect.left / sourceTexture.width(),
+                    srcRect.top / sourceTexture.height(), 0);
+            croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
+                    srcRect.getHeight() / sourceTexture.height(), 1);
+            croppedTexTransform.multiply(texTransform);
+        }
         Glop glop;
         GlopBuilder(renderState, caches, &glop)
                 .setRoundRectClipState(nullptr)
                 .setMeshTexturedUnitQuad(nullptr)
-                .setFillExternalTexture(sourceTexture, texTransform)
+                .setFillExternalTexture(sourceTexture, croppedTexTransform)
                 .setTransform(Matrix4::identity(), TransformFlags::None)
                 .setModelViewMapUnitToRect(Rect(destWidth, destHeight))
                 .build();
@@ -126,7 +135,8 @@
 }
 
 CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
-        Surface& surface, SkBitmap* bitmap) {
+        Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
+    ATRACE_CALL();
     renderThread.eglManager().initialize();
 
     Caches& caches = Caches::getInstance();
@@ -169,7 +179,7 @@
             EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
 
     if (sourceImage == EGL_NO_IMAGE_KHR) {
-        ALOGW("Error creating image (%#x)", eglGetError());
+        ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
         return CopyResult::UnknownError;
     }
     GLuint sourceTexId;
@@ -180,7 +190,8 @@
 
     GLenum status = GL_NO_ERROR;
     while ((status = glGetError()) != GL_NO_ERROR) {
-        ALOGW("Error creating image (%#x)", status);
+        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
+        eglDestroyImageKHR(display, sourceImage);
         return CopyResult::UnknownError;
     }
 
@@ -188,13 +199,22 @@
     sourceTexture.wrap(sourceTexId,
             sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0 /* total lie */);
 
-    return copyTextureInto(caches, renderThread.renderState(), sourceTexture, texTransform, bitmap);
+    CopyResult copyResult = copyTextureInto(caches, renderThread.renderState(),
+            sourceTexture, texTransform, srcRect, bitmap);
+    sourceTexture.deleteTexture();
+    // All we're flushing & finishing is the deletion of the texture since
+    // copyTextureInto already did a major flush & finish as an implicit
+    // part of glReadPixels, so this shouldn't pose any major stalls.
+    glFinish();
+    eglDestroyImageKHR(display, sourceImage);
+    return copyResult;
 }
 
 CopyResult Readback::copyTextureLayerInto(renderthread::RenderThread& renderThread,
         Layer& layer, SkBitmap* bitmap) {
+    ATRACE_CALL();
     return copyTextureInto(Caches::getInstance(), renderThread.renderState(),
-            layer.getTexture(), layer.getTexTransform(), bitmap);
+            layer.getTexture(), layer.getTexTransform(), Rect(), bitmap);
 }
 
 } // namespace uirenderer
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index bd73734..55c943c 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "renderthread/RenderThread.h"
+#include "Rect.h"
 
 #include <SkBitmap.h>
 #include <gui/Surface.h>
@@ -42,7 +43,7 @@
      * Copies the surface's most recently queued buffer into the provided bitmap.
      */
     static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread,
-            Surface& surface, SkBitmap* bitmap);
+            Surface& surface, const Rect& srcRect, SkBitmap* bitmap);
 
     /**
      * Copies the TextureLayer's texture content (thus, the currently rendering buffer) into the
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index f3078ce..a65c22c 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -508,7 +508,7 @@
             , mode(PaintUtils::getXfermodeDirect(paint))
             , colorFilter(paint ? paint->getColorFilter() : nullptr) {}
 
-    LayerOp(RenderNode& node)
+    explicit LayerOp(RenderNode& node)
             : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
             , layerHandle(node.getLayerHandle())
             , alpha(node.properties().layerProperties().alpha() / 255.0f)
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index dd20a76..8c36ab5 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -229,19 +229,6 @@
     }
 }
 
-static OffscreenBuffer* createLayer(RenderState& renderState, uint32_t width, uint32_t height) {
-    return renderState.layerPool().get(renderState, width, height);
-}
-
-static void destroyLayer(OffscreenBuffer* layer) {
-    RenderState& renderState = layer->renderState;
-    renderState.layerPool().putOrDelete(layer);
-}
-
-static bool layerMatchesWidthAndHeight(OffscreenBuffer* layer, int width, int height) {
-    return layer->viewportWidth == (uint32_t) width && layer->viewportHeight == (uint32_t)height;
-}
-
 void RenderNode::pushLayerUpdate(TreeInfo& info) {
     LayerType layerType = properties().effectiveLayerType();
     // If we are not a layer OR we cannot be rendered (eg, view was detached)
@@ -251,34 +238,15 @@
             || CC_UNLIKELY(properties().getWidth() == 0)
             || CC_UNLIKELY(properties().getHeight() == 0)) {
         if (CC_UNLIKELY(mLayer)) {
-            destroyLayer(mLayer);
-            mLayer = nullptr;
+            renderthread::CanvasContext::destroyLayer(this);
         }
         return;
     }
 
-    bool transformUpdateNeeded = false;
-    if (!mLayer) {
-        mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight());
+    if(info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
         damageSelf(info);
-        transformUpdateNeeded = true;
-    } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
-        // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
-        // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
-        RenderState& renderState = mLayer->renderState;
-        if (properties().fitsOnLayer()) {
-            mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
-        } else {
-            destroyLayer(mLayer);
-            mLayer = nullptr;
-        }
-        damageSelf(info);
-        transformUpdateNeeded = true;
     }
 
-    SkRect dirty;
-    info.damageAccumulator->peekAtDirty(&dirty);
-
     if (!mLayer) {
         Caches::getInstance().dumpMemoryUsage();
         if (info.errorHandler) {
@@ -296,13 +264,8 @@
         return;
     }
 
-    if (transformUpdateNeeded && mLayer) {
-        // update the transform in window of the layer to reset its origin wrt light source position
-        Matrix4 windowTransform;
-        info.damageAccumulator->computeCurrentTransform(&windowTransform);
-        mLayer->setWindowTransform(windowTransform);
-    }
-
+    SkRect dirty;
+    info.damageAccumulator->peekAtDirty(&dirty);
     info.layerUpdateQueue->enqueueLayerWithDamage(this, dirty);
 
     // There might be prefetched layers that need to be accounted for.
@@ -451,8 +414,7 @@
 
 void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
     if (mLayer) {
-        destroyLayer(mLayer);
-        mLayer = nullptr;
+        renderthread::CanvasContext::destroyLayer(this);
     }
     if (mDisplayList) {
         for (auto&& child : mDisplayList->getChildren()) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index a0679b1..da93c13 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -199,6 +199,7 @@
     }
     OffscreenBuffer* getLayer() const { return mLayer; }
     OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
+    void setLayer(OffscreenBuffer* layer) { mLayer = layer; }
 
     // Note: The position callbacks are relying on the listener using
     // the frameNumber to appropriately batch/synchronize these transactions.
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 09775496..9553ab4 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,6 +26,7 @@
 #include <SkDrawFilter.h>
 #include <SkGraphics.h>
 #include <SkImage.h>
+#include <SkImagePriv.h>
 #include <SkRSXform.h>
 #include <SkShader.h>
 #include <SkTemplates.h>
@@ -179,9 +180,10 @@
 static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
     SkCanvas::SaveLayerFlags layerFlags = 0;
 
-    if (!(flags & SaveFlags::HasAlphaLayer)) {
-        layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
-    }
+    // We intentionally ignore the SaveFlags::HasAlphaLayer and
+    // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it
+    // and our Android client may use it incorrectly.
+    // In Skia, this flag is purely for performance optimization.
 
     if (!(flags & SaveFlags::ClipToLayer)) {
         layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
@@ -593,10 +595,13 @@
     if (paint) {
         tmpPaint = *paint;
     }
-    SkShader* shader = SkShader::CreateBitmapShader(bitmap,
-                                                    SkShader::kClamp_TileMode,
-                                                    SkShader::kClamp_TileMode);
-    SkSafeUnref(tmpPaint.setShader(shader));
+    sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
+                                                SkShader::kClamp_TileMode,
+                                                SkShader::kClamp_TileMode,
+                                                nullptr,
+                                                kNever_SkCopyPixelsMode,
+                                                nullptr);
+    tmpPaint.setShader(std::move(shader));
 
     mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
                          texs, (const SkColor*)colors, NULL, indices,
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index cf77cbb..e68fbf4 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -97,7 +97,7 @@
 public:
     class Properties {
     public:
-        Properties(Node* node) : mNode(node) {}
+        explicit Properties(Node* node) : mNode(node) {}
         inline void onPropertyChanged() {
             mNode->onPropertyChanged(this);
         }
@@ -139,7 +139,7 @@
 
     class PathProperties : public Properties {
     public:
-        PathProperties(Node* node) : Properties(node) {}
+        explicit PathProperties(Node* node) : Properties(node) {}
         void syncProperties(const PathProperties& prop) {
             mData = prop.mData;
             onPropertyChanged();
@@ -225,7 +225,7 @@
             float strokeMiterLimit = 4;
             int fillType = 0; /* non-zero or kWinding_FillType in Skia */
         };
-        FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+        explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
         ~FullPathProperties() {
             SkSafeUnref(fillGradient);
             SkSafeUnref(strokeGradient);
@@ -416,7 +416,7 @@
 public:
     class GroupProperties : public Properties {
     public:
-        GroupProperties(Node* mNode) : Properties(mNode) {}
+        explicit GroupProperties(Node* mNode) : Properties(mNode) {}
         struct PrimitiveFields {
             float rotate = 0;
             float pivotX = 0;
@@ -546,7 +546,7 @@
 
 class ANDROID_API Tree : public VirtualLightRefBase {
 public:
-    Tree(Group* rootNode) : mRootNode(rootNode) {
+    explicit Tree(Group* rootNode) : mRootNode(rootNode) {
         mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
     }
 
@@ -583,7 +583,7 @@
 
     class TreeProperties {
     public:
-        TreeProperties(Tree* tree) : mTree(tree) {}
+        explicit TreeProperties(Tree* tree) : mTree(tree) {}
         // Properties that can only be modified by UI thread, therefore sync should
         // only go from UI to RT
         struct NonAnimatableProperties {
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/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index fcdde45..49e9f65 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -330,5 +330,17 @@
     return false;
 }
 
+uint32_t CacheTexture::calculateFreeMemory() const {
+    CacheBlock* cacheBlock = mCacheBlocks;
+    uint32_t free = 0;
+    // currently only two formats are supported: GL_ALPHA or GL_RGBA;
+    uint32_t bpp = mFormat == GL_RGBA ? 4 : 1;
+    while (cacheBlock) {
+        free += bpp * cacheBlock->mWidth * cacheBlock->mHeight;
+        cacheBlock = cacheBlock->mNext;
+    }
+    return free;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 4dfb41d..6750a8a 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -178,6 +178,8 @@
         return mCurrentQuad == mMaxQuadCount;
     }
 
+    uint32_t calculateFreeMemory() const;
+
 private:
     void setDirty(bool dirty);
 
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 9c812bc..24d497c 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -408,9 +408,15 @@
         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
             int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
             int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
-
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+            mState->historyTracker().glyphRendered(cachedGlyph, penX, penY);
+#endif
             (*this.*render)(cachedGlyph, penX, penY,
                     bitmap, bitmapW, bitmapH, bounds, positions);
+        } else {
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+            mState->historyTracker().glyphRendered(cachedGlyph, -1, -1);
+#endif
         }
 
         glyphsCount++;
diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp
new file mode 100644
index 0000000..a2bfb27
--- /dev/null
+++ b/libs/hwui/font/FontCacheHistoryTracker.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 "FontCacheHistoryTracker.h"
+
+#include "CachedGlyphInfo.h"
+#include "CacheTexture.h"
+
+namespace android {
+namespace uirenderer {
+
+void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) {
+    log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture,
+            glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
+}
+
+void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) {
+    if (entry.penX == -1 && entry.penY == -1) {
+        log.appendFormat("      glyph skipped in gen: %d\n", entry.glyph.generation);
+    } else {
+        log.appendFormat("      rendered ");
+        dumpCachedGlyph(log, entry.glyph);
+        log.appendFormat(" at (%d, %d)\n", entry.penX, entry.penY);
+    }
+}
+
+void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) {
+    if (glyph.bitmapW == 0 && glyph.bitmapH == 0) {
+        log.appendFormat("      cleared cachetexture %p in gen %d\n", glyph.texture,
+                glyph.generation);
+    } else {
+        log.appendFormat("      uploaded ");
+        dumpCachedGlyph(log, glyph);
+        log.appendFormat("\n");
+    }
+}
+
+void FontCacheHistoryTracker::dump(String8& log) const {
+    log.appendFormat("FontCacheHistory: \n");
+    log.appendFormat("  Upload history: \n");
+    for (size_t i = 0; i < mUploadHistory.size(); i++) {
+        dumpUploadEntry(log, mUploadHistory[i]);
+    }
+    log.appendFormat("  Render history: \n");
+    for (size_t i = 0; i < mRenderHistory.size(); i++) {
+        dumpRenderEntry(log, mRenderHistory[i]);
+    }
+}
+
+void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX, int penY) {
+    RenderEntry& entry = mRenderHistory.next();
+    entry.glyph.generation = generation;
+    entry.glyph.texture = glyphInfo->mCacheTexture;
+    entry.glyph.startX = glyphInfo->mStartX;
+    entry.glyph.startY = glyphInfo->mStartY;
+    entry.glyph.bitmapW = glyphInfo->mBitmapWidth;
+    entry.glyph.bitmapH = glyphInfo->mBitmapHeight;
+    entry.penX = penX;
+    entry.penY = penY;
+}
+
+void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y,
+        uint16_t glyphW, uint16_t glyphH) {
+    CachedGlyph& glyph = mUploadHistory.next();
+    glyph.generation = generation;
+    glyph.texture = texture;
+    glyph.startX = x;
+    glyph.startY = y;
+    glyph.bitmapW = glyphW;
+    glyph.bitmapH = glyphH;
+}
+
+void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) {
+    CachedGlyph& glyph = mUploadHistory.next();
+    glyph.generation = generation;
+    glyph.texture = texture;
+    glyph.startX = 0;
+    glyph.startY = 0;
+    glyph.bitmapW = 0;
+    glyph.bitmapH = 0;
+}
+
+void FontCacheHistoryTracker::frameCompleted() {
+    generation++;
+}
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h
new file mode 100644
index 0000000..f1d9b9f
--- /dev/null
+++ b/libs/hwui/font/FontCacheHistoryTracker.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include "../utils/RingBuffer.h"
+
+#include <utils/String8.h>
+
+namespace android {
+namespace uirenderer {
+
+class CacheTexture;
+struct CachedGlyphInfo;
+
+// Tracks glyph uploads and recent rendered/skipped glyphs, so it can give an idea
+// what a missing character is: skipped glyph, wrong coordinates in cache texture etc.
+class FontCacheHistoryTracker {
+public:
+    void glyphRendered(CachedGlyphInfo*, int penX, int penY);
+    void glyphUploaded(CacheTexture*, uint32_t x, uint32_t y, uint16_t glyphW, uint16_t glyphH);
+    void glyphsCleared(CacheTexture*);
+    void frameCompleted();
+
+    void dump(String8& log) const;
+private:
+    struct CachedGlyph {
+        void* texture;
+        uint16_t generation;
+        uint16_t startX;
+        uint16_t startY;
+        uint16_t bitmapW;
+        uint16_t bitmapH;
+    };
+
+    struct RenderEntry {
+        CachedGlyph glyph;
+        int penX;
+        int penY;
+    };
+
+    static void dumpCachedGlyph(String8& log, const CachedGlyph& glyph);
+    static void dumpRenderEntry(String8& log, const RenderEntry& entry);
+    static void dumpUploadEntry(String8& log, const CachedGlyph& glyph);
+
+    RingBuffer<RenderEntry, 300> mRenderHistory;
+    RingBuffer<CachedGlyph, 120> mUploadHistory;
+    uint16_t generation = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
\ No newline at end of file
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 6307926..10a1db9 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -30,7 +30,7 @@
 public:
     Paint();
     Paint(const Paint& paint);
-    Paint(const SkPaint& paint);
+    Paint(const SkPaint& paint);  // NOLINT(implicit)
     ~Paint();
 
     Paint& operator=(const Paint& other);
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index 73a3392..26d4e36 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -126,7 +126,7 @@
                 : width(OffscreenBuffer::computeIdealDimension(layerWidth))
                 , height(OffscreenBuffer::computeIdealDimension(layerHeight)) {}
 
-        Entry(OffscreenBuffer* layer)
+        explicit Entry(OffscreenBuffer* layer)
                 : layer(layer)
                 , width(layer->texture.width())
                 , height(layer->texture.height()) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9adcc8b..0f2d55b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -85,6 +85,18 @@
     return nullptr;
 }
 
+void CanvasContext::destroyLayer(RenderNode* node) {
+    auto renderType = Properties::getRenderPipelineType();
+    switch (renderType) {
+        case RenderPipelineType::OpenGL:
+            OpenGLPipeline::destroyLayer(node);
+            break;
+        default:
+            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+            break;
+    }
+}
+
 CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
         RenderNode* rootRenderNode, IContextFactory* contextFactory,
         std::unique_ptr<IRenderPipeline> renderPipeline)
@@ -412,6 +424,11 @@
     }
 
     GpuMemoryTracker::onFrameCompleted();
+#ifdef BUGREPORT_FONT_CACHE_USAGE
+    Caches& caches = Caches::getInstance();
+    caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
+#endif
+
 }
 
 // Called by choreographer to do an RT-driven animation
@@ -433,6 +450,9 @@
     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
     if (info.out.canDrawThisFrame) {
         draw();
+    } else {
+        // wait on fences so tasks don't overlap next frame
+        waitOnFences();
     }
 }
 
@@ -500,6 +520,10 @@
         for (const sp<RenderNode>& node : mRenderNodes) {
             node->destroyHardwareResources(observer);
         }
+        Caches& caches = Caches::getInstance();
+        // Make sure to release all the textures we were owning as there won't
+        // be another draw
+        caches.textureCache.resetMarkInUse(this);
         mRenderPipeline->onDestroyHardwareResources();
     }
 }
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a3b6261..652cddd 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -68,6 +68,23 @@
             RenderNode* rootRenderNode, IContextFactory* contextFactory);
     virtual ~CanvasContext();
 
+    /**
+     * Update or create a layer specific for the provided RenderNode. The layer
+     * attached to the node will be specific to the RenderPipeline used by this
+     * context
+     *
+     *  @return true if the layer has been created or updated
+     */
+    bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator) {
+        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator);
+    }
+
+    /**
+     * Destroy any layers that have been attached to the provided RenderNode removing
+     * any state that may have been set during createOrUpdateLayer().
+     */
+    static void destroyLayer(RenderNode* node);
+
     // Won't take effect until next EGLSurface creation
     void setSwapBehavior(SwapBehavior swapBehavior);
 
@@ -158,6 +175,8 @@
 
     ANDROID_API int64_t getFrameNumber();
 
+    void waitOnFences();
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
             IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -171,8 +190,6 @@
 
     void freePrefetchedLayers(TreeObserver* observer);
 
-    void waitOnFences();
-
     bool isSwapChainStuffed();
 
     SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index c9c07b3..e3b6dc6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -104,6 +104,9 @@
 
     if (CC_LIKELY(canDrawThisFrame)) {
         context->draw();
+    } else {
+        // wait on fences so tasks don't overlap next frame
+        context->waitOnFences();
     }
 
     if (!canUnblockUiThread) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index ac6a28f..86731c9 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -134,7 +134,12 @@
 void EglManager::initExtensions() {
     auto extensions = StringUtils::split(
             eglQueryString(mEglDisplay, EGL_EXTENSIONS));
-    EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age");
+    // For our purposes we don't care if EGL_BUFFER_AGE is a result of
+    // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
+    // under EGL_KHR_partial_update and we don't need the expanded scope
+    // that EGL_EXT_buffer_age provides.
+    EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age")
+            || extensions.has("EGL_KHR_partial_update");
     EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
     LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
             "Missing required extension EGL_KHR_swap_buffers_with_damage");
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 3250fed..97cdf7f 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -67,6 +67,8 @@
             LayerUpdateQueue* layerUpdateQueue, bool opaque,
             const BakedOpRenderer::LightInfo& lightInfo) = 0;
     virtual TaskManager* getTaskManager() = 0;
+    virtual bool createOrUpdateLayer(RenderNode* node,
+            const DamageAccumulator& damageAccumulator) = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 36be387..c758f6c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -163,10 +163,6 @@
 }
 
 void OpenGLPipeline::onDestroyHardwareResources() {
-    Caches& caches = Caches::getInstance();
-    // Make sure to release all the textures we were owning as there won't
-    // be another draw
-    caches.textureCache.resetMarkInUse(this);
     mRenderThread.renderState().flush(Caches::FlushMode::Layers);
 }
 
@@ -187,6 +183,46 @@
     return &Caches::getInstance().tasks;
 }
 
+static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
+    return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
+}
+
+bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
+        const DamageAccumulator& damageAccumulator) {
+    RenderState& renderState = mRenderThread.renderState();
+    OffscreenBufferPool& layerPool = renderState.layerPool();
+    bool transformUpdateNeeded = false;
+    if (node->getLayer() == nullptr) {
+        node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight()));
+        transformUpdateNeeded = true;
+    } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
+        // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+        // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
+        if (node->properties().fitsOnLayer()) {
+            node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
+        } else {
+            destroyLayer(node);
+        }
+        transformUpdateNeeded = true;
+    }
+
+    if (transformUpdateNeeded && node->getLayer()) {
+        // update the transform in window of the layer to reset its origin wrt light source position
+        Matrix4 windowTransform;
+        damageAccumulator.computeCurrentTransform(&windowTransform);
+        node->getLayer()->setWindowTransform(windowTransform);
+    }
+
+    return transformUpdateNeeded;
+}
+
+void OpenGLPipeline::destroyLayer(RenderNode* node) {
+    if (OffscreenBuffer* layer = node->getLayer()) {
+        layer->renderState.layerPool().putOrDelete(layer);
+        node->setLayer(nullptr);
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index e08fd9b..34d9bc0 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -56,6 +56,9 @@
             LayerUpdateQueue* layerUpdateQueue, bool opaque,
             const BakedOpRenderer::LightInfo& lightInfo) override;
     TaskManager* getTaskManager() override;
+    bool createOrUpdateLayer(RenderNode* node,
+            const DamageAccumulator& damageAccumulator) override;
+    static void destroyLayer(RenderNode* node);
 
 private:
     EglManager& mEglManager;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3edd423..dcbc980 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -617,17 +617,19 @@
     post(task);
 }
 
-CREATE_BRIDGE3(copySurfaceInto, RenderThread* thread,
-        Surface* surface, SkBitmap* bitmap) {
+CREATE_BRIDGE4(copySurfaceInto, RenderThread* thread,
+        Surface* surface, Rect srcRect, SkBitmap* bitmap) {
     return (void*) Readback::copySurfaceInto(*args->thread,
-            *args->surface, args->bitmap);
+            *args->surface, args->srcRect, args->bitmap);
 }
 
-int RenderProxy::copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap) {
+int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top,
+        int right, int bottom,  SkBitmap* bitmap) {
     SETUP_TASK(copySurfaceInto);
     args->bitmap = bitmap;
     args->surface = surface.get();
     args->thread = &RenderThread::getInstance();
+    args->srcRect.set(left, top, right, bottom);
     return static_cast<int>(
             reinterpret_cast<intptr_t>( staticPostAndWait(task) ));
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d812970..d4aaea6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -127,7 +127,8 @@
     ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
     ANDROID_API long getDroppedFrameReportCount();
 
-    ANDROID_API static int copySurfaceInto(sp<Surface>& surface, SkBitmap* bitmap);
+    ANDROID_API static int copySurfaceInto(sp<Surface>& surface,
+            int left, int top, int right, int bottom, SkBitmap* bitmap);
     ANDROID_API static void prepareToDraw(const SkBitmap& bitmap);
 
 private:
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index e3777ca..f6f7c62 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -52,7 +52,7 @@
 
     class Registrar {
     public:
-        Registrar(const TestScene::Info& info) {
+        explicit Registrar(const TestScene::Info& info) {
             TestScene::registerScene(info);
         }
     private:
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index ad94c96..78e9bc4 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -37,10 +37,10 @@
     EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
 
 #define EXPECT_RECT_APPROX_EQ(a, b) \
-    EXPECT_TRUE(MathUtils::areEqual(a.left, b.left) \
-            && MathUtils::areEqual(a.top, b.top) \
-            && MathUtils::areEqual(a.right, b.right) \
-            && MathUtils::areEqual(a.bottom, b.bottom));
+    EXPECT_TRUE(MathUtils::areEqual((a).left, (b).left) \
+            && MathUtils::areEqual((a).top, (b).top) \
+            && MathUtils::areEqual((a).right, (b).right) \
+            && MathUtils::areEqual((a).bottom, (b).bottom));
 
 #define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
         EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
@@ -91,7 +91,7 @@
     public:
         SignalingDtor()
                 : mSignal(nullptr) {}
-        SignalingDtor(int* signal)
+        explicit SignalingDtor(int* signal)
                 : mSignal(signal) {}
         void setSignal(int* signal) {
             mSignal = signal;
@@ -213,7 +213,7 @@
 
     class TestTask : public renderthread::RenderTask {
     public:
-        TestTask(RtCallback rtCallback)
+        explicit TestTask(RtCallback rtCallback)
                 : rtCallback(rtCallback) {}
         virtual ~TestTask() {}
         virtual void run() override;
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/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index c006d99..f3b7b51 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -117,6 +117,7 @@
 
     std::unique_ptr<TestScene> scene(info.createScene(opts));
 
+    Properties::forceDrawFrame = true;
     TestContext testContext;
     testContext.setRenderOffscreen(opts.renderOffscreen);
 
diff --git a/libs/hwui/tests/scripts/prep_buller.sh b/libs/hwui/tests/scripts/prep_buller.sh
index b2f68bd..65292c3 100755
--- a/libs/hwui/tests/scripts/prep_buller.sh
+++ b/libs/hwui/tests/scripts/prep_buller.sh
@@ -38,12 +38,27 @@
 adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on"
 adb shell "echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer"
 
-#0 762 1144 1525 2288 3509 4173 5271 5928 7904 9887 11863
+# angler: 0 762 1144 1525 2288 3509 4173 5271 5928 7904 9887 11863
 adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.70/min_freq" &> /dev/null
-adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.19/min_freq" &> /dev/null
+# bullhead: 0 762 1144 1525 2288 3509 4173 5271 5928 7102
+adb shell "echo 7102 > /sys/class/devfreq/qcom,gpubw.19/min_freq" &> /dev/null
 
-#600000000 510000000 450000000 390000000 305000000 180000000
-echo "performance mode, 305 MHz"
+
+board=$(adb shell "getprop ro.product.board")
+freq=0
+if [ "$board" = "bullhead" ]
+then
+    #600000000 490000000 450000000 367000000 300000000 180000000
+    freq=300000000
+else
+    #600000000 510000000 450000000 390000000 305000000 180000000
+    freq=305000000
+fi
+echo "performance mode, $freq Hz"
 adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor"
-adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
-adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq"
+adb shell "echo $freq > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
+adb shell "echo $freq > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq"
+
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel"
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel"
+
diff --git a/libs/hwui/tests/scripts/prep_fugu.sh b/libs/hwui/tests/scripts/prep_fugu.sh
new file mode 100755
index 0000000..04a3203
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_fugu.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+cpubase=/sys/devices/system/cpu
+gov=cpufreq/scaling_governor
+
+adb root
+adb wait-for-device
+thermal=$(adb shell "getprop persist.service.thermal")
+echo "thermal status: $thermal"
+if [ $thermal -eq 1 ]
+then
+    echo "Trying to setprop persist.service.thermal 0 and reboot"
+    adb shell "setprop persist.service.thermal 0"
+    adb reboot
+    adb wait-for-device
+    thermal=$(adb shell "getprop persist.service.thermal")
+    if [ $thermal -eq 1 ]
+    then
+        echo "thermal property is still 1. Abort."
+        exit -1
+    fi
+    echo "Successfully setup persist.service.thermal to 0"
+fi
+
+adb shell stop perfprod
+
+# cores
+# 1833000 1750000 1666000 1583000 1500000 1416000 1333000 1250000
+# 1166000 1083000 1000000 916000 833000 750000 666000 583000 500000
+
+cpu=0
+S=1166000
+while [ $((cpu < 3)) -eq 1 ]; do
+    echo "Setting cpu ${cpu} & $(($cpu + 1)) cluster to $S hz"
+    # cpu0/online doesn't exist, because you can't turned it off, so ignore results of this command
+    adb shell "echo 1 > $cpubase/cpu${cpu}/online" &> /dev/null
+    adb shell "echo userspace > $cpubase/cpu${cpu}/$gov"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_setspeed"
+    cpu=$(($cpu + 2))
+done
+
+#/sys/class/devfreq/dfrgx/available_frequencies is empty, so set to min
+echo "performance mode, 457 MHz"
+adb shell "echo performance > /sys/class/devfreq/dfrgx/governor"
+adb shell "echo 457000 > /sys/class/devfreq/dfrgx/min_freq"
+adb shell "echo 457000 > /sys/class/devfreq/dfrgx/max_freq"
diff --git a/libs/hwui/tests/scripts/stopruntime.sh b/libs/hwui/tests/scripts/stopruntime.sh
old mode 100644
new mode 100755
index bb8fcb6..85a91db
--- a/libs/hwui/tests/scripts/stopruntime.sh
+++ b/libs/hwui/tests/scripts/stopruntime.sh
@@ -22,6 +22,5 @@
     adb shell kill $pid
 done
 adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell setprop debug.sf.nobootanimation 1
 adb shell daemonize surfaceflinger
-sleep 3
-adb shell setprop service.bootanim.exit 1
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index fdf0b54..edc7191 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -740,10 +740,13 @@
     SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
-        SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(bitmap,
+        sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
                 SkShader::TileMode::kClamp_TileMode,
-                SkShader::TileMode::kClamp_TileMode));
-        paint.setShader(shader);
+                SkShader::TileMode::kClamp_TileMode,
+                nullptr,
+                kNever_SkCopyPixelsMode,
+                nullptr);
+        paint.setShader(std::move(shader));
         canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
     });
     auto& bitmaps = dl->getBitmapResources();
@@ -754,21 +757,24 @@
     SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
-        SkAutoTUnref<SkShader> shader1(SkShader::CreateBitmapShader(bitmap,
+        sk_sp<SkShader> shader1 = SkMakeBitmapShader(bitmap,
                 SkShader::TileMode::kClamp_TileMode,
-                SkShader::TileMode::kClamp_TileMode));
+                SkShader::TileMode::kClamp_TileMode,
+                nullptr,
+                kNever_SkCopyPixelsMode,
+                nullptr);
 
         SkPoint center;
         center.set(50, 50);
         SkColor colors[2];
         colors[0] = Color::Black;
         colors[1] = Color::White;
-        SkAutoTUnref<SkShader> shader2(SkGradientShader::CreateRadial(center, 50, colors, nullptr, 2,
-                SkShader::TileMode::kRepeat_TileMode));
+        sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(center, 50, colors, nullptr, 2,
+                SkShader::TileMode::kRepeat_TileMode);
 
-        SkAutoTUnref<SkShader> composeShader(SkShader::CreateComposeShader(shader1, shader2,
-                SkXfermode::Mode::kMultiply_Mode));
-        paint.setShader(composeShader);
+        sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(std::move(shader1), std::move(shader2),
+                SkXfermode::Mode::kMultiply_Mode);
+        paint.setShader(std::move(composeShader));
         canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
     });
     auto& bitmaps = dl->getBitmapResources();
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index cd759cb..a30ada0 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -17,8 +17,9 @@
 #include "tests/common/TestUtils.h"
 
 #include <gtest/gtest.h>
-#include <SkShader.h>
 #include <SkColorMatrixFilter.h>
+#include <SkImagePriv.h>
+#include <SkShader.h>
 
 using namespace android;
 using namespace android::uirenderer;
@@ -29,10 +30,13 @@
  */
 TEST(SkiaBehavior, CreateBitmapShader1x1) {
     SkBitmap origBitmap = TestUtils::createSkBitmap(1, 1);
-    SkAutoTUnref<SkShader> s(SkShader::CreateBitmapShader(
+    sk_sp<SkShader> s = SkMakeBitmapShader(
             origBitmap,
             SkShader::kClamp_TileMode,
-            SkShader::kRepeat_TileMode));
+            SkShader::kRepeat_TileMode,
+            nullptr,
+            kNever_SkCopyPixelsMode,
+            nullptr);
 
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
@@ -68,3 +72,13 @@
         EXPECT_FALSE(failFilter->asColorMode(nullptr, nullptr));
     }
 }
+
+TEST(SkiaBehavior, porterDuffCreateIsCached) {
+    SkPaint paint;
+    paint.setXfermodeMode(SkXfermode::kOverlay_Mode);
+    auto expected = paint.getXfermode();
+    paint.setXfermodeMode(SkXfermode::kClear_Mode);
+    ASSERT_NE(expected, paint.getXfermode());
+    paint.setXfermodeMode(SkXfermode::kOverlay_Mode);
+    ASSERT_EQ(expected, paint.getXfermode());
+}
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
index 93d37c2..df8cb076 100644
--- a/libs/hwui/utils/FatVector.h
+++ b/libs/hwui/utils/FatVector.h
@@ -53,7 +53,7 @@
     typedef T value_type; // needed to implement std::allocator
     typedef T* pointer; // needed to implement std::allocator
 
-    InlineStdAllocator(Allocation& allocation)
+    explicit InlineStdAllocator(Allocation& allocation)
             : mAllocation(allocation) {}
     InlineStdAllocator(const InlineStdAllocator& other)
             : mAllocation(other.mAllocation) {}
@@ -93,7 +93,7 @@
         this->reserve(SIZE);
     }
 
-    FatVector(size_t capacity) : FatVector() {
+    explicit FatVector(size_t capacity) : FatVector() {
         this->resize(capacity);
     }
 
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index 34c8c6b..f95a6fe 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -157,7 +157,7 @@
     typedef T value_type; // needed to implement std::allocator
     typedef T* pointer; // needed to implement std::allocator
 
-    LinearStdAllocator(LinearAllocator& allocator)
+    explicit LinearStdAllocator(LinearAllocator& allocator)
             : linearAllocator(allocator) {}
     LinearStdAllocator(const LinearStdAllocator& other)
             : linearAllocator(other.linearAllocator) {}
@@ -170,7 +170,7 @@
     };
     // enable allocators to be constructed from other templated types
     template <class U>
-    LinearStdAllocator(const LinearStdAllocator<U>& other)
+    LinearStdAllocator(const LinearStdAllocator<U>& other)  // NOLINT(implicit)
             : linearAllocator(other.linearAllocator) {}
 
     T* allocate(size_t num, const void* = 0) {
@@ -195,7 +195,7 @@
 template <class T>
 class LsaVector : public std::vector<T, LinearStdAllocator<T>> {
 public:
-    LsaVector(const LinearStdAllocator<T>& allocator)
+    explicit LsaVector(const LinearStdAllocator<T>& allocator)
             : std::vector<T, LinearStdAllocator<T>>(allocator) {}
 };
 
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 87a22ce..89b4fb2 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -36,6 +36,29 @@
 
 namespace android {
 
+// --- WeakLooperCallback ---
+
+class WeakLooperCallback: public LooperCallback {
+protected:
+    virtual ~WeakLooperCallback() { }
+
+public:
+    WeakLooperCallback(const wp<LooperCallback>& callback) :
+        mCallback(callback) {
+    }
+
+    virtual int handleEvent(int fd, int events, void* data) {
+        sp<LooperCallback> callback = mCallback.promote();
+        if (callback != NULL) {
+            return callback->handleEvent(fd, events, data);
+        }
+        return 0; // the client is gone, remove the callback
+    }
+
+private:
+    wp<LooperCallback> mCallback;
+};
+
 // --- PointerController ---
 
 // Time to wait before starting the fade when the pointer is inactive.
@@ -57,10 +80,11 @@
         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
     mHandler = new WeakMessageHandler(this);
+    mCallback = new WeakLooperCallback(this);
 
     if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
         mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
-                       Looper::EVENT_INPUT, this, nullptr);
+                       Looper::EVENT_INPUT, mCallback, nullptr);
     } else {
         ALOGE("Failed to initialize DisplayEventReceiver.");
     }
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 99292d7..4794f3d 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -144,6 +144,7 @@
     sp<Looper> mLooper;
     sp<SpriteController> mSpriteController;
     sp<WeakMessageHandler> mHandler;
+    sp<LooperCallback> mCallback;
 
     DisplayEventReceiver mDisplayEventReceiver;
 
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 905833c..7fc8d6f 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -214,7 +214,7 @@
         virtual ~SpriteImpl();
 
     public:
-        SpriteImpl(const sp<SpriteController> controller);
+        explicit SpriteImpl(const sp<SpriteController> controller);
 
         virtual void setIcon(const SpriteIcon& icon);
         virtual void setVisible(bool visible);
diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
index b152f48..335ad5e 100644
--- a/location/java/android/location/Address.java
+++ b/location/java/android/location/Address.java
@@ -28,7 +28,7 @@
 /**
  * A class representing an Address, i.e, a set of Strings describing a location.
  *
- * The addres format is a simplified version of xAL (eXtensible Address Language)
+ * The address format is a simplified version of xAL (eXtensible Address Language)
  * http://www.oasis-open.org/committees/ciq/ciq.html#6
  */
 public class Address implements Parcelable {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 5286f8f..89709ee 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseIntArray;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -170,6 +171,66 @@
     public final static int USAGE_VIRTUAL_SOURCE = 15;
 
     /**
+     * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
+     *            if applicable.
+     */
+
+    /**
+     * @hide
+     * Denotes a usage for notifications that do not expect immediate intervention from the user,
+     * will be muted when the Zen mode disables notifications
+     * @see #SUPPRESSIBLE_USAGES
+     */
+    public final static int SUPPRESSIBLE_NOTIFICATION = 1;
+    /**
+     * @hide
+     * Denotes a usage for notifications that do expect immediate intervention from the user,
+     * will be muted when the Zen mode disables calls
+     * @see #SUPPRESSIBLE_USAGES
+     */
+    public final static int SUPPRESSIBLE_CALL = 2;
+
+    /**
+     * @hide
+     * Array of all usage types for calls and notifications to assign the suppression behavior,
+     * used by the Zen mode restrictions.
+     * @see com.android.server.notification.ZenModeHelper
+     */
+    public static final SparseIntArray SUPPRESSIBLE_USAGES;
+
+    static {
+        SUPPRESSIBLE_USAGES = new SparseIntArray();
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION,                      SUPPRESSIBLE_NOTIFICATION);
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_RINGTONE,             SUPPRESSIBLE_CALL);
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_REQUEST,SUPPRESSIBLE_CALL);
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_INSTANT,SUPPRESSIBLE_NOTIFICATION);
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_DELAYED,SUPPRESSIBLE_NOTIFICATION);
+        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT,                SUPPRESSIBLE_NOTIFICATION);
+    }
+
+    /**
+     * @hide
+     * Array of all usage types exposed in the SDK that applications can use.
+     */
+    public final static int[] SDK_USAGES = {
+            USAGE_UNKNOWN,
+            USAGE_MEDIA,
+            USAGE_VOICE_COMMUNICATION,
+            USAGE_VOICE_COMMUNICATION_SIGNALLING,
+            USAGE_ALARM,
+            USAGE_NOTIFICATION,
+            USAGE_NOTIFICATION_RINGTONE,
+            USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+            USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+            USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+            USAGE_NOTIFICATION_EVENT,
+            USAGE_ASSISTANCE_ACCESSIBILITY,
+            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+            USAGE_ASSISTANCE_SONIFICATION,
+            USAGE_GAME
+    };
+
+    /**
      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
      */
     public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d413083..69710d6 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:
@@ -815,14 +816,14 @@
             if (value instanceof long[]) {
                 long[] array = (long[]) value;
                 if (array.length == 1) {
-                    return (double) array[0];
+                    return array[0];
                 }
                 throw new NumberFormatException("There are more than one component");
             }
             if (value instanceof int[]) {
                 int[] array = (int[]) value;
                 if (array.length == 1) {
-                    return (double) array[0];
+                    return array[0];
                 }
                 throw new NumberFormatException("There are more than one component");
             }
@@ -1305,6 +1306,7 @@
     private int mOrfThumbnailOffset;
     private int mOrfThumbnailLength;
     private int mRw2JpgFromRawOffset;
+    private boolean mIsSupportedFile;
 
     // Pattern to check non zero timestamp
     private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -1677,21 +1679,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 +1707,7 @@
                 case IMAGE_TYPE_PEF:
                 case IMAGE_TYPE_SRW:
                 case IMAGE_TYPE_UNKNOWN: {
-                    getRawAttributes(in);
+                    getRawAttributes(inputStream);
                     break;
                 }
                 default: {
@@ -1710,10 +1715,12 @@
                 }
             }
             // Set thumbnail image offset and length
-            setThumbnailData(in);
+            setThumbnailData(inputStream);
+            mIsSupportedFile = true;
         } catch (IOException e) {
             // Ignore exceptions in order to keep the compatibility with the old versions of
             // ExifInterface.
+            mIsSupportedFile = false;
             if (DEBUG) {
                 Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
                         + "(ExifInterface supports JPEG and some RAW image formats only) "
@@ -1754,9 +1761,14 @@
      * copying all the data from one file to another and deleting the old file and renaming the
      * other. It's best to use {@link #setAttribute(String,String)} to set all attributes to write
      * and make a single call rather than multiple calls for each attribute.
+     * <p>
+     * This method is only supported for JPEG files.
+     * </p>
+     *
+     * @throws UnsupportedOperationException If this method is called with unsupported files.
      */
     public void saveAttributes() throws IOException {
-        if (mMimeType != IMAGE_TYPE_JPEG) {
+        if (!mIsSupportedFile || mMimeType != IMAGE_TYPE_JPEG) {
             throw new UnsupportedOperationException(
                     "ExifInterface only supports saving attributes on JPEG formats.");
         }
@@ -2144,8 +2156,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 +2175,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 +2199,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 +2239,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 +2258,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 +2277,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 +2289,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 +2313,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 +2331,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 +2362,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 +2391,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 +2419,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 +2435,7 @@
                 }
                 return;
             }
-            dataInputStream.skip(numberOfBytes);
+            in.skipBytes(numberOfBytes);
         }
     }
 
@@ -2467,7 +2449,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 +2461,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 +2528,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 +2559,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 +2596,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 +2650,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 +2687,7 @@
         }
     }
 
-    private ByteOrder readByteOrder(ByteOrderAwarenessDataInputStream dataInputStream)
+    private ByteOrder readByteOrder(ByteOrderedDataInputStream dataInputStream)
             throws IOException {
         // Read byte order.
         short byteOrder = dataInputStream.readShort();
@@ -2725,7 +2707,7 @@
         }
     }
 
-    private void parseTiffHeaders(ByteOrderAwarenessDataInputStream dataInputStream,
+    private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream,
             int exifBytesLength) throws IOException {
         // Read byte order
         mExifByteOrder = readByteOrder(dataInputStream);
@@ -2745,22 +2727,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 +2771,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 +2892,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 +2927,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 +2950,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 +2979,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 +3011,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 +3020,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 +3048,7 @@
                 if (skipBytes < 0) {
                     Log.d(TAG, "Invalid strip offset value");
                 }
-                in.skip(skipBytes);
+                in.seek(skipBytes);
                 bytesRead += skipBytes;
 
                 // Read strip bytes
@@ -3140,6 +3126,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 +3160,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 +3216,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];
@@ -3300,7 +3271,7 @@
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
             int sum = 0;
             for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute exifAttribute = (ExifAttribute) ((Map.Entry) entry).getValue();
+                final ExifAttribute exifAttribute = (ExifAttribute) entry.getValue();
                 final int size = exifAttribute.size();
                 if (size > 4) {
                     sum += size;
@@ -3414,7 +3385,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 +3478,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 +3506,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 +3617,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 +3639,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 +3654,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 +3671,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 +3700,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 +3713,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;
@@ -3784,4 +3828,4 @@
         }
         return false;
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 2cbeb3a2..ed71849 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -241,6 +241,10 @@
      * same {@link Surface} can be reused with a different API once the first source is
      * disconnected from the {@link Surface}.</p>
      *
+     * <p>Please note that holding on to the Surface object returned by this method is not enough
+     * to keep its parent ImageReader from being reclaimed. In that sense, a Surface acts like a
+     * {@link java.lang.ref.WeakReference weak reference} to the ImageReader that provides it.</p>
+     *
      * @return A {@link Surface} to use for a drawing target for various APIs.
      */
     public Surface getSurface() {
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 9e560d5..4d332a8 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -510,6 +510,11 @@
     /**
      * Advance to the next sample. Returns false if no more sample data
      * is available (end of stream).
+     *
+     * When extracting a local file, the behaviors of {@link #advance} and
+     * {@link #readSampleData} are undefined in presence of concurrent
+     * writes to the same local file; more specifically, end of stream
+     * could be signalled earlier than expected.
      */
     public native boolean advance();
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 30395b8..82cf965 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityThread;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -982,17 +983,20 @@
     public void setDataSource(@NonNull Context context, @NonNull Uri uri,
             @Nullable Map<String, String> headers) throws IOException, IllegalArgumentException,
                     SecurityException, IllegalStateException {
+        // The context and URI usually belong to the calling user. Get a resolver for that user
+        // and strip out the userId from the URI if present.
         final ContentResolver resolver = context.getContentResolver();
         final String scheme = uri.getScheme();
+        final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
         if (ContentResolver.SCHEME_FILE.equals(scheme)) {
             setDataSource(uri.getPath());
             return;
         } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
-                && Settings.AUTHORITY.equals(uri.getAuthority())) {
+                && Settings.AUTHORITY.equals(authority)) {
             // 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;
@@ -1641,7 +1645,8 @@
      * (i.e. reaches the end of the stream).
      * The media framework will attempt to transition from this player to
      * the next as seamlessly as possible. The next player can be set at
-     * any time before completion. The next player must be prepared by the
+     * any time before completion, but shall be after setDataSource has been
+     * called successfully. The next player must be prepared by the
      * app, and the application should not call start() on it.
      * The next MediaPlayer must be different from 'this'. An exception
      * will be thrown if next == this.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index abbace1..bd68fec 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -389,8 +389,8 @@
         /** @hide Stream over a socket, limited to a single stream */
         public static final int OUTPUT_FORMAT_RTP_AVP = 7;
 
-        /** @hide H.264/AAC data encapsulated in MPEG2/TS */
-        public static final int OUTPUT_FORMAT_MPEG2TS = 8;
+        /** H.264/AAC data encapsulated in MPEG2/TS */
+        public static final int MPEG_2_TS = 8;
 
         /** VP8/VORBIS data in a WEBM container */
         public static final int WEBM = 9;
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 101facd..06dd3db 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);
@@ -220,8 +220,7 @@
 
             if (mBluetoothA2dpRoute != null) {
                 final boolean a2dpEnabled = isBluetoothA2dpOn();
-                if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
-                        mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
+                if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
                     selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
                         a2dpEnabled) {
@@ -357,8 +356,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 +1625,7 @@
 
         CharSequence getName(Resources res) {
             if (mNameResId != 0) {
-                return mName = res.getText(mNameResId);
+                return res.getText(mNameResId);
             }
             return mName;
         }
@@ -2079,6 +2077,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 +2274,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 +2589,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 +2717,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/MediaScanner.java b/media/java/android/media/MediaScanner.java
index f6e2a0c..ddfa025 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -21,12 +21,14 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.drm.DrmManagerClient;
 import android.graphics.BitmapFactory;
 import android.mtp.MtpConstants;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -153,6 +155,11 @@
     private static final String MUSIC_DIR = "/music/";
     private static final String PODCAST_DIR = "/podcasts/";
 
+    public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
+    public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
+    private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
+    private static String sLastInternalScanFingerprint;
+
     private static final String[] ID3_GENRES = {
         // ID3v1 Genres
         "Blues",
@@ -402,6 +409,13 @@
         mMediaProvider = mContext.getContentResolver()
                 .acquireContentProviderClient(MediaStore.AUTHORITY);
 
+        if (sLastInternalScanFingerprint == null) {
+            final SharedPreferences scanSettings =
+                    mContext.getSharedPreferences(SCANNED_BUILD_PREFS_NAME, Context.MODE_PRIVATE);
+            sLastInternalScanFingerprint =
+                    scanSettings.getString(LAST_INTERNAL_SCAN_FINGERPRINT, new String());
+        }
+
         mAudioUri = Audio.Media.getContentUri(volumeName);
         mVideoUri = Video.Media.getContentUri(volumeName);
         mImagesUri = Images.Media.getContentUri(volumeName);
@@ -585,16 +599,24 @@
                     entry.mRowId = 0;
                 }
 
-                if (entry.mPath != null &&
-                        ((!mDefaultNotificationSet &&
+                if (entry.mPath != null) {
+                    if (((!mDefaultNotificationSet &&
                                 doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
                         || (!mDefaultRingtoneSet &&
                                 doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
                         || (!mDefaultAlarmSet &&
                                 doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) {
-                    Log.w(TAG, "forcing rescan of " + entry.mPath +
-                            "since ringtone setting didn't finish");
-                    scanAlways = true;
+                        Log.w(TAG, "forcing rescan of " + entry.mPath +
+                                "since ringtone setting didn't finish");
+                        scanAlways = true;
+                    } else if (isSystemSoundWithMetadata(entry.mPath)
+                            && !Build.FINGERPRINT.equals(sLastInternalScanFingerprint)) {
+                        // file is located on the system partition where the date cannot be trusted:
+                        // rescan if the build fingerprint has changed since the last scan.
+                        Log.i(TAG, "forcing rescan of " + entry.mPath
+                                + " since build fingerprint changed");
+                        scanAlways = true;
+                    }
                 }
 
                 // rescan for metadata if file was modified since last scan
@@ -1128,6 +1150,15 @@
 
     }; // end of anonymous MediaScannerClient instance
 
+    private static boolean isSystemSoundWithMetadata(String path) {
+        if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
+                || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
+                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
+            return true;
+        }
+        return false;
+    }
+
     private String settingSetIndicatorName(String base) {
         return base + "_set";
     }
@@ -1252,16 +1283,6 @@
         }
     }
 
-    private boolean inScanDirectory(String path, String[] directories) {
-        for (int i = 0; i < directories.length; i++) {
-            String directory = directories[i];
-            if (path.startsWith(directory)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private void pruneDeadThumbnailFiles() {
         HashSet<String> existingFiles = new HashSet<String>();
         String directory = "/sdcard/DCIM/.thumbnails";
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index c2bcd93..8ae6e6b 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) {
@@ -257,6 +258,8 @@
                     title = uri.getLastPathSegment();
                 }
             }
+        } else {
+            title = context.getString(com.android.internal.R.string.ringtone_silent);
         }
 
         if (title == null) {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 86ebae1..3cb01de 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,16 @@
 
         String setting = getSettingForType(type);
         if (setting == null) return;
+        if(!isInternalRingtoneUri(ringtoneUri)) {
+            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);
@@ -679,6 +746,12 @@
         }
     }
 
+    private static boolean isInternalRingtoneUri(Uri uri) {
+        Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri);
+        return uriWithoutUserId == null ? false : uriWithoutUserId.toString()
+                        .startsWith(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString());
+    }
+
     /**
      * Try opening the given ringtone locally first, but failover to
      * {@link IRingtonePlayer} if we can't access it directly. Typically happens
@@ -715,15 +788,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;
     }
 
     /**
@@ -746,6 +824,7 @@
      * @return The type of the defaultRingtoneUri, or -1.
      */
     public static int getDefaultType(Uri defaultRingtoneUri) {
+        defaultRingtoneUri = ContentProvider.getUriWithoutUserId(defaultRingtoneUri);
         if (defaultRingtoneUri == null) {
             return -1;
         } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) {
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index b94a7e6..7dbca3b 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -53,7 +53,7 @@
  * than the priority used by the current effect engine owner, the control will be transfered to the
  * new object. Otherwise control will remain with the previous object. In this case, the new
  * application will be notified of changes in effect engine state or control ownership by the
- * appropiate listener.
+ * appropriate listener.
  */
 
 public class AudioEffect {
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 4f2d9fb..957c2d6 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -441,7 +441,7 @@
                     return;
                 }
                 Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
-                if (!(item instanceof MediaItem)) {
+                if (item != null && !(item instanceof MediaItem)) {
                     cb.onError(mediaId);
                     return;
                 }
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index d5115de..fbd3510 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -17,19 +17,18 @@
 package android.media.midi;
 
 import android.media.midi.MidiDeviceInfo;
-import android.os.ParcelFileDescriptor;
 
 /** @hide */
 interface IMidiDeviceServer
 {
-    ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
-    ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
+    FileDescriptor openInputPort(IBinder token, int portNumber);
+    FileDescriptor openOutputPort(IBinder token, int portNumber);
     void closePort(IBinder token);
     void closeDevice();
 
     // connects the input port pfd to the specified output port
     // Returns the PID of the called process.
-    int connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
+    int connectPorts(IBinder token, in FileDescriptor fd, int outputPortNumber);
 
     MidiDeviceInfo getDeviceInfo();
     void setDeviceInfo(in MidiDeviceInfo deviceInfo);
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index da44ca6..f79cd06 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -18,7 +18,6 @@
 
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -28,6 +27,7 @@
 import libcore.io.IoUtils;
 
 import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.IOException;
 
 /**
@@ -129,11 +129,11 @@
         }
         try {
             IBinder token = new Binder();
-            ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
-            if (pfd == null) {
+            FileDescriptor fd = mDeviceServer.openInputPort(token, portNumber);
+            if (fd == null) {
                 return null;
             }
-            return new MidiInputPort(mDeviceServer, token, pfd, portNumber);
+            return new MidiInputPort(mDeviceServer, token, fd, portNumber);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openInputPort");
             return null;
@@ -155,11 +155,11 @@
         }
         try {
             IBinder token = new Binder();
-            ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
-            if (pfd == null) {
+            FileDescriptor fd = mDeviceServer.openOutputPort(token, portNumber);
+            if (fd == null) {
                 return null;
             }
-            return new MidiOutputPort(mDeviceServer, token, pfd, portNumber);
+            return new MidiOutputPort(mDeviceServer, token, fd, portNumber);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openOutputPort");
             return null;
@@ -186,20 +186,20 @@
             return null;
         }
 
-        ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
-        if (pfd == null) {
+        FileDescriptor fd = inputPort.claimFileDescriptor();
+        if (fd == null) {
             return null;
         }
         try {
             IBinder token = new Binder();
-            int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
-            // If the service is a different Process then it will duplicate the pfd
+            int calleePid = mDeviceServer.connectPorts(token, fd, outputPortNumber);
+            // If the service is a different Process then it will duplicate the fd
             // and we can safely close this one.
-            // But if the service is in the same Process then closing the pfd will
+            // But if the service is in the same Process then closing the fd will
             // kill the connection. So don't do that.
             if (calleePid != Process.myPid()) {
                 // close our copy of the file descriptor
-                IoUtils.closeQuietly(pfd);
+                IoUtils.closeQuietly(fd);
             }
 
             return new MidiConnection(token, inputPort);
diff --git a/media/java/android/media/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
index f2f37a2..5b2ac9b 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.aidl
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.media.midi;
 
-parcelable MidiDeviceInfo;
+parcelable MidiDeviceInfo cpp_header "media/MidiDeviceInfo.h";
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index a59be54..5fd9006 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -20,6 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import android.util.Log;
+
 /**
  * This class contains information to describe a MIDI device.
  * For now we only have information that can be retrieved easily for USB devices,
@@ -32,6 +34,11 @@
 
     private static final String TAG = "MidiDeviceInfo";
 
+    /*
+     * Please note that constants and (un)marshalling code need to be kept in sync
+     * with the native implementation (MidiDeviceInfo.h|cpp)
+     */
+
     /**
      * Constant representing USB MIDI devices for {@link #getType}
      */
@@ -321,15 +328,17 @@
     public static final Parcelable.Creator<MidiDeviceInfo> CREATOR =
         new Parcelable.Creator<MidiDeviceInfo>() {
         public MidiDeviceInfo createFromParcel(Parcel in) {
+            // Needs to be kept in sync with code in MidiDeviceInfo.cpp
             int type = in.readInt();
             int id = in.readInt();
-            int inputPorts = in.readInt();
-            int outputPorts = in.readInt();
+            int inputPortCount = in.readInt();
+            int outputPortCount = in.readInt();
             String[] inputPortNames = in.createStringArray();
             String[] outputPortNames = in.createStringArray();
-            Bundle properties = in.readBundle();
             boolean isPrivate = (in.readInt() == 1);
-            return new MidiDeviceInfo(type, id, inputPorts, outputPorts,
+            Bundle basicPropertiesIgnored = in.readBundle();
+            Bundle properties = in.readBundle();
+            return new MidiDeviceInfo(type, id, inputPortCount, outputPortCount,
                     inputPortNames, outputPortNames, properties, isPrivate);
         }
 
@@ -342,14 +351,40 @@
         return 0;
     }
 
+    private Bundle getBasicProperties(String[] keys) {
+        Bundle basicProperties = new Bundle();
+        for (String key : keys) {
+            Object val = mProperties.get(key);
+            if (val != null) {
+                if (val instanceof String) {
+                    basicProperties.putString(key, (String) val);
+                } else if (val instanceof Integer) {
+                    basicProperties.putInt(key, (Integer) val);
+                } else {
+                    Log.w(TAG, "Unsupported property type: " + val.getClass().getName());
+                }
+            }
+        }
+        return basicProperties;
+    }
+
     public void writeToParcel(Parcel parcel, int flags) {
+        // Needs to be kept in sync with code in MidiDeviceInfo.cpp
         parcel.writeInt(mType);
         parcel.writeInt(mId);
         parcel.writeInt(mInputPortCount);
         parcel.writeInt(mOutputPortCount);
         parcel.writeStringArray(mInputPortNames);
         parcel.writeStringArray(mOutputPortNames);
-        parcel.writeBundle(mProperties);
         parcel.writeInt(mIsPrivate ? 1 : 0);
+        // "Basic" properties only contain properties of primitive types
+        // and thus can be read back by native code. "Extra" properties is
+        // a superset that contains all properties.
+        parcel.writeBundle(getBasicProperties(new String[] {
+            PROPERTY_NAME, PROPERTY_MANUFACTURER, PROPERTY_PRODUCT, PROPERTY_VERSION,
+            PROPERTY_SERIAL_NUMBER, PROPERTY_ALSA_CARD, PROPERTY_ALSA_DEVICE
+        }));
+        // Must be serialized last so native code can safely ignore it.
+        parcel.writeBundle(mProperties);
    }
 }
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index 4c49f67..eaa8654 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -18,9 +18,10 @@
 
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.Log;
 
@@ -31,6 +32,7 @@
 import libcore.io.IoUtils;
 
 import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -167,11 +169,22 @@
         }
     }
 
+    private static FileDescriptor[] createSeqPacketSocketPair() throws IOException {
+        try {
+            final FileDescriptor fd0 = new FileDescriptor();
+            final FileDescriptor fd1 = new FileDescriptor();
+            Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, fd0, fd1);
+            return new FileDescriptor[] { fd0, fd1 };
+        } catch (ErrnoException e) {
+            throw e.rethrowAsIOException();
+        }
+    }
+
     // Binder interface stub for receiving connection requests from clients
     private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
 
         @Override
-        public ParcelFileDescriptor openInputPort(IBinder token, int portNumber) {
+        public FileDescriptor openInputPort(IBinder token, int portNumber) {
             if (mDeviceInfo.isPrivate()) {
                 if (Binder.getCallingUid() != Process.myUid()) {
                     throw new SecurityException("Can't access private device from different UID");
@@ -190,8 +203,7 @@
                 }
 
                 try {
-                    ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
-                                                        OsConstants.SOCK_SEQPACKET);
+                    FileDescriptor[] pair = createSeqPacketSocketPair();
                     MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber);
                     mInputPortOutputPorts[portNumber] = outputPort;
                     outputPort.connect(mInputPortReceivers[portNumber]);
@@ -203,14 +215,14 @@
                     updateDeviceStatus();
                     return pair[1];
                 } catch (IOException e) {
-                    Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort");
+                    Log.e(TAG, "unable to create FileDescriptors in openInputPort");
                     return null;
                 }
             }
         }
 
         @Override
-        public ParcelFileDescriptor openOutputPort(IBinder token, int portNumber) {
+        public FileDescriptor openOutputPort(IBinder token, int portNumber) {
             if (mDeviceInfo.isPrivate()) {
                 if (Binder.getCallingUid() != Process.myUid()) {
                     throw new SecurityException("Can't access private device from different UID");
@@ -223,14 +235,13 @@
             }
 
             try {
-                ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
-                                                    OsConstants.SOCK_SEQPACKET);
+                FileDescriptor[] pair = createSeqPacketSocketPair();
                 MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
                 // Undo the default blocking-mode of the server-side socket for
                 // physical devices to avoid stalling the Java device handler if
                 // client app code gets stuck inside 'onSend' handler.
                 if (mDeviceInfo.getType() != MidiDeviceInfo.TYPE_VIRTUAL) {
-                    IoUtils.setBlocking(pair[0].getFileDescriptor(), false);
+                    IoUtils.setBlocking(pair[0], false);
                 }
                 MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber];
                 synchronized (dispatcher) {
@@ -250,7 +261,7 @@
                 }
                 return pair[1];
             } catch (IOException e) {
-                Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
+                Log.e(TAG, "unable to create FileDescriptors in openOutputPort");
                 return null;
             }
         }
@@ -281,9 +292,9 @@
         }
 
         @Override
-        public int connectPorts(IBinder token, ParcelFileDescriptor pfd,
+        public int connectPorts(IBinder token, FileDescriptor fd,
                 int outputPortNumber) {
-            MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
+            MidiInputPort inputPort = new MidiInputPort(fd, outputPortNumber);
             MidiDispatcher dispatcher = mOutputPortDispatchers[outputPortNumber];
             synchronized (dispatcher) {
                 dispatcher.getSender().connect(inputPort);
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
index db41b10..98ec779 100644
--- a/media/java/android/media/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -17,7 +17,6 @@
 package android.media.midi;
 
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -26,6 +25,7 @@
 import libcore.io.IoUtils;
 
 import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
@@ -38,7 +38,7 @@
     private IMidiDeviceServer mDeviceServer;
     private final IBinder mToken;
     private final int mPortNumber;
-    private ParcelFileDescriptor mParcelFileDescriptor;
+    private FileDescriptor mFileDescriptor;
     private FileOutputStream mOutputStream;
 
     private final CloseGuard mGuard = CloseGuard.get();
@@ -48,19 +48,19 @@
     private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
 
     /* package */ MidiInputPort(IMidiDeviceServer server, IBinder token,
-            ParcelFileDescriptor pfd, int portNumber) {
+            FileDescriptor fd, int portNumber) {
         super(MidiPortImpl.MAX_PACKET_DATA_SIZE);
 
         mDeviceServer = server;
         mToken = token;
-        mParcelFileDescriptor = pfd;
+        mFileDescriptor = fd;
         mPortNumber = portNumber;
-        mOutputStream = new FileOutputStream(pfd.getFileDescriptor());
+        mOutputStream = new FileOutputStream(fd);
         mGuard.open("close");
     }
 
-    /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
-        this(null, null, pfd, portNumber);
+    /* package */ MidiInputPort(FileDescriptor fd, int portNumber) {
+        this(null, null, fd, portNumber);
     }
 
     /**
@@ -102,21 +102,21 @@
     }
 
     // used by MidiDevice.connectInputPort() to connect our socket directly to another device
-    /* package */ ParcelFileDescriptor claimFileDescriptor() {
+    /* package */ FileDescriptor claimFileDescriptor() {
         synchronized (mGuard) {
-            ParcelFileDescriptor pfd;
+            FileDescriptor fd;
             synchronized (mBuffer) {
-                pfd = mParcelFileDescriptor;
-                if (pfd == null) return null;
+                fd = mFileDescriptor;
+                if (fd == null) return null;
                 IoUtils.closeQuietly(mOutputStream);
-                mParcelFileDescriptor = null;
+                mFileDescriptor = null;
                 mOutputStream = null;
             }
 
             // Set mIsClosed = true so we will not call mDeviceServer.closePort() in close().
             // MidiDevice.MidiConnection.close() will do the cleanup instead.
             mIsClosed = true;
-            return pfd;
+            return fd;
         }
     }
 
@@ -136,9 +136,9 @@
             if (mIsClosed) return;
             mGuard.close();
             synchronized (mBuffer) {
-                if (mParcelFileDescriptor != null) {
-                    mParcelFileDescriptor.close();
-                    mParcelFileDescriptor = null;
+                if (mFileDescriptor != null) {
+                    IoUtils.closeQuietly(mFileDescriptor);
+                    mFileDescriptor = null;
                 }
                 if (mOutputStream != null) {
                     mOutputStream.close();
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
index 54c31e3..ce0402c 100644
--- a/media/java/android/media/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -28,6 +28,7 @@
 import libcore.io.IoUtils;
 
 import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
 
@@ -91,17 +92,17 @@
     };
 
     /* package */ MidiOutputPort(IMidiDeviceServer server, IBinder token,
-            ParcelFileDescriptor pfd, int portNumber) {
+            FileDescriptor fd, int portNumber) {
         mDeviceServer = server;
         mToken = token;
         mPortNumber = portNumber;
-        mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(new ParcelFileDescriptor(fd));
         mThread.start();
         mGuard.open("close");
     }
 
-    /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
-        this(null, null, pfd, portNumber);
+    /* package */ MidiOutputPort(FileDescriptor fd, int portNumber) {
+        this(null, null, fd, portNumber);
     }
 
     /**
diff --git a/media/java/android/media/midi/MidiPortImpl.java b/media/java/android/media/midi/MidiPortImpl.java
index 16fc214..1cd9ed2 100644
--- a/media/java/android/media/midi/MidiPortImpl.java
+++ b/media/java/android/media/midi/MidiPortImpl.java
@@ -34,7 +34,7 @@
     public static final int PACKET_TYPE_FLUSH = 2;
 
     /**
-     * Maximum size of a packet that can pass through our ParcelFileDescriptor.
+     * Maximum size of a packet that can be passed between processes.
      */
     public static final int MAX_PACKET_SIZE = 1024;
 
@@ -54,7 +54,7 @@
     public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - DATA_PACKET_OVERHEAD;
 
     /**
-     * Utility function for packing MIDI data to be sent through our ParcelFileDescriptor
+     * Utility function for packing MIDI data to be passed between processes
      *
      * message byte array contains variable length MIDI message.
      * messageSize is size of variable length MIDI message
@@ -84,7 +84,7 @@
     }
 
     /**
-     * Utility function for packing a flush command to be sent through our ParcelFileDescriptor
+     * Utility function for packing a flush command to be passed between processes
      */
     public static int packFlush(byte[] dest) {
         dest[0] = PACKET_TYPE_FLUSH;
@@ -99,7 +99,7 @@
     }
 
     /**
-     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
+     * Utility function for unpacking MIDI data received from other process
      * returns the offset of the MIDI message in packed buffer
      */
     public static int getDataOffset(byte[] buffer, int bufferLength) {
@@ -108,7 +108,7 @@
     }
 
     /**
-     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
+     * Utility function for unpacking MIDI data received from other process
      * returns size of MIDI data in packed buffer
      */
     public static int getDataSize(byte[] buffer, int bufferLength) {
@@ -117,7 +117,7 @@
     }
 
     /**
-     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
+     * Utility function for unpacking MIDI data received from other process
      * unpacks timestamp from packed buffer
      */
     public static long getPacketTimestamp(byte[] buffer, int bufferLength) {
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index a215493..4f3314c 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -46,7 +46,7 @@
     void setExtras(in Bundle extras);
     void setRatingType(int type);
     void setRepeatMode(int repeatMode);
-    void setShuffleMode(boolean shuffleMode);
+    void setShuffleModeEnabled(boolean enabled);
 
     // These commands relate to volume handling
     void setPlaybackToLocal(in AudioAttributes attributes);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index b3c6d59..2f6e260 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -47,7 +47,7 @@
     void onSeekTo(long pos);
     void onRate(in Rating rating);
     void onRepeatMode(int repeatMode);
-    void onShuffleMode(boolean shuffleMode);
+    void onShuffleMode(boolean enabled);
     void onCustomAction(String action, in Bundle args);
 
     // These callbacks are for volume handling
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index b73f167..e92758c 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -55,7 +55,7 @@
     Bundle getExtras();
     int getRatingType();
     int getRepeatMode();
-    boolean getShuffleMode();
+    boolean isShuffleModeEnabled();
 
     // These commands are for the TransportControls
     void prepare();
@@ -76,6 +76,6 @@
     void seekTo(long pos);
     void rate(in Rating rating);
     void repeatMode(int repeatMode);
-    void shuffleMode(boolean shuffleMode);
+    void shuffleMode(boolean enabled);
     void sendCustomAction(String action, in Bundle args);
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index ddff1b7..8cbf8e1 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -251,15 +251,15 @@
     }
 
     /**
-     * Get the shuffle mode for this session.
+     * Return whether the shuffle mode is enabled for this session.
      *
-     * @return The latest shuffle mode set to the session, or false if not set.
+     * @return {@code true} if the shuffle mode is enabled, {@code false} if disabled or not set.
      */
-    public boolean getShuffleMode() {
+    public boolean isShuffleModeEnabled() {
         try {
-            return mSessionBinder.getShuffleMode();
+            return mSessionBinder.isShuffleModeEnabled();
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getShuffleMode.", e);
+            Log.wtf(TAG, "Error calling isShuffleModeEnabled.", e);
             return false;
         }
     }
@@ -625,10 +625,9 @@
         /**
          * Override to handle changes to the shuffle mode.
          *
-         * @param shuffleMode The shuffle mode. {@code true} if _the_ shuffle mode is on,
-         *                    {@code false} otherwise.
+         * @param enabled {@code true} if the shuffle mode is enabled, {@code false} otherwise.
          */
-        public void onShuffleModeChanged(boolean shuffleMode) {
+        public void onShuffleModeChanged(boolean enabled) {
         }
     }
 
@@ -931,13 +930,13 @@
         /**
          * Set the shuffle mode for this session.
          *
-         * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise.
+         * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable.
          */
-        public void setShuffleMode(boolean shuffleMode) {
+        public void setShuffleModeEnabled(boolean enabled) {
             try {
-                mSessionBinder.shuffleMode(shuffleMode);
+                mSessionBinder.shuffleMode(enabled);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling shuffleQueue.", e);
+                Log.wtf(TAG, "Error calling shuffleMode.", e);
             }
         }
 
@@ -1151,10 +1150,10 @@
         }
 
         @Override
-        public void onShuffleModeChanged(boolean shuffleMode) {
+        public void onShuffleModeChanged(boolean enabled) {
             MediaController controller = mController.get();
             if (controller != null) {
-                controller.postMessage(MSG_UPDATE_SHUFFLE_MODE, shuffleMode, null);
+                controller.postMessage(MSG_UPDATE_SHUFFLE_MODE, enabled, null);
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cab5d93..84dc93a 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -501,16 +501,16 @@
     /**
      * Set the shuffle mode for this session.
      * <p>
-     * Note that if this method is not called before, {@link MediaController#getShuffleMode}
+     * Note that if this method is not called before, {@link MediaController#isShuffleModeEnabled}
      * will return {@code false}.
      *
-     * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise.
+     * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable.
      */
-    public void setShuffleMode(boolean shuffleMode) {
+    public void setShuffleModeEnabled(boolean enabled) {
         try {
-            mBinder.setShuffleMode(shuffleMode);
+            mBinder.setShuffleModeEnabled(enabled);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error in setShuffleMode.", e);
+            Log.e(TAG, "Error in setShuffleModeEnabled.", e);
         }
     }
 
@@ -637,8 +637,8 @@
         postToCallback(CallbackMessageHandler.MSG_REPEAT_MODE, repeatMode);
     }
 
-    private void dispatchShuffleMode(boolean shuffleMode) {
-        postToCallback(CallbackMessageHandler.MSG_SHUFFLE_MODE, shuffleMode);
+    private void dispatchShuffleMode(boolean enabled) {
+        postToCallback(CallbackMessageHandler.MSG_SHUFFLE_MODE, enabled);
     }
 
     private void dispatchCustomAction(String action, Bundle args) {
@@ -1024,13 +1024,13 @@
         /**
          * Override to handle the setting of the shuffle mode.
          * <p>
-         * You should call {@link #setShuffleMode} before end of this method in order to notify
-         * the change to the {@link MediaController}, or {@link MediaController#getShuffleMode}
-         * could return an invalid value.
+         * You should call {@link #setShuffleModeEnabled} before the end of this method in order to
+         * notify the change to the {@link MediaController}, or
+         * {@link MediaController#isShuffleModeEnabled} could return an invalid value.
          *
-         * @param shuffleMode true if the shuffle mode is on, false otherwise.
+         * @param enabled true when the shuffle mode is enabled, false otherwise.
          */
-        public void onSetShuffleMode(boolean shuffleMode) {
+        public void onSetShuffleModeEnabled(boolean enabled) {
         }
 
         /**
@@ -1223,10 +1223,10 @@
         }
 
         @Override
-        public void onShuffleMode(boolean shuffleMode) {
+        public void onShuffleMode(boolean enabled) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchShuffleMode(shuffleMode);
+                session.dispatchShuffleMode(enabled);
             }
         }
 
@@ -1468,7 +1468,7 @@
                     mCallback.onSetRepeatMode((int) msg.obj);
                     break;
                 case MSG_SHUFFLE_MODE:
-                    mCallback.onSetShuffleMode((boolean) msg.obj);
+                    mCallback.onSetShuffleModeEnabled((boolean) msg.obj);
                     break;
                 case MSG_CUSTOM_ACTION:
                     mCallback.onCustomAction((String) msg.obj, msg.getData());
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 5cdd201..1ea6109 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -46,7 +46,7 @@
             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
             ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI,
-            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE})
+            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Actions {}
 
@@ -184,11 +184,11 @@
     public static final long ACTION_SET_REPEAT_MODE = 1 << 18;
 
     /**
-     * Indicates this session supports the set shuffle mode command.
+     * Indicates this session supports the set shuffle mode enabled command.
      *
      * @see Builder#setActions(long)
      */
-    public static final long ACTION_SET_SHUFFLE_MODE = 1 << 19;
+    public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19;
 
     /**
      * @hide
@@ -467,7 +467,7 @@
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
      * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li>
-     * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}</li>
+     * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
      * </ul>
      */
     @Actions
@@ -1003,7 +1003,7 @@
          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
          * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li>
-         * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}</li>
+         * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
          * </ul>
          *
          * @param actions The set of actions allowed.
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 6970cff..4e7551c 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -18,11 +18,13 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 
+import android.os.UserManager;
 import com.android.internal.util.Preconditions;
 
 import java.io.IOException;
@@ -63,7 +65,17 @@
      * @return true if the device was successfully opened.
      */
     public boolean open(@NonNull UsbDeviceConnection connection) {
-        boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
+        boolean result = false;
+
+        Context context = connection.getContext();
+        if (context != null) {
+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+            if (!userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
+                result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
+            }
+        }
+
         if (!result) {
             connection.close();
         }
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index a811ad0..a19e347 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -91,10 +91,12 @@
     public static final String KEY_MEDIA_ITEM = "media_item";
 
     private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 0x00000001;
+    private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 0x00000002;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED })
+    @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
+            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
     private @interface ResultFlags { }
 
     private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
@@ -433,11 +435,9 @@
      * been loaded.
      * </p><p>
      * When the given {@code itemId} is invalid, implementations must call
-     * {@link Result#sendResult result.sendResult} with {@code null}, which will
-     * invoke {@link MediaBrowser.ItemCallback#onError}.
+     * {@link Result#sendResult result.sendResult} with {@code null}.
      * </p><p>
-     * The default implementation calls {@link Result#sendResult result.sendResult}
-     * with {@code null}.
+     * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
      * </p>
      *
      * @param itemId The id for the specific
@@ -445,6 +445,7 @@
      * @param result The Result to send the item to.
      */
     public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+        result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
         result.sendResult(null);
     }
 
@@ -703,6 +704,10 @@
                 new Result<MediaBrowser.MediaItem>(itemId) {
             @Override
             void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
+                if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
+                    receiver.send(-1, null);
+                    return;
+                }
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(KEY_MEDIA_ITEM, item);
                 receiver.send(0, bundle);
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 810996e..c2c66fd 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -32,6 +32,7 @@
 #include <gui/Surface.h>
 
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -407,7 +408,7 @@
 
 status_t JMediaCodec::getBuffers(
         JNIEnv *env, bool input, jobjectArray *bufArray) const {
-    Vector<sp<ABuffer> > buffers;
+    Vector<sp<MediaCodecBuffer> > buffers;
 
     status_t err =
         input
@@ -425,7 +426,7 @@
     }
 
     for (size_t i = 0; i < buffers.size(); ++i) {
-        const sp<ABuffer> &buffer = buffers.itemAt(i);
+        const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
 
         jobject byteBuffer = NULL;
         err = createByteBufferFromABuffer(
@@ -446,8 +447,9 @@
 }
 
 // static
+template <typename T>
 status_t JMediaCodec::createByteBufferFromABuffer(
-        JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+        JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
         jobject *buf) const {
     // if this is an ABuffer that doesn't actually hold any accessible memory,
     // use a null ByteBuffer
@@ -492,7 +494,7 @@
 
 status_t JMediaCodec::getBuffer(
         JNIEnv *env, bool input, size_t index, jobject *buf) const {
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
 
     status_t err =
         input
@@ -509,7 +511,7 @@
 
 status_t JMediaCodec::getImage(
         JNIEnv *env, bool input, size_t index, jobject *buf) const {
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
 
     status_t err =
         input
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c0c47ef..5f0d3df 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -31,7 +31,7 @@
 struct AMessage;
 struct AString;
 struct ICrypto;
-struct IGraphicBufferProducer;
+class IGraphicBufferProducer;
 struct MediaCodec;
 struct PersistentSurface;
 class Surface;
@@ -146,8 +146,9 @@
 
     status_t mInitStatus;
 
+    template <typename T>
     status_t createByteBufferFromABuffer(
-            JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+            JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
             jobject *buf) const;
 
     void cacheJavaObjects(JNIEnv *env);
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 8184f94..39c1554 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -37,7 +37,7 @@
     size_t mPosition;
 
 public:
-    AssetStream(SkStream* stream);
+    explicit AssetStream(SkStream* stream);
     ~AssetStream();
 
     // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
@@ -60,7 +60,7 @@
     const size_t kMinSizeToRead = 8192;
 
 public:
-    BufferedStream(SkStream* stream);
+    explicit BufferedStream(SkStream* stream);
     ~BufferedStream();
 
     // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
@@ -79,8 +79,8 @@
     size_t mPosition;
 
 public:
-    FileStream(const int fd);
-    FileStream(const String8 filename);
+    explicit FileStream(const int fd);
+    explicit FileStream(const String8 filename);
     ~FileStream();
 
     // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 75a3b6f..0645543 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -435,14 +435,12 @@
 
 // ----------------------------------------------------------------------------
 static void android_media_visualizer_native_release(JNIEnv *env,  jobject thiz) {
-    // ensure that lpVisualizer is deleted before lpJniStorage
-    {
+    { //limit scope so that lpVisualizer is deleted before JNI storage data.
         sp<Visualizer> lpVisualizer = setVisualizer(env, thiz, 0);
         if (lpVisualizer == 0) {
             return;
         }
     }
-
     // delete the JNI data
     VisualizerJniStorage* lpJniStorage =
         (VisualizerJniStorage *)env->GetLongField(thiz, fields.fidJniData);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 98d2fa2..aff101f 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -37,7 +37,7 @@
 // for queued events
 class SoundPoolEvent {
 public:
-    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
+    explicit SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
         mMsg(msg), mArg1(arg1), mArg2(arg2) {}
     int         mMsg;
     int         mArg1;
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index 9096aeb..7b3e1dd 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -40,7 +40,7 @@
  */
 class SoundPoolThread {
 public:
-    SoundPoolThread(SoundPool* SoundPool);
+    explicit SoundPoolThread(SoundPool* SoundPool);
     ~SoundPoolThread();
     void loadSample(int sampleID);
     void quit();
diff --git a/media/mca/filterfw/native/core/gl_frame.h b/media/mca/filterfw/native/core/gl_frame.h
index f2a1ad5..fdbb1f5 100644
--- a/media/mca/filterfw/native/core/gl_frame.h
+++ b/media/mca/filterfw/native/core/gl_frame.h
@@ -38,7 +38,7 @@
     // Create an empty GL frame in the specified GL environment. Note, that the GLFrame does NOT
     // take ownership. The caller must make sure the GLEnv stays valid as long as the GLFrame is
     // alive.
-    GLFrame(GLEnv* gl_env);
+    explicit GLFrame(GLEnv* gl_env);
 
     // Deallocate a GL frame.
     ~GLFrame();
diff --git a/media/mca/filterfw/native/core/native_frame.h b/media/mca/filterfw/native/core/native_frame.h
index 0d335b3..2da557d 100644
--- a/media/mca/filterfw/native/core/native_frame.h
+++ b/media/mca/filterfw/native/core/native_frame.h
@@ -27,7 +27,7 @@
 class NativeFrame {
   public:
     // Create an empty native frame.
-    NativeFrame(int size);
+    explicit NativeFrame(int size);
 
     ~NativeFrame();
 
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 7e438a1..20575e0 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -9,8 +9,8 @@
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
-    mockito-target \
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    mockito-target-minus-junit4 \
     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/native/android/Android.bp b/native/android/Android.bp
new file mode 100644
index 0000000..33c9655
--- /dev/null
+++ b/native/android/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+// The headers module is in frameworks/native/Android.bp.
+ndk_library {
+    name: "libandroid.ndk",
+    symbol_file: "libandroid.map.txt",
+    first_version: "9",
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
new file mode 100644
index 0000000..5758a3c
--- /dev/null
+++ b/native/android/libandroid.map.txt
@@ -0,0 +1,194 @@
+LIBANDROID {
+  global:
+    AAssetDir_close;
+    AAssetDir_getNextFileName;
+    AAssetDir_rewind;
+    AAssetManager_fromJava;
+    AAssetManager_open;
+    AAssetManager_openDir;
+    AAsset_close;
+    AAsset_getBuffer;
+    AAsset_getLength;
+    AAsset_getLength64; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AAsset_getRemainingLength;
+    AAsset_getRemainingLength64; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AAsset_isAllocated;
+    AAsset_openFileDescriptor;
+    AAsset_openFileDescriptor64; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AAsset_read;
+    AAsset_seek;
+    AAsset_seek64; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AChoreographer_getInstance; # introduced=24
+    AChoreographer_postFrameCallback; # introduced=24
+    AChoreographer_postFrameCallbackDelayed; # introduced=24
+    AConfiguration_copy;
+    AConfiguration_delete;
+    AConfiguration_diff;
+    AConfiguration_fromAssetManager;
+    AConfiguration_getCountry;
+    AConfiguration_getDensity;
+    AConfiguration_getKeyboard;
+    AConfiguration_getKeysHidden;
+    AConfiguration_getLanguage;
+    AConfiguration_getLayoutDirection; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
+    AConfiguration_getMcc;
+    AConfiguration_getMnc;
+    AConfiguration_getNavHidden;
+    AConfiguration_getNavigation;
+    AConfiguration_getOrientation;
+    AConfiguration_getScreenHeightDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_getScreenLong;
+    AConfiguration_getScreenSize;
+    AConfiguration_getScreenWidthDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_getSdkVersion;
+    AConfiguration_getSmallestScreenWidthDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_getTouchscreen;
+    AConfiguration_getUiModeNight;
+    AConfiguration_getUiModeType;
+    AConfiguration_isBetterThan;
+    AConfiguration_match;
+    AConfiguration_new;
+    AConfiguration_setCountry;
+    AConfiguration_setDensity;
+    AConfiguration_setKeyboard;
+    AConfiguration_setKeysHidden;
+    AConfiguration_setLanguage;
+    AConfiguration_setLayoutDirection; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
+    AConfiguration_setMcc;
+    AConfiguration_setMnc;
+    AConfiguration_setNavHidden;
+    AConfiguration_setNavigation;
+    AConfiguration_setOrientation;
+    AConfiguration_setScreenHeightDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_setScreenLong;
+    AConfiguration_setScreenSize;
+    AConfiguration_setScreenWidthDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_setSdkVersion;
+    AConfiguration_setSmallestScreenWidthDp; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AConfiguration_setTouchscreen;
+    AConfiguration_setUiModeNight;
+    AConfiguration_setUiModeType;
+    AInputEvent_getDeviceId;
+    AInputEvent_getSource;
+    AInputEvent_getType;
+    AInputQueue_attachLooper;
+    AInputQueue_detachLooper;
+    AInputQueue_finishEvent;
+    AInputQueue_getEvent;
+    AInputQueue_hasEvents;
+    AInputQueue_preDispatchEvent;
+    AKeyEvent_getAction;
+    AKeyEvent_getDownTime;
+    AKeyEvent_getEventTime;
+    AKeyEvent_getFlags;
+    AKeyEvent_getKeyCode;
+    AKeyEvent_getMetaState;
+    AKeyEvent_getRepeatCount;
+    AKeyEvent_getScanCode;
+    ALooper_acquire;
+    ALooper_addFd;
+    ALooper_forThread;
+    ALooper_pollAll;
+    ALooper_pollOnce;
+    ALooper_prepare;
+    ALooper_release;
+    ALooper_removeFd;
+    ALooper_wake;
+    AMotionEvent_getAction;
+    AMotionEvent_getAxisValue; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AMotionEvent_getButtonState; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
+    AMotionEvent_getDownTime;
+    AMotionEvent_getEdgeFlags;
+    AMotionEvent_getEventTime;
+    AMotionEvent_getFlags;
+    AMotionEvent_getHistoricalAxisValue; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    AMotionEvent_getHistoricalEventTime;
+    AMotionEvent_getHistoricalOrientation;
+    AMotionEvent_getHistoricalPressure;
+    AMotionEvent_getHistoricalRawX;
+    AMotionEvent_getHistoricalRawY;
+    AMotionEvent_getHistoricalSize;
+    AMotionEvent_getHistoricalToolMajor;
+    AMotionEvent_getHistoricalToolMinor;
+    AMotionEvent_getHistoricalTouchMajor;
+    AMotionEvent_getHistoricalTouchMinor;
+    AMotionEvent_getHistoricalX;
+    AMotionEvent_getHistoricalY;
+    AMotionEvent_getHistorySize;
+    AMotionEvent_getMetaState;
+    AMotionEvent_getOrientation;
+    AMotionEvent_getPointerCount;
+    AMotionEvent_getPointerId;
+    AMotionEvent_getPressure;
+    AMotionEvent_getRawX;
+    AMotionEvent_getRawY;
+    AMotionEvent_getSize;
+    AMotionEvent_getToolMajor;
+    AMotionEvent_getToolMinor;
+    AMotionEvent_getToolType; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
+    AMotionEvent_getTouchMajor;
+    AMotionEvent_getTouchMinor;
+    AMotionEvent_getX;
+    AMotionEvent_getXOffset;
+    AMotionEvent_getXPrecision;
+    AMotionEvent_getY;
+    AMotionEvent_getYOffset;
+    AMotionEvent_getYPrecision;
+    ANativeActivity_finish;
+    ANativeActivity_hideSoftInput;
+    ANativeActivity_setWindowFlags;
+    ANativeActivity_setWindowFormat;
+    ANativeActivity_showSoftInput;
+    ANativeWindow_acquire;
+    ANativeWindow_fromSurface;
+    ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13
+    ANativeWindow_getFormat;
+    ANativeWindow_getHeight;
+    ANativeWindow_getWidth;
+    ANativeWindow_lock;
+    ANativeWindow_release;
+    ANativeWindow_setBuffersGeometry;
+    ANativeWindow_unlockAndPost;
+    AObbInfo_delete;
+    AObbInfo_getFlags;
+    AObbInfo_getPackageName;
+    AObbInfo_getVersion;
+    AObbScanner_getObbInfo;
+    ASensorEventQueue_disableSensor;
+    ASensorEventQueue_enableSensor;
+    ASensorEventQueue_getEvents;
+    ASensorEventQueue_hasEvents;
+    ASensorEventQueue_setEventRate;
+    ASensorManager_createEventQueue;
+    ASensorManager_destroyEventQueue;
+    ASensorManager_getDefaultSensor;
+    ASensorManager_getDefaultSensorEx; # introduced=21
+    ASensorManager_getInstance;
+    ASensorManager_getSensorList;
+    ASensor_getFifoMaxEventCount; # introduced=21
+    ASensor_getFifoReservedEventCount; # introduced=21
+    ASensor_getMinDelay;
+    ASensor_getName;
+    ASensor_getReportingMode; # introduced=21
+    ASensor_getResolution;
+    ASensor_getStringType; # introduced=21
+    ASensor_getType;
+    ASensor_getVendor;
+    ASensor_isWakeUpSensor; # introduced=21
+    AStorageManager_delete;
+    AStorageManager_getMountedObbPath;
+    AStorageManager_isObbMounted;
+    AStorageManager_mountObb;
+    AStorageManager_new;
+    AStorageManager_unmountObb;
+    ATrace_beginSection; # introduced=23
+    ATrace_endSection; # introduced=23
+    ATrace_isEnabled; # introduced=23
+    android_getTtsEngine; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+    android_getaddrinfofornetwork; # introduced=23
+    android_setprocnetwork; # introduced=23
+    android_setsocknetwork; # introduced=23
+    getTtsEngine; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
+  local:
+    *;
+};
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
new file mode 100644
index 0000000..e09b0b4
--- /dev/null
+++ b/native/graphics/jni/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+// The headers module is in frameworks/native/Android.bp.
+ndk_library {
+    name: "libjnigraphics.ndk",
+    symbol_file: "libjnigraphics.map.txt",
+    first_version: "9",
+}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
new file mode 100644
index 0000000..a601d8a
--- /dev/null
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -0,0 +1,8 @@
+LIBJNIGRAPHICS {
+  global:
+    AndroidBitmap_getInfo;
+    AndroidBitmap_lockPixels;
+    AndroidBitmap_unlockPixels;
+  local:
+    *;
+};
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/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index 804f980..44d01de 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -19,7 +19,7 @@
     <string name="backup_confirm_title" msgid="827563724209303345">"Úplná záloha"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Úplné obnovenie"</string>
     <string name="backup_confirm_text" msgid="1878021282758896593">"Bola vyžiadaná úplná záloha všetkých dát do pripojeného počítača. Chcete túto akciu povoliť?\n\nAk ste zálohu nevyžiadali vy, túto operáciu nepovoľujte."</string>
-    <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovať dáta"</string>
+    <string name="allow_backup_button_label" msgid="4217228747769644068">"Zálohovať moje dáta"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nezálohovať"</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
index 32e3358..808ec36 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
@@ -102,6 +102,14 @@
         return false;
     }
 
+    public static void registerJobIfNeeded(Context context, long intervalMinutes) {
+        JobScheduler jss = context.getSystemService(JobScheduler.class);
+        JobInfo info = jss.getPendingJob(JOB_ID);
+        if (info == null) {
+            registerJob(context, intervalMinutes);
+        }
+    }
+
     public static void registerJob(Context context, long intervalMinutes) {
         JobScheduler jss = context.getSystemService(JobScheduler.class);
         jss.cancel(JOB_ID);
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
index 8a3ec8f..159b40a 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
@@ -68,6 +68,9 @@
         Tile tile = getQsTile();
         int foodState = mPrefs.getFoodState();
         Food food = new Food(foodState);
+        if (foodState != 0) {
+            NekoService.registerJobIfNeeded(this, food.getInterval(this));
+        }
         tile.setIcon(food.getIcon(this));
         tile.setLabel(food.getName(this));
         tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
index 5f54180..bf71b19 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
+++ b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
@@ -43,13 +43,11 @@
     public void addCat(Cat cat) {
         mPrefs.edit()
               .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
-              .commit();
+              .apply();
     }
 
     public void removeCat(Cat cat) {
-        mPrefs.edit()
-                .remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()))
-                .commit();
+        mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
     }
 
     public List<Cat> getCats() {
@@ -71,7 +69,7 @@
     }
 
     public void setFoodState(int foodState) {
-        mPrefs.edit().putInt(FOOD_STATE, foodState).commit();
+        mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
     }
 
     public void setListener(PrefsListener listener) {
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index ec6af2f..db825ff4 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,7 +5,6 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
 LOCAL_PACKAGE_NAME := ExternalStorageProvider
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 1341476..33d6b9a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -44,7 +44,6 @@
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
 import android.provider.Settings;
-import android.support.provider.DocumentArchiveHelper;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
@@ -101,7 +100,6 @@
 
     private StorageManager mStorageManager;
     private Handler mHandler;
-    private DocumentArchiveHelper mArchiveHelper;
 
     private final Object mRootsLock = new Object();
 
@@ -115,7 +113,6 @@
     public boolean onCreate() {
         mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
         mHandler = new Handler();
-        mArchiveHelper = new DocumentArchiveHelper(this, (char) 0);
 
         updateVolumes();
         return true;
@@ -377,10 +374,6 @@
         }
 
         final String mimeType = getTypeForFile(file);
-        if (mArchiveHelper.isSupportedArchiveType(mimeType)) {
-            flags |= Document.FLAG_ARCHIVE;
-        }
-
         final String displayName = file.getName();
         if (mimeType.startsWith("image/")) {
             flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
@@ -392,7 +385,6 @@
         row.add(Document.COLUMN_SIZE, file.length());
         row.add(Document.COLUMN_MIME_TYPE, mimeType);
         row.add(Document.COLUMN_FLAGS, flags);
-        row.add(DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH, file.getPath());
 
         // Only publish dates reasonably after epoch
         long lastModified = file.lastModified();
@@ -421,14 +413,6 @@
     @Override
     public boolean isChildDocument(String parentDocId, String docId) {
         try {
-            if (mArchiveHelper.isArchivedDocument(docId)) {
-                return mArchiveHelper.isChildDocument(parentDocId, docId);
-            }
-            // Archives do not contain regular files.
-            if (mArchiveHelper.isArchivedDocument(parentDocId)) {
-                return false;
-            }
-
             final File parent = getFileForDocId(parentDocId).getCanonicalFile();
             final File doc = getFileForDocId(docId).getCanonicalFile();
             return FileUtils.contains(parent, doc);
@@ -473,10 +457,7 @@
         displayName = FileUtils.buildValidFatFilename(displayName);
 
         final File before = getFileForDocId(docId);
-        final File after = new File(before.getParentFile(), displayName);
-        if (after.exists()) {
-            throw new IllegalStateException("Already exists " + after);
-        }
+        final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
         if (!before.renameTo(after)) {
             throw new IllegalStateException("Failed to rename to " + after);
         }
@@ -541,10 +522,6 @@
     @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.queryDocument(documentId, projection);
-        }
-
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
         includeFile(result, documentId, null);
         return result;
@@ -554,11 +531,6 @@
     public Cursor queryChildDocuments(
             String parentDocumentId, String[] projection, String sortOrder)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(parentDocumentId) ||
-                mArchiveHelper.isSupportedArchiveType(getDocumentType(parentDocumentId))) {
-            return mArchiveHelper.queryChildDocuments(parentDocumentId, projection, sortOrder);
-        }
-
         final File parent = getFileForDocId(parentDocumentId);
         final MatrixCursor result = new DirectoryCursor(
                 resolveDocumentProjection(projection), parentDocumentId, parent);
@@ -573,6 +545,7 @@
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
 
+        query = query.toLowerCase();
         final File parent;
         synchronized (mRootsLock) {
             parent = mRoots.get(rootId).path;
@@ -614,10 +587,6 @@
 
     @Override
     public String getDocumentType(String documentId) throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.getDocumentType(documentId);
-        }
-
         final File file = getFileForDocId(documentId);
         return getTypeForFile(file);
     }
@@ -626,10 +595,6 @@
     public ParcelFileDescriptor openDocument(
             String documentId, String mode, CancellationSignal signal)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.openDocument(documentId, mode, signal);
-        }
-
         final File file = getFileForDocId(documentId);
         final File visibleFile = getFileForDocId(documentId, true);
 
@@ -658,10 +623,6 @@
     public AssetFileDescriptor openDocumentThumbnail(
             String documentId, Point sizeHint, CancellationSignal signal)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.openDocumentThumbnail(documentId, sizeHint, signal);
-        }
-
         final File file = getFileForDocId(documentId);
         return DocumentsContract.openImageThumbnail(file);
     }
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index ebea6ee..b98a253 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -128,5 +128,5 @@
       <item quantity="one">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
       <item quantity="other">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
     </plurals>
-    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Kan ikke genkendes"</string>
+    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ikke genkendt"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 527c8e6..4a1d67b 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -34,7 +34,7 @@
     <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"Laddas snabbt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"Laddas långsamt"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Anslut din laddare."</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tryck på Meny om du vill låsa upp."</string>
+    <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tryck på Meny för att låsa upp."</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Nätverk låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Inget SIM-kort"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Inget SIM-kort i surfplattan."</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 8d41145..0474df7 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -28,13 +28,16 @@
 import android.telecom.TelecomManager;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.policy.EmergencyAffordanceManager;
 
 /**
  * This class implements a smart emergency button that updates itself based
@@ -51,7 +54,10 @@
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
     private static final String LOG_TAG = "EmergencyButton";
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
 
+    private int mDownX;
+    private int mDownY;
     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -64,6 +70,7 @@
             updateEmergencyCallButton();
         }
     };
+    private boolean mLongPressWasDragged;
 
     public interface EmergencyButtonCallback {
         public void onEmergencyButtonClickedWhenInCall();
@@ -86,6 +93,7 @@
                 com.android.internal.R.bool.config_voice_capable);
         mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
     }
 
     @Override
@@ -110,10 +118,45 @@
                 takeEmergencyCallAction();
             }
         });
+        setOnLongClickListener(new OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                if (!mLongPressWasDragged
+                        && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+                    mEmergencyAffordanceManager.performEmergencyCall();
+                    return true;
+                }
+                return false;
+            }
+        });
         updateEmergencyCallButton();
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mDownX = x;
+            mDownY = y;
+            mLongPressWasDragged = false;
+        } else {
+            final int xDiff = Math.abs(x - mDownX);
+            final int yDiff = Math.abs(y - mDownY);
+            int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+            if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
+                mLongPressWasDragged = true;
+            }
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    public boolean performLongClick() {
+        return super.performLongClick();
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         updateEmergencyCallButton();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 4f5152a..285b1ae 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -16,12 +16,8 @@
 
 package com.android.keyguard;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.RenderNode;
-import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
@@ -144,9 +140,10 @@
         setTranslationY(0);
         AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
                 mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? mDisappearAnimationUtils
-                : mDisappearAnimationUtilsLocked;
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+                .needsSlowUnlockTransition()
+                        ? mDisappearAnimationUtilsLocked
+                        : mDisappearAnimationUtils;
         disappearAnimationUtils.startAnimation2d(mViews,
                 new Runnable() {
                     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 69eb538..7d1a6fb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -408,9 +408,9 @@
 
     @Override
     public boolean startDisappearAnimation(final Runnable finishRunnable) {
-        float durationMultiplier = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? 1f
-                : DISAPPEAR_MULTIPLIER_LOCKED;
+        float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
+                ? DISAPPEAR_MULTIPLIER_LOCKED
+                : 1f;
         mLockPatternView.clearPattern();
         enableClipping(false);
         setTranslationY(0);
@@ -419,9 +419,10 @@
                 -mDisappearAnimationUtils.getStartTranslation(),
                 mDisappearAnimationUtils.getInterpolator());
 
-        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor.isUserUnlocked()
-                ? mDisappearAnimationUtils
-                : mDisappearAnimationUtilsLocked;
+        DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+                .needsSlowUnlockTransition()
+                        ? mDisappearAnimationUtilsLocked
+                        : mDisappearAnimationUtils;
         disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
                 () -> {
                     enableClipping(true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2c61372..288b954 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,14 +29,17 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
-import android.app.IUserSwitchObserver;
 import android.app.PendingIntent;
+import android.app.UserSwitchObserver;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.hardware.fingerprint.FingerprintManager;
@@ -108,12 +111,6 @@
 
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
-    /**
-     * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a
-     * strong auth method like password, PIN or pattern.
-     */
-    private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000;
-
     // Callback messages
     private static final int MSG_TIME_UPDATE = 301;
     private static final int MSG_BATTERY_UPDATE = 302;
@@ -138,6 +135,7 @@
     private static final int MSG_SERVICE_STATE_CHANGE = 330;
     private static final int MSG_SCREEN_TURNED_ON = 331;
     private static final int MSG_SCREEN_TURNED_OFF = 332;
+    private static final int MSG_DREAMING_STATE_CHANGED = 333;
 
     /** Fingerprint state: Not listening to fingerprint. */
     private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -159,6 +157,9 @@
 
     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
 
+    private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
+            "com.android.settings", "com.android.settings.FallbackHome");
+
     private static KeyguardUpdateMonitor sInstance;
 
     private final Context mContext;
@@ -177,7 +178,8 @@
     private boolean mGoingToSleep;
     private boolean mBouncer;
     private boolean mBootCompleted;
-    private boolean mUserUnlocked;
+    private boolean mNeedsSlowUnlockTransition;
+    private boolean mHasLockscreenWallpaper;
 
     // Device provisioning state
     private boolean mDeviceProvisioned;
@@ -286,6 +288,9 @@
                     handleScreenTurnedOff();
                     Trace.endSection();
                     break;
+                case MSG_DREAMING_STATE_CHANGED:
+                    handleDreamingStateChanged(msg.arg1);
+                    break;
             }
         }
     };
@@ -379,7 +384,7 @@
     }
 
     /** @return List of SubscriptionInfo records, maybe empty but never null */
-    List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
+    public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> sil = mSubscriptionInfo;
         if (sil == null || forceReload) {
             sil = mSubscriptionManager.getActiveSubscriptionInfoList();
@@ -571,8 +576,8 @@
                 && !hasFingerprintUnlockTimedOut(sCurrentUser);
     }
 
-    public boolean isUserUnlocked() {
-        return mUserUnlocked;
+    public boolean needsSlowUnlockTransition() {
+        return mNeedsSlowUnlockTransition;
     }
 
     public StrongAuthTracker getStrongAuthTracker() {
@@ -597,7 +602,10 @@
     }
 
     private void scheduleStrongAuthTimeout() {
-        long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS;
+        final DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null,
+                sCurrentUser);
         Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT);
         intent.putExtra(USER_ID, sCurrentUser);
         PendingIntent sender = PendingIntent.getBroadcast(mContext,
@@ -983,6 +991,17 @@
         }
     }
 
+    private void handleDreamingStateChanged(int dreamStart) {
+        final int count = mCallbacks.size();
+        boolean showingDream = dreamStart == 1;
+        for (int i = 0; i < count; i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onDreamingStateChanged(showingDream);
+            }
+        }
+    }
+
     /**
      * IMPORTANT: Must be called from UI thread.
      */
@@ -1052,7 +1071,7 @@
         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new IUserSwitchObserver.Stub() {
+                    new UserSwitchObserver() {
                         @Override
                         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
@@ -1063,10 +1082,6 @@
                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
                                     newUserId, 0));
                         }
-                        @Override
-                        public void onForegroundProfileSwitch(int newProfileId) {
-                            // Ignore.
-                        }
                     }, TAG);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
@@ -1173,6 +1188,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() {
@@ -1413,7 +1452,18 @@
     private void handleKeyguardReset() {
         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
         updateFingerprintListeningState();
-        mUserUnlocked = mUserManager.isUserUnlocked(getCurrentUser());
+        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
+    }
+
+    private boolean resolveNeedsSlowUnlockTransition() {
+        if (mUserManager.isUserUnlocked(getCurrentUser())) {
+            return false;
+        }
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME);
+        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
+                0 /* flags */);
+        return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName());
     }
 
     /**
@@ -1697,6 +1747,14 @@
         mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF);
     }
 
+    public void dispatchDreamingStarted() {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 1, 0));
+    }
+
+    public void dispatchDreamingStopped() {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 0, 0));
+    }
+
     public boolean isDeviceInteractive() {
         return mDeviceInteractive;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index bd6c51c..eb29d9b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -240,4 +240,15 @@
      * has changed.
      */
     public void onStrongAuthStateChanged(int userId) { }
+
+    /**
+     * Called when the state whether we have a lockscreen wallpaper has changed.
+     */
+    public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { }
+
+    /**
+     * Called when the dream's window state is changed.
+     * @param dreaming true if the dream's window has been created and is visible
+     */
+    public void onDreamingStateChanged(boolean dreaming) { }
 }
diff --git a/packages/MtpDocumentsProvider/res/values-gl-rES/strings.xml b/packages/MtpDocumentsProvider/res/values-gl-rES/strings.xml
index 54bf4a9..7e61c7c 100644
--- a/packages/MtpDocumentsProvider/res/values-gl-rES/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-gl-rES/strings.xml
@@ -19,7 +19,7 @@
     <string name="app_label" msgid="6271216747302322594">"Host MTP"</string>
     <string name="downloads_app_label" msgid="7120690641874849726">"Descargas"</string>
     <string name="root_name" msgid="5819495383921089536">"<xliff:g id="STORAGE_NAME">%2$s</xliff:g> de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
-    <string name="accessing_notification_title" msgid="3030133609230917944">"Accedendo aos ficheiros de <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+    <string name="accessing_notification_title" msgid="3030133609230917944">"Accedendo aos ficheiros do dispositivo <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
     <string name="error_busy_device" msgid="3997316850357386589">"O outro dispositivo está ocupado. Non podes transferir ficheiros ata que estea dispoñible."</string>
     <string name="error_locked_device" msgid="7557872102188356147">"Non se atopou ningún ficheiro. Se o outro dispositivo está bloqueado, desbloquéao e téntao de novo."</string>
 </resources>
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/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 2db6fb0..31a776c 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -16,7 +16,6 @@
 
 <com.android.printspooler.widget.PrintContentView
         xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:printspooler="http://schemas.android.com/apk/res/com.android.printspooler"
     android:id="@+id/options_content"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent">
@@ -28,12 +27,14 @@
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:paddingStart="8dip"
+        android:layout_marginEnd="16dp"
         android:elevation="@dimen/preview_controls_elevation"
         android:background="?android:attr/colorPrimary">
 
         <Spinner
             android:id="@+id/destination_spinner"
-            android:layout_width="@dimen/preview_destination_spinner_width"
+            android:layout_width="wrap_content"
+            android:minWidth="@dimen/preview_destination_spinner_width"
             android:layout_height="wrap_content"
             android:layout_marginTop="4dip"
             android:dropDownWidth="wrap_content"
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 103c157..0d8a90a 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -16,7 +16,8 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
-      android:layout_height="?android:attr/listPreferredItemHeightSmall"
+      android:layout_height="wrap_content"
+      android:minHeight="?android:attr/listPreferredItemHeightSmall"
       style="?android:attr/spinnerItemStyle"
       android:orientation="horizontal"
       android:gravity="start|center_vertical">
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index ec12ba2..885f549 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -30,7 +30,7 @@
     <string name="destination_default_text" msgid="5422708056807065710">"اختر طابعة"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"جميع الصفحات وعددها <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="template_page_range" msgid="428638530038286328">"النطاق <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
-    <string name="pages_range_example" msgid="8558694453556945172">"مثلاً، ۱—۵،‏۹،۷—۱۰"</string>
+    <string name="pages_range_example" msgid="8558694453556945172">"مثلاً، ١—٥،‏٨،‏١١—١٣"</string>
     <string name="print_preview" msgid="8010217796057763343">"معاينة قبل الطباعة"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"‏تثبيت برنامج عرض PDF للمعاينة"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"تعطّل تطبيق الطباعة"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 6cbc657..62119ef 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -29,7 +29,7 @@
     <string name="label_pages" msgid="7768589729282182230">"ページ"</string>
     <string name="destination_default_text" msgid="5422708056807065710">"プリンタを選択"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ページすべて"</string>
-    <string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ページ分"</string>
+    <string name="template_page_range" msgid="428638530038286328">"範囲選択(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ページ内)"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"例: 1-5,8,11-13"</string>
     <string name="print_preview" msgid="8010217796057763343">"印刷プレビュー"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"プレビュー用PDFビューアをインストール"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 3ce49aa..ef3ea16 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -84,7 +84,7 @@
     <string name="cancel" msgid="4373674107267141885">"ರದ್ದುಮಾಡು"</string>
     <string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ಮುದ್ರಕಕ್ಕೆ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
-    <string name="reason_unknown" msgid="5507940196503246139">"ಅಜ್ಞಾತ"</string>
+    <string name="reason_unknown" msgid="5507940196503246139">"ಅಪರಿಚಿತ"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ಬಳಸುವುದೇ?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"ನಿಮ್ಮ ಡಾಕ್ಯುಮೆಂಟ್‌ ಪ್ರಿಂಟರ್‌ಗೆ ಹೋಗುವ ಸಂದರ್ಭದಲ್ಲಿ ಒಂದು ಅಥವಾ ಅದಕ್ಕಿಂತ ಹೆಚ್ಚು ಸರ್ವರ್‌ಗಳ ಮೂಲಕ ಹಾದು ಹೋಗಬಹುದು."</string>
   <string-array name="color_mode_labels">
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/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 1d50a24..23c6615 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -46,7 +46,6 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.print.IPrintDocumentAdapter;
 import android.print.PageRange;
@@ -760,6 +759,13 @@
                 mPrintJob.setPrinterId(printerInfo.getId());
                 mPrintJob.setPrinterName(printerInfo.getName());
 
+                if (canPrint(printerInfo)) {
+                    updatePrintAttributesFromCapabilities(printerInfo.getCapabilities());
+                    onPrinterAvailable(printerInfo);
+                } else {
+                    onPrinterUnavailable(printerInfo);
+                }
+
                 mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
 
                 MetricsLogger.action(this, MetricsEvent.ACTION_PRINTER_SELECT_ALL,
@@ -1359,8 +1365,8 @@
         // Page range
         mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
         mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
-        mPageRangeEditText.setVisibility(View.INVISIBLE);
-        mPageRangeTitle.setVisibility(View.INVISIBLE);
+        mPageRangeEditText.setVisibility(View.GONE);
+        mPageRangeTitle.setVisibility(View.GONE);
         mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
         mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
 
@@ -1881,8 +1887,8 @@
                         }
                     } else {
                         mPageRangeEditText.setEnabled(false);
-                        mPageRangeEditText.setVisibility(View.INVISIBLE);
-                        mPageRangeTitle.setVisibility(View.INVISIBLE);
+                        mPageRangeEditText.setVisibility(View.GONE);
+                        mPageRangeTitle.setVisibility(View.GONE);
                     }
                 }
             } else {
@@ -1892,8 +1898,8 @@
                 }
                 mRangeOptionsSpinner.setEnabled(false);
                 mPageRangeEditText.setEnabled(false);
-                mPageRangeEditText.setVisibility(View.INVISIBLE);
-                mPageRangeTitle.setVisibility(View.INVISIBLE);
+                mPageRangeEditText.setVisibility(View.GONE);
+                mPageRangeTitle.setVisibility(View.GONE);
             }
         }
 
@@ -2046,7 +2052,7 @@
     }
 
     public void onPrinterUnavailable(PrinterInfo printer) {
-        if (mCurrentPrinter.getId().equals(printer.getId())) {
+        if (mCurrentPrinter == null || mCurrentPrinter.getId().equals(printer.getId())) {
             setState(STATE_PRINTER_UNAVAILABLE);
             mPrintedDocument.cancel(false);
             ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
@@ -2305,8 +2311,7 @@
         public int getPrinterIndex(PrinterId printerId) {
             for (int i = 0; i < getCount(); i++) {
                 PrinterHolder printerHolder = (PrinterHolder) getItem(i);
-                if (printerHolder != null && !printerHolder.removed
-                        && printerHolder.printer.getId().equals(printerId)) {
+                if (printerHolder != null && printerHolder.printer.getId().equals(printerId)) {
                     return i;
                 }
             }
@@ -2535,7 +2540,11 @@
                 if (updatedPrinter != null) {
                     printerHolder.printer = updatedPrinter;
                     printerHolder.removed = false;
-                    onPrinterAvailable(printerHolder.printer);
+                    if (canPrint(printerHolder.printer)) {
+                        onPrinterAvailable(printerHolder.printer);
+                    } else {
+                        onPrinterUnavailable(printerHolder.printer);
+                    }
                     newPrinterHolders.add(printerHolder);
                 } else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
                     printerHolder.removed = true;
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index 1098a8e..ad07283 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -19,3 +19,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# For the test package.
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0ca36f6..20e3f6f 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-verbinding het misluk"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Stawingsprobleem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang bespeur nie, sal nie outomaties herkoppel nie."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sal nie outomaties koppel nie"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang nie"</string>
     <string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Gekoppel via Wi-Fi-assistent"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
@@ -341,6 +342,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..e4455a4 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"የWiFi ግንኙነት መሰናከል"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"የማረጋገጫ ችግር"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ምንም የበይነ መረብ መዳረሻ ተፈልጎ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"በራስ-ሰር አይገናኝም"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
     <string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
@@ -341,6 +342,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..24b51ec 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏أخفق اتصال WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"حدثت مشكلة في المصادقة"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"لم يتم اكتشاف اتصال بالإنترنت."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"لن يتم الاتصال تلقائيًا"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"لا يتوفر اتصال بالإنترنت"</string>
     <string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏تم الاتصال عبر %1$s"</string>
@@ -329,7 +330,7 @@
     <string name="home" msgid="3256884684164448244">"الشاشة الرئيسية للإعدادات"</string>
   <string-array name="battery_labels">
     <item msgid="8494684293649631252">"٠‏٪"</item>
-    <item msgid="8934126114226089439">"٪۵۰"</item>
+    <item msgid="8934126114226089439">"٥٠٪"</item>
     <item msgid="1286113608943010849">"٪۱۰۰"</item>
   </string-array>
     <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -341,6 +342,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..5eb7a00 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi Bağlantı Uğursuzluğu"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikasiya problemi"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik qoşulmayacaq"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"İnternet girişi yoxdur"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi köməkçisi vasitəsilə qoşulub"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
@@ -341,6 +342,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..1acc445 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi veza je otkazala"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem sa potvrdom autentičnosti"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automatsko povezivanje nije uspelo"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezano preko Wi‑Fi pomoćnika"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
@@ -341,6 +342,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..0e3faca 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Доступ да інтэрнэту не выяўлены, аўтаматычнае перападлучэнне не адбудзецца."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не будзе аўтаматычна падключацца"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Няма доступу да інтэрнэту"</string>
     <string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Падлучана праз памочніка Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
@@ -341,6 +342,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..1d618d7 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Неуспешна връзка с Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем при удостоверяването"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е открит достъп до интернет. Няма да се свърже отново автоматично."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Няма да се свърже автоматично"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Няма достъп до интернет"</string>
     <string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Установена е връзка чрез помощника за Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
@@ -341,6 +342,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..c094d27 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi সংযোগের ব্যর্থতা"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"প্রমাণীকরণ সমস্যা"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্রিয়ভাবে সংযোগ করবে না"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সংরক্ষিত"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"ওয়াই-ফাই সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
@@ -341,6 +342,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..b7a7d29 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se automatski povezati"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
@@ -341,6 +342,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..0d696d5 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de connexió Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema d\'autenticació"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No s\'ha detectat accés a Internet, no s\'hi tornarà a connectar automàticament."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No es connectarà automàticament"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No hi ha accés a Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
@@ -341,6 +342,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..486819a 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Selhání připojení Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s ověřením"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Připojení nebude automaticky navázáno"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nebyl zjištěn žádný přístup k internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
@@ -341,6 +342,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..af4bf05 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-forbindelsesfejl"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem med godkendelse"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Der oprettes ikke automatisk forbindelse"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetadgang"</string>
     <string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Forbindelse via Wi-Fi-assistent"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
@@ -341,6 +342,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..e4da20d 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN-Verbindungsfehler"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentifizierungsproblem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Keine Internetverbindung erkannt, es kann nicht automatisch eine Verbindung hergestellt werden."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Kein automatischer Verbindungsaufbau"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Kein Internetzugriff"</string>
     <string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Über WLAN-Assistenten verbunden"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
@@ -341,6 +342,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..715b6c4 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Αποτυχία σύνδεσης Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Πρόβλημα ελέγχου ταυτότητας"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Δεν εντοπίστηκε καμία πρόσβαση στο διαδίκτυο, δεν θα γίνει αυτόματη επανασύνδεση."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Δεν θα συνδεθεί αυτόματα"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
     <string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
@@ -341,6 +342,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..f3bc540 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -341,6 +342,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..f3bc540 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -341,6 +342,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..f3bc540 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -341,6 +342,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..8f91cb7 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se conectará automáticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No se detectó acceso a Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexión por asistente de Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
@@ -341,6 +342,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..fc8da79 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Error de autenticación"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"No se ha detectado acceso a Internet, no se volverá a conectar automáticamente."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se establecerá conexión automáticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"No se ha detectado acceso a Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado a través de asistente Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
@@ -173,7 +174,7 @@
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/No permitir búsquedas de Wi-Fi basadas en la cantidad de tráfico de datos presente en la interfaz"</string>
-    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños del búfer de Logger"</string>
+    <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de registrador"</string>
     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string>
     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"¿Borrar almacenamiento continuo del registrador?"</string>
     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cuando ya no supervisamos la actividad con el registrador de forma continua, estamos obligados a borrar los datos del registrador almacenados en el dispositivo."</string>
@@ -341,6 +342,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..d28818b 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-ühenduse viga"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentimise probleem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automaatselt ei ühendata"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Interneti-ühendus puudub"</string>
     <string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Ühendatud WiFi-abi kaudu"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
@@ -341,6 +342,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..a975971 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ezin izan da konektatu Wi-Fi sarera"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikazio-arazoa"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ez da konektatuko automatikoki"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ezin da konektatu Internetera"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
@@ -341,6 +342,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..8f613aa 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏اتصال Wi-Fi برقرار نشد"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"مشکل احراز هویت"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"دسترسی به اینترنت شناسایی نشد، به صورت خودکار وصل نمی‌شود."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"اتصال به‌صورت خودکار انجام نمی‌شود"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"دسترسی به اینترنت وجود ندارد"</string>
     <string name="saved_network" msgid="4352716707126620811">"ذخیره‌شده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"‏متصل شده از طریق دستیار Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏متصل از طریق %1$s"</string>
@@ -183,7 +184,7 @@
     <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"‏انتخاب پیکربندی USB"</string>
     <string name="allow_mock_location" msgid="2787962564578664888">"مکان‌های کاذب مجاز هستند"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"مکان‌های کاذب مجاز هستند"</string>
-    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن بازبینی ویژگی بازدید"</string>
+    <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن نمایش بازبینی ویژگی"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏داده سلولی همیشه فعال نگه داشته می‌شود، حتی وقتی Wi-Fi فعال است (برای جابه‌جایی سریع شبکه)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"‏اشکال‌زدایی USB انجام شود؟"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"‏اشکال‌زدایی USB فقط برای اهداف برنامه‌نویسی در نظر گرفته شده است. از آن برای رونوشت‌برداری داده بین رایانه و دستگاهتان، نصب برنامه‌ها در دستگاهتان بدون اعلان و خواندن داده‌های گزارش استفاده کنید."</string>
@@ -341,6 +342,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..ea2a17f 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-yhteysvirhe"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Todennusvirhe"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetyhteyttä ei havaittu, yhteyttä ei muodosteta automaattisesti uudelleen."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Yhteyttä ei muodosteta automaattisesti"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ei internetyhteyttä"</string>
     <string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
@@ -341,6 +342,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..3001a69 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de connexion Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
@@ -341,6 +342,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..c00a030 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de la connexion Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification."</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté via l\'assistant Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
@@ -341,6 +342,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..03cf223 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Erro na conexión wifi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Non se detectou acceso a Internet e non se volverá conectar automaticamente."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non se conectará automaticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Non hai acceso a Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado ao asistente de wifi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
@@ -341,6 +342,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..737af54 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi કનેક્શન નિષ્ફળ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"પ્રમાણીકરણ સમસ્યા"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ શોધાયું નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"આપમેળે કનેક્ટ કરશે નહીં"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi સહાયક દ્વારા કનેક્ટ થયું"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
@@ -341,6 +342,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..efefca3 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफ़ाई कनेक्‍शन विफलता"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप पुन: कनेक्‍ट नहीं हो सकता."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"अपने आप कनेक्ट नहीं होगा"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"कोई इंटरनेट एक्सेस नहीं"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
@@ -341,6 +342,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..8990536 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezivanje s Wi-Fi-jem nije uspjelo"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem u autentifikaciji"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se povezati automatski"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Spremljeno: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani putem pomoćnika za Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
@@ -341,6 +342,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..c557161 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-kapcsolati hiba"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Azonosítási probléma"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nem csatlakozik automatikusan"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nincs internet-hozzáférés"</string>
     <string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Csatlakozva Wi‑Fi-segéddel"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
@@ -341,6 +342,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..41556dc 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi կապի ձախողում"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Նույնականացման խնդիր"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ինտերնետի հասանելիություն չկա. ավտոմատ կերպով կրկին չի միանա:"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ավտոմատ միացում չի կատարվի"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ինտերնետ կապ չկա"</string>
     <string name="saved_network" msgid="4352716707126620811">"Պահել է հետևյալ օգտվողը՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
@@ -38,7 +39,7 @@
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Անջատվում է..."</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"Միանում է..."</string>
     <string name="bluetooth_connected" msgid="6038755206916626419">"Միացված է"</string>
-    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգավորում..."</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգակցում..."</string>
     <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Միացված (առանց հեռախոսի)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Միացված է (առանց մեդիա)"</string>
     <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Միացված է (հաղորդագրությանը մուտք չկա)"</string>
@@ -72,7 +73,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Զուգավորել"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Զուգավորել"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Չեղարկել"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգավորում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Զուգակցում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Չհաջողվեց զուգավորել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Հնարավոր չեղավ զուգավորվել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ սխալ PIN-ի կամ անցաբառի պատճառով:."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Հնարավոր չէ կապ հաստատել  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
@@ -341,6 +342,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..039457d 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah autentikasi"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Tidak akan tersambung otomatis"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Tidak ada akses internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Terhubung melalui Asisten Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
@@ -341,6 +342,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..a3126bf 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-tengingarvilla"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Vandamál við auðkenningu"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Enginn netaðgangur fannst; endurtengist ekki sjálfkrafa."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Mun ekki tengjast sjálfkrafa"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Enginn netaðgangur"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Tengt í gegnum Wi-Fi aðstoð"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
@@ -341,6 +342,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..bff3bb7 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Errore connessione Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema di autenticazione"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nessun accesso a Internet rilevato, non verrà eseguita la riconnessione automatica."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non verrà eseguita la connessione automatica"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nessun accesso a Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Connesso tramite assistente Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
@@ -191,7 +192,7 @@
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Consentire impostazioni di sviluppo?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
-    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le applicazioni installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
+    <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
     <string name="enable_terminal_summary" msgid="67667852659359206">"Abilita l\'app Terminale che offre l\'accesso alla shell locale"</string>
@@ -328,9 +329,9 @@
     <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="8934126114226089439">"50%%"</item>
-    <item msgid="1286113608943010849">"100%%"</item>
+    <item msgid="8494684293649631252">"0%"</item>
+    <item msgid="8934126114226089439">"50%"</item>
+    <item msgid="1286113608943010849">"100%"</item>
   </string-array>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
@@ -341,6 +342,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..4d794fc 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏כשל בחיבור Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"לא יתבצע חיבור באופן אוטומטי"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"אין גישה לאינטרנט"</string>
     <string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏מחובר דרך %1$s"</string>
@@ -341,6 +342,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..4c4eed0 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"インターネットアクセスを検出できないため、自動的に再接続されません。"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"自動的に接続されません"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"インターネットに接続していません"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
@@ -343,6 +344,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..2142fa3 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi კავშირის შეფერხება"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ავთენტიკაციის პრობლემა"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ინტერნეტთან წვდომის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ავტომატურად დაკავშირება ვერ მოხერხდება"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ინტერნეტთან კავშირი არ არის"</string>
     <string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"დაკავშირებულია Wi-Fi თანაშემწით"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
@@ -341,6 +342,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..e00e820 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке қатынас анықталмады, автоматты түрде қайта қосылу орындалмайды."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматты қосылмайды"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетпен байланыс жоқ"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
@@ -341,6 +342,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..3593c4a 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ការ​ភ្ជាប់​ WiFi បរាជ័យ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"បញ្ហា​ក្នុង​ការ​ផ្ទៀងផ្ទាត់"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"នៅ​ក្រៅ​តំបន់"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"រក​មិន​ឃើញ​ការ​ចូល​ដំណើរការ​អ៊ីនធឺណិត, នឹង​មិន​ភ្ជាប់​ឡើង​វិញ​ដោយ​ស្វ័យ​ប្រវត្តិ​ទេ។"</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
@@ -341,6 +344,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..312beae 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ಸಂಪರ್ಕ ವಿಫಲತೆ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ಪ್ರಮಾಣೀಕರಣ ಸಮಸ್ಯೆ"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ರಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -93,7 +94,7 @@
     <string name="tether_settings_title_all" msgid="8356136101061143841">"ಟೆಥರಿಂಗ್ &amp; ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
     <string name="managed_user_title" msgid="8109605045406748842">"ಎಲ್ಲ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
     <string name="user_guest" msgid="8475274842845401871">"ಅತಿಥಿ"</string>
-    <string name="unknown" msgid="1592123443519355854">"ಅಜ್ಞಾತ"</string>
+    <string name="unknown" msgid="1592123443519355854">"ಅಪರಿಚಿತ"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"ಬಳಕೆದಾರ: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="313159469856372621">"ಕೆಲವು ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="launch_defaults_none" msgid="4241129108140034876">"ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿಲ್ಲ"</string>
@@ -312,7 +313,7 @@
     <string name="power_charging_duration_usb_short" msgid="941854728040426399">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_duration_wireless" msgid="1829295708243159464">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ವೈರ್‌‌ಲೆಸ್‌ನಿಂದ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
     <string name="power_charging_duration_wireless_short" msgid="1642664799869599476">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಜ್ಞಾತ"</string>
+    <string name="battery_info_status_unknown" msgid="196130600938058547">"ಅಪರಿಚಿತ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_charging_ac" msgid="2909861890674399949">"AC ನಲ್ಲಿ ಚಾರ್ಜ್‌"</string>
     <string name="battery_info_status_charging_ac_short" msgid="7431401092096415502">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
@@ -341,6 +342,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..72b5fe3 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi 연결 실패"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"인증 문제"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"자동으로 연결되지 않습니다."</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"인터넷에 연결되어 있지 않습니다."</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi 도우미를 통해 연결됨"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
@@ -341,6 +342,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..a5386c8 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi туташуусу бузулду"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Аутентификация маселеси бар"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке кирүү мүмкүнчүлүгү табылган жок, андыктан автоматтык түрдө кайра туташпайт."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматтык түрдө туташпайт"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетке туташпай турат"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
@@ -341,6 +342,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..2dc4fd7 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"​ການ​ເຊື່ອມ​ຕໍ່ WiFi ລົ້ມ​ເຫຼວ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ບັນຫາການພິສູດຢືນຢັນ"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"​ບໍ່​ພົບ​ການ​ເຊື່ອມ​ຕໍ່​ອິນ​ເຕີ​ເນັດ​, ຈະ​ບໍ່​ຖືກ​ເຊື່ອມ​ຕໍ່​ໃໝ່​ໂດຍ​ອັດ​ຕະ​ໂນ​ມັດ."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດ"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
     <string name="saved_network" msgid="4352716707126620811">"ບັນທຶກ​​​ໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
@@ -341,6 +342,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..51fb7fa 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"„Wi-Fi“ ryšio triktis"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikavimo problema"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nebus automatiškai prisijungiama"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nėra interneto ryšio"</string>
     <string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
@@ -341,6 +342,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..9d4d055 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi savienojuma kļūme"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentificēšanas problēma"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Savienojums netiks izveidots automātiski"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nav piekļuves internetam"</string>
     <string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
@@ -341,6 +342,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..7521250 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Поврзувањето преку Wi-Fi не успеа"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем со автентикација"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е откриен пристап до интернет, нема автоматски повторно да се поврзете."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не може да се поврзе автоматски"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Нема пристап до Интернет"</string>
     <string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Поврзано преку помошник за Wi-Fismile"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
@@ -341,6 +342,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..fed05c9 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi കണക്ഷൻ പരാജയം"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ആധികാരികമാക്കുന്നതിലെ പ്രശ്‌നം"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"വൈഫൈ അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
@@ -341,6 +344,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..3d32aea 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi холболт амжилтгүй"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Гэрчлэлийн асуудал"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернэт холболт илэрсэнгүй, автоматаар дахин холболт хийгдэхгүй"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматаар холбогдохгүй"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Интернэт холболт алга"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
@@ -341,6 +342,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..e81b5ae 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi कनेक्शन अयशस्वी"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे रीकनेक्ट करणार नाही."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"इंटरनेट प्रवेश नाही"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
@@ -341,6 +342,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..2368d09 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah pengesahan"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Disambungkan melalui Pembantu Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
@@ -341,6 +344,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..95711a4 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ချိတ်ဆက်မှု မအောင်မြင်ပါ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"စစ်မှန်ကြောင်းအတည်ပြုရန်၌ ပြသနာရှိခြင်း"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"မည်သည့် အင်တာနက်မျှမရှိပါ၊ အလိုအလျောက် ပြန်လည်မချိတ်ဆက်ပါ။"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်၏"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
@@ -341,6 +342,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..1a053e2 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-tilkoblingsfeil"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen Internett-tilgang ble funnet. Kan ikke koble til på nytt automatisk."</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Koblet til via en Wi-Fi-assistent"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
@@ -341,6 +344,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..0a7cdab 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"कुनै इन्टरनेट पहुँच पाईएन, स्वचालित रूपमा पुन: जडान छैन।"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वतः जडान हुने छैन"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"इन्टरनेट माथिको पहुँच छैन"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi सहायक द्वारा जोडिएको"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
@@ -341,6 +342,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..27478a4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wifi-verbinding mislukt"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authenticatieprobleem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Er wordt niet automatisch verbinding gemaakt"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang"</string>
     <string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Verbonden via wifi-assistent"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
@@ -341,6 +342,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..d06a88f 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ਕਨੈਕਸ਼ਨ ਅਸਫਲਤਾ"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ਪ੍ਰਮਾਣੀਕਰਨ ਸਮੱਸਿਆ"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਆਟੋਮੈਟਿਕਲੀ ਰੀਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਏਗਾ।"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ਸਹਾਇਕ ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -341,6 +342,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..3c09335 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Błąd połączenia Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem z uwierzytelnianiem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nie można połączyć automatycznie"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Brak dostępu do internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Połączono przez Asystenta Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
@@ -341,6 +342,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..1b46c84 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
@@ -341,6 +342,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..c8be0da 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de ligação Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detetado; não será efetuada uma nova ligação automaticamente."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não é efetuada uma ligação automaticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Ligado através do Assistente de Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
@@ -341,6 +342,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..1b46c84 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
@@ -341,6 +342,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..b022163 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Eroare de conexiune Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problemă la autentificare"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nu s-a detectat acces la internet, nu se va efectua reconectarea automată."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nu se va conecta automat"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nu există acces la internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Conexiune realizată printr-un asistent Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
@@ -341,6 +342,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..3a4e85b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -28,13 +28,14 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ошибка подключения Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Ошибка аутентификации"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Подключение к Интернету отсутствует и не будет восстановлено автоматически."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Подключение не будет выполняться автоматически"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Отсутствует подключение к Интернету"</string>
     <string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Установлено подключение через Ассистента Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Подключено, без Интернета"</string>
-    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Отключено"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Нет подключения"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"Подключение..."</string>
     <string name="bluetooth_connected" msgid="6038755206916626419">"Подключено"</string>
@@ -341,6 +342,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..24779b3 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi සම්බන්ධතාව අසාර්ථකයි"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"සත්‍යාපනයේ ගැටලුවකි"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"අන්තර්ජාල ප්‍රවේශය අනාවරණය වුයේ නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ වීම වූ නැත"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ස්වයංක්‍රිය නැවත සම්බන්ධ නොවනු ඇත"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"අන්තර්ජාල ප්‍රවේශය නැත"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
@@ -341,6 +342,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..e8db85b 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Zlyhanie pripojenia Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s overením totožnosti"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nedôjde k automatickému pripojeniu"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Žiadny prístup k internetu"</string>
     <string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Pripojené pomocou Asistenta Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
@@ -173,8 +174,8 @@
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
     <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Povoliť alebo zakázať funkciu Wifi Roam Scans na základe objemu prenosu údajov v rozhraní"</string>
-    <string name="select_logd_size_title" msgid="7433137108348553508">"Veľkosti vyrovnávacej pamäte denníka"</string>
-    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť na vyrovnávaciu pamäť nástroja denníkov"</string>
+    <string name="select_logd_size_title" msgid="7433137108348553508">"Vyrovnávacia pamäť nástroja denníkov"</string>
+    <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť vyrovnávacej pamäte nástroja denníkov"</string>
     <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Vymazať trvalé úložisko zapisovača do denníka?"</string>
     <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Keď prestaneme monitorovať pomocou trvalého zapisovača do denníka, musíme vymazať jeho dáta, ktoré sa nachádzajú vo vašom zariadení."</string>
     <string name="select_logpersist_title" msgid="7530031344550073166">"Natrvalo ukladať dáta zapisovača do denníka na zariadení"</string>
@@ -186,8 +187,8 @@
     <string name="debug_view_attributes" msgid="6485448367803310384">"Kontrola atribútov zobrazenia"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Vždy ponechávať mobilné dáta aktívne, dokonca aj pri aktívnej sieti Wi‑Fi (na rýchle prepínanie sietí)"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Povoliť ladenie cez USB?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie prostredníctvom USB je určené iba na účely vývoja. Použite ho na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie údajov denníka."</string>
-    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete odvolať prístup k ladeniu cez USB zo všetkých počítačov, ktoré ste predtým autorizovali?"</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"Ladenie cez USB je určené iba na účely vývoja. Možno ho použiť na kopírovanie dát medzi počítačom a zariadením, inštaláciu aplikácií do zariadenia bez upozornenia a čítanie dát denníka."</string>
+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Chcete všetkým v minulosti autorizovaným počítačom odvolať prístup k ladeniu cez USB?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Povoliť nastavenia pre vývojárov?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
@@ -341,6 +342,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..d908e6d 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezava prek Wi-Fi-ja ni uspela"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Težava s preverjanjem pristnosti"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Samodejna vnovična vzpostavitev povezave se ne bo izvedla"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ni dostopa do interneta"</string>
     <string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
@@ -341,6 +342,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..69318a1 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Dështim i lidhjes WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem me vërtetimin"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Nuk u diktua qasje në internet. Lidhja nuk do të realizohet automatikisht."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nuk do të lidhet automatikisht"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Nuk ka qsaje në internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"I lidhur nëpërmjet ndihmësit të Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
@@ -341,6 +342,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..459d92e 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi веза је отказала"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем са потврдом аутентичности"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Аутоматско повезивање није успело"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Нема приступа интернету"</string>
     <string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Повезано преко Wi‑Fi помоћника"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
@@ -341,6 +342,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..d52882a 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-anslutningsfel"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Det går inte att ansluta automatiskt"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetåtkomst"</string>
     <string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Ansluten via Wi-Fi-assistent"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
@@ -341,6 +342,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..6f2e0cb 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Haikuweza Kuunganisha kwenye WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tatizo la uthibitishaji"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Hakuna Ufikiaji kwa Intaneti Uliogunduliwa, haitaweza kuunganisha kiotomatiki."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Haiwezi kuunganisha kiotomatiki"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Hakuna muunganisho wa Intaneti"</string>
     <string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
@@ -341,6 +342,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..5f218e0 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"வைஃபை இணைப்பில் தோல்வி"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"அங்கீகரிப்புச் சிக்கல்"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"தானாக இணைக்கப்படாது"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"இணைய அணுகல் இல்லை"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
@@ -341,6 +342,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..0bd77f7 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi కనెక్షన్ వైఫల్యం"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ప్రామాణీకరణ సమస్య"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
@@ -341,6 +342,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..d8ee2f3 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"การเชื่อมต่อ Wi-Fi ล้มเหลว"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ปัญหาในการตรวจสอบสิทธิ์"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
     <string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
@@ -341,6 +342,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..9b9d26f 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Pagkabigo ng Koneksyon sa WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema sa pagpapatotoo"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Walang Natukoy na Access sa Internet, hindi awtomatikong muling kumonekta."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Hindi awtomatikong kokonekta"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Walang access sa Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Na-save ni <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
@@ -146,7 +147,7 @@
     <string name="vpn_settings_not_available" msgid="956841430176985598">"Hindi available ang mga setting ng VPN para sa user na ito"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"Hindi available ang mga setting ng pagte-theter para sa user na ito"</string>
     <string name="apn_settings_not_available" msgid="7873729032165324000">"Hindi available ang mga setting ng Access Point Name para sa user na ito"</string>
-    <string name="enable_adb" msgid="7982306934419797485">"Pagde-debug ng USB"</string>
+    <string name="enable_adb" msgid="7982306934419797485">"Pag-debug ng USB"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"Debug mode kapag nakakonekta ang USB"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"Bawiin ang mga pahintulot sa pag-debug ng USB"</string>
     <string name="bugreport_in_power" msgid="7923901846375587241">"Shortcut ng ulat sa bug"</string>
@@ -186,8 +187,8 @@
     <string name="debug_view_attributes" msgid="6485448367803310384">"I-enable ang pagsisiyasat sa attribute na view"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Palaging panatilihing aktibo ang mobile data, kahit na aktibo ang Wi‑Fi (para sa mabilis na paglipat ng network)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Payagan ang pag-debug ng USB?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay nilalayon para sa mga layuning pagpapabuti lamang. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng apps sa iyong device nang walang notification, at magbasa ng data ng log."</string>
-    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pagde-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"Ang pag-debug ng USB ay para lang sa mga layuning pag-develop. Gamitin ito upang kumopya ng data sa pagitan ng iyong computer at iyong device, mag-install ng mga app sa iyong device nang walang notification, at magbasa ng data ng log."</string>
+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"Bawiin ang access sa pag-debug ng USB mula sa lahat ng computer na dati mong pinahintulutan?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Payagan ang mga setting ng pag-develop?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
@@ -341,6 +342,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..643b710 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kablosuz Bağlantı Hatası"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Kimlik doğrulama sorunu"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet Erişimi algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
@@ -341,6 +344,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..b1fbef5 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Помилка з’єднання Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблема з автентифікацією"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не під’єднуватиметься автоматично"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Немає доступу до Інтернету"</string>
     <string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
@@ -341,6 +342,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..322b468 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏WiFi کنکشن کی ناکامی"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"توثیق کا مسئلہ"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خود بخود دوبارہ منسلک نہیں ہوگا۔"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"خودکار طور پر منسلک نہیں ہو گا"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏منسلک بذریعہ ‎%1$s"</string>
@@ -341,6 +342,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..09ac4b1 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Aloqada emas"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Internet aloqasi yo‘q"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi yordamchisi orqali ulangan"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
@@ -341,6 +342,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..fa41b45 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Lỗi kết nối WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Sự cố xác thực"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Không phát hiện thấy truy cập Internet nào, mạng sẽ không được tự động kết nối lại."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sẽ không tự động kết nối"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Không có quyền truy cập Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
@@ -341,6 +342,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..2e515da 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -28,7 +28,10 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN 连接失败"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"身份验证出现问题"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"未检测到任何互联网连接,因此不会自动重新连接。"</string>
+    <!-- no translation found for wifi_no_internet_no_reconnect (5724903347310541706) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (3880396223819116454) -->
+    <skip />
     <string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"已连接(通过 WLAN 助手)"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
@@ -186,7 +189,7 @@
     <string name="debug_view_attributes" msgid="6485448367803310384">"启用视图属性检查功能"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"始终开启移动数据网络,即使 WLAN 网络已开启(便于快速切换网络)。"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"是否允许USB调试?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB调试仅适用于开发工作。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用而不发送通知以及读取日志数据。"</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB 调试仅用于开发目的。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用(事先不发通知)以及读取日志数据。"</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"是否针对您之前授权的所有计算机撤消USB调试的访问权限?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"允许开发设置?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
@@ -341,6 +344,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..f6c2f93 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"未能偵測到互聯網連線,因此不會自動重新連線。"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"不會自動連線"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"無法偵測互聯網連線"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> 的儲存"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi-Fi 小幫手連線"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
@@ -341,6 +342,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..df9238a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"未偵測到可用的網際網路連線,系統無法為您自動重新連線。"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"無法自動連線"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"沒有可用的網際網路連線"</string>
     <string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>儲存"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi‑Fi 小幫手連線"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
@@ -341,6 +342,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..fc9e81f 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -28,7 +28,8 @@
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ukwehlulekla koxhumo le-WiFi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Inkinga yokufakazela ubuqiniso"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
-    <string name="wifi_no_internet" msgid="9151470775868728896">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ngeke ize ixhumeke ngokuzenzakalela"</string>
+    <string name="wifi_no_internet" msgid="3880396223819116454">"Akukho ukufinyelela ku-inthanethi"</string>
     <string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_wfa" msgid="3805736726317410714">"Ixhunywe ngomsizi we-Wi-FI"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
@@ -341,6 +342,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..0cf4a41 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -19,4 +19,22 @@
 <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>
+
+    <!-- Whether to send a custom package name with the PSD. translatable="false"-->
+    <bool name="config_sendPackageName">true</bool>
+
+    <!-- Name for the set of keys associating package names -->
+    <string name="config_helpPackageNameKey" translatable="false"></string>
+
+    <!-- Name for the set of values of package names -->
+    <string name="config_helpPackageNameValue" translatable="false"></string>
+
+    <!-- Intent key for the package name keys -->
+    <string name="config_helpIntentExtraKey" translatable="false"></string>
+
+    <!-- Intent key for package name values -->
+    <string name="config_helpIntentNameKey" translatable="false"></string>
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3bdb6fb..1a1aa57 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -64,8 +64,10 @@
     <string name="wifi_disabled_password_failure">Authentication problem</string>
     <!-- Summary for the remembered network but currently not in range. -->
     <string name="wifi_not_in_range">Not in range</string>
+    <!-- Summary for the network but no internet connection was detected. -->
+    <string name="wifi_no_internet_no_reconnect">Won\'t automatically connect</string>
     <!-- Summary for the remembered network but no internet connection was detected. -->
-    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
+    <string name="wifi_no_internet">No Internet access</string>
     <!-- Summary for saved networks -->
     <string name="saved_network">Saved by <xliff:g id="name">%1$s</xliff:g></string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 78e8ea8..381f903 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.net.Uri;
@@ -145,7 +146,7 @@
         try {
             Intent intent = Intent.parseUri(helpUriString,
                     Intent.URI_ANDROID_APP_SCHEME | Intent.URI_INTENT_SCHEME);
-            addIntentParameters(context, intent, backupContext);
+            addIntentParameters(context, intent, backupContext, true /* sendPackageName */);
             ComponentName component = intent.resolveActivity(context.getPackageManager());
             if (component != null) {
                 return intent;
@@ -169,11 +170,28 @@
         return intent;
     }
 
-    public static void addIntentParameters(Context context, Intent intent, String backupContext) {
+    public static void addIntentParameters(Context context, Intent intent, String backupContext,
+            boolean sendPackageName) {
         if (!intent.hasExtra(EXTRA_CONTEXT)) {
             // Insert some context if none exists.
             intent.putExtra(EXTRA_CONTEXT, backupContext);
         }
+
+        Resources resources = context.getResources();
+        boolean includePackageName = resources.getBoolean(R.bool.config_sendPackageName);
+
+        if (sendPackageName && includePackageName) {
+            String[] packageNameKey =
+                    {resources.getString(R.string.config_helpPackageNameKey)};
+            String[] packageNameValue =
+                    {resources.getString(R.string.config_helpPackageNameValue)};
+            String intentExtraKey =
+                    resources.getString(R.string.config_helpIntentExtraKey);
+            String intentNameKey =
+                    resources.getString(R.string.config_helpIntentNameKey);
+            intent.putExtra(intentExtraKey, packageNameKey);
+            intent.putExtra(intentNameKey, packageNameValue);
+        }
         intent.putExtra(EXTRA_THEME, 1 /* Light, dark action bar */);
         TypedArray array = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimary});
         intent.putExtra(EXTRA_PRIMARY_COLOR, array.getColor(0, 0));
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/deviceinfo/PrivateStorageInfo.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java
new file mode 100644
index 0000000..ca8edf5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/PrivateStorageInfo.java
@@ -0,0 +1,81 @@
+/*
+ * 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.deviceinfo;
+
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.util.Log;
+
+import java.io.File;
+import java.util.Objects;
+
+/**
+ * PrivateStorageInfo provides information about the total and free storage on the device.
+ */
+public class PrivateStorageInfo {
+    private static final String TAG = "PrivateStorageInfo";
+    public final long freeBytes;
+    public final long totalBytes;
+
+    private PrivateStorageInfo(long freeBytes, long totalBytes) {
+        this.freeBytes = freeBytes;
+        this.totalBytes = totalBytes;
+    }
+
+    public static PrivateStorageInfo getPrivateStorageInfo(StorageVolumeProvider sm) {
+        long totalInternalStorage = sm.getPrimaryStorageSize();
+        long privateFreeBytes = 0;
+        long privateTotalBytes = 0;
+        for (VolumeInfo info : sm.getVolumes()) {
+            final File path = info.getPath();
+            if (info.getType() != VolumeInfo.TYPE_PRIVATE || path == null) {
+                continue;
+            }
+            privateTotalBytes += getTotalSize(info, totalInternalStorage);
+            privateFreeBytes += path.getFreeSpace();
+        }
+        return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes);
+    }
+
+    /**
+     * Returns the total size in bytes for a given volume info.
+     * @param info Info of the volume to check.
+     * @param totalInternalStorage Total number of bytes in the internal storage to use if the
+     *                             volume is the internal disk.
+     */
+    public static long getTotalSize(VolumeInfo info, long totalInternalStorage) {
+        // Device could have more than one primary storage, which could be located in the
+        // internal flash (UUID_PRIVATE_INTERNAL) or in an external disk.
+        // If it's internal, try to get its total size from StorageManager first
+        // (totalInternalStorage), because that size is more precise because it accounts for
+        // the system partition.
+        if (info.getType() == VolumeInfo.TYPE_PRIVATE
+                && Objects.equals(info.getFsUuid(), StorageManager.UUID_PRIVATE_INTERNAL)
+                && totalInternalStorage > 0) {
+            return totalInternalStorage;
+        } else {
+            final File path = info.getPath();
+            if (path == null) {
+                // Should not happen, caller should have checked.
+                Log.e(TAG, "info's path is null on getTotalSize(): " + info);
+                return 0;
+            }
+            return path.getTotalSpace();
+        }
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.java
new file mode 100644
index 0000000..de76279
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageManagerVolumeProvider.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 com.android.settingslib.deviceinfo;
+
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+
+import java.util.List;
+
+/**
+ * StorageManagerVolumeProvider is a thin wrapper around the StorageManager to provide insight into
+ * the storage volumes on a device.
+ */
+public class StorageManagerVolumeProvider implements StorageVolumeProvider {
+    private StorageManager mStorageManager;
+
+    public StorageManagerVolumeProvider(StorageManager sm) {
+        mStorageManager = sm;
+    }
+
+    @Override
+    public long getPrimaryStorageSize() {
+        return mStorageManager.getPrimaryStorageSize();
+    }
+
+    @Override
+    public List<VolumeInfo> getVolumes() {
+        return mStorageManager.getVolumes();
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 0e3e0d5..5c577f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -126,6 +126,13 @@
          * internal storage. Key is {@link UserHandle}.
          */
         public SparseLongArray usersSize = new SparseLongArray();
+
+        @Override
+        public String toString() {
+            return "MeasurementDetails: [totalSize: " + totalSize + " availSize: " + availSize
+                    + " cacheSize: " + cacheSize + " mediaSize: " + mediaSize
+                    + " miscSize: " + miscSize + "usersSize: " + usersSize + "]";
+        }
     }
 
     public interface MeasurementReceiver {
@@ -435,7 +442,7 @@
     private static long getDirectorySize(IMediaContainerService imcs, File path) {
         try {
             final long size = imcs.calculateDirectorySize(path.toString());
-            Log.d(TAG, "getDirectorySize(" + path + ") returned " + size);
+            if (LOGV) Log.v(TAG, "getDirectorySize(" + path + ") returned " + size);
             return size;
         } catch (Exception e) {
             Log.w(TAG, "Could not read memory from default container service for " + path, e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java
new file mode 100644
index 0000000..95bb18d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageVolumeProvider.java
@@ -0,0 +1,37 @@
+/*
+ * 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.deviceinfo;
+
+import android.os.storage.VolumeInfo;
+
+import java.util.List;
+
+/**
+ * StorageVolumeProvider provides access to the storage volumes on a device for free space
+ * calculations.
+ */
+public interface StorageVolumeProvider {
+    /**
+     * Returns the number of bytes of total storage on the primary storage.
+     */
+    long getPrimaryStorageSize();
+
+    /**
+     * Returns a list of VolumeInfos for the device.
+     */
+    List<VolumeInfo> getVolumes();
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index a99e668..af8fd4c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -23,6 +23,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.AsyncTask;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.MathUtils;
@@ -207,39 +208,41 @@
 
     /**
      * Asynchronously applies display density changes to the specified display.
+     * <p>
+     * The change will be applied to the user specified by the value of
+     * {@link UserHandle#myUserId()} at the time the method is called.
      *
      * @param displayId the identifier of the display to modify
      */
     public static void clearForcedDisplayDensity(final int displayId) {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-                    wm.clearForcedDisplayDensity(displayId);
-                } catch (RemoteException exc) {
-                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
-                }
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(() -> {
+            try {
+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                wm.clearForcedDisplayDensityForUser(displayId, userId);
+            } catch (RemoteException exc) {
+                Log.w(LOG_TAG, "Unable to clear forced display density setting");
             }
         });
     }
 
     /**
      * Asynchronously applies display density changes to the specified display.
+     * <p>
+     * The change will be applied to the user specified by the value of
+     * {@link UserHandle#myUserId()} at the time the method is called.
      *
      * @param displayId the identifier of the display to modify
      * @param density the density to force for the specified display
      */
     public static void setForcedDisplayDensity(final int displayId, final int density) {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-                    wm.setForcedDisplayDensity(displayId, density);
-                } catch (RemoteException exc) {
-                    Log.w(LOG_TAG, "Unable to save forced display density setting");
-                }
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(() -> {
+            try {
+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                wm.setForcedDisplayDensityForUser(displayId, density, userId);
+            } catch (RemoteException exc) {
+                Log.w(LOG_TAG, "Unable to save forced display density setting");
             }
         });
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
new file mode 100644
index 0000000..4ec4f4f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -0,0 +1,34 @@
+/**
+ * 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.drawer;
+
+public final class CategoryKey {
+
+    // Activities in this category shows up in Settings homepage.
+    public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.ia.homepage";
+
+    // Top level category.
+    public static final String CATEGORY_NETWORK = "com.android.settings.category.ia.wireless";
+    public static final String CATEGORY_DEVICE = "com.android.settings.category.ia.device";
+    public static final String CATEGORY_APPS = "com.android.settings.category.ia.apps";
+    public static final String CATEGORY_BATTERY = "com.android.settings.category.ia.battery";
+    public static final String CATEGORY_DISPLAY = "com.android.settings.category.ia.display";
+    public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound";
+    public static final String CATEGORY_STORAGE = "com.android.settings.category.ia.storage";
+    public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
+    public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
+    public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
new file mode 100644
index 0000000..ce16336
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
@@ -0,0 +1,116 @@
+/**
+ * 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.drawer;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.settingslib.applications.InterestingConfigChanges;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CategoryManager {
+
+    private static final String TAG = "CategoryManager";
+
+    private static CategoryManager sInstance;
+    private final InterestingConfigChanges mInterestingConfigChanges;
+
+    // Tile cache (key: <packageName, activityName>, value: tile)
+    private final Map<Pair<String, String>, Tile> mTileByComponentCache;
+
+    // Tile cache (key: category key, value: category)
+    private final Map<String, DashboardCategory> mCategoryByKeyMap;
+
+    private List<DashboardCategory> mCategories;
+
+    public static CategoryManager get(Context context) {
+        if (sInstance == null) {
+            sInstance = new CategoryManager(context);
+        }
+        return sInstance;
+    }
+
+    CategoryManager(Context context) {
+        mTileByComponentCache = new ArrayMap<>();
+        mCategoryByKeyMap = new ArrayMap<>();
+        mInterestingConfigChanges = new InterestingConfigChanges();
+        mInterestingConfigChanges.applyNewConfig(context.getResources());
+    }
+
+    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
+        tryInitCategories(context);
+
+        final DashboardCategory category = mCategoryByKeyMap.get(categoryKey);
+        if (category == null) {
+            throw new IllegalStateException("Can't find category with key " + categoryKey);
+        }
+        return category;
+    }
+
+    public synchronized List<DashboardCategory> getCategories(Context context) {
+        tryInitCategories(context);
+        return mCategories;
+    }
+
+    public synchronized void reloadAllCategories(Context context) {
+        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
+                context.getResources());
+        mCategories = null;
+        tryInitCategories(context, forceClearCache);
+    }
+
+    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
+        if (mCategories == null) {
+            Log.w(TAG, "Category is null, skipping blacklist update");
+        }
+        for (int i = 0; i < mCategories.size(); i++) {
+            DashboardCategory category = mCategories.get(i);
+            for (int j = 0; j < category.tiles.size(); j++) {
+                Tile tile = category.tiles.get(j);
+                if (tileBlacklist.contains(tile.intent.getComponent())) {
+                    category.tiles.remove(j--);
+                }
+            }
+        }
+    }
+
+    private synchronized void tryInitCategories(Context context) {
+        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
+        // happens.
+        tryInitCategories(context, false /* forceClearCache */);
+    }
+
+    private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
+        if (mCategories == null) {
+            if (forceClearCache) {
+                mTileByComponentCache.clear();
+            }
+            mCategoryByKeyMap.clear();
+            mCategories = TileUtils.getCategories(context, mTileByComponentCache,
+                    false /* categoryDefinedInManifest */);
+            for (DashboardCategory category : mCategories) {
+                mCategoryByKeyMap.put(category.key, category);
+            }
+        }
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index 53be0e6..3fc999f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -16,15 +16,20 @@
 
 package com.android.settingslib.drawer;
 
+import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class DashboardCategory implements Parcelable {
 
+    private static final String TAG = "DashboardCategory";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     /**
      * Title of the category that is shown to the user.
      */
@@ -74,6 +79,22 @@
         return tiles.get(n);
     }
 
+    public boolean containsComponent(ComponentName component) {
+        for (Tile tile : tiles) {
+            if (TextUtils.equals(tile.intent.getComponent().getClassName(),
+                    component.getClassName())) {
+                if (DEBUG) {
+                    Log.d(TAG,  "category " + key + "contains component" + component);
+                }
+                return true;
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG,  "category " + key + " does not contain component" + component);
+        }
+        return false;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a50b366..bad7ba4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -28,7 +28,10 @@
 import android.content.res.TypedArray;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.support.v4.widget.DrawerLayout;
 import android.util.ArraySet;
 import android.util.Log;
@@ -56,15 +59,13 @@
 
     protected static final boolean DEBUG_TIMING = false;
     private static final String TAG = "SettingsDrawerActivity";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
 
-    private static List<DashboardCategory> sDashboardCategories;
-    private static HashMap<Pair<String, String>, Tile> sTileCache;
     // Serves as a temporary list of tiles to ignore until we heard back from the PM that they
     // are disabled.
     private static ArraySet<ComponentName> sTileBlacklist = new ArraySet<>();
-    private static InterestingConfigChanges sConfigTracker;
 
     private final PackageReceiver mPackageReceiver = new PackageReceiver();
     private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
@@ -73,6 +74,16 @@
     private FrameLayout mContentHeaderContainer;
     private DrawerLayout mDrawerLayout;
     private boolean mShowingMenu;
+    private UserManager mUserManager;
+
+    // Remove below after new IA
+    @Deprecated
+    private static List<DashboardCategory> sDashboardCategories;
+    @Deprecated
+    private static HashMap<Pair<String, String>, Tile> sTileCache;
+    @Deprecated
+    private static InterestingConfigChanges sConfigTracker;
+    // Remove above after new IA
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -99,7 +110,9 @@
             mDrawerLayout = null;
             return;
         }
-        getDashboardCategories();
+        if (!isDashboardFeatureEnabled()) {
+            getDashboardCategories();
+        }
         setActionBar(toolbar);
         mDrawerAdapter = new SettingsDrawerAdapter(this);
         ListView listView = (ListView) findViewById(R.id.left_drawer);
@@ -108,8 +121,10 @@
             public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
                     long id) {
                 onTileClicked(mDrawerAdapter.getTile(position));
-            };
+            }
         });
+
+        mUserManager = UserManager.get(this);
         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
                 + " ms");
     }
@@ -136,10 +151,22 @@
             filter.addDataScheme("package");
             registerReceiver(mPackageReceiver, filter);
 
-            new CategoriesUpdater().execute();
+            if (isDashboardFeatureEnabled()) {
+                new CategoriesUpdateTask().execute();
+            } else {
+                new CategoriesUpdater().execute();
+            }
         }
-        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_SHOW_MENU, false)) {
-            showMenuIcon();
+        final Intent intent = getIntent();
+        if (intent != null) {
+            if (intent.hasExtra(EXTRA_SHOW_MENU)) {
+                if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
+                    // Intent explicitly set to show menu.
+                    showMenuIcon();
+                }
+            } else if (isTopLevelTile(intent)) {
+                showMenuIcon();
+            }
         }
     }
 
@@ -152,6 +179,30 @@
         super.onPause();
     }
 
+    private boolean isTopLevelTile(Intent intent) {
+        final ComponentName componentName = intent.getComponent();
+        if (componentName == null) {
+            return false;
+        }
+        if (isDashboardFeatureEnabled()) {
+            final DashboardCategory homepageCategories = CategoryManager.get(this)
+                    .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE);
+            return homepageCategories.containsComponent(componentName);
+        } else {
+            // Look for a tile that has the same component as incoming intent
+            final List<DashboardCategory> categories = getDashboardCategories();
+            for (DashboardCategory category : categories) {
+                if (category.containsComponent(componentName)) {
+                    return true;
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, "Intent is not for top level settings " + intent);
+            }
+            return false;
+        }
+    }
+
     public void addCategoryListener(CategoryListener listener) {
         mCategoryListeners.add(listener);
     }
@@ -215,7 +266,11 @@
             return;
         }
         // TODO: Do this in the background with some loading.
-        mDrawerAdapter.updateCategories();
+        if (isDashboardFeatureEnabled()) {
+            mDrawerAdapter.updateHomepageCategories();
+        } else {
+            mDrawerAdapter.updateCategories();
+        }
         if (mDrawerAdapter.getCount() != 0) {
             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
         } else {
@@ -257,6 +312,7 @@
             return true;
         }
         try {
+            updateUserHandlesIfNeeded(tile);
             int numUserHandles = tile.userHandle.size();
             if (numUserHandles > 1) {
                 ProfileSelectDialog.show(getFragmentManager(), tile);
@@ -278,19 +334,30 @@
         return true;
     }
 
+    private void updateUserHandlesIfNeeded(Tile tile) {
+        List<UserHandle> userHandles = tile.userHandle;
+
+        for (int i = userHandles.size() - 1; i >= 0; i--) {
+            if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
+                }
+                userHandles.remove(i);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public void setUserManager(UserManager userManager) {
+        mUserManager = userManager;
+    }
+
     protected void onTileClicked(Tile tile) {
         if (openTile(tile)) {
             finish();
         }
     }
 
-    public HashMap<Pair<String, String>, Tile> getTileCache() {
-        if (sTileCache == null) {
-            getDashboardCategories();
-        }
-        return sTileCache;
-    }
-
     public void onProfileTileOpen() {
         finish();
     }
@@ -309,7 +376,11 @@
                     ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                     : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     PackageManager.DONT_KILL_APP);
-            new CategoriesUpdater().execute();
+            if (isDashboardFeatureEnabled()) {
+                new CategoriesUpdateTask().execute();
+            } else {
+                new CategoriesUpdater().execute();
+            }
         }
     }
 
@@ -317,6 +388,10 @@
         void onCategoriesChanged();
     }
 
+    /**
+     * @deprecated remove after new IA
+     */
+    @Deprecated
     private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
         @Override
         protected List<DashboardCategory> doInBackground(Void... params) {
@@ -349,10 +424,39 @@
         }
     }
 
+    private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
+
+        private final CategoryManager mCategoryManager;
+
+        public CategoriesUpdateTask() {
+            mCategoryManager = CategoryManager.get(SettingsDrawerActivity.this);
+        }
+
+        @Override
+        protected Void doInBackground(Void... params) {
+            mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this);
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
+            onCategoriesChanged();
+        }
+    }
+
+    protected boolean isDashboardFeatureEnabled() {
+        return false;
+    }
+
     private class PackageReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            new CategoriesUpdater().execute();
+            if (isDashboardFeatureEnabled()) {
+                new CategoriesUpdateTask().execute();
+            } else {
+                new CategoriesUpdater().execute();
+            }
         }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
index 1d6197a..602d135 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -37,6 +37,10 @@
         mActivity = activity;
     }
 
+    /**
+     * @deprecated Remove after new IA
+     */
+    @Deprecated
     void updateCategories() {
         List<DashboardCategory> categories = mActivity.getDashboardCategories();
         mItems.clear();
@@ -64,6 +68,27 @@
         notifyDataSetChanged();
     }
 
+    public void updateHomepageCategories() {
+        final DashboardCategory category = CategoryManager.get(mActivity)
+                        .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE);
+        mItems.clear();
+        // Spacer.
+        mItems.add(null);
+        Item tile = new Item();
+        tile.label = mActivity.getString(R.string.home);
+        tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
+        mItems.add(tile);
+        for (int j = 0; j < category.tiles.size(); j++) {
+            tile = new Item();
+            Tile dashboardTile = category.tiles.get(j);
+            tile.label = dashboardTile.title;
+            tile.icon = dashboardTile.icon;
+            tile.tile = dashboardTile;
+            mItems.add(tile);
+        }
+        notifyDataSetChanged();
+    }
+
     public Tile getTile(int position) {
         return mItems.get(position) != null ? mItems.get(position).tile : null;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index e70cc29..b2ce13f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -113,8 +113,24 @@
 
     private static final String SETTING_PKG = "com.android.settings";
 
+    /**
+     * Build a list of DashboardCategory. Each category must be defined in manifest.
+     * eg: .Settings$DeviceSettings
+     * @deprecated
+     */
+    @Deprecated
     public static List<DashboardCategory> getCategories(Context context,
-            HashMap<Pair<String, String>, Tile> cache) {
+            Map<Pair<String, String>, Tile> cache) {
+        return getCategories(context, cache, true /*categoryDefinedInManifest*/);
+    }
+
+    /**
+     * Build a list of DashboardCategory.
+     * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to
+     * represent this category (eg: .Settings$DeviceSettings)
+     */
+    public static List<DashboardCategory> getCategories(Context context,
+            Map<Pair<String, String>, Tile> cache, boolean categoryDefinedInManifest) {
         final long startTime = System.currentTimeMillis();
         boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
                 != 0;
@@ -134,11 +150,12 @@
                 getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
             }
         }
+
         HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
         for (Tile tile : tiles) {
             DashboardCategory category = categoryMap.get(tile.category);
             if (category == null) {
-                category = createCategory(context, tile.category);
+                category = createCategory(context, tile.category, categoryDefinedInManifest);
                 if (category == null) {
                     Log.w(LOG_TAG, "Couldn't find category " + tile.category);
                     continue;
@@ -157,9 +174,21 @@
         return categories;
     }
 
-    private static DashboardCategory createCategory(Context context, String categoryKey) {
+    /**
+     * Create a new DashboardCategory from key.
+     *
+     * @param context Context to query intent
+     * @param categoryKey The category key
+     * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to
+     * represent this category (eg: .Settings$DeviceSettings)
+     */
+    private static DashboardCategory createCategory(Context context, String categoryKey,
+            boolean categoryDefinedInManifest) {
         DashboardCategory category = new DashboardCategory();
         category.key = categoryKey;
+        if (!categoryDefinedInManifest) {
+            return category;
+        }
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivities(new Intent(categoryKey), 0);
         if (results.size() == 0) {
@@ -204,6 +233,8 @@
             ActivityInfo activityInfo = resolved.activityInfo;
             Bundle metaData = activityInfo.metaData;
             String categoryKey = defaultCategory;
+
+            // Load category
             if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
                     && categoryKey == null) {
                 Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
@@ -213,6 +244,7 @@
             } else {
                 categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
             }
+
             Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
                     activityInfo.name);
             Tile tile = addedCache.get(key);
@@ -238,16 +270,6 @@
         }
     }
 
-    private static DashboardCategory getCategory(List<DashboardCategory> target,
-            String categoryKey) {
-        for (DashboardCategory category : target) {
-            if (categoryKey.equals(category.key)) {
-                return category;
-            }
-        }
-        return null;
-    }
-
     private static boolean updateTileData(Context context, Tile tile,
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
         if (applicationInfo.isSystemApp()) {
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..a514ebb 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.Map;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 
 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";
@@ -91,6 +95,7 @@
     private static final String KEY_PSKTYPE = "key_psktype";
     private static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
     private static final String KEY_CONFIG = "key_config";
+    private static final AtomicInteger sLastId = new AtomicInteger(0);
 
     /**
      * These values are matched in string arrays -- changes must be kept in sync
@@ -123,10 +128,13 @@
 
     private WifiInfo mInfo;
     private NetworkInfo mNetworkInfo;
-    private AccessPointListener mAccessPointListener;
+    AccessPointListener mAccessPointListener;
 
     private Object mTag;
 
+    // used to co-relate internal vs returned accesspoint.
+    int mId;
+
     public AccessPoint(Context context, Bundle savedState) {
         mContext = context;
         mConfig = savedState.getParcelable(KEY_CONFIG);
@@ -149,7 +157,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);
             }
@@ -157,16 +165,46 @@
         update(mConfig, mInfo, mNetworkInfo);
         mRssi = getRssi();
         mSeen = getSeen();
+        mId = sLastId.incrementAndGet();
     }
 
     AccessPoint(Context context, ScanResult result) {
         mContext = context;
         initWithScanResult(result);
+        mId = sLastId.incrementAndGet();
     }
 
     AccessPoint(Context context, WifiConfiguration config) {
         mContext = context;
         loadConfig(config);
+        mId = sLastId.incrementAndGet();
+    }
+
+    AccessPoint(Context context, AccessPoint other) {
+        mContext = context;
+        copyFrom(other);
+    }
+
+    /**
+     * Copy accesspoint information. NOTE: We do not copy tag information because that is never
+     * set on the internal copy.
+     * @param that
+     */
+    void copyFrom(AccessPoint that) {
+        that.evictOldScanResults();
+        this.ssid = that.ssid;
+        this.bssid = that.bssid;
+        this.security = that.security;
+        this.networkId = that.networkId;
+        this.pskType = that.pskType;
+        this.mConfig = that.mConfig; //TODO: Watch out, this object is mutated.
+        this.mRssi = that.mRssi;
+        this.mSeen = that.mSeen;
+        this.mInfo = that.mInfo;
+        this.mNetworkInfo = that.mNetworkInfo;
+        this.mScanResultCache.clear();
+        this.mScanResultCache.putAll(that.mScanResultCache);
+        this.mId = that.mId;
     }
 
     @Override
@@ -233,6 +271,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 +317,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 +329,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;
             }
@@ -341,8 +392,8 @@
     }
 
     public CharSequence getSsid() {
-        SpannableString str = new SpannableString(ssid);
-        str.setSpan(new TtsSpan.VerbatimBuilder(ssid).build(), 0, ssid.length(),
+        final SpannableString str = new SpannableString(ssid);
+        str.setSpan(new TtsSpan.TelephoneBuilder(ssid).build(), 0, ssid.length(),
                 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
         return str;
     }
@@ -360,17 +411,18 @@
     }
 
     public String getSavedNetworkSummary() {
-        if (mConfig != null) {
+        WifiConfiguration config = mConfig;
+        if (config != null) {
             PackageManager pm = mContext.getPackageManager();
             String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
-            int userId = UserHandle.getUserId(mConfig.creatorUid);
+            int userId = UserHandle.getUserId(config.creatorUid);
             ApplicationInfo appInfo = null;
-            if (mConfig.creatorName != null && mConfig.creatorName.equals(systemName)) {
+            if (config.creatorName != null && config.creatorName.equals(systemName)) {
                 appInfo = mContext.getApplicationInfo();
             } else {
                 try {
                     IPackageManager ipm = AppGlobals.getPackageManager();
-                    appInfo = ipm.getApplicationInfo(mConfig.creatorName, 0 /* flags */, userId);
+                    appInfo = ipm.getApplicationInfo(config.creatorName, 0 /* flags */, userId);
                 } catch (RemoteException rex) {
                 }
             }
@@ -385,29 +437,36 @@
     }
 
     public String getSummary() {
-        return getSettingsSummary();
+        return getSettingsSummary(mConfig);
     }
 
     public String getSettingsSummary() {
+        return getSettingsSummary(mConfig);
+    }
+
+    private String getSettingsSummary(WifiConfiguration config) {
         // Update to new summary
         StringBuilder summary = new StringBuilder();
 
-        if (isActive() && mConfig != null && mConfig.isPasspoint()) {
+        if (isActive() && config != null && config.isPasspoint()) {
             // This is the active connection on passpoint
             summary.append(getSummary(mContext, getDetailedState(),
-                    false, mConfig.providerFriendlyName));
+                    false, config.providerFriendlyName));
         } else if (isActive()) {
             // This is the active connection on non-passpoint network
             summary.append(getSummary(mContext, getDetailedState(),
                     mInfo != null && mInfo.isEphemeral()));
-        } else if (mConfig != null && mConfig.isPasspoint()) {
+        } else if (config != null && config.isPasspoint()) {
             String format = mContext.getString(R.string.available_via_passpoint);
-            summary.append(String.format(format, mConfig.providerFriendlyName));
-        } else if (mConfig != null && mConfig.hasNoInternetAccess()) {
-            summary.append(mContext.getString(R.string.wifi_no_internet));
-        } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+            summary.append(String.format(format, config.providerFriendlyName));
+        } else if (config != null && config.hasNoInternetAccess()) {
+            int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+                    ? R.string.wifi_no_internet_no_reconnect
+                    : R.string.wifi_no_internet;
+            summary.append(mContext.getString(messageID));
+        } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
             WifiConfiguration.NetworkSelectionStatus networkStatus =
-                    mConfig.getNetworkSelectionStatus();
+                    config.getNetworkSelectionStatus();
             switch (networkStatus.getNetworkSelectionDisableReason()) {
                 case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
                     summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
@@ -423,7 +482,7 @@
         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
             summary.append(mContext.getString(R.string.wifi_not_in_range));
         } else { // In range, not disabled.
-            if (mConfig != null) { // Is saved network
+            if (config != null) { // Is saved network
                 summary.append(mContext.getString(R.string.wifi_remembered));
             }
         }
@@ -435,11 +494,11 @@
                 summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
             }
             summary.append(" " + getVisibilityStatus());
-            if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
-                summary.append(" (" + mConfig.getNetworkSelectionStatus().getNetworkStatusString());
-                if (mConfig.getNetworkSelectionStatus().getDisableTime() > 0) {
+            if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
+                summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
+                if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
                     long now = System.currentTimeMillis();
-                    long diff = (now - mConfig.getNetworkSelectionStatus().getDisableTime()) / 1000;
+                    long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
                     long sec = diff%60; //seconds
                     long min = (diff/60)%60; //minutes
                     long hour = (min/60)%60; //hours
@@ -451,9 +510,9 @@
                 summary.append(")");
             }
 
-            if (mConfig != null) {
+            if (config != null) {
                 WifiConfiguration.NetworkSelectionStatus networkStatus =
-                        mConfig.getNetworkSelectionStatus();
+                        config.getNetworkSelectionStatus();
                 for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
                         index < WifiConfiguration.NetworkSelectionStatus
                         .NETWORK_SELECTION_DISABLED_MAX; index++) {
@@ -505,9 +564,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 +743,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 +757,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/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 7d279eb..bfe8c07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -29,10 +29,13 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -62,30 +65,59 @@
     // TODO: Allow control of this?
     // Combo scans can take 5-6s to complete - set to 10s.
     private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
+    private static final int NUM_SCANS_TO_CONFIRM_AP_LOSS = 3;
 
     private final Context mContext;
     private final WifiManager mWifiManager;
     private final IntentFilter mFilter;
     private final ConnectivityManager mConnectivityManager;
     private final NetworkRequest mNetworkRequest;
-    private WifiTrackerNetworkCallback mNetworkCallback;
-
     private final AtomicBoolean mConnected = new AtomicBoolean(false);
     private final WifiListener mListener;
     private final boolean mIncludeSaved;
     private final boolean mIncludeScans;
     private final boolean mIncludePasspoints;
-
     private final MainHandler mMainHandler;
     private final WorkHandler mWorkHandler;
 
+    private WifiTrackerNetworkCallback mNetworkCallback;
+
     private boolean mSavedNetworksExist;
     private boolean mRegistered;
-    private ArrayList<AccessPoint> mAccessPoints = new ArrayList<>();
-    private HashMap<String, Integer> mSeenBssids = new HashMap<>();
-    private HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
+
+    /** Updated using main handler. Clone of this collection is returned
+     * from {@link #getAccessPoints()}
+     */
+    private final List<AccessPoint> mAccessPoints = new ArrayList<>();
+
+    /**
+     * Protects APs contained in {@link #mInternalAccessPoints} from being modified concurrently
+     * while its being read. Usage contract:
+     *
+     * 1. MainHandler opens the condition after copying the states thereby
+     *    allowing WorkerHandler to mutate the contents.
+     * 2. WorkerHandler after mutating the contents, sends a message to MainHandler to copy the
+     *    states and closes the condition.
+     *
+     * This is better than synchronizing on a variable because it prevents MainHandler from
+     * unnecessarily blocking/waiting to acquire lock for copying states. When MainHandler is about
+     * to access {@link #mInternalAccessPoints}, it is assumed that it has exclusively lock on the
+     * contents.
+     */
+    private final ConditionVariable mInternalAccessPointsWriteLock = new ConditionVariable(true);
+
+    /** Guarded by mInternalAccessPointsWriteLock, updated using worker handler.
+     * Never exposed outside this class.
+     */
+    private final List<AccessPoint> mInternalAccessPoints = new ArrayList<>();
+
+    //visible to both worker and main thread. Guarded by #mInternalAccessPoints
+    private final AccessPointListenerAdapter mAccessPointListenerAdapter
+            = new AccessPointListenerAdapter();
+
+    private final HashMap<String, Integer> mSeenBssids = new HashMap<>();
+    private final HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
     private Integer mScanId = 0;
-    private static final int NUM_SCANS_TO_CONFIRM_AP_LOSS = 3;
 
     private NetworkInfo mLastNetworkInfo;
     private WifiInfo mLastInfo;
@@ -231,12 +263,11 @@
     }
 
     /**
-     * Gets the current list of access points.
+     * Gets the current list of access points. Should be called from main thread, otherwise
+     * expect inconsistencies
      */
     public List<AccessPoint> getAccessPoints() {
-        synchronized (mAccessPoints) {
-            return new ArrayList<>(mAccessPoints);
-        }
+        return new ArrayList<>(mAccessPoints);
     }
 
     public WifiManager getManager() {
@@ -316,8 +347,17 @@
     }
 
     private void updateAccessPoints() {
+        // Wait until main worker is done copying the states. This is done to prevent propagation
+        // of accesspoint states while the update is in progress.
+        long before = System.currentTimeMillis();
+        mInternalAccessPointsWriteLock.block();
+        if (DBG) {
+            Log.d(TAG, "Acquired AP lock on WorkerHandler. Time to wait = "
+                    + (System.currentTimeMillis() - before) + " ms.");
+        }
+
         // Swap the current access points into a cached list.
-        List<AccessPoint> cachedAccessPoints = getAccessPoints();
+        List<AccessPoint> cachedAccessPoints = new ArrayList<>(mInternalAccessPoints);
         ArrayList<AccessPoint> accessPoints = new ArrayList<>();
 
         // Clear out the configs so we don't think something is saved when it isn't.
@@ -325,7 +365,7 @@
             accessPoint.clearConfig();
         }
 
-        /** Lookup table to more quickly update AccessPoints by only considering objects with the
+        /* Lookup table to more quickly update AccessPoints by only considering objects with the
          * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
         Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
         WifiConfiguration connectionConfig = null;
@@ -406,8 +446,8 @@
                     if (mLastInfo != null && mLastInfo.getBSSID() != null
                             && mLastInfo.getBSSID().equals(result.BSSID)
                             && connectionConfig != null && connectionConfig.isPasspoint()) {
-                        /* This network is connected via this passpoint config */
-                        /* SSID match is not going to work for it; so update explicitly */
+                    /* This network is connected via this passpoint config */
+                    /* SSID match is not going to work for it; so update explicitly */
                         accessPoint.update(connectionConfig);
                     }
 
@@ -422,12 +462,14 @@
 
         // Log accesspoints that were deleted
         if (DBG) Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
-        for (AccessPoint prevAccessPoint : mAccessPoints) {
-            if (prevAccessPoint.getSsid() == null) continue;
+        for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
+            if (prevAccessPoint.getSsid() == null)
+                continue;
             String prevSsid = prevAccessPoint.getSsidStr();
             boolean found = false;
             for (AccessPoint newAccessPoint : accessPoints) {
-                if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid().equals(prevSsid)) {
+                if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid()
+                        .equals(prevSsid)) {
                     found = true;
                     break;
                 }
@@ -435,10 +477,11 @@
             if (!found)
                 if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan");
         }
-        if (DBG)  Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
+        if (DBG) Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
 
-        mAccessPoints = accessPoints;
-        mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+        mInternalAccessPoints.clear();
+        mInternalAccessPoints.addAll(accessPoints);
+        mMainHandler.scheduleAPCopyingAndCloseWriteLock();
     }
 
     private AccessPoint getCachedOrCreate(ScanResult result, List<AccessPoint> cache) {
@@ -462,7 +505,9 @@
                 return ret;
             }
         }
-        return new AccessPoint(mContext, config);
+        AccessPoint accessPoint = new AccessPoint(mContext, config);
+        accessPoint.setListener(mAccessPointListenerAdapter);
+        return accessPoint;
     }
 
     private void updateNetworkInfo(NetworkInfo networkInfo) {
@@ -489,17 +534,24 @@
             connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
         }
 
+        // Lock required to prevent accidental copying of AccessPoint states while the modification
+        // is in progress. see #copyAndNotifyListeners
+        long before = System.currentTimeMillis();
+        mInternalAccessPointsWriteLock.block();
+        if (DBG) {
+            Log.d(TAG, "Acquired AP lock on WorkerHandler for updating NetworkInfo. Wait time = " +
+                    (System.currentTimeMillis() - before) + "ms.");
+        }
+
         boolean reorder = false;
-        for (int i = mAccessPoints.size() - 1; i >= 0; --i) {
-            if (mAccessPoints.get(i).update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
+        for (int i = mInternalAccessPoints.size() - 1; i >= 0; --i) {
+            if (mInternalAccessPoints.get(i).update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
                 reorder = true;
             }
         }
         if (reorder) {
-            synchronized (mAccessPoints) {
-                Collections.sort(mAccessPoints);
-            }
-            mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+            Collections.sort(mInternalAccessPoints);
+            mMainHandler.scheduleAPCopyingAndCloseWriteLock();
         }
     }
 
@@ -512,6 +564,7 @@
         WifiTracker tracker = new WifiTracker(context,
                 null, null, includeSaved, includeScans, includePasspoints);
         tracker.forceUpdate();
+        tracker.copyAndNotifyListeners(false /*notifyListeners*/);
         return tracker.getAccessPoints();
     }
 
@@ -576,6 +629,7 @@
                     mListener.onWifiStateChanged(msg.arg1);
                     break;
                 case MSG_ACCESS_POINT_CHANGED:
+                    copyAndNotifyListeners(true /*notifyListeners*/);
                     mListener.onAccessPointsChanged();
                     break;
                 case MSG_RESUME_SCANNING:
@@ -590,6 +644,12 @@
                     break;
             }
         }
+
+        void scheduleAPCopyingAndCloseWriteLock() {
+            //prevent worker thread from modifying mInternalAccessPoints
+            mInternalAccessPointsWriteLock.close();
+            sendEmptyMessage(MSG_ACCESS_POINT_CHANGED);
+        }
     }
 
     private final class WorkHandler extends Handler {
@@ -725,4 +785,94 @@
          */
         void onAccessPointsChanged();
     }
+
+    /**
+     * Helps capture notifications that were generated during AccessPoint modification. Used later
+     * on by {@link #copyAndNotifyListeners(boolean)} to send notifications.
+     */
+    private static class AccessPointListenerAdapter implements AccessPoint.AccessPointListener {
+        static final int AP_CHANGED = 1;
+        static final int LEVEL_CHANGED = 2;
+
+        final SparseIntArray mPendingNotifications = new SparseIntArray();
+
+        @Override
+        public void onAccessPointChanged(AccessPoint accessPoint) {
+            int type = mPendingNotifications.get(accessPoint.mId);
+            mPendingNotifications.put(accessPoint.mId, type | AP_CHANGED);
+        }
+
+        @Override
+        public void onLevelChanged(AccessPoint accessPoint) {
+            int type = mPendingNotifications.get(accessPoint.mId);
+            mPendingNotifications.put(accessPoint.mId, type | LEVEL_CHANGED);
+        }
+    }
+
+    /**
+     * Responsible for copying access points from {@link #mInternalAccessPoints} and notifying
+     * accesspoint listeners. Mutation of the accesspoints returned is done on the main thread.
+     *
+     * @param notifyListeners if true, accesspoint listeners are notified, otherwise notifications
+     *                        dropped.
+     */
+    private void copyAndNotifyListeners(boolean notifyListeners) {
+        // Need to watch out for memory allocations on main thread.
+        SparseArray<AccessPoint> oldAccessPoints = new SparseArray<>();
+        SparseIntArray notificationMap = null;
+        List<AccessPoint> updatedAccessPoints = new ArrayList<>();
+
+        for (AccessPoint accessPoint : mAccessPoints) {
+            oldAccessPoints.put(accessPoint.mId, accessPoint);
+        }
+
+        //synchronize to prevent modification of "mInternalAccessPoints" by worker thread.
+        long before = System.currentTimeMillis();
+        try {
+            if (DBG) {
+                Log.d(TAG, "Starting to copy AP items on the MainHandler");
+            }
+            if (notifyListeners) {
+                notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
+            }
+
+            mAccessPointListenerAdapter.mPendingNotifications.clear();
+            for (AccessPoint internalAccessPoint : mInternalAccessPoints) {
+                AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
+                if (accessPoint == null) {
+                    accessPoint = new AccessPoint(mContext, internalAccessPoint);
+                } else {
+                    accessPoint.copyFrom(internalAccessPoint);
+                }
+                updatedAccessPoints.add(accessPoint);
+            }
+        } finally {
+            mInternalAccessPointsWriteLock.open();
+            if (DBG) {
+                Log.d(TAG, "Opened AP Write lock on the MainHandler. Time to copy = " +
+                        (System.currentTimeMillis() - before) + " ms.");
+            }
+        }
+
+        mAccessPoints.clear();
+        mAccessPoints.addAll(updatedAccessPoints);
+
+        if (notificationMap != null && notificationMap.size() > 0) {
+            for (AccessPoint accessPoint : updatedAccessPoints) {
+                int notificationType = notificationMap.get(accessPoint.mId);
+                AccessPoint.AccessPointListener listener = accessPoint.mAccessPointListener;
+                if (notificationType == 0 || listener == null) {
+                    continue;
+                }
+
+                if ((notificationType & AccessPointListenerAdapter.AP_CHANGED) != 0) {
+                    listener.onAccessPointChanged(accessPoint);
+                }
+
+                if ((notificationType & AccessPointListenerAdapter.LEVEL_CHANGED) != 0) {
+                    listener.onLevelChanged(accessPoint);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SettingsLib/tests/Android.mk b/packages/SettingsLib/tests/Android.mk
index d3ffffa..4208522 100644
--- a/packages/SettingsLib/tests/Android.mk
+++ b/packages/SettingsLib/tests/Android.mk
@@ -16,6 +16,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -23,7 +24,10 @@
 
 LOCAL_PACKAGE_NAME := SettingsLibTests
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    espresso-core \
+    mockito-target-minus-junit4
 
 include frameworks/base/packages/SettingsLib/common.mk
 
diff --git a/packages/SettingsLib/tests/AndroidManifest.xml b/packages/SettingsLib/tests/AndroidManifest.xml
index 00d16fc..18bbbed 100644
--- a/packages/SettingsLib/tests/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/AndroidManifest.xml
@@ -17,11 +17,16 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.settingslib">
 
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
+
     <application>
         <uses-library android:name="android.test.runner" />
+        <activity android:name=".drawer.SettingsDrawerActivityTest$TestActivity"/>
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.settingslib"
         android:label="Tests for SettingsLib">
     </instrumentation>
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
new file mode 100644
index 0000000..4d7d4cf
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.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.settingslib.drawer;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.settingslib.drawer.SettingsDrawerActivity;
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SettingsDrawerActivityTest {
+    @Mock
+    private UserManager mUserManager;
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityRule =
+            new ActivityTestRule<>(TestActivity.class, true, true);
+
+    private static final UserHandle NORMAL_USER = UserHandle.of(1111);
+    private static final UserHandle REMOVED_USER = UserHandle.of(2222);
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        final UserInfo userInfo = new UserInfo(
+                NORMAL_USER.getIdentifier(), "test_user", UserInfo.FLAG_RESTRICTED);
+        when(mUserManager.getUserInfo(NORMAL_USER.getIdentifier())).thenReturn(userInfo);
+    }
+
+    @Test
+    public void testUpdateUserHandlesIfNeeded_Normal() {
+        TestActivity activity = mActivityRule.getActivity();
+        activity.setUserManager(mUserManager);
+
+        Tile tile = new Tile();
+        tile.intent = new Intent();
+        tile.userHandle.add(NORMAL_USER);
+
+        activity.openTile(tile);
+
+        assertEquals(tile.userHandle.size(), 1);
+        assertEquals(tile.userHandle.get(0).getIdentifier(), NORMAL_USER.getIdentifier());
+        verify(mUserManager, times(1)).getUserInfo(NORMAL_USER.getIdentifier());
+    }
+
+    @Test
+    public void testUpdateUserHandlesIfNeeded_Remove() {
+        TestActivity activity = mActivityRule.getActivity();
+        activity.setUserManager(mUserManager);
+
+        Tile tile = new Tile();
+        tile.intent = new Intent();
+        tile.userHandle.add(REMOVED_USER);
+        tile.userHandle.add(NORMAL_USER);
+        tile.userHandle.add(REMOVED_USER);
+
+        activity.openTile(tile);
+
+        assertEquals(tile.userHandle.size(), 1);
+        assertEquals(tile.userHandle.get(0).getIdentifier(), NORMAL_USER.getIdentifier());
+        verify(mUserManager, times(1)).getUserInfo(NORMAL_USER.getIdentifier());
+        verify(mUserManager, times(2)).getUserInfo(REMOVED_USER.getIdentifier());
+    }
+
+    @Test
+    public void startActivityWithNoExtra_showNoHamburgerMenu() {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.startActivitySync(new Intent(instrumentation.getTargetContext(),
+                TestActivity.class));
+
+        onView(withContentDescription(R.string.content_description_menu_button))
+                .check(doesNotExist());
+    }
+
+    @Test
+    public void startActivityWithExtraToHideMenu_showNoHamburgerMenu() {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
+                .putExtra(TestActivity.EXTRA_SHOW_MENU, false);
+        instrumentation.startActivitySync(intent);
+
+        onView(withContentDescription(R.string.content_description_menu_button))
+                .check(doesNotExist());
+    }
+
+    @Test
+    public void startActivityWithExtraToShowMenu_showHamburgerMenu() {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
+                .putExtra(TestActivity.EXTRA_SHOW_MENU, true);
+        instrumentation.startActivitySync(intent);
+
+        onView(withContentDescription(R.string.content_description_menu_button))
+                .check(matches(isDisplayed()));
+    }
+
+    /**
+     * Test Activity in this test.
+     *
+     * Use this activity because SettingsDrawerActivity hasn't been registered in its
+     * AndroidManifest.xml
+     */
+    public static class TestActivity extends SettingsDrawerActivity {}
+}
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/SettingsLib/tests/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
new file mode 100644
index 0000000..ee03d50
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.utils;
+
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkTemplate;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.settingslib.NetworkPolicyEditor;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertEquals;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkPolicyEditorTest {
+    private static final long MAX_LIMIT_BYTES = 500000;
+    private static final long TEST_LIMIT_BYTES = 2500;
+    private static final long[] WARNING_BYTES_LIST = {100, 1000, 2000, 3000, 40000};
+
+    private NetworkTemplate mNetworkTemplate;
+    private NetworkPolicyEditor mNetworkPolicyEditor;
+
+    @Before
+    public void setUp() {
+        mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll("123456789123456");
+        NetworkPolicyManager policyManager = NetworkPolicyManager.from(InstrumentationRegistry
+                .getContext());
+        mNetworkPolicyEditor = new NetworkPolicyEditor(policyManager);
+    }
+
+    @Test
+    public void setPolicyWarningBytes_withoutLimit_shouldNotCapWarningBytes() {
+        // Set the limit to disable so we can change the warning bytes freely
+        mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, NetworkPolicy.LIMIT_DISABLED);
+
+        for (int i = 0; i < WARNING_BYTES_LIST.length; i++) {
+            mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, WARNING_BYTES_LIST[i]);
+            assertEquals(WARNING_BYTES_LIST[i],
+                    mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
+        }
+    }
+
+    @Test
+    public void setPolicyWarningBytes_withLimit_shouldCapWarningBytes() {
+        // Set the limit bytes, so warning bytes cannot exceed the limit bytes.
+        mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, TEST_LIMIT_BYTES);
+
+        for (int i = 0; i < WARNING_BYTES_LIST.length; i++) {
+            mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, WARNING_BYTES_LIST[i]);
+            long expectedWarningBytes = Math.min(WARNING_BYTES_LIST[i], TEST_LIMIT_BYTES);
+            assertEquals(expectedWarningBytes,
+                    mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
+        }
+    }
+
+    @Test
+    public void setPolicyLimitBytes_warningBytesSmallerThanLimit_shouldNotCapWarningBytes() {
+        long testWarningBytes = MAX_LIMIT_BYTES / 2;
+
+        mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, MAX_LIMIT_BYTES);
+        mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, testWarningBytes);
+
+        assertEquals(MAX_LIMIT_BYTES, mNetworkPolicyEditor.getPolicyLimitBytes(mNetworkTemplate));
+        assertEquals(testWarningBytes,
+                mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
+    }
+
+    @Test
+    public void setPolicyLimitBytes_warningBytesBiggerThanLimit_shouldCapWarningBytes() {
+        long testWarningBytes = TEST_LIMIT_BYTES * 2;
+
+        mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, MAX_LIMIT_BYTES);
+        mNetworkPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, testWarningBytes);
+        mNetworkPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, TEST_LIMIT_BYTES);
+
+        assertEquals(TEST_LIMIT_BYTES, mNetworkPolicyEditor.getPolicyLimitBytes(mNetworkTemplate));
+        long expectedWarningBytes = Math.min(testWarningBytes, TEST_LIMIT_BYTES);
+        assertEquals(expectedWarningBytes,
+                mNetworkPolicyEditor.getPolicyWarningBytes(mNetworkTemplate));
+    }
+
+}
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
index 4ac461d..6481f4d 100644
--- a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -11,87 +11,108 @@
  * 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.
+ * limitations under the License
  */
 package com.android.settingslib.wifi;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiSsid;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.SpannableString;
+import android.text.style.TtsSpan;
 
-import com.android.settingslib.BaseTest;
-import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
+import java.util.ArrayList;
 
-// TODO: Add some coverage
-public class AccessPointTest extends BaseTest {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AccessPointTest {
 
-    private static final String TEST_SSID = "TestSsid";
-    private static final int NETWORK_ID = 0;
+    private static final String TEST_SSID = "test_ssid";
+    private Context mContext;
 
-    private AccessPointListener mAccessPointListener;
-    private AccessPoint mAccessPoint;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mAccessPointListener = Mockito.mock(AccessPointListener.class);
-
-        WifiConfiguration wifiConfig = new WifiConfiguration();
-        wifiConfig.networkId = NETWORK_ID;
-        wifiConfig.SSID = TEST_SSID;
-
-        mAccessPoint = new AccessPoint(mContext, wifiConfig);
-        mAccessPoint.setListener(mAccessPointListener);
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
-    public void testOnLevelChanged() {
-        ScanResult result = new ScanResult();
-        result.capabilities = "";
-        result.SSID = TEST_SSID;
+    @Test
+    public void testSsidIsTelephoneSpan() {
+        final Bundle bundle = new Bundle();
+        bundle.putString("key_ssid", TEST_SSID);
+        final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
+        final CharSequence ssid = ap.getSsid();
 
-        // Give it a level.
-        result.level = WifiTrackerTest.levelToRssi(1);
-        mAccessPoint.update(result);
-        verifyOnLevelChangedCallback(1);
+        assertTrue(ssid instanceof SpannableString);
 
-        // Give it a better level.
-        result.level = WifiTrackerTest.levelToRssi(2);
-        mAccessPoint.update(result);
-        verifyOnLevelChangedCallback(1);
+        TtsSpan[] spans = ((SpannableString) ssid).getSpans(0, TEST_SSID.length(), TtsSpan.class);
+
+        assertEquals(1, spans.length);
+        assertEquals(TtsSpan.TYPE_TELEPHONE, spans[0].getType());
     }
 
-    public void testOnAccessPointChangedCallback() {
-        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
-        Mockito.when(wifiInfo.getNetworkId()).thenReturn(NETWORK_ID);
+    @Test
+    public void testCopyAccessPoint_dataShouldMatch() {
+        WifiConfiguration configuration = createWifiConfiguration();
 
-        mAccessPoint.update(wifiInfo, null);
-        verifyOnAccessPointsCallback(1);
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
+        AccessPoint originalAccessPoint = new AccessPoint(mContext, configuration);
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
+        wifiInfo.setBSSID(configuration.BSSID);
+        originalAccessPoint.update(configuration, wifiInfo, networkInfo);
+        AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
 
-        mAccessPoint.update(null, null);
-        verifyOnAccessPointsCallback(2);
-
-        ScanResult result = new ScanResult();
-        result.capabilities = "";
-        result.SSID = TEST_SSID;
-        mAccessPoint.update(result);
-        verifyOnAccessPointsCallback(3);
+        assertEquals(originalAccessPoint.getSsid().toString(), copy.getSsid().toString());
+        assertEquals(originalAccessPoint.getBssid(), copy.getBssid());
+        assertSame(originalAccessPoint.getConfig(), copy.getConfig());
+        assertEquals(originalAccessPoint.getSecurity(), copy.getSecurity());
+        assertTrue(originalAccessPoint.compareTo(copy) == 0);
     }
 
-    private void verifyOnLevelChangedCallback(int num) {
-        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
-        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
-                .onLevelChanged(accessPoint.capture());
-        assertEquals(mAccessPoint, accessPoint.getValue());
+    @Test
+    public void testThatCopyAccessPoint_scanCacheShouldMatch() {
+        Bundle bundle = new Bundle();
+        ArrayList<ScanResult> scanResults = new ArrayList<>();
+        for (int i = 0; i < 5; i++) {
+            ScanResult scanResult = new ScanResult();
+            scanResult.level = i;
+            scanResult.BSSID = "bssid-" + i;
+            scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
+            scanResults.add(scanResult);
+        }
+
+        bundle.putParcelableArrayList("key_scanresultcache", scanResults);
+        AccessPoint original = new AccessPoint(mContext, bundle);
+        assertEquals(4, original.getRssi());
+        AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
+        assertEquals(Integer.MIN_VALUE, copy.getRssi());
+        copy.copyFrom(original);
+        assertEquals(original.getRssi(), copy.getRssi());
     }
 
-    private void verifyOnAccessPointsCallback(int num) {
-        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
-        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
-                .onAccessPointChanged(accessPoint.capture());
-        assertEquals(mAccessPoint, accessPoint.getValue());
+    private WifiConfiguration createWifiConfiguration() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.BSSID = "bssid";
+        configuration.SSID = "ssid";
+        configuration.networkId = 123;
+        return configuration;
     }
-
 }
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
deleted file mode 100644
index 479c7be..0000000
--- a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ /dev/null
@@ -1,369 +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.settingslib.wifi;
-
-import android.content.Intent;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.util.Log;
-
-import com.android.settingslib.BaseTest;
-import com.android.settingslib.wifi.WifiTracker.Scanner;
-import com.android.settingslib.wifi.WifiTracker.WifiListener;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-public class WifiTrackerTest extends BaseTest {
-
-    private static final String TAG = "WifiTrackerTest";
-
-    private static final String[] TEST_SSIDS = new String[] {
-        "TEST_SSID_1",
-        "TEST_SSID_2",
-        "TEST_SSID_3",
-        "TEST_SSID_4",
-        "TEST_SSID_5",
-    };
-    private static final int NUM_NETWORKS = 5;
-
-    private WifiManager mWifiManager;
-    private WifiListener mWifiListener;
-
-    private WifiTracker mWifiTracker;
-
-    private HandlerThread mWorkerThread;
-    private Looper mLooper;
-    private HandlerThread mMainThread;
-    private Looper mMainLooper;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mWifiManager = Mockito.mock(WifiManager.class);
-        mWifiListener = Mockito.mock(WifiListener.class);
-        mWorkerThread = new HandlerThread("TestHandlerThread");
-        mWorkerThread.start();
-        mLooper = mWorkerThread.getLooper();
-        mMainThread = new HandlerThread("TestHandlerThread");
-        mMainThread.start();
-        mMainLooper = mMainThread.getLooper();
-        mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, true, true,
-                mWifiManager, mMainLooper);
-        mWifiTracker.mScanner = mWifiTracker.new Scanner();
-        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(true);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        mWifiTracker.dump(pw);
-        pw.flush();
-        Log.d(TAG, sw.toString());
-        super.tearDown();
-    }
-
-    public void testAccessPointsCallback() {
-        sendScanResultsAndProcess(false);
-
-        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onAccessPointsChanged();
-    }
-
-    public void testConnectedCallback() {
-        sendConnected();
-        waitForThreads();
-
-        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onConnectedChanged();
-        assertEquals(true, mWifiTracker.isConnected());
-    }
-
-    public void testWifiStateCallback() {
-        final int TEST_WIFI_STATE = WifiManager.WIFI_STATE_ENABLED;
-
-        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        i.putExtra(WifiManager.EXTRA_WIFI_STATE, TEST_WIFI_STATE);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-        waitForThreads();
-
-        ArgumentCaptor<Integer> wifiState = ArgumentCaptor.forClass(Integer.class);
-        Mockito.verify(mWifiListener, Mockito.atLeastOnce())
-                .onWifiStateChanged(wifiState.capture());
-        assertEquals(TEST_WIFI_STATE, (int) wifiState.getValue());
-    }
-
-    public void testScanner() {
-        // TODO: Figure out how to verify more of the Scanner functionality.
-        // Make scans be successful.
-        Mockito.when(mWifiManager.startScan()).thenReturn(true);
-
-        mWifiTracker.mScanner.handleMessage(mWifiTracker.mScanner.obtainMessage(Scanner.MSG_SCAN));
-        Mockito.verify(mWifiManager, Mockito.atLeastOnce()).startScan();
-    }
-
-    public void testNetworkSorting() {
-        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
-        List<ScanResult> scanResults = new ArrayList<ScanResult>();
-        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
-
-        // Tell WifiTracker we are connected now.
-        sendConnected();
-
-        // Send all of the configs and scan results to the tracker.
-        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
-        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
-        sendScanResultsAndProcess(false);
-
-        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
-        assertEquals("Expected number of results", NUM_NETWORKS, accessPoints.size());
-        for (int i = 0; i < NUM_NETWORKS; i++) {
-            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
-        }
-    }
-
-    public void testSavedOnly() {
-        mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, false, true,
-                mWifiManager, mMainLooper);
-        mWifiTracker.mScanner = mWifiTracker.new Scanner();
-
-        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
-        List<ScanResult> scanResults = new ArrayList<ScanResult>();
-        generateTestNetworks(wifiConfigs, scanResults, true);
-
-        // Tell WifiTracker we are connected now.
-        sendConnected();
-
-        // Send all of the configs and scan results to the tracker.
-        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
-        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
-        sendScanResultsAndProcess(false);
-
-        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
-        // Only expect the first two to come back in the results.
-        assertEquals("Expected number of results", 2, accessPoints.size());
-        assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
-        assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
-    }
-
-    /**
-     * This tests the case where Settings runs this on a non-looper thread for indexing.
-     */
-    public void testSavedOnlyNoLooper() {
-        mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, false, true,
-                mWifiManager,  null);
-        mWifiTracker.mScanner = mWifiTracker.new Scanner();
-
-        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
-        List<ScanResult> scanResults = new ArrayList<ScanResult>();
-        generateTestNetworks(wifiConfigs, scanResults, true);
-
-        // Send all of the configs and scan results to the tracker.
-        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
-        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
-        mWifiTracker.forceUpdate();
-
-        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
-        // Only expect the first two to come back in the results.
-        assertEquals("Expected number of results", 2, accessPoints.size());
-        assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
-        assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
-    }
-
-    public void testAvailableOnly() {
-        mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, false, true, true,
-                mWifiManager, mMainLooper);
-        mWifiTracker.mScanner = mWifiTracker.new Scanner();
-
-        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
-        List<ScanResult> scanResults = new ArrayList<ScanResult>();
-        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
-
-        // Tell WifiTracker we are connected now.
-        sendConnected();
-
-        // Send all of the configs and scan results to the tracker.
-        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
-        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
-        sendScanResultsAndProcess(false);
-
-        // Expect the last one (sorted order) to be left off since its only saved.
-        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
-        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
-        for (int i = 0; i < NUM_NETWORKS - 1; i++) {
-            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
-        }
-    }
-
-    public void testNonEphemeralConnected() {
-        mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, false, true, true,
-                mWifiManager, mMainLooper);
-        mWifiTracker.mScanner = mWifiTracker.new Scanner();
-
-        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
-        List<ScanResult> scanResults = new ArrayList<ScanResult>();
-        generateTestNetworks(wifiConfigs, scanResults, false);
-
-        // Tell WifiTracker we are connected now.
-        sendConnected();
-
-        // Send all of the configs and scan results to the tracker.
-        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
-        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
-        // Do this twice to catch a bug that was happening in the caching, making things ephemeral.
-        sendScanResultsAndProcess(true);
-
-        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
-        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
-        assertFalse("Connection is not ephemeral", accessPoints.get(0).isEphemeral());
-        assertTrue("Connected to wifi", accessPoints.get(0).isActive());
-    }
-
-    public void testEnableResumeScanning() {
-        mWifiTracker.mScanner = null;
-
-        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        // Make sure disable/enable cycle works with no scanner (no crashing).
-        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-
-        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(false);
-        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-        // Now enable scanning while wifi is off, it shouldn't start.
-        mWifiTracker.resumeScanning();
-        assertFalse(mWifiTracker.mScanner.isScanning());
-
-        // Turn on wifi and make sure scanning starts.
-        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-        assertTrue(mWifiTracker.mScanner.isScanning());
-    }
-
-    private String[] generateTestNetworks(List<WifiConfiguration> wifiConfigs,
-            List<ScanResult> scanResults, boolean connectedIsEphemeral) {
-        String[] expectedSsids = new String[NUM_NETWORKS];
-
-        // First is just saved;
-        addConfig(wifiConfigs, TEST_SSIDS[0]);
-        // This should come last since its not available.
-        expectedSsids[4] = TEST_SSIDS[0];
-
-        // Second is saved and available.
-        addConfig(wifiConfigs, TEST_SSIDS[1]);
-        addResult(scanResults, TEST_SSIDS[1], 0);
-        // This one is going to have a couple extra results, to verify de-duplication.
-        addResult(scanResults, TEST_SSIDS[1], 2);
-        addResult(scanResults, TEST_SSIDS[1], 1);
-        // This should come second since it is available and saved but not connected.
-        expectedSsids[1] = TEST_SSIDS[1];
-
-        // Third is just available, but higher rssi.
-        addResult(scanResults, TEST_SSIDS[2], 3);
-        // This comes after the next one since it has a lower rssi.
-        expectedSsids[3] = TEST_SSIDS[2];
-
-        // Fourth also just available but with even higher rssi.
-        addResult(scanResults, TEST_SSIDS[3], 4);
-        // This is the highest rssi but not saved so it should be after the saved+availables.
-        expectedSsids[2] = TEST_SSIDS[3];
-
-        // Last is going to be connected.
-        int netId = WifiConfiguration.INVALID_NETWORK_ID;
-        if (!connectedIsEphemeral) {
-            netId = addConfig(wifiConfigs, TEST_SSIDS[4]);
-        }
-        addResult(scanResults, TEST_SSIDS[4], 2);
-        // Setup wifi connection to be this one.
-        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
-        Mockito.when(wifiInfo.getSSID()).thenReturn(TEST_SSIDS[4]);
-        Mockito.when(wifiInfo.getNetworkId()).thenReturn(netId);
-        Mockito.when(mWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
-        // This should come first since it is connected.
-        expectedSsids[0] = TEST_SSIDS[4];
-
-        return expectedSsids;
-    }
-
-    private void addResult(List<ScanResult> results, String ssid, int level) {
-        results.add(new ScanResult(WifiSsid.createFromAsciiEncoded(ssid),
-                ssid, ssid, levelToRssi(level), AccessPoint.LOWER_FREQ_24GHZ, 0));
-    }
-
-    public static int levelToRssi(int level) {
-        // Reverse level to rssi calculation based off from WifiManager.calculateSignalLevel.
-        final int MAX_RSSI = -55;
-        final int MIN_RSSI = -100;
-        final int NUM_LEVELS = 4;
-        return level * (MAX_RSSI - MIN_RSSI) / (NUM_LEVELS - 1) + MIN_RSSI;
-    }
-
-    private int addConfig(List<WifiConfiguration> configs, String ssid) {
-        WifiConfiguration config = new WifiConfiguration();
-        config.networkId = configs.size();
-        config.SSID = '"' + ssid + '"';
-        configs.add(config);
-        return config.networkId;
-    }
-
-    private void sendConnected() {
-        NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
-        Mockito.when(networkInfo.isConnected()).thenReturn(true);
-        Mockito.when(networkInfo.getState()).thenReturn(State.CONNECTED);
-        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
-        mWifiTracker.mReceiver.onReceive(mContext, intent);
-    }
-
-    private void sendScanResultsAndProcess(boolean sendTwice) {
-        Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        mWifiTracker.mReceiver.onReceive(mContext, i);
-        if (sendTwice) {
-            mWifiTracker.mReceiver.onReceive(mContext, i);
-        }
-        waitForThreads();
-    }
-
-    private void waitForThreads() {
-        // Run all processing.
-        mWorkerThread.quitSafely();
-        try {
-            mWorkerThread.join();
-        } catch (InterruptedException e) {
-        }
-        // Send all callbacks.
-        mMainThread.quitSafely();
-        try {
-            mMainThread.join();
-        } catch (InterruptedException e) {
-        }
-    }
-
-}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index fad102f..672f88d 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -36,7 +36,7 @@
     <fraction name="def_window_transition_scale">100%</fraction>
     <bool name="def_haptic_feedback">true</bool>
 
-    <bool name="def_bluetooth_on">false</bool>
+    <bool name="def_bluetooth_on">true</bool>
     <bool name="def_wifi_display_on">false</bool>
     <bool name="def_install_non_market_apps">false</bool>
     <bool name="def_package_verifier_enable">true</bool>
@@ -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/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index f4f7986..222cc5c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -32,7 +32,7 @@
  * processes can read to determine if their local caches are stale,
  */
 final class GenerationRegistry {
-    private static final String LOG_TAG = "GenerationTracker";
+    private static final String LOG_TAG = "GenerationRegistry";
 
     private static final boolean DEBUG = false;
 
@@ -120,6 +120,9 @@
             final int size = 1 + 2 + 10 + 2 * UserManager.getMaxSupportedUsers();
             try {
                 mBackingStore = new MemoryIntArray(size, false);
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Created backing store " + mBackingStore);
+                }
             } catch (IOException e) {
                 Slog.e(LOG_TAG, "Error creating generation tracker", e);
             }
@@ -131,6 +134,9 @@
         if (mBackingStore != null) {
             try {
                 mBackingStore.close();
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Destroyed backing store " + mBackingStore);
+                }
             } catch (IOException e) {
                 Slog.e(LOG_TAG, "Cannot close generation memory array", e);
             }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ac311ba..afc524c 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;
 
@@ -114,7 +116,7 @@
 public class SettingsProvider extends ContentProvider {
     private static final boolean DEBUG = false;
 
-    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
+    private static final boolean DROP_DATABASE_ON_MIGRATION = true;
 
     private static final String LOG_TAG = "SettingsProvider";
 
@@ -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;
 
@@ -2148,6 +2177,12 @@
 
                     // Now upgrade should work fine.
                     onUpgradeLocked(mUserId, oldVersion, newVersion);
+
+                    // Make a note what happened, so we don't wonder why data was lost
+                    String reason = "Settings rebuilt! Current version: "
+                            + curVersion + " while expected: " + newVersion;
+                    getGlobalSettingsLocked().insertSettingLocked(
+                            Settings.Global.DATABASE_DOWNGRADE_REASON, reason, "android");
                 }
 
                 // Set the global settings version if owner.
@@ -2432,8 +2467,20 @@
                     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 "
+                    Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
                             + currentVersion + " instead; this is probably a bug", new Throwable());
                     if (DEBUG) {
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 73a0449..2170cc1 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,13 +5,14 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \
-        android-support-documents-archive
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 
 LOCAL_PACKAGE_NAME := Shell
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.shell.*
+
 include $(BUILD_PACKAGE)
 
 include $(LOCAL_PATH)/tests/Android.mk
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f1789ea..227d0e9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -114,6 +114,8 @@
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+    <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 18c7dbe..772c344 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -180,7 +180,7 @@
     /** System property (and value) used to stop dumpstate. */
     // TODO: should call ActiveManager API instead
     private static final String CTL_STOP = "ctl.stop";
-    private static final String BUGREPORT_SERVICE = "bugreportplus";
+    private static final String BUGREPORT_SERVICE = "bugreport";
 
     /**
      * Directory on Shell's data storage where screenshots will be stored.
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 8b07599..b9b77a4 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -27,7 +27,6 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
-import android.support.provider.DocumentArchiveHelper;
 import android.webkit.MimeTypeMap;
 
 import java.io.File;
@@ -48,12 +47,10 @@
     };
 
     private File mRoot;
-    private DocumentArchiveHelper mArchiveHelper;
 
     @Override
     public boolean onCreate() {
         mRoot = new File(getContext().getFilesDir(), "bugreports");
-        mArchiveHelper = new DocumentArchiveHelper(this, (char) 0);
         return true;
     }
 
@@ -72,10 +69,6 @@
     @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.queryDocument(documentId, projection);
-        }
-
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
         if (DOC_ID_ROOT.equals(documentId)) {
             final RowBuilder row = result.newRow();
@@ -94,11 +87,6 @@
     public Cursor queryChildDocuments(
             String parentDocumentId, String[] projection, String sortOrder)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(parentDocumentId) ||
-                mArchiveHelper.isSupportedArchiveType(getDocumentType(parentDocumentId))) {
-            return mArchiveHelper.queryChildDocuments(parentDocumentId, projection, sortOrder);
-        }
-
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
         if (DOC_ID_ROOT.equals(parentDocumentId)) {
             final File[] files = mRoot.listFiles();
@@ -116,10 +104,6 @@
     public ParcelFileDescriptor openDocument(
             String documentId, String mode, CancellationSignal signal)
             throws FileNotFoundException {
-        if (mArchiveHelper.isArchivedDocument(documentId)) {
-            return mArchiveHelper.openDocument(documentId, mode, signal);
-        }
-
         if (ParcelFileDescriptor.parseMode(mode) != ParcelFileDescriptor.MODE_READ_ONLY) {
             throw new FileNotFoundException("Failed to open: " + documentId + ", mode = " + mode);
         }
@@ -132,6 +116,7 @@
         if (!getFileForDocId(documentId).delete()) {
             throw new FileNotFoundException("Failed to delete: " + documentId);
         }
+        getContext().getContentResolver().notifyChange(getNotificationUri(), null);
     }
 
     // This is used by BugreportProgressService so that the notification uri shared by
@@ -181,10 +166,6 @@
     private void addFileRow(MatrixCursor result, File file) {
         String mimeType = getTypeForName(file.getName());
         int flags = Document.FLAG_SUPPORTS_DELETE;
-        if (mArchiveHelper.isSupportedArchiveType(mimeType)) {
-            flags |= Document.FLAG_ARCHIVE;
-        }
-
         final RowBuilder row = result.newRow();
         row.add(Document.COLUMN_DOCUMENT_ID, getDocIdForFile(file));
         row.add(Document.COLUMN_MIME_TYPE, mimeType);
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 258c82e..71bfe85 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -23,6 +23,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
+    SystemUIPluginLib \
     Keyguard \
     android-support-v7-recyclerview \
     android-support-v7-preference \
@@ -43,9 +44,11 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
-ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
+ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
     LOCAL_JACK_ENABLED := incremental
+    LOCAL_DX_FLAGS := --multi-dex
+    LOCAL_JACK_FLAGS := --multi-dex native
 endif
 
 include frameworks/base/packages/SettingsLib/common.mk
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3cc16de..8ed1be5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -138,6 +138,9 @@
             android:protectionLevel="signature" />
     <uses-permission android:name="com.android.systemui.permission.SELF" />
 
+    <permission android:name="com.android.systemui.permission.PLUGIN"
+            android:protectionLevel="signature" />
+
     <!-- Adding Quick Settings tiles -->
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
 
diff --git a/packages/SystemUI/plugin/Android.mk b/packages/SystemUI/plugin/Android.mk
new file mode 100644
index 0000000..86527db
--- /dev/null
+++ b/packages/SystemUI/plugin/Android.mk
@@ -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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := SystemUIPluginLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_JAR_EXCLUDE_FILES := none
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/packages/SystemUI/plugin/AndroidManifest.xml b/packages/SystemUI/plugin/AndroidManifest.xml
new file mode 100644
index 0000000..7c057dc
--- /dev/null
+++ b/packages/SystemUI/plugin/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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.systemui.plugins">
+
+    <uses-sdk
+        android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.mk b/packages/SystemUI/plugin/ExamplePlugin/Android.mk
new file mode 100644
index 0000000..4c82c75
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_PACKAGE_NAME := ExamplePlugin
+
+LOCAL_JAVA_LIBRARIES := SystemUIPluginLib
+
+LOCAL_CERTIFICATE := platform
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml
new file mode 100644
index 0000000..ff89bbc
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.plugin.testoverlayplugin">
+
+    <uses-permission android:name="com.android.systemui.permission.PLUGIN" />
+
+    <application>
+        <activity android:name=".PluginSettings"
+            android:label="@string/plugin_label">
+            <intent-filter>
+                <action android:name="com.android.systemui.action.PLUGIN_SETTINGS" />
+            </intent-filter>
+        </activity>
+
+        <service android:name=".SampleOverlayPlugin"
+            android:label="@string/plugin_label">
+            <intent-filter>
+                <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" />
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/layout/colored_overlay.xml b/packages/SystemUI/plugin/ExamplePlugin/res/layout/colored_overlay.xml
new file mode 100644
index 0000000..b2910cb
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/res/layout/colored_overlay.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<com.android.systemui.plugin.testoverlayplugin.CustomView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#80ff0000" />
diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml
new file mode 100644
index 0000000..eb90283
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/res/layout/plugin_settings.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:text="@string/plugin_settings_here"
+    android:gravity="center" />
diff --git a/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml
new file mode 100644
index 0000000..a0bfe84
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <string name="plugin_settings_here" translatable="false">Plugin settings go here</string>
+    <string name="plugin_label" translatable="false">Overlay Plugin</string>
+
+</resources>
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/CustomView.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/CustomView.java
new file mode 100644
index 0000000..5fdbbf9
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/CustomView.java
@@ -0,0 +1,46 @@
+/*
+ * 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.systemui.plugin.testoverlayplugin;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * View with some logging to show that its being run.
+ */
+public class CustomView extends View {
+
+    private static final String TAG = "CustomView";
+
+    public CustomView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        Log.d(TAG, "new instance");
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Log.d(TAG, "onAttachedToWindow");
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        Log.d(TAG, "onDetachedFromWindow");
+    }
+}
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java
new file mode 100644
index 0000000..cf39075
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/PluginSettings.java
@@ -0,0 +1,32 @@
+/*
+ * 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.systemui.plugin.testoverlayplugin;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * DO NOT Reference Plugin interfaces here, this runs in the plugin APK's process
+ * and is only for modifying settings.
+ */
+public class PluginSettings extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.plugin_settings);
+    }
+}
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
new file mode 100644
index 0000000..a2f84dc
--- /dev/null
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
@@ -0,0 +1,71 @@
+/*
+ * 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.systemui.plugin.testoverlayplugin;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.plugins.OverlayPlugin;
+
+public class SampleOverlayPlugin implements OverlayPlugin {
+    private static final String TAG = "SampleOverlayPlugin";
+    private Context mPluginContext;
+
+    private View mStatusBarView;
+    private View mNavBarView;
+
+    @Override
+    public int getVersion() {
+        Log.d(TAG, "getVersion " + VERSION);
+        return VERSION;
+    }
+
+    @Override
+    public void onCreate(Context sysuiContext, Context pluginContext) {
+        Log.d(TAG, "onCreate");
+        mPluginContext = pluginContext;
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy");
+        if (mStatusBarView != null) {
+            mStatusBarView.post(
+                    () -> ((ViewGroup) mStatusBarView.getParent()).removeView(mStatusBarView));
+        }
+        if (mNavBarView != null) {
+            mNavBarView.post(() -> ((ViewGroup) mNavBarView.getParent()).removeView(mNavBarView));
+        }
+    }
+
+    @Override
+    public void setup(View statusBar, View navBar) {
+        Log.d(TAG, "Setup");
+
+        if (statusBar instanceof ViewGroup) {
+            mStatusBarView = LayoutInflater.from(mPluginContext)
+                    .inflate(R.layout.colored_overlay, (ViewGroup) statusBar, false);
+            ((ViewGroup) statusBar).addView(mStatusBarView);
+        }
+        if (navBar instanceof ViewGroup) {
+            mNavBarView = LayoutInflater.from(mPluginContext)
+                    .inflate(R.layout.colored_overlay, (ViewGroup) navBar, false);
+            ((ViewGroup) navBar).addView(mNavBarView);
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
new file mode 100644
index 0000000..1b8efa7
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+
+/**
+ * An Intent Button represents a triggerable element in SysUI that consists of an
+ * Icon and an intent to trigger when it is activated (clicked, swiped, etc.).
+ */
+public interface IntentButtonProvider extends Plugin {
+
+    public static final int VERSION = 1;
+
+    public IntentButton getIntentButton();
+
+    public interface IntentButton {
+        public static class IconState {
+            public boolean isVisible = true;
+            public CharSequence contentDescription = null;
+            public Drawable drawable;
+        }
+
+        public IconState getIcon();
+
+        public Intent getIntent();
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
new file mode 100644
index 0000000..91a2604
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java
@@ -0,0 +1,24 @@
+/*
+ * 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.systemui.plugins;
+
+import android.view.View;
+
+public interface OverlayPlugin extends Plugin {
+
+    String ACTION = "com.android.systemui.action.PLUGIN_OVERLAY";
+    int VERSION = 1;
+
+    void setup(View statusBar, View navBar);
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
new file mode 100644
index 0000000..b31b199
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Plugin.java
@@ -0,0 +1,132 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.Context;
+
+/**
+ * Plugins are separate APKs that
+ * are expected to implement interfaces provided by SystemUI.  Their
+ * code is dynamically loaded into the SysUI process which can allow
+ * for multiple prototypes to be created and run on a single android
+ * build.
+ *
+ * PluginLifecycle:
+ * <pre class="prettyprint">
+ *
+ * plugin.onCreate(Context sysuiContext, Context pluginContext);
+ * --- This is always called before any other calls
+ *
+ * pluginListener.onPluginConnected(Plugin p);
+ * --- This lets the plugin hook know that a plugin is now connected.
+ *
+ * ** Any other calls back and forth between sysui/plugin **
+ *
+ * pluginListener.onPluginDisconnected(Plugin p);
+ * --- Lets the plugin hook know that it should stop interacting with
+ *     this plugin and drop all references to it.
+ *
+ * plugin.onDestroy();
+ * --- Finally the plugin can perform any cleanup to ensure that its not
+ *     leaking into the SysUI process.
+ *
+ * Any time a plugin APK is updated the plugin is destroyed and recreated
+ * to load the new code/resources.
+ *
+ * </pre>
+ *
+ * Creating plugin hooks:
+ *
+ * To create a plugin hook, first create an interface in
+ * frameworks/base/packages/SystemUI/plugin that extends Plugin.
+ * Include in it any hooks you want to be able to call into from
+ * sysui and create callback interfaces for anything you need to
+ * pass through into the plugin.
+ *
+ * Then to attach to any plugins simply add a plugin listener and
+ * onPluginConnected will get called whenever new plugins are installed,
+ * updated, or enabled.  Like this example from SystemUIApplication:
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * PluginManager.getInstance(this).addPluginListener(OverlayPlugin.COMPONENT,
+ *        new PluginListener<OverlayPlugin>() {
+ *        @Override
+ *        public void onPluginConnected(OverlayPlugin plugin) {
+ *            PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
+ *            if (phoneStatusBar != null) {
+ *                plugin.setup(phoneStatusBar.getStatusBarWindow(),
+ *                phoneStatusBar.getNavigationBarView());
+ *            }
+ *        }
+ * }, OverlayPlugin.VERSION, true /* Allow multiple plugins *\/);
+ * }
+ * </pre>
+ * Note the VERSION included here.  Any time incompatible changes in the
+ * interface are made, this version should be changed to ensure old plugins
+ * aren't accidentally loaded.  Since the plugin library is provided by
+ * SystemUI, default implementations can be added for new methods to avoid
+ * version changes when possible.
+ *
+ * Implementing a Plugin:
+ *
+ * See the ExamplePlugin for an example Android.mk on how to compile
+ * a plugin.  Note that SystemUILib is not static for plugins, its classes
+ * are provided by SystemUI.
+ *
+ * Plugin security is based around a signature permission, so plugins must
+ * hold the following permission in their manifest.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <uses-permission android:name="com.android.systemui.permission.PLUGIN" />
+ * }
+ * </pre>
+ *
+ * A plugin is found through a querying for services, so to let SysUI know
+ * about it, create a service with a name that points at your implementation
+ * of the plugin interface with the action accompanying it:
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <service android:name=".TestOverlayPlugin">
+ *    <intent-filter>
+ *        <action android:name="com.android.systemui.action.PLUGIN_COMPONENT" />
+ *    </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public interface Plugin {
+
+    /**
+     * Should be implemented as the following directly referencing the version constant
+     * from the plugin interface being implemented, this will allow recompiles to automatically
+     * pick up the current version.
+     * <pre class="prettyprint">
+     * {@literal
+     * public int getVersion() {
+     *     return VERSION;
+     * }
+     * }
+     * @return
+     */
+    int getVersion();
+
+    default void onCreate(Context sysuiContext, Context pluginContext) {
+    }
+
+    default void onDestroy() {
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
new file mode 100644
index 0000000..f98667d
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -0,0 +1,317 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PluginInstanceManager<T extends Plugin> {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "PluginInstanceManager";
+    private static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
+
+    private final Context mContext;
+    private final PluginListener<T> mListener;
+    private final String mAction;
+    private final boolean mAllowMultiple;
+    private final int mVersion;
+
+    @VisibleForTesting
+    final MainHandler mMainHandler;
+    @VisibleForTesting
+    final PluginHandler mPluginHandler;
+    private final boolean isDebuggable;
+    private final PackageManager mPm;
+    private final PluginManager mManager;
+
+    PluginInstanceManager(Context context, String action, PluginListener<T> listener,
+            boolean allowMultiple, Looper looper, int version, PluginManager manager) {
+        this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
+                manager, Build.IS_DEBUGGABLE);
+    }
+
+    @VisibleForTesting
+    PluginInstanceManager(Context context, PackageManager pm, String action,
+            PluginListener<T> listener, boolean allowMultiple, Looper looper, int version,
+            PluginManager manager, boolean debuggable) {
+        mMainHandler = new MainHandler(Looper.getMainLooper());
+        mPluginHandler = new PluginHandler(looper);
+        mManager = manager;
+        mContext = context;
+        mPm = pm;
+        mAction = action;
+        mListener = listener;
+        mAllowMultiple = allowMultiple;
+        mVersion = version;
+        isDebuggable = debuggable;
+    }
+
+    public void loadAll() {
+        if (DEBUG) Log.d(TAG, "startListening");
+        mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
+    }
+
+    public void destroy() {
+        if (DEBUG) Log.d(TAG, "stopListening");
+        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
+        for (PluginInfo plugin : plugins) {
+            mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
+                    plugin.mPlugin).sendToTarget();
+        }
+    }
+
+    public void onPackageRemoved(String pkg) {
+        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
+    }
+
+    public void onPackageChange(String pkg) {
+        mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
+        mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkg).sendToTarget();
+    }
+
+    public boolean checkAndDisable(String className) {
+        boolean disableAny = false;
+        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
+        for (PluginInfo info : plugins) {
+            if (className.startsWith(info.mPackage)) {
+                disable(info);
+                disableAny = true;
+            }
+        }
+        return disableAny;
+    }
+
+    public void disableAll() {
+        ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
+        plugins.forEach(this::disable);
+    }
+
+    private void disable(PluginInfo info) {
+        // Live by the sword, die by the sword.
+        // Misbehaving plugins get disabled and won't come back until uninstall/reinstall.
+
+        // If a plugin is detected in the stack of a crash then this will be called for that
+        // plugin, if the plugin causing a crash cannot be identified, they are all disabled
+        // assuming one of them must be bad.
+        Log.w(TAG, "Disabling plugin " + info.mPackage + "/" + info.mClass);
+        mPm.setComponentEnabledSetting(
+                new ComponentName(info.mPackage, info.mClass),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    private class MainHandler extends Handler {
+        private static final int PLUGIN_CONNECTED = 1;
+        private static final int PLUGIN_DISCONNECTED = 2;
+
+        public MainHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case PLUGIN_CONNECTED:
+                    if (DEBUG) Log.d(TAG, "onPluginConnected");
+                    PluginPrefs.setHasPlugins(mContext);
+                    PluginInfo<T> info = (PluginInfo<T>) msg.obj;
+                    info.mPlugin.onCreate(mContext, info.mPluginContext);
+                    mListener.onPluginConnected(info.mPlugin);
+                    break;
+                case PLUGIN_DISCONNECTED:
+                    if (DEBUG) Log.d(TAG, "onPluginDisconnected");
+                    mListener.onPluginDisconnected((T) msg.obj);
+                    ((T) msg.obj).onDestroy();
+                    break;
+                default:
+                    super.handleMessage(msg);
+                    break;
+            }
+        }
+    }
+
+    private class PluginHandler extends Handler {
+        private static final int QUERY_ALL = 1;
+        private static final int QUERY_PKG = 2;
+        private static final int REMOVE_PKG = 3;
+
+        private final ArrayList<PluginInfo<T>> mPlugins = new ArrayList<>();
+
+        public PluginHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case QUERY_ALL:
+                    if (DEBUG) Log.d(TAG, "queryAll " + mAction);
+                    for (int i = mPlugins.size() - 1; i >= 0; i--) {
+                        PluginInfo<T> plugin = mPlugins.get(i);
+                        mListener.onPluginDisconnected(plugin.mPlugin);
+                        plugin.mPlugin.onDestroy();
+                    }
+                    mPlugins.clear();
+                    handleQueryPlugins(null);
+                    break;
+                case REMOVE_PKG:
+                    String pkg = (String) msg.obj;
+                    for (int i = mPlugins.size() - 1; i >= 0; i--) {
+                        final PluginInfo<T> plugin = mPlugins.get(i);
+                        if (plugin.mPackage.equals(pkg)) {
+                            mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
+                                    plugin.mPlugin).sendToTarget();
+                            mPlugins.remove(i);
+                        }
+                    }
+                    break;
+                case QUERY_PKG:
+                    String p = (String) msg.obj;
+                    if (DEBUG) Log.d(TAG, "queryPkg " + p + " " + mAction);
+                    if (mAllowMultiple || (mPlugins.size() == 0)) {
+                        handleQueryPlugins(p);
+                    } else {
+                        if (DEBUG) Log.d(TAG, "Too many of " + mAction);
+                    }
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+
+        private void handleQueryPlugins(String pkgName) {
+            // This isn't actually a service and shouldn't ever be started, but is
+            // a convenient PM based way to manage our plugins.
+            Intent intent = new Intent(mAction);
+            if (pkgName != null) {
+                intent.setPackage(pkgName);
+            }
+            List<ResolveInfo> result =
+                    mPm.queryIntentServices(intent, 0);
+            if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
+            if (result.size() > 1 && !mAllowMultiple) {
+                // TODO: Show warning.
+                Log.w(TAG, "Multiple plugins found for " + mAction);
+                return;
+            }
+            for (ResolveInfo info : result) {
+                ComponentName name = new ComponentName(info.serviceInfo.packageName,
+                        info.serviceInfo.name);
+                PluginInfo<T> t = handleLoadPlugin(name);
+                if (t == null) continue;
+                mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
+                mPlugins.add(t);
+            }
+        }
+
+        protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
+            // This was already checked, but do it again here to make extra extra sure, we don't
+            // use these on production builds.
+            if (!isDebuggable) {
+                // Never ever ever allow these on production builds, they are only for prototyping.
+                Log.d(TAG, "Somehow hit second debuggable check");
+                return null;
+            }
+            String pkg = component.getPackageName();
+            String cls = component.getClassName();
+            try {
+                PackageManager pm = mPm;
+                ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+                // TODO: This probably isn't needed given that we don't have IGNORE_SECURITY on
+                if (pm.checkPermission(PLUGIN_PERMISSION, pkg)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    Log.d(TAG, "Plugin doesn't have permission: " + pkg);
+                    return null;
+                }
+                // Create our own ClassLoader so we can use our own code as the parent.
+                ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
+                Context pluginContext = new PluginContextWrapper(
+                        mContext.createApplicationContext(info, 0), classLoader);
+                Class<?> pluginClass = Class.forName(cls, true, classLoader);
+                T plugin = (T) pluginClass.newInstance();
+                if (plugin.getVersion() != mVersion) {
+                    // TODO: Warn user.
+                    Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
+                            + ", expected " + mVersion);
+                    return null;
+                }
+                if (DEBUG) Log.d(TAG, "createPlugin");
+                return new PluginInfo(pkg, cls, plugin, pluginContext);
+            } catch (Exception e) {
+                Log.w(TAG, "Couldn't load plugin: " + pkg, e);
+                return null;
+            }
+        }
+    }
+
+    public static class PluginContextWrapper extends ContextWrapper {
+        private final ClassLoader mClassLoader;
+        private LayoutInflater mInflater;
+
+        public PluginContextWrapper(Context base, ClassLoader classLoader) {
+            super(base);
+            mClassLoader = classLoader;
+        }
+
+        @Override
+        public ClassLoader getClassLoader() {
+            return mClassLoader;
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            if (LAYOUT_INFLATER_SERVICE.equals(name)) {
+                if (mInflater == null) {
+                    mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
+                }
+                return mInflater;
+            }
+            return getBaseContext().getSystemService(name);
+        }
+    }
+
+    private static class PluginInfo<T> {
+        private final Context mPluginContext;
+        private T mPlugin;
+        private String mClass;
+        private String mPackage;
+
+        public PluginInfo(String pkg, String cls, T plugin, Context pluginContext) {
+            mPlugin = plugin;
+            mClass = cls;
+            mPackage = pkg;
+            mPluginContext = pluginContext;
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
new file mode 100644
index 0000000..b2f92d6
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
@@ -0,0 +1,36 @@
+/*
+ * 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.systemui.plugins;
+
+/**
+ * Interface for listening to plugins being connected.
+ */
+public interface PluginListener<T extends Plugin> {
+    /**
+     * Called when the plugin has been loaded and is ready to be used.
+     * This may be called multiple times if multiple plugins are allowed.
+     * It may also be called in the future if the plugin package changes
+     * and needs to be reloaded.
+     */
+    void onPluginConnected(T plugin);
+
+    /**
+     * Called when a plugin has been uninstalled/updated and should be removed
+     * from use.
+     */
+    default void onPluginDisconnected(T plugin) {
+        // Optional.
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
new file mode 100644
index 0000000..686b4d4
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -0,0 +1,234 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Build;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import dalvik.system.PathClassLoader;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Map;
+
+/**
+ * @see Plugin
+ */
+public class PluginManager extends BroadcastReceiver {
+
+    private static PluginManager sInstance;
+
+    private final HandlerThread mBackgroundThread;
+    private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
+            = new ArrayMap<>();
+    private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
+    private final Context mContext;
+    private final PluginInstanceManagerFactory mFactory;
+    private final boolean isDebuggable;
+    private final PluginPrefs mPluginPrefs;
+    private ClassLoaderFilter mParentClassLoader;
+
+    private PluginManager(Context context) {
+        this(context, new PluginInstanceManagerFactory(),
+                Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
+    }
+
+    @VisibleForTesting
+    PluginManager(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
+            UncaughtExceptionHandler defaultHandler) {
+        mContext = context;
+        mFactory = factory;
+        mBackgroundThread = new HandlerThread("Plugins");
+        mBackgroundThread.start();
+        isDebuggable = debuggable;
+        mPluginPrefs = new PluginPrefs(mContext);
+
+        PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
+                defaultHandler);
+        Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
+    }
+
+    public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
+            int version) {
+        addPluginListener(action, listener, version, false);
+    }
+
+    public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
+            int version, boolean allowMultiple) {
+        if (!isDebuggable) {
+            // Never ever ever allow these on production builds, they are only for prototyping.
+            return;
+        }
+        mPluginPrefs.addAction(action);
+        PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
+                allowMultiple, mBackgroundThread.getLooper(), version, this);
+        p.loadAll();
+        mPluginMap.put(listener, p);
+        if (mPluginMap.size() == 1) {
+            startListening();
+        }
+    }
+
+    public void removePluginListener(PluginListener<?> listener) {
+        if (!isDebuggable) {
+            // Never ever ever allow these on production builds, they are only for prototyping.
+            return;
+        }
+        if (!mPluginMap.containsKey(listener)) return;
+        mPluginMap.remove(listener).destroy();
+        if (mPluginMap.size() == 0) {
+            stopListening();
+        }
+    }
+
+    private void startListening() {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(this, filter);
+        filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
+        mContext.registerReceiver(this, filter);
+    }
+
+    private void stopListening() {
+        mContext.unregisterReceiver(this);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+            for (PluginInstanceManager manager : mPluginMap.values()) {
+                manager.loadAll();
+            }
+        } else {
+            Uri data = intent.getData();
+            String pkg = data.getEncodedSchemeSpecificPart();
+            clearClassLoader(pkg);
+            if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                for (PluginInstanceManager manager : mPluginMap.values()) {
+                    manager.onPackageChange(pkg);
+                }
+            } else {
+                for (PluginInstanceManager manager : mPluginMap.values()) {
+                    manager.onPackageRemoved(pkg);
+                }
+            }
+        }
+    }
+
+    public ClassLoader getClassLoader(String sourceDir, String pkg) {
+        if (mClassLoaders.containsKey(pkg)) {
+            return mClassLoaders.get(pkg);
+        }
+        ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
+        mClassLoaders.put(pkg, classLoader);
+        return classLoader;
+    }
+
+    private void clearClassLoader(String pkg) {
+        mClassLoaders.remove(pkg);
+    }
+
+    ClassLoader getParentClassLoader() {
+        if (mParentClassLoader == null) {
+            // Lazily load this so it doesn't have any effect on devices without plugins.
+            mParentClassLoader = new ClassLoaderFilter(getClass().getClassLoader(),
+                    "com.android.systemui.plugin");
+        }
+        return mParentClassLoader;
+    }
+
+    public static PluginManager getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new PluginManager(context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    @VisibleForTesting
+    public static class PluginInstanceManagerFactory {
+        public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
+                String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
+                int version, PluginManager manager) {
+            return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
+                    version, manager);
+        }
+    }
+
+
+    // This allows plugins to include any libraries or copied code they want by only including
+    // classes from the plugin library.
+    private static class ClassLoaderFilter extends ClassLoader {
+        private final String mPackage;
+        private final ClassLoader mBase;
+
+        public ClassLoaderFilter(ClassLoader base, String pkg) {
+            super(ClassLoader.getSystemClassLoader());
+            mBase = base;
+            mPackage = pkg;
+        }
+
+        @Override
+        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            if (!name.startsWith(mPackage)) super.loadClass(name, resolve);
+            return mBase.loadClass(name);
+        }
+    }
+
+    private class PluginExceptionHandler implements UncaughtExceptionHandler {
+        private final UncaughtExceptionHandler mHandler;
+
+        private PluginExceptionHandler(UncaughtExceptionHandler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void uncaughtException(Thread thread, Throwable throwable) {
+            // Search for and disable plugins that may have been involved in this crash.
+            boolean disabledAny = checkStack(throwable);
+            if (!disabledAny) {
+                // We couldn't find any plugins involved in this crash, just to be safe
+                // disable all the plugins, so we can be sure that SysUI is running as
+                // best as possible.
+                for (PluginInstanceManager manager : mPluginMap.values()) {
+                    manager.disableAll();
+                }
+            }
+
+            // Run the normal exception handler so we can crash and cleanup our state.
+            mHandler.uncaughtException(thread, throwable);
+        }
+
+        private boolean checkStack(Throwable throwable) {
+            if (throwable == null) return false;
+            boolean disabledAny = false;
+            for (StackTraceElement element : throwable.getStackTrace()) {
+                for (PluginInstanceManager manager : mPluginMap.values()) {
+                    disabledAny |= manager.checkAndDisable(element.getClassName());
+                }
+            }
+            return disabledAny | checkStack(throwable.getCause());
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java
new file mode 100644
index 0000000..3671b3c
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginPrefs.java
@@ -0,0 +1,61 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.ArraySet;
+
+import java.util.Set;
+
+/**
+ * Storage for all plugin actions in SharedPreferences.
+ *
+ * This allows the list of actions that the Tuner needs to search for to be generated
+ * instead of hard coded.
+ */
+public class PluginPrefs {
+
+    private static final String PREFS = "plugin_prefs";
+
+    private static final String PLUGIN_ACTIONS = "actions";
+    private static final String HAS_PLUGINS = "plugins";
+
+    private final Set<String> mPluginActions;
+    private final SharedPreferences mSharedPrefs;
+
+    public PluginPrefs(Context context) {
+        mSharedPrefs = context.getSharedPreferences(PREFS, 0);
+        mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null));
+    }
+
+    public Set<String> getPluginList() {
+        return mPluginActions;
+    }
+
+    public synchronized void addAction(String action) {
+        if (mPluginActions.add(action)){
+            mSharedPrefs.edit().putStringSet(PLUGIN_ACTIONS, mPluginActions).commit();
+        }
+    }
+
+    public static boolean hasPlugins(Context context) {
+        return context.getSharedPreferences(PREFS, 0).getBoolean(HAS_PLUGINS, false);
+    }
+
+    public static void setHasPlugins(Context context) {
+        context.getSharedPreferences(PREFS, 0).edit().putBoolean(HAS_PLUGINS, true).commit();
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java
new file mode 100644
index 0000000..af49d43
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java
@@ -0,0 +1,27 @@
+/*
+ * 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.systemui.plugins;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+public class PluginUtils {
+
+    public static void setId(Context sysuiContext, View view, String id) {
+        int i = sysuiContext.getResources().getIdentifier(id, "id", sysuiContext.getPackageName());
+        view.setId(i);
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ViewProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ViewProvider.java
new file mode 100644
index 0000000..18ca8e6
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ViewProvider.java
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.plugins;
+
+import android.view.View;
+
+public interface ViewProvider extends Plugin {
+    View getView();
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
new file mode 100644
index 0000000..3270587
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.systemui.plugins.qs;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+public abstract class QSContainer extends FrameLayout {
+
+    public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
+
+    // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
+    // change in incompatible ways.
+    public static final int VERSION = 1;
+
+    public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public abstract void setPanelView(HeightListener notificationPanelView);
+    public abstract BaseStatusBarHeader getHeader();
+
+    public abstract int getQsMinExpansionHeight();
+    public abstract int getDesiredHeight();
+    public abstract void setHeightOverride(int desiredHeight);
+    public abstract void setHeaderClickable(boolean qsExpansionEnabled);
+    public abstract boolean isCustomizing();
+    public abstract void setOverscrolling(boolean overscrolling);
+    public abstract void setExpanded(boolean qsExpanded);
+    public abstract void setListening(boolean listening);
+    public abstract boolean isShowingDetail();
+    public abstract void closeDetail();
+    public abstract void setKeyguardShowing(boolean keyguardShowing);
+    public abstract void animateHeaderSlidingIn(long delay);
+    public abstract void animateHeaderSlidingOut();
+    public abstract void setQsExpansion(float qsExpansionFraction, float headerTranslation);
+    public abstract void setHeaderListening(boolean listening);
+    public abstract void notifyCustomizeChanged();
+
+    public abstract void setContainer(ViewGroup container);
+
+    public interface HeightListener {
+        void onQsHeightChanged();
+    }
+
+    public interface Callback {
+        void onShowingDetail(DetailAdapter detail, int x, int y);
+        void onToggleStateChanged(boolean state);
+        void onScanStateChanged(boolean state);
+    }
+
+    public interface DetailAdapter {
+        CharSequence getTitle();
+        Boolean getToggleState();
+        default boolean getToggleEnabled() {
+            return true;
+        }
+        View createDetailView(Context context, View convertView, ViewGroup parent);
+        Intent getSettingsIntent();
+        void setToggleState(boolean state);
+        int getMetricsCategory();
+
+        /**
+         * Indicates whether the detail view wants to have its header (back button, title and
+         * toggle) shown.
+         */
+        default boolean hasHeader() { return true; }
+    }
+
+    public abstract static class BaseStatusBarHeader extends RelativeLayout {
+
+        public BaseStatusBarHeader(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public abstract int getCollapsedHeight();
+        public abstract int getExpandedHeight();
+
+        public abstract void setExpanded(boolean b);
+        public abstract void setExpansion(float headerExpansionFraction);
+        public abstract void setListening(boolean listening);
+        public abstract void updateEverything();
+        public abstract void setActivityStarter(ActivityStarter activityStarter);
+        public abstract void setCallback(Callback qsPanelCallback);
+        public abstract View getExpandView();
+    }
+
+    /**
+     * An interface to start activities. This is used to as a callback from the views to
+     * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
+     * Keyguard.
+     */
+    public static interface ActivityStarter {
+
+        void startPendingIntentDismissingKeyguard(PendingIntent intent);
+        void startActivity(Intent intent, boolean dismissShade);
+        void startActivity(Intent intent, boolean dismissShade, Callback callback);
+        void preventNextAnimation();
+
+        interface Callback {
+            void onActivityStarted(int resultCode);
+        }
+    }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
new file mode 100644
index 0000000..09879d8
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.plugins.statusbar.phone;
+
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.plugins.Plugin;
+
+public interface NavBarButtonProvider extends Plugin {
+
+    public static final String ACTION = "com.android.systemui.action.PLUGIN_NAV_BUTTON";
+
+    public static final int VERSION = 1;
+
+    /**
+     * Returns a view in the nav bar.  If the id is set "back", "home", "recent_apps", "menu",
+     * or "ime_switcher", it is expected to implement ButtonInterface.
+     */
+    public View createView(String spec, ViewGroup parent);
+
+    /**
+     * Interface for button actions.
+     */
+    interface ButtonInterface {
+        void setImageResource(@DrawableRes int resId);
+
+        void setImageDrawable(@Nullable Drawable drawable);
+
+        void abortCurrentGesture();
+
+        void setLandscape(boolean landscape);
+
+        void setCarMode(boolean carMode);
+    }
+}
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 9182f7e..364885a 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -37,3 +37,6 @@
 
 -keep class ** extends android.support.v14.preference.PreferenceFragment
 -keep class com.android.systemui.tuner.*
+-keep class com.android.systemui.plugins.** {
+    public protected **;
+}
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-nodpi/play.xml b/packages/SystemUI/res/drawable-nodpi/play.xml
index 747e60b..7720230 100644
--- a/packages/SystemUI/res/drawable-nodpi/play.xml
+++ b/packages/SystemUI/res/drawable-nodpi/play.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M8.0,5.0l0.0,14.0l11.0,-7.0z"/>
-    <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
 </vector>
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/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml
index 9d292cc..2c5ad27 100644
--- a/packages/SystemUI/res/drawable/car_ic_arrow.xml
+++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
index 7ddb40c..314a25a 100644
--- a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
@@ -18,9 +18,6 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:pathData="M0 0h24v24H0z" />
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
index 6519673..1183203 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_backspace.xml
@@ -19,7 +19,6 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-    <path android:pathData="M0 0h24v24H0z" />
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M22 3H7c-.69 0-1.23 .35 -1.59 .88 L0 12l5.41 8.11c.36 .53 .9 .89
 1.59 .89 h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
index 599f350..66b1307 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_enter.xml
@@ -19,7 +19,6 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-    <path android:pathData="M0 0h24v24H0z" />
    <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
index 038187e..57d0423e9c 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_left.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
index 1e2195e..be8fe8c 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_meta.xml
@@ -24,5 +24,4 @@
 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27 .28 v.79l5 4.99L20.49
 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5
 14z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
index f2d7315..720d4e4 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_right.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
index 36a83b1..350c994 100644
--- a/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
+++ b/packages/SystemUI/res/drawable/ic_ksh_key_up.xml
@@ -21,5 +21,4 @@
         android:viewportHeight="24">
     <path android:fillColor="@color/ksh_key_item_color"
             android:pathData="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" />
-    <path android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
index d9a4f7b..5b65f10 100644
--- a/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_pause_white_24dp.xml
@@ -22,6 +22,4 @@
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
index b8fa99e..ddc9e8d 100644
--- a/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white_24dp.xml
@@ -22,6 +22,4 @@
     <path
         android:fillColor="#FFFFFF"
         android:pathData="M8 5v14l11-7z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
index b4144a3..d11b6f4 100644
--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
@@ -14,8 +14,9 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
+        android:autoMirrored="true"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="40.0"
         android:viewportHeight="40.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
index 4d2a35e..2dcdb71 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M0 0h26v24H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M21.0,8.5
         c0.85,0.0 1.6,0.23 2.3,0.62l2.24,-2.79
diff --git a/packages/SystemUI/res/drawable/ic_send.xml b/packages/SystemUI/res/drawable/ic_send.xml
index 6ce3672..7cac2a4 100644
--- a/packages/SystemUI/res/drawable/ic_send.xml
+++ b/packages/SystemUI/res/drawable/ic_send.xml
@@ -22,7 +22,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
-    <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
index 4e2a024..694019e9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
@@ -14,9 +14,9 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="17.0dp"
+        android:width="8.5dp"
         android:height="17.0dp"
-        android:viewportWidth="40.0"
+        android:viewportWidth="20.0"
         android:viewportHeight="40.0">
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.xml
new file mode 100644
index 0000000..0a1730a
--- /dev/null
+++ b/packages/SystemUI/res/layout/emergency_cryptkeeper_text.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
+  -->
+
+<com.android.systemui.statusbar.policy.EmergencyCryptkeeperText
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/emergency_cryptkeeper_text"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+        android:paddingStart="6dp"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:gravity="center_vertical|start"
+        />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 26c7339..9e0a6fe 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.systemui.qs.QSContainer
+<com.android.systemui.qs.QSContainerImpl
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/quick_settings_container"
         android:layout_width="match_parent"
@@ -38,4 +38,4 @@
     <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
         android:visibility="gone" />
 
-</com.android.systemui.qs.QSContainer>
+</com.android.systemui.qs.QSContainerImpl>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 1978a93..c8e5b61 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -30,8 +30,8 @@
         android:id="@+id/lock_to_app_fab"
         android:layout_width="@dimen/recents_lock_to_app_size"
         android:layout_height="@dimen/recents_lock_to_app_size"
-        android:layout_gravity="bottom|right"
-        android:layout_marginRight="15dp"
+        android:layout_gravity="bottom|end"
+        android:layout_marginEnd="15dp"
         android:layout_marginBottom="15dp"
         android:translationZ="4dp"
         android:contentDescription="@string/recents_lock_to_app_button_label"
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index f0c4e59..73f26e2 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
             android:singleLine="true"
             android:ellipsize="start"
             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
-            android:imeOptions="actionNone|flagNoExtractUi" />
+            android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen" />
 
     <FrameLayout
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 39c16d7..63af3e0 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -77,4 +77,11 @@
         </com.android.keyguard.AlphaOptimizedLinearLayout>
     </LinearLayout>
 
+    <ViewStub
+        android:id="@+id/emergency_cryptkeeper_text"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout="@layout/emergency_cryptkeeper_text"
+    />
+
 </com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 3d70969..0339e03 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -19,7 +19,7 @@
 
 <com.android.systemui.statusbar.phone.NotificationPanelView 
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/notification_panel"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -39,14 +39,15 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <com.android.systemui.AutoReinflateContainer
+        <com.android.systemui.PluginInflateContainer
             android:id="@+id/qs_auto_reinflate_container"
             android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
             android:clipToPadding="false"
-            android:clipChildren="false" />
+            android:clipChildren="false"
+            systemui:viewType="com.android.systemui.plugins.qs.QSContainer" />
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml
new file mode 100644
index 0000000..c89c02f
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_widget_settings_switch.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="center_vertical">
+
+    <ImageView
+        android:id="@+id/settings"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_settings"
+        android:tint="@android:color/black"
+        android:padding="12dp"
+        android:background="?android:attr/selectableItemBackgroundBorderless" />
+
+    <View
+        android:id="@+id/divider"
+        android:layout_width="1dp"
+        android:layout_height="30dp"
+        android:layout_marginEnd="8dp"
+        android:background="?android:attr/listDivider" />
+
+    <Switch
+        android:id="@android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:background="@null" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 02f08c5..7d3eb8d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die gestelde dataperk bereik is, het die toestel datagebruik vir die res van hierdie siklus onderbreek.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Jy het die datalimiet wat jy gestel het, bereik. Jy gebruik nie meer sellulêre data nie.\n\nAs jy voortgaan, kan heffings vir datagebruik geld."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Toestel kan gemonitor word"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan gemonitor word"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan dalk gemonitor word"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan dalk gemonitor word"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Toestelmonitering"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielmonitering"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Netwerkmonitering"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nKontak jou administrateur vir meer inligting."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jou toestel word bestuur deur <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nJou administrateur kan instelings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word en jou toestel se ligginginligting monitor en bestuur.\n\nJy is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nVir meer inligting, kontak jou administrateur."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktiveer die verdeling van die skerm deur op te swiep"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiveer gebaar om skerm te verdeel deur van die Oorsig-knoppie af op te swiep"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f717ee9..fb73729 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"እርስዎ ያስቀመጡት የውሂብ ገደብ ላይ ተደርሷል። ከእንግዲህ ተንቀሳቃሽ ውሂብ እየተጠቀሙ አይደለም ያሉት።\n\nከቆመበት ከቀጠሉ የውሂብ አጠቃቀም ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"መሣሪያው ክትትል የሚደረግበት ሊሆን ይችላል"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"መገለጫ ክትትል ሊደረግበት ይችላል"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"አውታረ መረብ በክትትል እየተደረገበት ሊሆን ይችላል"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"አውታረ መረብ ክትትል የሚደረግበት ሊሆን ይችላል"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"የመሣሪያ ክትትል"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"መገለጫን መከታተል"</string>
     <string name="monitoring_title" msgid="169206259253048106">"የአውታረ መረብ ክትትል"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nእንዲሁም የግል አውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋርም ተገናኝተዋል።"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"የእርስዎ መሣሪያ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚተዳደረው።\n\nየእርስዎ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ የአካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nእርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችን  ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"የተከፈለ ማያ ገጽ ወደ ላይ የማንሸራተት ጣት ምልክትን ያንቁ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ከአጠቃላይ እይታ አዝራሩ ወደ ላይ በማንሸራተት ወደ የተከፈለ ማያ ገጽ የሚገቡበትን የጣት ምልክት ያንቁ"</string>
     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 07af00e..b7bb97e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"تم الوصول إلى حد البيانات الذي عيَّنته، ولم يعد بإمكانك استخدام بيانات شبكة الجوّال.\n\nعند الاستئناف، قد يتم تحصيل رسوم مقابل استخدام البيانات."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل"</string>
@@ -411,6 +411,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ربما تتم مراقبة الجهاز"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ربما تتم مراقبة الملف الشخصي"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"قد تكون الشبكة خاضعة للمراقبة"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"قد تكون الشبكة خاضعة للمراقبة"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"مراقبة الأجهزة"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"مراقبة الملف الشخصي"</string>
     <string name="monitoring_title" msgid="169206259253048106">"مراقبة الشبكات"</string>
@@ -423,6 +424,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nأنت متصل أيضًا بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"تتم إدارة جهازك عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nيمكن للمشرف مراقبة وإدارة كل من الإعدادات والوصول إلى الشركة والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع لجهازك.\n\nأنت متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
@@ -499,8 +501,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"تمكين إيماءة تقسيم الشاشة بالتمرير السريع لأعلى"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"تمكين الإيماء لإدخال تقسيم الشاشة من خلال التمرير السريع لأعلى من زر النظرة العامة"</string>
     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index b60618e..ee98b8f 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil məlumatlara fasilə verildi"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Məlumatlar dəsti limitinizi keçdiyiniz üçün cihaz bu dövrənin qalan hissəsi üçün məlumatların istifadəsinə fasilə verib.\n\nDavam etmək operaturunuzdan xərclərə səbəb ola bilər."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Daha limitini keçdiniz. Artıq mobil data istifadə etmirsiniz.\n\nDavam etsəniz, data istifadəsi üçün ödəniş tətbiq oluna bilər."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz nəzarət altında ola bilər"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlənə bilər"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Şəbəkə nəzərdən keçirilə bilər"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Şəbəkə nəzərdən keçirilə bilər"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaza nəzarət"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izlənməsi"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Şəbəkə monitorinqi"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizə nəzarət edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir.\n\nƏtraflı məlumat üçün administratorunuz ilə əlaqə saxlayın."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizi idarə edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir\n\nSiz, həmçinin, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə də qoşulsunuz və o, şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Sizin cihaz tərəfindən idarə olunur <xliff:g id="ORGANIZATION">%1$s</xliff:g> . \n\n Sizin administrator nəzarət və parametrləri, korporativ giriş, apps, sizin cihaz ilə bağlı məlumat və cihaz yer məlumat idarə edə bilərsiniz. \n\n Siz bağlı olduğunuz <xliff:g id="APPLICATION">%2$s</xliff:g> , E-poçt, apps, və web o cümlədən, şəbəkə fəaliyyətinə nəzarət edə bilər. \n\n Daha ətraflı məlumat üçün, administratora müraciət."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bölünmüş ekran sürüşdürməsi aktiv edin"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Jestlərin icmal düyməsindən yuxarı sürüşdürərək bölünmüş ekrana daxil olmasını aktiv edin"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 6e2301f..ac8699b 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -238,7 +238,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zbog toga što ste dostigli podešeno ograničenje za podatke, uređaj je pauzirao korišćenje podataka tokom ostatka ovog ciklusa.\n\nAko nastavite, mobilni operater može da vam naplati dodatne troškove."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ograničenje potrošnje podataka koje ste podesili je dostignuto. Više ne koristite mobilne podatke.\n\nAko nastavite, možda će biti naplaćeni troškovi za potrošnju podataka."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadgleda"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadgleda"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadgleda"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadgleda"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadgledanje uređaja"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadgledanje profila"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Nadgledanje mreže"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret za prevlačenje nagore za podeljeni ekran"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućava pokret za prelazak na podeljeni ekran prevlačenjem nagore od dugmeta Pregled"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 9aed31a..fb43971 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Быў дасягнуты ліміт перадачы даных, таму прылада прыпыніла перадачу даных на астатнюю частку гэтага цыкла.\n\nУзнаўленне перадачы можа прывесці да спагнання платы вашым аператарам."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ліміт даных, які вы задалі, быў дасягнуты. Вы больш не выкарыстоўваеце сотавую перадачу даных.\n\nКалі вы ўзновіце карыстанне, можа спаганяцца плата за выкарыстанне трафіка."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"За прыладай могуць назіраць"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"За профілем могуць назіраць"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"За сеткай могуць назіраць"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"За сеткай могуць назіраць"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Маніторынг прылад"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Маніторынг профіляў"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Маніторынг сеткі"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падлучаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nВы падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>,  якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Паказваць секунды гадзінніка на панэлі стану. Можа паўплываць на рэсурс акумулятара."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Змяніць парадак Хуткіх налад"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Паказваць яркасць у Хуткіх наладах"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Уключ. пераход да рэжыму дзялення экрана правядзеннем уверх"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Уключыць пераход да рэжыму дзялення экрана правядзеннем пальцам уверх ад кнопкі «Агляд»"</string>
     <string name="experimental" msgid="6198182315536726162">"Эксперыментальныя"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Уключыць Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Для падлучэння клавіятуры да планшэта трэба спачатку ўключыць Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 570f0c6..8ef1c85 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнахте зададеното от вас ограничение за данните. Вече не използвате мобилната мрежа.\n\nАко възобновите връзката с нея, може да бъдете таксувани за пренос на данни."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Устройството може да се наблюдава"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Възможно е потребителският профил да се наблюдава"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се наблюдава"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се наблюдава"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Наблюдение на устройството"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Наблюдаване на потр. профил"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Наблюдение на мрежата"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Устройството ви се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава и управлява настройките, корпоративния достъп, приложенията и данните, свързани с устройството ви, включително информацията за местоположението му.\n\nУстановена е връзка с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделяне на екрана с прекарване на пръст нагоре: Активиране"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Активиране на жеста за влизане в режим на разделен екран чрез прокарване на пръст нагоре от бутона за общ преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 595584e..3ef8892 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"আপনার সেটা করা ডেটা সীমা ছাড়িয়ে গেছে৷ আপনি আর সেলুলার ডেটা ব্যবহার করতে পারবেন না৷\n\nআপনি যদি আবার ব্যবহার করতে শুরু করেন তাহলে ডেটা ব্যবহারের জন্য চার্জ লাগতে পারে৷"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ডিভাইসটি নিরীক্ষণ করা হতে পারে"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"প্রোফাইল পর্যবেক্ষণ করা হতে পারে"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ডিভাইস নিরীক্ষণ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"প্রোফাইল দেখরেখ করা"</string>
     <string name="monitoring_title" msgid="169206259253048106">"নেটওয়ার্ক নিরীক্ষণ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nএছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার ডিভাইস পরিচালনা করে৷\n\nআপনার প্রশাসক আপনার ডিভাইসের সাথে সম্পর্কিত সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্লিকেশান ডেটা এবং ডিভাইসের অবস্থান সম্পর্কিত তথ্য নিরীক্ষণ ও পরিচালনা করতে পারেন৷\n\nআপনি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"উপরের দিকে সোয়াইপ করে বিভক্ত-স্ক্রীনে প্রবেশ করার অঙ্গভঙ্গি সক্ষম করুন"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\'এক নজরে\' বোতাম থেকে উপরের দিকে সোয়াইপ করে, বিভক্ত-স্ক্রীনে প্রবেশ করতে অঙ্গভঙ্গি সক্ষম করুন"</string>
     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ব্লুটুথ চালু করবেন?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে ব্লুটুথ চালু করতে হবে।"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 22cdd7d..6ce6dbe 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -238,7 +238,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dostigli ste postavljeno ograničenje prijenosa podataka pa je uređaj zaustavio prijenos podataka za preostali dio ovog ciklusa.\n\nAko nastavite, operater vam može naplatiti dodatne troškove."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
@@ -313,7 +313,7 @@
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobilni podaci"</string>
-    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Korištenje podataka"</string>
+    <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Prijenos podataka"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
     <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj može biti nadziran"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil može biti nadziran"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Mreža može biti nadzirana"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža može biti nadzirana"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Praćenje uređaja"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Praćenje profila"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Praćenje mreže"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane sa vašim uređajem i informacije o lokaciji uređaja, kao i upravljati njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
@@ -495,8 +497,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaži sekunde na statusnoj traci. Može skratiti trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi \"Brze postavke\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvjetljenje u opciji \"Brze postavke\""</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogućiti potez za podjelu ekrana prevlačenjem prema gore"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Uključite pokrete prstima da biste ušli u podijeljeni ekran tako što ćete od dugmeta Pregled prevući prstom prema gore"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7a6b27c..8810ce3 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"S\'ha assolit el límit de dades establert. Ja no estàs utilitzant dades mòbils. \n\n Si reprens l\'ús de les dades, es poden aplicar càrrecs."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"És possible que el dispositiu estigui supervisat."</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"El perfil es pot supervisar"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"És possible que la xarxa estigui supervisada."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"És possible que la xarxa estigui supervisada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisió del dispositiu"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisió del perfil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Supervisió de la xarxa"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nA més, estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que també pot supervisar la teva activitat personal a la xarxa."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el dispositiu.\n\nL\'administrador pot supervisar i gestionar el següent: configuració, accés corporatiu, aplicacions i dades associades amb el dispositiu, inclosa la informació d\'ubicació.\n\nEstàs connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar l\'activitat a la xarxa, com ara els correus, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activa el gest per dividir la pantalla en lliscar cap amunt"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa el gest per entrar al mode de pantalla dividida en lliscar cap amunt des del botó Visió general"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1e17a6c..4a515a6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Bylo dosaženo limitu dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Zařízení může být sledováno"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil může být monitorován"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Síť může být sledována"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Síť může být monitorována"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledování zařízení"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoring profilu"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Sledování sítě"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Toto zařízení spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a informace o jeho poloze.\n\nJste připojeni k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovat rozdělenou obrazovku přejetím prstem nahoru"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovat rozdělenou obrazovku přejetím prstem nahoru od tlačítka Přehled."</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3318fb1..d23bd26 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Du har nået den angivne datagrænse. Du vil ikke længere bruge mobildata.\n\nHvis du fortsætter, vil du muligvis blive opkrævet betaling for dit dataforbrug."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Enheden kan være overvåget"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Overvågning af enhed"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervågning"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Overvågning af netværk"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens stedoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivér bevægelsen Stryg opad for at dele skærmen"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivér bevægelse for at dele skærmen ved at stryge opad fra knappen Oversigt"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 43a931c..3ba8f5dd 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da dein festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn du die Nutzung fortsetzt, entstehen möglicherweise Kosten bei deinem Mobilfunkanbieter."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Das von dir festgelegte Datenlimit wurde erreicht. Die mobile Datennutzung wurde deaktiviert.\n\nWenn du weiterhin mobile Daten nutzt, können Gebühren anfallen."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Aktivität auf dem Gerät kann vom Eigentümer protokolliert werden"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil wird möglicherweise überwacht."</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Das Netzwerk wird möglicherweise überwacht."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Das Netzwerk wird möglicherweise überwacht"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Geräteüberwachung"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilüberwachung"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Netzwerküberwachung"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du bist mit der App \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" verbunden. Diese kann deine persönlichen Netzwerkaktivitäten erfassen, einschließlich E-Mails, Apps und Websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dein Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Teilen des Bildschirms durch Wischen nach oben aktivieren"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktiviert die Bewegung zum Teilen des Bildschirms, bei der von der Schaltfläche \"Übersicht\" nach oben gewischt wird"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5e3677d..fc248cf 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Το όριο δεδομένων που ορίσατε έχει εξαντληθεί. Δεν χρησιμοποιείτε πλέον δεδομένα κινητής τηλεφωνίας.\n\nΑν συνεχίσετε, ενδέχεται να ισχύσουν χρεώσεις για τη χρήση δεδομένων."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Η συσκευή μπορεί να παρακολουθείται"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Το προφίλ ενδέχεται να παρακολουθείται"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Παρακολούθηση συσκευής"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Παρακολούθηση προφίλ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Παρακολούθηση δικτύου"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Η διαχείριση της συσκευής γίνεται από <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής μπορεί να παρακολουθεί και να διαχειρίζεται ρυθμίσεις, εταιρική πρόσβαση, εφαρμογές, δεδομένα σχετικά με τη συσκευή και πληρ. τοποθεσίας της συσκευής.\n\nΕίστε συνδεδ. σε <xliff:g id="APPLICATION">%2$s</xliff:g> που μπορεί να παρακολουθεί τη δραστηρ. του δικτύου εργασίας, όπως μηνύματα ηλεκτρ. ταχυδρομείου, εφαρμογές και ιστότοπους.\n\nΓια περισ. πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ενεργοποίηση κίνησης ολίσθησης επάνω για διαχωρισμό οθόνης"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ενεργοποίηση κίνησης για μετάβαση σε διαχωρισμό οθόνης μέσω ολίσθησης επάνω από το κουμπί \"Επισκόπηση\""</string>
     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 6ac3c4f..75ec92f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6ac3c4f..75ec92f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 6ac3c4f..75ec92f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Device may be monitored"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profile may be monitored"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Network may be monitored"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Network may be monitored"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Device monitoring"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profile monitoring"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Network monitoring"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Your device is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Enable split-screen swipe-up gesture"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Enable gesture to enter split-screen by swiping up from the Overview button"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 23c53e1..5c98ae7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se alcanzó el límite de datos que estableciste. Ya no estás usando datos móviles.\n\nSi reanudas el uso de datos, es posible que se apliquen cargos."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que el dispositivo esté supervisado."</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil."</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Es posible que la red esté supervisada."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Es posible que la red esté supervisada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión del dispositivo"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Te conectaste a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de tu red personal, incluidos los correos electrónicos, las apps y los sitios web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién tienes conexión a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar la actividad de la red personal."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu dispositivo.\n\nEl administrador puede supervisar y administrar la configuración, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo y la información de la ubicación.\n\nTienes conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar gesto de dedo hacia arriba para dividir pantalla"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Recientes para acceder al modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c800c4a..4da5ba4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se ha alcanzado el límite de datos establecido. Ya no estás utilizando datos móviles.\n\nSi vuelves a activar el uso de datos, es posible que se apliquen cargos."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Es posible que este dispositivo esté supervisado"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Es posible que se supervise el perfil"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Puede que la red esté supervisada"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Puede que la red esté supervisada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivo"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión del perfil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de red"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede controlar tu actividad de red del trabajo, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con el administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nTú también estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"El administrador de tu dispositivo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nTu administrador puede supervisar y administrar los ajustes, el acceso corporativo, las aplicaciones, los datos asociados al dispositivo e información de su ubicación.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Habilitar deslizar dedo hacia arriba para dividir pantalla"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Habilita el gesto de deslizar el dedo hacia arriba desde el botón Aplicaciones recientes para acceder al modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 1ef7a14..0a09e48 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -47,7 +47,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Pööra ekraani automaatselt"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SUMMUTA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Teatised"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Märguanded"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth on jagatud"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Seadista sisestusmeetodeid"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Füüsiline klaviatuur"</string>
@@ -164,7 +164,7 @@
     <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
     <skip />
     <string name="accessibility_settings_button" msgid="799583911231893380">"Süsteemiseaded"</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Teatised"</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Märguanded"</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Märguande eemaldamine."</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS on lubatud."</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS-signaali otsimine."</string>
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Olete jõudnud enda määratud andmemahupiiranguni. Te ei kasuta enam mobiilset andmesidet.\n\nKui jätkate, võivad rakenduda andmekasutustasud."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Seadet võidakse jälgida"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiili võidakse jälgida"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Võrku võidakse jälgida"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Võrku võidakse jälgida"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Seadme jälgimine"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiili jälgimine"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Võrgu jälgimine"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nTeie seade on ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Teie seadet haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida ja hallata seadeid, ettevõttesisest juurdepääsu, rakendusi, seadmega seotud andmeid ja seadme asukohateavet.\n\nOlete ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Luba ülespühkimise liigutus ekraani poolitamiseks"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Lubab žesti, mis poolitab ekraani, kui kasutaja pühib üles nupul Ülevaade."</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 30b0d22..74b3a61 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gainditu egin da ezarri duzun datu-muga. Datu-konexioa erabiltzeari utzi diozu.\n\nBerriro hasten bazara erabiltzen, baliteke datuen erabileraren kostua ordaindu behar izatea."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Baliteke gailua kontrolatuta egotea"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Baliteke profila kontrolatuta egotea"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Baliteke sarea kontrolatuta egotea"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Baliteke sarea kontrolatuta egotea"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Gailuen kontrola"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila kontrolatzeko aukera"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Sareen kontrola"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN konexioa"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nHorrez gain, sarean egiten dituzun jarduera pertsonalak kontrola ditzakeen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora konektatuta zaude."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da gailuaren kudeatzailea.\n\nAdministratzaileak ezarpenak, enpresako sarbidea, aplikazioak, gailuarekin lotutako datuak eta gailuaren kokapenari buruzko informazioa kontrola eta kudea ditzake.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Gaitu pantaila zatitzeko keinua hatza gora pasatuta"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Sakatu Ikuspegi nagusia botoia eta gaitu hatza gora pasatuta pantaila zatitzeko keinua"</string>
     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
diff --git a/packages/SystemUI/res/values-fa-land/strings.xml b/packages/SystemUI/res/values-fa-land/strings.xml
index adc2b11..fe67cf0 100644
--- a/packages/SystemUI/res/values-fa-land/strings.xml
+++ b/packages/SystemUI/res/values-fa-land/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در جهت افقی قفل است."</string>
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"صفحه اکنون در حالت افقی قفل است."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 3b246c0..1ccc804 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"به حداکثر محدودیت داده‌ای که تنظیم کردید رسیدید. دیگر از داده شبکه تلفن همراه استفاده نمی‌کنید.\n\nدر صورت ازسرگیری، ممکن است مصرف داده هزینه‌هایی دربرداشته باشد."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
@@ -253,10 +253,10 @@
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"تنظیمات اعلان"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"تنظیمات <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
-    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
+    <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در حالت افقی قفل است."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
     <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"صفحه اکنون به صورت خودکار می‌چرخد."</string>
-    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون روی جهت افقی قفل شده است."</string>
+    <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"صفحه اکنون در حالت افقی قفل است."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"صفحه اکنون روی جهت عمودی قفل شده است."</string>
     <string name="dessert_case" msgid="1295161776223959221">"ویترین دسر"</string>
     <string name="start_dreams" msgid="5640361424498338327">"محافظ صفحه"</string>
@@ -346,8 +346,8 @@
     <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="zen_priority_introduction" msgid="3070506961866919502">"صداها و لرزش‌هایی به جز هشدارها، یادآوری‌ها، رویدادها و تماس‌گیرنده‌هایی که مشخص می‌کنید، مزاحم شما نمی‌شوند."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"سفارشی کردن"</string>
-    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
-    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدیوها و بازی‌ها را مسدود می‌کند."</string>
+    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند. همچنان می‌توانید تماس تلفنی برقرار کنید."</string>
+    <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزش‌ها از جمله هشدارها، موسیقی، ویدئوها و بازی‌ها را مسدود می‌کند."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلان‌های کمتر فوری در زیر"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"دوباره ضربه بزنید تا باز شود"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ممکن است دستگاه کنترل شود"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"شاید نمایه کنترل شود"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ممکن است شبکه کنترل شود"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ممکن است شبکه کنترل شود"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"کنترل دستگاه"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"کنترل نمایه"</string>
     <string name="monitoring_title" msgid="169206259253048106">"کنترل شبکه"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل است که فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل می‌کند.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت شبکه شخصی‌تان را کنترل کند."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"دستگاهتان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود.\n\nسرپرستتان می‌تواند تنظیمات، دسترسی شرکت، برنامه‌ها، داده‌های مرتبط با دستگاهتان و اطلاعات مکان دستگاهتان را کنترل و مدیریت کند.\n\nشما به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل هستید که می‌تواند فعالیت شبکه شما را کنترل کند، از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
@@ -481,7 +483,7 @@
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"نمایه کاری"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"برای بعضی افراد سرگرم‌کننده است اما نه برای همه"</string>
     <string name="tuner_warning" msgid="8730648121973575701">"‏«تنظیم‌کننده واسط کاربری سیستم» روش‌های بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار می‌دهد. ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده جود نداشته باشند. با احتیاط ادامه دهید."</string>
-    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این ویژگی‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشند. با احتیاط ادامه دهید."</string>
+    <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این قابلیت‌های آزمایشی تغییر کنند، خراب شوند یا در نسخه‌های آینده وجود نداشته باشد. بااحتیاط ادامه دهید."</string>
     <string name="got_it" msgid="2239653834387972602">"متوجه شدم"</string>
     <string name="tuner_toast" msgid="603429811084428439">"تبریک می‌گوییم! «تنظیم‌کننده واسط کاربری سیستم» به «تنظیمات» اضافه شد"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"فعال کردن تقسیم صفحه با اشاره بالا کشیدن"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"اشاره ورود به تقسیم صفحه با بالا کشیدن صفحه از دکمه نمای کلی را فعال می‌کند"</string>
     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 2894abba..b97a6465 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -25,7 +25,7 @@
     <string name="pip_pause" msgid="8412075640017218862">"مکث"</string>
     <string name="pip_hold_home" msgid="340086535668778109">"‏کنترل PIP ‏با نگه‌داشتن "<b>"HOME"</b></string>
     <string name="pip_onboarding_title" msgid="7850436557670253991">"تصویر در تصویر"</string>
-    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدیوی دیگری را پخش کنید، این صفحه حالت ویدیو در ویدیوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
+    <string name="pip_onboarding_description" msgid="4028124563309465267">"تا زمانی که ویدئوی دیگری را پخش کنید، این صفحه حالت ویدئو در ویدئوی شما را حفظ می‌کند. برای کنترل آن، دکمه "<b>"صفحه اصلی"</b>" را فشار دهید و نگه دارید."</string>
     <string name="pip_onboarding_button" msgid="3957426748484904611">"متوجه شدم"</string>
     <string name="recents_tv_dismiss" msgid="3555093879593377731">"رد کردن"</string>
   <string-array name="recents_tv_blacklist_array">
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index fe27459..9ec1ffd 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Määrittämäsi datankäyttöraja on täynnä. Mobiilidata poistettiin käytöstä.\n\nOperaattorisi voi veloittaa sinua, jos jatkat mobiilidatan käyttöä."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Laitetta voidaan valvoa"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiilia saatetaan valvoa"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Verkkoa saatetaan valvoa"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Verkkoa saatetaan valvoa"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Laitteiden valvonta"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profiilin valvonta"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Verkon valvonta"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi esimerkiksi seurata avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nSaat lisätietoja järjestelmänvalvojaltasi."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Laitettasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvojasi voi valvoa ja hallinnoida laitteesi asetuksia, yrityskäyttöä, sovelluksia, laitteeseesi liittyviä tietoja ja laitteen sijaintitietoja.\n\nOlet yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisätietoja saat järjestelmänvalvojaltasi."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Siirry jaetun näytön tilaan pyyhkäisemällä ylöspäin"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Voit siirtyä jaetun näytön tilaan pyyhkäisemällä Viimeisimmät-painikkeesta ylöspäin."</string>
     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index fac3e24..67e717e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de données que vous avez définie a été atteinte. Vous n\'utilisez plus les données cellulaires.\n\nSi vous rétablissez la connexion de données cellulaires, des frais peuvent s\'appliquer."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"le profil peut être contrôlé"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Le réseau peut être surveillé"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Le réseau peut être surveillé"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Surveillance d\'appareils"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle de profil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Surveillance réseau"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"RPV"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et ses données de localisation.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>, qui peut contrôler votre activité réseau, y compris les courriels, les applications et les  sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer le geste d\'écran partagé en balayant vers le haut"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton « Aperçu »"</string>
     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a93c3e2..7310a47 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de consommation des données que vous avez définie a été atteinte. Vous n\'utilisez plus les données mobiles.\n\nSi vous les réactivez, des frais pourront être facturés."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Il est possible que cet appareil soit surveillé."</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Le profil peut être contrôlé."</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Il est possible que le réseau soit surveillé."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Il est possible que le réseau soit surveillé."</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Contrôle des appareils"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Contrôle du profil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Contrôle du réseau"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nPour en savoir plus, contactez votre administrateur."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut surveiller votre activité personnelle sur le réseau."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Votre appareil géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler et gérer les paramètres, l\'accès aux contenus de l\'entreprise, les applications, les données associées à cet appareil et les informations de localisation de celui-ci.\n\nVous êtes connecté à <xliff:g id="APPLICATION">%2$s</xliff:g> qui peut contrôler votre activité sur le réseau (e-mails, applications et sites Web).\n\nPour en savoir plus, contactez votre administrateur."</string>
@@ -445,7 +447,7 @@
   <string-array name="volume_stream_titles">
     <item msgid="5841843895402729630">"Appeler"</item>
     <item msgid="5997713001067658559">"Système"</item>
-    <item msgid="7858983209929864160">"Faire sonner"</item>
+    <item msgid="7858983209929864160">"Sonnerie"</item>
     <item msgid="1850038478268896762">"Multimédia"</item>
     <item msgid="8265110906352372092">"Alarme"</item>
     <item msgid="5339394737636839168"></item>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activer l\'écran partagé en balayant vers le haut"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activer le geste permettant d\'utiliser l\'écran partagé en balayant l\'écran vers le haut à partir du bouton \"Aperçu\""</string>
     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 21154fc..6152872 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Alcanzouse o límite de datos establecido e xa non utilizas datos móbiles.\n\nSe continúas, é posible que se apliquen cargos por uso de datos."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"É posible que se supervise o dispositivo"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pódese supervisar"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"É posible que se supervise a rede"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"É posible que se supervise a rede"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Supervisión de dispositivos"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Supervisión do perfil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Supervisión de rede"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co teu administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode supervisar a túa actividade persoal na rede."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O dispositivo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO teu administrador pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co dispositivo e a información de localización do dispositivo.\n\nEstás conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede: os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, contacta co teu administrador."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activar pantalla dividida pasando o dedo cara arriba"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activa o xesto de pasar o dedo cara arriba desde o botón Visión xeral para acceder ao modo de pantalla dividida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado coa tableta, primeiro tes que activar o Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 02fc8c0..26b1c06 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"સેલ્યુલર ડેટા થોભાવ્યો છે"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"તમે સેટ કરેલ ડેટા મર્યાદા સુધી પહોંચી ગયા હોવાથી, ઉપકરણે આ ચક્રના શેષ માટે ડેટા વપરાશ થોભાવ્યો છે.\n\nફરીથી શરૂ કરવું તમારા કેરીઅર તરફથી શુલ્ક તરફ દોરી શકે છે."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"તમારા દ્વારા સેટ કરેલ ડેટા મર્યાદા પર તમે પહોંચી ગયાં છો. તમે હવે સેલ્યુલર ડેટાનો ઉપયોગ કરી રહ્યાં નથી.\n\nજો તમે ફરી શરૂ કરો છો, તો ડેટા વપરાશ માટે શુલ્ક લાગુ થઈ શકે છે."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi કનેક્ટ કર્યું"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ઉપકરણ મૉનિટર કરી શકાય છે"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ઉપકરણ નિરીક્ષણ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"પ્રોફાઇલ નિરીક્ષણ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"નેટવર્ક મૉનિટરિંગ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ થયેલ છો, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"તમારું ઉપકરણ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે.\n\nતમારા વ્યવસ્થાપક, સેટિંગ્સ, કોર્પોરેટ ઍક્સેસ, ઍપ્લિકેશનો, તમારા ઉપકરણ સાથે સંકળાયેલ ડેટા અને તમારા ઉપકરણની સ્થાન માહિતીને મૉનિટર કરી અને સંચાલિત કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"સ્પ્લિટ-સ્ક્રીન સ્વાઇપ-અપ હાવભાવ સક્ષમ કરો"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"વિહંગાવલોકન બટનમાંથી સ્વાઇપ કરીને સ્પ્લિટ-સ્ક્રીનમાં દાખલ થવા માટે હાવભાવ સક્ષમ કરો"</string>
     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 9a09266..42c049d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपकी सेट की हुई डेटा सीमा समाप्त हो गई है. अब आप सेल्युलर डेटा का उपयोग नहीं कर रहे हैं.\n\nयदि आप फिर से शुरू करते हैं, तो डेटा उपयोग के लिए शुल्क लग सकता है."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई  कनेक्‍ट किया गया"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"डिवाइस को मॉनीटर किया जा सकता है"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफ़ाइल को मॉनीटर किया जा सकता है"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्क को मॉनीटर किया जा सकता है"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिवाइस को मॉनीटर करना"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफ़ाइल को मॉनीटर करना"</string>
     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क को मॉनीटर करना"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्‍ट हैं, जो आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपका डिवाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है.\n\nआपका नियंत्रक सेटिंग, कॉर्पोरेट ऐक्‍सेस, ऐप्स, आपके डिवाइस से संबद्ध डेटा और आपके डिवाइस की स्‍थान जानकारी की निगरानी और उसका प्रबंधन कर सकता है.\n\nआप <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ऊपर स्वाइप करके विभाजित स्क्रीन में जाने का जेस्चर सक्षम करें"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"अवलोकन बटन से ऊपर स्वाइप करके स्क्रीन विभाजन में आने का हावभाव सक्षम करें"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f549de9..58dd92e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -238,7 +238,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegnuto je vaše ograničenje podataka. Više ne upotrebljavate mobilne podatke.\n\nAko nastavite, moguća je naplata za potrošnju podataka."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadzire"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadzire"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadzire"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mreža se možda nadzire"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor uređaja"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor profila"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Nadzor mreže"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vašim uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati postavke, poslovni pristup, aplikacije, podatke povezane s uređajem i podatke o lokaciji uređaja te upravljati njima.\n\nPovezani ste s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogući pokret povlačenja prema gore za podijeljen zaslon"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogućivanje pokreta za otvaranje podijeljenog zaslona tako da se od gumba Pregled prstom prijeđe prema gore"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 25f436d..0804093 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Elérte a beállított adatkorlátot. A továbbiakban nem használ mobiladat-forgalmat.\n\nHa a folytatást választja, szolgáltatója adathasználati díjat számíthat fel."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Lehet, hogy az eszközt figyelik"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilját felügyelhetik"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Lehet, hogy a hálózatot figyelik"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Lehet, hogy a hálózat felügyelt"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Eszközfigyelés"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilfelügyelet"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Hálózatfigyelés"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ön a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz csatlakozik, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, alkalmazásokat és webhelyeket."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nTovábbi információért forduljon a rendszergazdájához."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely szintén figyelemmel kísérheti személyes hálózati tevékenységét."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Eszközét a következő felügyeli: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nA rendszergazda figyelemmel kísérheti és módosíthatja beállításait, vállalati hozzáféréseit, alkalmazásait, az eszközéhez társított adatokat és eszköze helyadatait.\n\nÖn a következőhöz csatlakozik: <xliff:g id="APPLICATION">%2$s</xliff:g>, amely (az e-mailekre, alkalmazásokra és webhelyekre is kiterjedően) figyelemmel kísérheti hálózati tevékenységét.\n\nTovábbi információért forduljon a rendszergazdához."</string>
@@ -480,7 +482,7 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Munkaprofil"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Egyeseknek tetszik, másoknak nem"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban,illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string>
     <string name="got_it" msgid="2239653834387972602">"Értem"</string>
     <string name="tuner_toast" msgid="603429811084428439">"Gratulálunk! A Kezelőfelület-hangolót hozzáadtuk a Beállításokhoz"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Képernyőfelosztó gyors felfelé csúsztatás engedélyezése"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Kézmozdulat engedélyezése osztott képernyős nézet aktiválásához, ha az Áttekintés gombról felfelé húzza az ujját"</string>
     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 23d7ab6..1b0f3d7 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>
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Տվյալների օգտագործման համար նշված սահմանաչափը լրացել է: Դուք բջջային տվյալներ այլևս չեք օգտագործում:\n\nԵթե վերսկսեք բջջային տվյալների օգտագործումը, դրա համար կարող են վճարներ գանձվել:"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Սարքը կարող է վերահսկվել"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Պրոֆիլը կարող է վերահսկվել"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Ցանցը կարող է վերահսկվել"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ցանցը կարող է վերահսկվել"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Սարքի մշտադիտարկում"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Պրոֆիլի վերահսկում"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Ցանցի մշտադիտարկում"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք նույնպես կապակցված եք <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Սարքի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>:\n\nԱդմինիստրատորը կարող է վերահսկել և կառավարել կարգավորումները, կորպորատիվ հաշիվը, հավելվածները, սարքի հետ առնչվող և սարքի տեղադրության տվյալները:\n\nՆաև կապակցված եք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, ինչը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև՝ էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ակտիվացնել մատը վերև սահեցնելով էկրանը տրոհելու ժեստը"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Միացնել Համատեսք կոճակից մատը դեպի վերև սահեցնելու միջոցով տրոհված էկրանի ռեժիմ անցնելու ժեստը"</string>
     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index e2d8166..be27eca 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Batas data yang disetel telah tercapai. Anda tidak menggunakan data seluler lagi.\n\nJika Anda melanjutkan, biaya penggunaan data mungkin berlaku."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Perangkat mungkin dipantau"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil dapat dipantau"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Jaringan mungkin dipantau"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Jaringan mungkin dipantau"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan perangkat"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan jaringan"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Perangkat dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat.\n\nAnda tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktifkan isyarat gesek atas untuk layar terpisah"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktifkan isyarat untuk masuk layar terpisah dengan menggesek tombol Ringkasan ke atas"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 4ca3677..0b65a95 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gagnamörkunum sem þú stilltir hefur verið náð. Þú ert ekki lengur að nota farsímagögn.\n\nEf þú heldur áfram gætu gjöld fyrir gagnanotkun átt við."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Hugsanlega er fylgst með tækjum"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Hugsanlega er fylgst með þessu sniði"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Hugsanlega er fylgst með netinu"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Hugsanlega er fylgst með netinu"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Tækjaeftirlit"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Fylgst með sniði"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Neteftirlit"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Tækinu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nKerfisstjórinn þinn getur fylgst með og stjórnað stillingum, fyrirtækjaaðgangi, forritum, gögnum sem tengd eru tækinu og staðsetningarupplýsingum tækisins.\n\nÞú ert með tengingu við <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Virkja skjáskiptingu með því að strjúka upp"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Virkja skjáskiptingarbendingu með því að strjúka upp frá yfirlitshnappi"</string>
     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e8459ab..5eae72c 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"È stato raggiunto il limite di dati impostato. La rete dati è stata disattivata.\n\nSe la riattivi, potrebbero essere applicati costi per l\'utilizzo dei dati."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Il dispositivo potrebbe essere monitorato"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Il profilo potrebbe essere monitorato"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"La rete potrebbe essere monitorata"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"La rete potrebbe essere monitorata"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoraggio del dispositivo"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoraggio del profilo"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitoraggio rete"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, che consente di monitorare la tua attività di rete personale, inclusi siti web, email e app."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nSei connesso anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Il tuo dispositivo è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare e gestire impostazioni, accesso aziendale, app e dati associati al dispositivo, incluse le informazioni sulla posizione del dispositivo.\n\nSei connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta l\'amministratore."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Attiva Schermo diviso mediante scorrimento verso l\'alto"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Consente di attivare la modalità Schermo diviso scorrendo verso l\'alto dal pulsante Panoramica"</string>
     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2d740b3..ef4d683 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"הגעת למגבלת הנתונים שהגדרת. אתה כבר לא משתמש בנתונים סלולריים.\n\nאם תמשיך, ייתכנו חיובים לשימוש בנתונים."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi מחובר"</string>
@@ -407,6 +407,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ייתכן שהמכשיר נמצא במעקב"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ייתכן שהפרופיל נתון למעקב"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ייתכן שהרשת נמצאת במעקב"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ייתכן שהרשת מנוטרת"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"מעקב אחר מכשיר"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"מעקב אחר פרופיל"</string>
     <string name="monitoring_title" msgid="169206259253048106">"מעקב אחר פעילות ברשת"</string>
@@ -419,6 +420,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nאתה מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"המכשיר שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nמנהל המערכת שלך יכול לעקוב אחר הגדרות, גישה עסקית, אפליקציות, נתונים המשויכים למכשיר שלך ומידע על מיקום המכשיר, ולנהל אותם.\n\nאתה מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
@@ -495,8 +497,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"הפעל מסך מפוצל על ידי תנועת החלקה כלפי מעלה"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"הפעל את התנועה לכניסה למסך מפוצל על ידי החלקה כלפי מעלה מלחצן הסקירה"</string>
     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7df2f1e..fcc5ae1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"設定されたデータの上限に達しているため、モバイルデータの使用を停止しました。\n\n再開すると、携帯通信会社からデータ使用量に応じた通信料を課金される可能性があります。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ネットワークが監視されている可能性があります"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」に接続しています。このアプリはあなたの個人のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>にも接続しているため、個人のネットワークアクティビティも監視できます。"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"この端末は<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理されています。\n\n管理者は設定、コーポレートアクセス、アプリ、端末に関連付けられたデータ、端末の位置情報を監視、管理できます。\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しているため、このアプリもネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"上にスワイプして分割画面に切り替える操作を有効にする"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"[概要] ボタンから上にスワイプして分割画面に切り替える操作を有効にします"</string>
     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9632a87..b799116 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"მიღწეულია მონაცემთა მოხმარების თქვენ მიერ მითითებული ლიმიტი. ამიტომ, მობილური ინტერნეტის გამოყენება აღარ ხდება.\n\nგანახლების შემთხვევაში, შეიძლება მობილური ინტერნეტის საფასურის გადახდა მოგიწიოთ."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"შესაძლოა მოწყობილობის მონიტორინგი არ ხორციელდება"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"შესაძლოა პროფილზე ხორციელდებოდეს მონიტორინგი"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"შესაძლოა ქსელზე ხორციელდება მონიტორინგი"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ქსელზე შესაძლოა მონიტორინგი ხორციელდებოდეს"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"მოწყობილობის მონიტორინგი"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"პროფილის მონიტორინგი"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ქსელის მონიტორინგი"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც თქვენი პირადი ქსელის აქტივობის მონიტორინგი შეუძლია, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის მიმართეთ თქვენს ადმინისტრატორს."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nასევე, დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის მონიტორინგი."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"თქვენს მოწყობილობას მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nადმინისტრატორს შეუძლია თქვენი მოწყობილობასთან ასოცირებული პარამეტრების, კორპორატიული წვდომის, აპებისა და მონაცემების, და ასევე მოწყობილობის მდებარეობის ინფორმაციის მონიტორინგი და მართვა.\n\nთქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებ-საიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისათვის, დაუკავშირდით თქვენს ადმინისტრატორს."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ზემოთ გადაფურცვლისას ეკრანის გაყოფის ჟესტის ჩართვა"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"მიმოხილვის ღილაკიდან ზემოთ გადაფურცვლისას ეკრანის გაყოფის რეჟიმზე გადასვლის ჟესტის ჩართვა"</string>
     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index da05ec3..872caa7 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Белгіленген деректер шегіне жеттіңіз. Ұялы деректер енді пайдаланылмайды.\n\nЕгер жалғастырсаңыз, деректер трафигі үшін ақы алынуы мүмкін."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Құрылғы бақылануы мүмкін"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профиль бақылануы мүмкін"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Желі бақылауда болуы мүмкін"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Желі бақылауда болуы мүмкін"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Құрылғыны бақылау"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профильді бақылау"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Желіні бақылау"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Жеке желідегі әрекеттеріңізді, соның ішінде электрондық пошта хабарларын, қолданбаларды және вебсайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол жұмыс кезінде желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылған.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз желідегі жеке белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Құрылғыңызды <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші параметрлерді, корпоративтік рұқсатты, қолданбаларды, құрылғыңызбен байланысты деректерді және құрылғының орны туралы ақпаратты бақылай және басқара алады.\n\nСіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және евб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылғансыз.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Бөлінген экранда жоғары қарай сырғыту қимылын қосу"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"\"Шолу\" түймесінен жоғары қарай жанау арқылы бөлінген экранға кіру қимылын қосу"</string>
     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index d381da7..ee63681 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ដោយសារទិន្នន័យរបស់អ្នកបានឈានដល់កំណត់ ឧបករណ៍នេះបានផ្អាកការប្រើប្រាស់ទិន្នន័យសម្រាប់ការរំលឹកនៃវគ្គនេះ។\n\nការបន្តប្រើប្រាស់អាចនាំឲ្យមានការគិតប្រាក់ពីក្រុមហ៊ុនផ្តល់សេវាកម្ម។"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ អ្នកមិនអាចប្រើទិន្នន័យចល័តបានទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើ។"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បាន​ភ្ជាប់​វ៉ាយហ្វាយ"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ឧបករណ៍​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ប្រវត្តិរូបអាចត្រូវបានតាមដាន"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"បណ្ដាញ​អាច​ត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"បណ្ដាញអាចត្រូវបានត្រួតពិនិត្យ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ការ​ត្រួតពិនិត្យ​ឧបករណ៍"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"តាមដានប្រវត្ថិរូប"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ការ​ត្រួតពិនិត្យ​បណ្ដាញ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"អ្នកត្រូវបានភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រប់របស់អ្នក។"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nអ្នកក៏ត្រូវបានតភ្ជាប់ផងដែរទៅនឹង <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ឧបករណ៍របស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចឃ្លាំមើល និងគ្រប់គ្រងការកំណត់ ការចូលប្រើជាក្រុម កម្មវិធី ទិន្នន័យដែលជាប់ទាក់ទងនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងនៃឧបករណ៍របស់អ្នក។\n\nអ្នកត្រូវបានភ្ជាប់ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលវាអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រួមបញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"បើកដំណើរការកាយវិការអូសទៅលើដើម្បីបំបែកអេក្រង់"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"បើកដំណើរការកាយវិការដើម្បីបំបែកអេក្រង់ដោយអូសទៅលើចាប់ពីប៊ូតុងទិដ្ឋភាព"</string>
     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 9b13d80..189cce0 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ನೀವು ಹೊಂದಿಸಿರುವ ಡೇಟಾ ಮಿತಿ ತಲುಪಿದೆ. ನೀವು ಎಂದಿಗೂ ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾವನ್ನು ಬಳಸದೆ ಇರಬಹುದು.\n\nನೀವು ಮುಂದುವರಿಸಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ಸಾಧನವನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ಪ್ರೊಫೈಲ್ ಅನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ಸಾಧನ ಪರಿವೀಕ್ಷಣೆ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ಪ್ರೊಫೈಲ್ ಮೇಲ್ವಿಚಾರಣೆ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ನೆಟ್‌ವರ್ಕ್‌ ಪರಿವೀಕ್ಷಣೆ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ.\n\nನೀವು ಕೂಡಾ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ನಿಮ್ಮ ಸಾಧನವನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಾಗೂ ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳ ಮಾಹಿತಿಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಸ್ವೈಪ್-ಅಪ್ ಗೆಶ್ಚರ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ಸಮಗ್ರ ನೋಟದ ಬಟನ್‌ನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಸ್ಪ್ಲಿಟ್‌-ಸ್ಕ್ರೀನ್ ನಮೂದಿಸಲು ಗೆಸ್ಚರ್‌ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
@@ -592,8 +592,8 @@
     <string name="add_button" msgid="4134946063432258161">"ಬಟನ್ ಸೇರಿಸು"</string>
     <string name="save" msgid="2311877285724540644">"ಉಳಿಸು"</string>
     <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string>
-    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಹೋಮ್ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
-    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಹೋಮ್ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಹೋಮ್ ಬಟನ್ ಸೇರಿಸಿ."</string>
+    <string name="no_home_title" msgid="1563808595146071549">"ಯಾವುದೇ ಮುಖಪುಟ ಬಟನ್ ಕಂಡುಬಂದಿಲ್ಲ"</string>
+    <string name="no_home_message" msgid="5408485011659260911">"ಈ ಸಾಧನವನ್ನು ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಮುಖಪುಟ ಬಟನ್ ಅಗತ್ಯವಿರುತ್ತದೆ. ಉಳಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಮುಖಪುಟ ಬಟನ್ ಸೇರಿಸಿ."</string>
     <string name="adjust_button_width" msgid="6138616087197632947">"ಬಟನ್ ಅಳತೆ ಹೊಂದಿಸು"</string>
     <string name="clipboard" msgid="1313879395099896312">"ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"</string>
     <string name="clipboard_description" msgid="3819919243940546364">"ಐಟಂಗಳನ್ನು ನೇರವಾಗಿ ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ಅನುಮತಿಸುತ್ತದೆ. ಐಟಂಗಳು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವಾಗ ಅವುಗಳನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಿಂದ ನೇರವಾಗಿ ಹೊರಗೆ ಹಾಕಬಹುದಾಗಿರುತ್ತದೆ."</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
index 5afb322..edaa8e6 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
@@ -25,7 +25,7 @@
     <string name="pip_pause" msgid="8412075640017218862">"ವಿರಾಮ"</string>
     <string name="pip_hold_home" msgid="340086535668778109">"PIP ನಿಯಂತ್ರಿಸಲು "<b>"HOME"</b>" ಕೀಯನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
     <string name="pip_onboarding_title" msgid="7850436557670253991">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
-    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಹೋಮ್"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
+    <string name="pip_onboarding_description" msgid="4028124563309465267">"ನೀವು ಮತ್ತೊಂದನ್ನು ಪ್ಲೇ ಮಾಡುವ ತನಕ ಇದು ನಿಮ್ಮ ವೀಡಿಯೋವನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿರಿಸುತ್ತದೆ. ಅದನ್ನು ನಿಯಂತ್ರಿಸಲು "<b>"ಮುಖಪುಟ"</b>" ಅನ್ನು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
     <string name="pip_onboarding_button" msgid="3957426748484904611">"ಅರ್ಥವಾಯಿತು"</string>
     <string name="recents_tv_dismiss" msgid="3555093879593377731">"ವಜಾಗೊಳಿಸಿ"</string>
   <string-array name="recents_tv_blacklist_array">
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index c65af92..af40128 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"설정한 데이터 한도에 도달했습니다. 더 이상 모바일 데이터를 사용하지 않습니다.\n\n계속 사용하면 데이터 사용 요금이 부과될 수 있습니다."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"기기가 모니터링될 수 있음"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"프로필이 모니터링될 수 있음"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"네트워크가 모니터링될 수 있음"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"네트워크가 모니터링될 수 있음"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"기기 모니터링"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"프로필 모니터링"</string>
     <string name="monitoring_title" msgid="169206259253048106">"네트워크 모니터링"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n또한 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에 연결되어 있으며, 여기에서 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 기기를 관리합니다.\n\n관리자는 설정, 기업 액세스, 앱, 기기와 연결된 데이터, 기기의 위치 정보를 모니터링하고 관리할 수 있습니다.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"화면 분할 위로 스와이프 동작 사용"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"최근 사용 버튼에서 위로 스와이프하기 동작으로 창 분할 모드를 사용 설정합니다."</string>
     <string name="experimental" msgid="6198182315536726162">"베타"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index aaac2ebf..62775d1 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Сиз койгон дайындардын чегине жетти. Сиз мобилдик дайындарды колдонгон жоксуз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Түзмөктү көзөмөлдөсө болот"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилди көзөмөлдөсө болот"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Тармак көзөмөлдөнүшү мүмкүн"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Тармак көзөмөлдөнүшү мүмкүн"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Түзмөккө көз салуу"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профилди көзөмөлдөө"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Тармакка көз салуу"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди тескей турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%2$s</xliff:g> менен туташкан.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> менен туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Түзмөгүңүздү <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\nАдминистраторуңуз түзмөгүңүздөгү жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, дайындарды, ошону менен катар жайгашкан жер дайындарын башкарып, тийиштүү маалыматты карай алат.\n\nСиз электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тармактагы аракетиңизди тескей турган APPLICATION колдонмосуна туташып турасыз.\n<xliff:g id="APPLICATION">%2$s</xliff:g>Көбүрөөк маалымат алуу үчүн, администраторуңузга кайрылыңыз.\n\n"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Өйдө серпип экранды бөлүү жаңсоосун иштетүү"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Сереп баскычынан өйдө серпип, экранды бөлүү режимин киргизүү үчүн жаңсоону иштетиңиз"</string>
     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 8b90611..81ee168 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້​ມູນເຊວ​ລູ​ລາຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້​ມູນ​ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງ​ຈາກວ່າ​ຮອດ​ຂີດ​ຈຳ​ກັດ​ຂໍ້​ມູນ​ທີ່​ຕັ້ງ​ໄວ້​ຂອ​ງ​ທ່ານ​ແລ້ວ, ອຸ​ປະ​ກອນ​ຢຸດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ສຳ​ລັບ​ສ່ວນ​ທີ່​ຍັງ​ເຫຼືອ​ຂອງ​ຮອບ​ວຽນ​ນີ້.\n\nການ​ເລີ່ມ​ຕໍ່​ອາດ​ຈະ​ນຳ​ໄປ​ສູ່​ການ​ປ່ຽນ​ແປງ​ຈາກ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ທ່ານໃຊ້ອິນເຕີເນັດຮອດຈຳນວນທີ່ທ່ານຈຳກັດປະລິມານໄວ້ແລ້ວ. ທ່ານຈະບໍ່ນຳໃຊ້ການເຊື່ອມຕໍ່ຜ່ານເຄືອຂ່າຍມືຖືອີກຕໍ່ໄປ.\n\nຫາກທ່ານສືບຕໍ່ໃຊ້ໄປອີກ, ທ່ານອາດຖືກຮຽກເກັບເງິນຄ່າບໍລິການໄດ້."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມ​ຕໍ່ Wi-​-Fi ແລ້ວ"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ອຸ​ປະ​ກອນ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ໂປຣ​ໄຟລ໌​ອາດ​ຖືກ​ເຝົ້າ​ຕິດ​ຕາມ​ຢູ່"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"​ເຄືອ​ຂ່າຍ​ອາດ​ມີ​ການ​ເຝົ້າ​ຕິດ​ຕາມ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ອຸ​ປະ​ກອນ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ການ​ຕິດ​ຕາມ​ໂປຣ​ໄຟລ໌"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ການກວດ​ສອບ​ຕິດ​ຕາມ​ເຄືອ​ຂ່າຍ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ຮວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊໄດ້."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຄວບຄຸມໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນຖືກເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ,​ ແອັບ ແລະເວັບໄຊທ໌.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ້ບໍລິຫານຂອງທ່ານ."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌.\n\nທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຖືກ​ຄຸ້ມ​ຄອງ​ໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nຜູ້​ຄວບ​ຄຸມຂອງ​ທ່ານ​ສາ​ມາດ​ຕິດ​ຕາມ​ກວດ​ກາ ​ແລະ​ການ​ຄຸ້ມ​ຄອງ​ການຕັ້ງ​ຄ່າ, ແອັບ​ການ​ເຂົ້າ​ຫາ​ບໍ​ລິ​ສັດ, ຂໍ້​ມູນ​ທີ່​ກ່ຽວ​ຂ້ອງ​ກັບ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ, ແລະ​ຂໍ້​ມູນທີ່​ຕັ້ງ​ຂອງອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ.\n\nທ່ານ​ເຊື່ອມ​ຕໍ່​ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ແລ້ວ, ເຊິ່ງ​ສາ​ມາດ​ຕິດ​ຕາມການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ, ລວມ​ທັງ​ອີ​ເມວ, ແອັບ, ແລະ​ເວັບ​ໄຊ​ທ໌.\n\nສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ເປີດໃຊ້ທ່າທາງການປັດຂຶ້ນເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ເປີດໃຊ້ທ່າທາງເພື່ອເຂົ້າສູ່ໜ້າຈໍແບບແຍກກັນ ໂດຍການປັດຂຶ້ນຈາກປຸ່ມພາບຮວມ"</string>
     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f933608..df1765a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Pasiektas nustatytas duomenų apribojimas. Nebenaudojate mobiliojo ryšio duomenų.\n\nJei atnaujinsite, gali būti taikomi mokesčiai už duomenų naudojimą."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
@@ -274,10 +274,10 @@
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nėra pasiekiamų susietų įrenginių"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
-    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis kaitaliojimas"</string>
+    <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis pasukimas"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatiškai sukti ekraną"</string>
     <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Nustatyti kaip <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Kaitaliojimas užrakintas"</string>
+    <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Pasukimas užrakintas"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stačias"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Gulsčias"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Įvesties metodas"</string>
@@ -407,6 +407,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Įrenginys gali būti stebimas"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilis gali būti stebimas"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Tinklas gali būti stebimas"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tinklas gali būti stebimas"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Įrenginio stebėjimas"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilio stebėjimas"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Tinklo stebėjimas"</string>
@@ -419,6 +420,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsų įrenginį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nAdministratorius gali stebėti ir tvarkyti nustatymus, įmonės informacijos pasiekiamumo nustatymus, programas, su įrenginiu susietus duomenis ir įrenginio vietovės informaciją.\n\nEsate prisijungę prie programos „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
@@ -495,8 +497,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Įgalinti ekrano skaidymo perbraukimo aukštyn gestą"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Įgalinti gestą, kuriuo galima įjungti skaidytą ekraną, perbraukiant aukštyn nuo apžvalgos mygtuko"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2c1fb2e..ffad77b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -238,7 +238,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ir sasniegts jūsu iestatītais datu ierobežojums. Jūs vairs neizmantojat mobilos datus.\n\nJa atsāksiet, var tikt piemērota maksa par datu lietojumu."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Ierīci var pārraudzīt"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilu var pārraudzīt"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Var tikt pārraudzītas tīklā veiktās darbības."</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ierīces pārraudzība"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profila pārraudzība"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Tīkla pārraudzība"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nIr piesaistīta arī lietojumprogramma <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Jūsu ierīci pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJūsu administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes un datus, kas ir saistīti ar šo ierīci, kā arī informāciju par jūsu ierīces atrašanās vietu.\n\nIr piesaistīta lietojumprogramma <xliff:g id="APPLICATION">%2$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Iespējot vilkšanu augšup, lai sadalītu ekrānu"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Iespējot žestu ekrāna sadalīšanai, velkot augšup no pogas Pārskats"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index b28938a..4aa1821 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Го достигнавте ограничувањето за сообраќај на податоци што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Уредот може да се следи"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профилот можеби се следи"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Мрежата може да се следи"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежата може да се следи"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Следење на уредот"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Следење профил"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Следење на мрежата"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"ВПН"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nВие исто така сте поврзани на <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот уред.\n\nВашиот администратор може да ги следи и да управува со параметрите, корпоративниот пристап, апликациите, податоците поврзани со уредот и информациите за локацијата на уредот.\n\nПоврзани сте на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Овозможи го гестот повлекување нагоре за поделен екран"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Овозможете гест за отворање поделен екран со повлекување нагоре од копчето Краток преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index c5a440d..225a284 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങൾ നേരത്തെ ക്രമീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗം, ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾക്ക് ഇടയാക്കാം."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"നിങ്ങൾ സജ്ജമാക്കിയ ഡാറ്റ പരിധി എത്തിക്കഴിഞ്ഞു. ഇനിയങ്ങോട്ട് നിങ്ങൾ സെല്ലുലാർ ഡാറ്റ ഉപയോഗിക്കില്ല.\n\nതുടരുകയാണെങ്കിൽ, ഡാറ്റാ ഉപയോഗത്തിന് നിരക്കുകൾ ബാധകമായേക്കാം."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്‌റ്റുചെയ്‌തു"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ഉപകരണം നിരീക്ഷിക്കപ്പെടാം"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"പ്രൊഫൈൽ നിരീക്ഷിക്കപ്പെടാം"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കപ്പെടാം"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ഉപകരണം നിരീക്ഷിക്കൽ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"പ്രൊഫൈൽ നിരീക്ഷിക്കൽ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"നെറ്റ്‌വർക്ക് നിരീക്ഷിക്കൽ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nനിങ്ങൾ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> എന്നതിലേക്കും കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"നിങ്ങളുടെ ഉപകരണം നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nനിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്റർക്ക്, ഉപകരണവുമായി ബന്ധപ്പെട്ട ക്രമീകരണവും കോർപ്പറേറ്റ് ആക്‌സസ്സും അപ്ലിക്കേഷനുകളും വിവരവും ഒപ്പം ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരവും നിരീക്ഷിച്ച് നിയന്ത്രിക്കാനാകും.\n\nഇമെയിലുകളും അപ്ലിക്കേഷനുകളും വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെയുള്ള നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകുന്ന ഒരു <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്തിരിക്കുന്നു.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, അഡ്‌മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"സ്പ്ലിറ്റ്-സ്ക്രീൻ സ്വൈപ്പ്-അപ്പ് ജെസ്റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ചുരുക്കവിവരണ ബട്ടണിൽ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്തുകൊണ്ട് സ്പ്ലിറ്റ്-സ്ക്രീനിലേക്ക് പ്രവേശിക്കാൻ ജെസ്‌റ്റർ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 766af7c..a84aae6 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -235,7 +235,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Таны тогтоосон дата хэмжээний хязгаарт хүрсэн байна. Та одоогоор мобайл датаг ашиглаагүй байна.\n\nҮргэлжлүүлсэн тохиолдолд төлбөр гарах болно."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
@@ -401,6 +401,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Төхөөрөмжийг хянах боломжтой"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профайлыг хянаж байж болзошгүй"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Сүлжээ хянагдаж байж болзошгүй"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сүлжээг хянаж байж болзошгүй"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Төхөөрөмжийн хяналт"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Профайл хяналт"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Сүлжээний хяналт"</string>
@@ -413,6 +414,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вебсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Дэлгэц хуваах дээш шудрах дохиог идэвхжүүлэх"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Тойм товчлуурыг дээш шударч, хуваагдсан дэлгэцэд зангаагаар орох тохиргоог идэвхжүүлэх"</string>
     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
@@ -504,14 +504,14 @@
     <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Тэжээлийн мэдэгдлийн удирдлага"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Идэвхтэй"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Идэвхгүй"</string>
-    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын төвшин тогтоох боломжтой. \n\n"<b>"5-р төвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р төвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р төвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
+    <string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын түвшин тогтоох боломжтой. \n\n"<b>"5-р түвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р түвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
     <string name="user_unspecified_importance" msgid="361613856933432117">"Ач холбогдол: Автомат"</string>
-    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р төвшин"</string>
-    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р төвшин"</string>
-    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р төвшин"</string>
-    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р төвшин"</string>
-    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р төвшин"</string>
-    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р төвшин"</string>
+    <string name="blocked_importance" msgid="5035073235408414397">"Ач холбогдол: 0-р түвшин"</string>
+    <string name="min_importance" msgid="560779348928574878">"Ач холбогдол: 1-р түвшин"</string>
+    <string name="low_importance" msgid="7571498511534140">"Ач холбогдол: 2-р түвшин"</string>
+    <string name="default_importance" msgid="7609889614553354702">"Ач холбогдол: 3-р түвшин"</string>
+    <string name="high_importance" msgid="3441537905162782568">"Ач холбогдол: 4-р түвшин"</string>
+    <string name="max_importance" msgid="4880179829869865275">"Ач холбогдол: 5-р түвшин"</string>
     <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Апп нь мэдэгдэл бүрийн ач холбогдлыг тодорхойлдог."</string>
     <string name="notification_importance_blocked" msgid="4237497046867398057">"Энэ апп-н мэдэгдлийг хэзээ ч бүү харуул."</string>
     <string name="notification_importance_min" msgid="7844224511187027155">"Бүтэн дэлгэцэд саадгүй, гарч ирэхгүй, дуугүй, чичиргээгүй. Түгжигдсэн дэлгэц, статусын хэсгээс нуух."</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 82a07ba..6c92213 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपण सेट केलेली डेटा मर्यादा गाठली आहे. आपण यापुढे मोबाइल डेटा वापरणार नाही.\n\nआपण पुन: सुरु केल्यास, डेटा वापरासाठी शुल्क आकारले जाऊ शकतात."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"डिव्हाइसचे परीक्षण केले जाऊ शकते"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाईलचे परीक्षण केले जाऊ शकते"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिव्हाइस परीक्षण"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाईल परीक्षण"</string>
     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क परीक्षण"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्‍या प्रशासकाशी संपर्क साधा."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nआपण <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शी देखील कनेक्‍ट केले आहे, जे आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपले डिव्हाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे.\n\nआपला प्रशासक आपल्या डिव्हाइसशी संबद्ध सेटिंग्ज, कॉर्पोरेट प्रवेश, अ‍ॅप्स, डेटा आणि आपल्या डिव्हाइसच्या स्थान माहितीचे परीक्षण करू शकतो आणि व्‍यवस्थापित करू शकतो.\n\nआपण <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रीन स्वाइप-अप जेश्चर सक्षम करा"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"विहंगावलोकन बटणावरून वर स्वाइप करून विभाजित-स्क्रीन प्रविष्ट करण्यासाठी जेश्चर सक्षम करा"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index c653f25..95e7a4d 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Had data yang anda tetapkan telah dicapai. Anda tidak lagi menggunakan data selular.\n\nJika anda menyambung semula, caj mungkin dikenakan untuk penggunaan data."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Peranti mungkin dipantau"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil mungkin dipantau"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Rangkaian mungkin dipantau"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rangkaian mungkin dipantau"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pemantauan peranti"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pemantauan profil"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Pemantauan rangkaian"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, sila hubungi pentadbir anda."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil disambungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut disambungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Peranti anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti anda serta maklumat lokasi peranti anda.\n\nAnda disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Dayakan gerak isyarat leret ke atas utk masuk skrin terpisah"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Dayakan gerak isyarat untuk memasuki skrin terpisah dengan meleret ke atas daripada butang Ikhtisar"</string>
     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 47f5a86..905c865 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"သင်သတ်မှတ်ထားသော ဒေတာကန့်သတ်ချက်သို့ ရောက်နေပါပြီ။ သင်သည် ဆယ်လူလာဒေတာကို အသုံးမပြုတော့ပါ။\n\nသင်ဆက်လုပ်မည်ဆိုလျှင် ဒေတာသုံးစွဲမှုအတွက် အခငွေ ကျသင့်မှုရှိနိုင်ပါသည်။"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ကိရိယာကို စောင့်ကြပ် နိုင်ပါသည်"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ပရိုဖိုင်ကို စောင့်ကြပ်နိုင်သည်"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ကွန်ရက်ကို ကို စောင့်ကြပ် နိုင်ပါသည်"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ကွန်ရက်ကို စောင့်ကြည့်စစ်ဆေးမှု ရှိနိုင်ပါသည်"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ကိရိယာကို စောင့်ကြပ်ခြင်း"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ပရိုဖိုင် စောင့်ကြပ်မှု"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ကွန်ရက်ကို စောင့်ကြပ်ခြင်း"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးများ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"သင်သည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကိုယ်ရေးကိုယ်တာ ကွန်ရက်အသုံးပြုမှုကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"သင့်အလုပ် ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\n သင်သည်<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ကိုလည်း ချိတ်ဆက်ထားသည်၊ ၎င်းသည် သင့်ကိုယ်ပိုင်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"သင့်စက်ကိရိယာကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲပါသည်။ \n\n စီမံခန့်ခွဲသူသည် ကြိုတင်ပြင်ဆင်မှုများ၊ စုပေါင်းဝင်ရောက်ခွင့်၊ အက်ပ်များ၊ သင့်ကိရိယာနှင့်သက်ဆိုင်သော ဒေတာနှင့် သင့်ကိရိယာ၏ တည်နေရာအချက်အလက်များကို စောင့်ကြည့်ပြီး စီမံခန့်ခွဲနိုင်သည်။ \n\nသင်သည် <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များ၊ နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"မျက်နှာပြင်ခွဲကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲခြင်း အမူအရာကိုဖွင့်ပါ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ခြုံကြည့်သည့်ခလုတ်မှ အပေါ်သို့ပွတ်ဆွဲခြင်းဖြင့် မျက်နှာပြင်ခွဲကြည့်ရန် လက်ဟန်ကိုဖွင့်ပါ"</string>
     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
@@ -587,7 +587,7 @@
     <string name="center" msgid="4327473927066010960">"ဌာန"</string>
     <string name="end" msgid="125797972524818282">"ပြီးပါပြီ"</string>
     <string name="space" msgid="804232271282109749">"နေရာလွတ်ခြားစနစ်"</string>
-    <string name="menu_ime" msgid="4943221416525250684">"မန်နယူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
+    <string name="menu_ime" msgid="4943221416525250684">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
     <string name="select_button" msgid="1597989540662710653">"ပေါင်းထည့်ရန် ခလုတ်ကိုရွေးပါ"</string>
     <string name="add_button" msgid="4134946063432258161">"ခလုတ်ပေါင်းထည့်ပါ"</string>
     <string name="save" msgid="2311877285724540644">"သိမ်းရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index de88e15..41d70e6 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Datagrensen du satte, er nådd. Du bruker ikke mobildata lenger.\n\nHvis du gjenopptar bruk av mobildata, kan gebyrer for databruk påløpe."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan være overvåket"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåkes"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Nettverket kan være overvåket"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nettverket kan bli overvåket"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsovervåking"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilovervåking"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Nettverksovervåking"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nFor å få mer informasjon, ta kontakt med administratoren."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data tilknyttet enheten din og enhetens posisjonsinformasjon.\n\nDu er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nFor mer informasjon, ta kontakt med administratoren."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Slå på delt skjerm ved å sveipe opp"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Slå på bevegelsen for å åpne delt skjerm ved å sveipe opp fra Oversikt-knappen"</string>
     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 198555b..d0dfd66 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डेटाको सीमा पुगेकाले, यन्त्रले यस चक्रको बाँकी भागका लागि डेटाको प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"तपाईँले सेट गर्नुभएको डेटाको सीमामा पुगिएको छ। अबदेखि तपाईँ सेलुलर डेटाको प्रयोग गर्नुहुने छैन। \n\nतपाईँले प्रयोग जारी राख्नुभयो भने डेटा प्रयोगका शुल्कहरू लाग्न सक्छन्।"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"उपकरण अनुगमन हुन सक्छ"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफाइल अनुगमन हुन सक्छ"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"सञ्जाल अनुगमित हुन सक्छ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्कको अनुगमन गरिने सम्भावना छ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"उपकरण अनुगमन"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफाइल अनुगमन गर्दै"</string>
     <string name="monitoring_title" msgid="169206259253048106">"सञ्जाल अनुगमन"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँका नेटवर्क गतिविधिको अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायतको तपाईंको  व्यक्तिगत नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> सँग पनि जडित हुनुहुन्छ, जसले तपाईँको व्यक्तिगत नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थित गरिन्छ।\n\nतपाईँको प्रशासकले तपाईँको यन्त्र र त्यसको स्थान जानकारीमार्फत सेटिङहरू,  कर्पोरेट पहुँच, अनुप्रयोगहरू, तपाईँको यन्त्रसँग सम्बद्ध डेटा  र तपाईँको यन्त्रको स्थान जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जडित हुनुहुन्छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि तपाईको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"विभाजित-स्क्रिन स्वाइप-अप इशारा सक्षम गर्नुहोस्"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"परिदृश्य बटनदेखि माथि स्वाइप गरी विभाजित-स्क्रिन प्रविष्ट गर्न इसारालाई सक्रिय गर्नुहोस्"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8ba27af..6bcd642 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan je provider kosten in rekening brengen."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Apparaat wordt mogelijk gecontroleerd"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profiel kan worden gecontroleerd"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Netwerk kan worden gecontroleerd"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Netwerk kan worden gecontroleerd"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Apparaatcontrole"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profielcontrole"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Netwerkcontrole"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, zakelijke toegang, apps, gekoppelde apparaatgegevens en locatiegegevens voor je apparaat controleren en beheren.\n\nU bent verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g> waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omhoog vegen voor gesplitst scherm inschakelen"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Gebaar inschakelen om gesplitst scherm te openen door vanaf de knop Overzicht omhoog te vegen"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index dbf9f86..d5b4a5d 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ਸੈਲਿਊਲਰ ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ਕਿਉਂਕਿ ਤੁਹਾਡੀ ਸੈਟ ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ ਸੀ,  ਡੀਵਾਈਸ ਨੇ ਇਸ ਬਾਕੀ ਚੱਕਰ ਲਈ ਡੈਟਾ ਉਪਯੋਗ ਰੋਕ ਦਿੱਤਾ ਹੈ।\n\nਇਸਨੂੰ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰਨ ਨਾਲ ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਵੱਲੋਂ ਖ਼ਰਚੇ ਪਾਏ ਜਾ ਸਕਦੇ ਹਨ।"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ਤੁਸੀਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਗਈ ਡੈਟਾ ਸੀਮਾ \'ਤੇ ਪਹੁੰਚ ਚੁੱਕੇ ਹੋ। ਤੁਸੀਂ ਹੁਣ ਸੈਲਿਊਲਰ ਡੈਟੇ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।\n\nਜੇਕਰ ਤੁਸੀਂ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਤਾਂ ਡੈਟਾ ਵਰਤੋਂ ਲਈ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ਨੈੱਟਵਰਕ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ਹੋ ਸਕਦਾ ਹੈ ਨੈੱਟਵਰਕ ਦੀ ਨਿਗਰਾਨੀ ਹੋ ਰਹੀ ਹੋਵੇ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"ਡੀਵਾਈਸ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕਰਨਾ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ਨੈੱਟਵਰਕ ਨਿਰੀਖਣ ਕਰ ਰਿਹਾ ਹੈ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ।"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਪ੍ਰਬੰਧਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਸ, ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਡੈਟਾ ਅਤੇ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਜਾਣਕਾਰੀ ਦਾ ਨਿਰੀਖਣ ਅਤੇ ਉਸਨੂੰ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦਾ ਹੈ।\n\nਤੁਸੀਂ ਇੱਕ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈੱਬਪੰਨੇ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਸਵਾਈਪ-ਅੱਪ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"ਰੂਪ-ਰੇਖਾ ਬਟਨ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਨ ਦੁਆਰਾ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਣ ਲਈ ਸੰਕੇਤ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 294381e..92df542 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Osiągnięto ustawiony limit danych. Nie korzystasz już z komórkowej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za transmisję danych."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
@@ -407,6 +407,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Urządzenie może być monitorowane"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil może być monitorowany"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Sieć może być monitorowana"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieć może być monitorowana"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorowanie urządzeń"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorowanie profilu"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitorowanie sieci"</string>
@@ -419,6 +420,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Twoim urządzeniem zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować ustawienia, firmowe uprawnienia dostępu, aplikacje, dane powiązane z urządzeniem i informacje o jego lokalizacji oraz nimi zarządzać.\n\nMasz połączenie z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
@@ -495,8 +497,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Włącz dzielenie ekranu gestem przesunięcia w górę"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Włącz dzielenie ekranu po wykonaniu gestu przesunięcia palcem w górę od przycisku Przegląd"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 89aa5d3..5fe2def 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e06df93..ff5f566 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados definido foi atingido. Já não está a utilizar dados móveis.\n\nSe retomar, podem aplicar-se custos relativos à utilização de dados."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorizado"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorizado"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorizada"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorizada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorização de dispositivos"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorização de perfis"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitorização da rede"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nTambém está ligado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"O seu dispositivo é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu administrador pode monitorizar e gerir as definições, o acesso empresarial, as aplicações, os dados associados ao dispositivo e as informações de localização do dispositivo.\n\nEstá ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto de deslize rápido para cima do ecrã dividido"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativar o gesto para aceder ao ecrã dividido ao deslizar rapidamente para cima a partir do botão Vista geral"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 89aa5d3..5fe2def 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"O dispositivo pode ser monitorado"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"O perfil pode ser monitorado"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"A rede pode ser monitorada"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"A rede pode ser monitorada"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitoramento de dispositivos"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitoramento de perfis"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitoramento de rede"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Seu dispositivo é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar e gerenciar configurações, acesso corporativo, apps, dados associados ao seu dispositivo e informações sobre localização do dispositivo.\n\nVocê está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ativar gesto para dividir a tela ao deslizar para cima"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Ativa o gesto para entrar no modo de tela dividida deslizando a partir do botão \"Visão geral\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 11ef6f1..0f7a7db 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -240,7 +240,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"A fost atinsă limita de date setată. Datele mobile nu mai sunt folosite \n\nDacă reluați, este posibil să se aplice taxe pentru utilizarea datelor."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
@@ -407,6 +407,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Dispozitivul poate fi monitorizat"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilul poate fi monitorizat"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Rețeaua poate fi monitorizată"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Este posibil ca rețeaua să fie monitorizată"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorizarea dispozitivului"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorizarea profilului"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitorizarea rețelei"</string>
@@ -419,6 +420,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"V-ați conectat la aplicația <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea personală în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nDe asemenea, sunteți conectat(ă) la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dispozitivul este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul poate monitoriza și gestiona setările, accesul la rețeaua companiei, aplicațiile, datele asociate cu dispozitivul și informațiile privind locația dispozitivului.\n\nSunteți conectat(ă) la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
@@ -495,8 +497,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Activați gestul de accesare a ecranului împărțit prin glisare în sus"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Activați gestul de accesare a ecranului împărțit prin glisarea în sus de la butonul Recente"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c4205fb..0e49132 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнут установленный вами лимит на передачу мобильных данных.\n\nЕсли вы продолжите, может взиматься дополнительная плата."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Устройство может контролироваться"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Действия в профиле могут отслеживаться"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Сеть может отслеживаться"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Сеть может отслеживаться"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Отслеживание устройств"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Мониторинг профиля"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Отслеживание сетей"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"Сеть VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа дополнительной информацией обратитесь к своему администратору."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nПриложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\" может отслеживать ваши действия в Интернете, выполняемые в личном профиле."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим корпоративным профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может управлять настройками, корпоративным доступом, приложениями, данными на вашем устройстве, в том числе геоданными, а также просматривать соответствующие сведения.\n\nПриложение <xliff:g id="APPLICATION">%2$s</xliff:g> также может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа подробностями обратитесь к своему администратору."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Разделять экран пролистыванием вверх"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Включить разделение экрана пролистыванием вверх с кнопки \"Обзор\""</string>
     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 3b49cc1..ff8031e 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්‍රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම් වලට පොළඹවනු ඇත."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ඔබ සැකසූ දත්ත සීමාව ළඟා වී ඇත. ඔබ තවදුරටත් සෙලියුලර් දත්ත භාවිත නොකරයි. \n\nඔබ නැවත ආරම්භ කළහොත්, දත්ත භාවිතය සඳහා ගාස්තු අදාළ විය හැකිය."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"ඇතැම් විට උපාංගය නිරීක්ෂණය විය හැක"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ඇතැම් විට පැතිකඩ නිරීක්ෂණය කරන ලදි"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"ඇතැම් විට ජාලය නිරීක්ෂණය විය හැක"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"උපාංගය නිරීක්ෂණය"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"පැතිකඩ නිරීක්ෂණය කිරීම"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ජාල නිරීක්ෂණය"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%2$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත.\n\nවැඩිදුර විස්තර සඳහා, ඔබේ පරිපාලක අමතන්න."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"ඔබේ උපාංගය කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි.\n\nඔබේ පරිපාලකට ඔබේ උපාංගය හා සම්බන්ධිත සැකසීම්, ආයතනික ප්‍රවේශය, යෙදුම්, දත්ත සහ ඔබේ උපාංගය තිබෙන ස්ථානයේ තොරතුරු නිරීක්ෂණය කිරීමට සහ කළමනාකරණය කිරීමට හැකිය.\n\nඔබ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකි <xliff:g id="APPLICATION">%2$s</xliff:g>, වෙතද සම්බන්ධව ඇත.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"බෙදුම්-තිරය ඉහළට-ස්වයිප් කිරීමේ අභිනය සබල කරන්න"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"දළ විශ්ලේෂණ බොත්තම හරහා ඉහළට ස්වයිප් කිරීමෙන් බෙදුම් තිරයට ඇතුළු වීමට ඉඟිය සබල කිරීම"</string>
     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 099e9c1..f6e43dd 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosiahli ste nastavený limit dát. Už nepoužívate mobilné dátové pripojenie.\n\nAk ho však obnovíte, môžu vám byť účtované poplatky za spotrebu dát."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Zariadenie môže byť sledované"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil môže byť monitorovaný"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Sieť môže byť sledovaná"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Sieť môže byť monitorovaná"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Sledovanie zariadenia"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorovanie profilu"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Sledovanie siete"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nSte tiež pripojený/-á k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Vaše zariadenie spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať a spravovať nastavenia, podnikový prístup, aplikácie a údaje priradené k vášmu účtu, ako aj informácie o polohe zariadenia.\n\nSte pripojený/-á k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácii a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivovať rozdelenú obrazovku prejdením prstom"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umožňuje aktivovať rozdelenú obrazovku prejdením prstom nahor od tlačidla Prehľad"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 49fc355..9f2f7c4 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegli ste nastavljeno omejitev porabe podatkov. Prenosa podatkov v mobilnih omrežjih ne uporabljate več.\n\nČe nadaljujete, lahko nastanejo stroški prenosa podatkov."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Naprava je morda nadzorovana"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil je morda nadziran"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Omrežje je lahko nadzorovano"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Omrežje je morda nadzorovano"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadzor naprave"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadzor nad profilom"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Nadzor omrežja"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Napravo upravlja organizcija <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, podatke, povezane z napravo, in podatke o lokaciji naprave.\n\nPovezani ste z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Omogočanje poteze za razdeljen zaslon z vlečenjem navzgor"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Omogočanje poteze za vklop razdeljenega zaslona, tako da uporabnik od gumba za pregled povleče s prstom navzgor"</string>
     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 92b8e35..b07f551 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Të dhënat celulare janë ndërprerë"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Pajisja jote ka ndërprerë përdorimin e të dhënave për pjesën e mbetur të ciklit sepse është arritur kufiri i caktuar i të dhënave.\n\nVazhdimi mund të sjellë tarifa nga operatori celular."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Kufiri i të dhënave që ke caktuar është arritur. Nuk po përdor më të dhënat celulare.\n\nNëse vazhdon, mund të zbatohen tarifa për përdorimin e të dhënave."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Pajisja mund të monitorohet"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profili mund të monitorohet"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Rrjeti mund të jetë i monitoruar"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Rrjeti mund të jetë i monitoruar"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Monitorimi i pajisjes"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Monitorimi i profilit"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Monitorimi i rrjetit"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori mund të monitorojë dhe menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat që shoqërojnë pajisjen tënde si dhe informacionin e vendndodhjes së pajisjes.\n\nJe i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, që mund të monitorojë aktivitetin tënd të punës në rrjet përfshirë mail-at, aplikacionet dhe faqet e internetit.\n\nPër më shumë informacion, kontakto me administratorin tënd."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivizo gjestin e rrëshqitjes lart për ekranin e ndarë"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivizo gjestin për të hyrë tek ekrani i ndarë duke rrëshqitur lart nga butoni \"Përmbledhja\""</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 9c4fefb..35d7d52 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -238,7 +238,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ограничење потрошње података које сте подесили је достигнуто. Више не користите мобилне податке.\n\nАко наставите, можда ће бити наплаћени трошкови за потрошњу података."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Уређај се можда надгледа"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профил се можда надгледа"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Мрежа се можда надгледа"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мрежа се можда надгледа"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Надгледање уређаја"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Надгледање профила"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Надгледање мреже"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Уређајем управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима.\n\nПовезани сте са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Омогући покрет за превлачење нагоре за подељени екран"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Омогућава покрет за прелазак на подељени екран превлачењем нагоре од дугмета Преглед"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4b15537..26b0d9f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Den angivna datagränsen har uppnåtts. Du använder inte längre mobildata.\n\nOm du fortsätter kan avgifter för dataanvändning tillkomma."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
@@ -351,7 +351,7 @@
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt om du vill låsa upp"</string>
+    <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt för att låsa upp"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Svep från ikonen och öppna telefonen"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Svep från ikonen och öppna röstassistenten"</string>
     <string name="camera_hint" msgid="7939688436797157483">"Svep från ikonen och öppna kameran"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Enheten kan övervakas"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Det kan hända att profilen övervakas"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Nätverket kan vara övervakat"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Nätverket kan vara övervakat"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Enhetsövervakning"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilövervakning"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Nätverksövervakning"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan övervaka din privata aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nKontakta administratören för mer information."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan hantera privat aktivitet på nätverket."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Enheten hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan bevaka och hantera inställningar, företagsåtkomst, appar, data som är kopplad till enheten och enhetens platsuppgifter.\n\nDu är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan övervaka aktivitet på nätverket, inklusive e-post. appar och webbplatser .\n\nKontakta administratören för mer information."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Aktivera delad skärm när du sveper uppåt"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Aktivera en rörelse som delar skärmen när du sveper uppåt från knappen Översikt"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 101bfa4..396731b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umefikia kikomo cha data ulichoweka. Hutaweza kutumia tena data ya simu ya mkononi.\n\nIkiwa utaendelea, huenda ukatozwa ada za matumizi ya data."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Huenda kifaa kinafuatiliwa"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Huenda wasifu ukafuatiliwa"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Huenda mtandao unafuatiliwa"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Huenda mtandao unafuatiliwa"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ufuatiliaji wa kifaa"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ufuatiliaji wasifu"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Ufuatiliaji wa mtandao"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti. \n\n Wewe pia umeunganishwa kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako kibinafsi."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Kifaa chako kinasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. \n\nMsimamizi wako anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa kampuni, programu, data inayohusiana na kifaa chako, na maelezo ya mahali kilipo kifaa chako. \n\n Umeuganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli ya mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\n Kwa maelezo zaidi, wasiliana na msimamizi wako."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Ruhusu kugawanya skrini kwa ishara ya kutelezesha kidole juu"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Washa kipengele cha ishara ili utumie skrini iliyogawanywa kwa kutelezesha kidole juu kutoka kitufe cha Muhtasari"</string>
     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index d7ef941..465d70e 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"நீங்கள் அமைத்த தரவு வரம்பை அடைந்துவிட்டீர்கள். இப்போது செல்லுலார் தரவைப் பயன்படுத்த முடியாது.\n\nமீண்டும் தொடங்கினால், தரவுப் பயன்பாட்டிற்குக் கட்டணங்கள் விதிக்கப்படலாம்."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"சாதனம் கண்காணிக்கப்படலாம்"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"சுயவிவரம் கண்காணிக்கப்படலாம்"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"நெட்வொர்க் கண்காணிக்கப்படலாம்"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"சாதனத்தைக் கண்காணித்தல்"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"சுயவிவரத்தைக் கண்காணித்தல்"</string>
     <string name="monitoring_title" msgid="169206259253048106">"நெட்வொர்க்கைக் கண்காணித்தல்"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nமேலும் <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டையும் அதனால் கண்காணிக்க முடியும்."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"சாதனத்தை நிர்வகிப்பது: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nஉங்கள் நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், பயன்பாடுகள், சாதனத்துடன் தொடர்புடைய தரவு மற்றும் சாதனத்தின் இருப்பிடத் தகவல் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்.\n\n<xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"மேலே ஸ்வைப் செய்வதன் மூலம் திரையைப் பிரிக்கும் சைகையை இயக்கு"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"மேலோட்டப் பார்வை பொத்தானிலிருந்து மேலே ஸ்வைப் செய்வதன் மூலம், திரைப் பிரிப்பைச் செயலாக்குவதற்கான சைகையை இயக்கும்"</string>
     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 29c8781..783664d 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్‌లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు సెల్యులార్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు వర్తించవచ్చు."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"పరికరం పర్యవేక్షించబడవచ్చు"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"ప్రొఫైల్‌ని పర్యవేక్షించవచ్చు"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"నెట్‌వర్క్ పర్యవేక్షించబడవచ్చు"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"పరికర పర్యవేక్షణ"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"ప్రొఫైల్ పర్యవేక్షణ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"నెట్‌వర్క్ పర్యవేక్షణ"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌‍సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమీరు <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా కనెక్ట్ చేయబడ్డారు, ఇది మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"మీ పరికరాన్ని <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది.\n\nమీ నిర్వాహకుడు సెట్టింగ్‌లను, కార్పొరేట్ ప్రాప్యతను, అనువర్తనాలను, మీ పరికరంతో అనుబంధించిన డేటాను మరియు మీ పరికర స్థాన సమాచారాన్ని పర్యవేక్షించగలరు మరియు నిర్వహించగలరు.\n\nమీరు <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజన సంజ్ఞను ప్రారంభించు"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"స్థూలదృష్టి బటన్ నుండి పైకి స్వైప్ చేయడం ద్వారా స్క్రీన్ విభజనలోకి ప్రవేశించడానికి సంజ్ఞను ప్రారంభిస్తుంది"</string>
     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 808a2a1..1fbd6f4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้แล้ว คุณจะไม่สามารถใช้ข้อมูลเครือข่ายมือถืออีก\n\nหากใช้ต่อ อาจมีค่าบริการสำหรับปริมาณการใช้อินเทอร์เน็ต"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"อาจมีการตรวจสอบอุปกรณ์"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"อาจมีการตรวจสอบโปรไฟล์"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"เครือข่ายอาจถูกตรวจสอบ"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"การตรวจสอบอุปกรณ์"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"การตรวจสอบโปรไฟล์"</string>
     <string name="monitoring_title" msgid="169206259253048106">"การตรวจสอบเครือข่าย"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nนอกจากนี้ คุณยังเชื่อมต่อกับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวได้"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"อุปกรณ์ได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูและรบบของคุณสามารถตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป ข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ได้\n\nคุณมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายรวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"เปิดใช้ท่าทางสัมผัสการเลื่อนขึ้นเพื่อแยกหน้าจอ"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"เปิดใช้ท่าทางสัมผัสเพื่อเข้าสู่โหมดแยกหน้าจอโดยเลื่อนขึ้นจากปุ่มภาพรวม"</string>
     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 1eb5295..acaf86c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Naabot na ang limitasyon sa data na itinakda mo. Hindi ka na gumagamit ng cellular data.\n\nKung magpapatuloy ka, maaari kang masingil para sa paggamit ng data."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Maaaring subaybayan ang device"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Maaaring subaybayan ang profile"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Maaaring sinusubaybayan ang network"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Maaaring sinusubaybayan ang network"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Pagsubaybay sa device"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Pagsubaybay sa Profile"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Pagsubaybay sa network"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network kabilang ang mga email, app at website."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network, kabilang ang mga email, app at website."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Pinapamahalaan ang iyong device ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMaaaring subaybayan at pamahalaan ng iyong administrator ang mga setting, corporate na access, app, data na nauugnay sa iyong device at ang impormasyon ng lokasyon ng iyong device.\n\nNakakonekta ka sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring subaybayan ang iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"I-enable ang pag-swipe pataas na galaw para sa split-screen"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"I-enable ang gesture upang makapasok sa split-screen sa pamamagitan ng pagsa-swipe pataas mula sa button ng Pangkalahatang-ideya"</string>
     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f29d9b5..b4dc25d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ayarladığınız veri limitine ulaşıldı. Artık hücresel verilerinizi kullanmıyorsunuz.\n\nHücresel veri kullanımını devam ettirirseniz veri kullanım ücretleri ödemeniz gerekebilir."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Cihaz izlenebilir"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil izlenebilir"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Ağ etkinliği izlenebilir"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Ağ etkinliği izlenebilir"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Cihaz izleme"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profil izleme"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Ağ izleme"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\n Ayrıca kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Cihazınız <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz; ayarları, şirket erişimini, uygulamaları, cihazınızla ilişkilendirilmiş verileri ve cihazınızın konum bilgilerini izleyebilir ve yönetebilir.\n\nE-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlısınız.\n\nDaha fazla bilgi edinmek için yöneticinizle iletişim kurun."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Hızlıca yukarı kaydırma hareketiyle ekran bölm. etkinleştir"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Genel bakış düğmesinden yukarı hızlıca kaydırarak bölünmüş ekrana geçme hareketini etkinleştir"</string>
     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index a930589..4d2b6c39 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -241,7 +241,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ви досягнули вказаного ліміту даних. Мобільний трафік вимкнено.\n\nЯкщо продовжите, може стягуватися плата за використання трафіку."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
@@ -409,6 +409,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Дії на пристрої можуть відстежуватися"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Профіль може відстежуватись"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Дії в мережі можуть відстежуватися"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Мережа може відстежуватися"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Відстеження дій на пристрої"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Відстеження профілю"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Відстеження дій у мережі"</string>
@@ -421,6 +422,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема доступ до електронної пошти, додатків і веб-сайтів."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Вашим пристроєм керує організація <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдміністратор може відстежувати та контролювати налаштування, корпоративний доступ, додатки, геодані й інші дані, пов’язані з вашим пристроєм.\n\nВаш профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
@@ -497,8 +499,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Увімкнути розділення екрана рухом пальця вгору"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Увімкнути жест розділення екрана рухом пальця вгору від кнопки \"Огляд\""</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 16c1792..cbe3d23 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"آپ کی سیٹ کردہ ڈیٹا کی حد پوری ہو گئی ہے۔ آپ اب سیلولر ڈیٹا استعمال نہیں کر رہے۔\n\nاگر آپ دوبارہ شروع کرتے ہیں تو ڈیٹا کے استعمال کے چارجز لاگو ہو سکتے ہیں۔"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"آلہ کو مانیٹر کیا جا سکتا ہے"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"پروفائل کو مانیٹر کیا جا سکتا ہے"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"نیٹ ورک کو مانیٹر کیا جا سکتا ہے"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"نیٹ ورک کو شاید مانیٹر کیا جائے"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"آلہ کو مانیٹر کرنا"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"پروفائل کو مانیٹر کرنا"</string>
     <string name="monitoring_title" msgid="169206259253048106">"نیٹ ورک کو مانیٹر کرنا"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی کو مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"آپ کا آلہ <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔\n\nآپ کا منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کو مانیٹر اور ان کا نظم کر سکتا ہے۔\n\nآپ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"سپلٹ اسکرین کیلئے سوائپ اپ اشارہ فعال کریں"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"مجموعی جائزہ بٹن سے سوائپ اپ کرکے سپلٹ اسکرین میں داخل ہونے کیلئے اشارہ فعال کریں"</string>
     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index eb6ffb3..3f1bb9b 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O‘rnatilgan trafik sarflab bo‘lindi. Endi mobil internetdan foydalana olmaysiz.\n\nDavom ettiradigan bo‘lsangiz, trafik uchun to‘lov olinishi mumkin."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Qurilma kuzatilishi mumkin"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profil kuzatilishi mumkin"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Tarmoqni kuzatish mumkin"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Tarmoq kuzatilishi mumkin"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Qurilmalarni kuzatish"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Profilni kuzatish"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Tarmoqlarni kuzatish"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Qurilmangiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator sozlamalar, korporativ kirish huquqi, ilovalar, qurilmangizdagi ma’lumotlar, jumladan, joylashuv ma’lumotlarini boshqarishi mumkin.\n\nShuningdek, siz <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasiga ham ulangansiz. Ushbu ilova internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlar bilan ishlashingizni kuzata oladi.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Tepaga surish orqali ekranni ikkiga bo‘lish"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Umumiy ma’lumot tugmasini tepaga surish orqali ekranni bo‘lish ishorasini yoqish"</string>
     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a15ba26..ceeaf18 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vì bạn đã đạt tới giới hạn dữ liệu thiết lập nên thiết bị đã tạm dừng sử dụng dữ liệu cho phần còn lại của chu kỳ này.\n\nTiếp tục có thể dẫn tới nhà cung cấp dịch vụ của bạn sẽ tính phí."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Đã đạt đến giới hạn dữ liệu mà bạn đặt. Bạn hiện không còn sử dụng dữ liệu di động.\n\nNếu tiếp tục, bạn có thể bị tính phí khi sử dụng dữ liệu."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Thiết bị có thể được giám sát"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Hồ sơ có thể được giám sát"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Mạng có thể được giám sát"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Mạng có thể được giám sát"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Giám sát thiết bị"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Giám sát hồ sơ"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Giám sát mạng"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng được kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, có thể giám sát hoạt động mạng cá nhân của bạn."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Thiết bị của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nQuản trị viên có thể giám sát và quản lý cài đặt, quyền truy cập của công ty, ứng dụng, dữ liệu được liên kết với thiết bị của bạn và thông tin về vị trí của thiết bị.\n\nBạn được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Bật cử chỉ vuốt lên ở chế độ chia đôi màn hình"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Cho phép cử chỉ truy cập chế độ chia đôi màn hình bằng cách vuốt lên từ nút Tổng quan"</string>
     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e4572fe..1217318 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"您的数据用量已达到设置的上限。您无法再使用移动数据网络。\n\n如果您继续操作,可能需要支付相应的数据流量费用。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"设备可能会受到监控"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"资料可能会受到监控"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"网络可能会受到监控"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"网络可能会受到监控"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"设备监测"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"资料监控"</string>
     <string name="monitoring_title" msgid="169206259253048106">"网络监控"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n此外,您还连接到了<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,该应用可以监控您的个人网络活动。"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的设备由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您单位的管理员可以监控和管理与此设备相关的设置、企业权限、应用、数据以及设备位置信息。\n\n您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"启用分屏上滑手势"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"启用通过从“概览”按钮向上滑动的手势进入分屏模式"</string>
     <string name="experimental" msgid="6198182315536726162">"实验性功能"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 486c23e..bb51ebe 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -239,7 +239,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。\n\n如恢復使用數據,流動網絡供應商可能會向您收取費用。"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"已達到您設定的數據上限。系統將停止使用流動數據網絡。\n\n如果您恢復使用流動數據網絡,可能需要支付數據費用。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
@@ -405,6 +405,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"個人檔案可能受到監控"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"網絡可能會受到監控"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"網絡可能會受到監控"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"個人檔案監控"</string>
     <string name="monitoring_title" msgid="169206259253048106">"網絡監控"</string>
@@ -417,6 +418,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g> ,它能夠監控您的網絡活動,包括電郵、應用程式和網站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n如需進一步資訊,請聯絡您的管理員。"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n此外,您亦連結至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,因此它亦能夠監控您的個人網絡活動。"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由 <xliff:g id="ORGANIZATION">%1$s</xliff:g> 管理。\n\n您的管理員可以監控及管理您裝置的設定、企業存取、應用程式、資料及位置資訊。\n\n此外,您的裝置連至 <xliff:g id="APPLICATION">%2$s</xliff:g>,它能監控您的網絡活動,包括電郵、應用程式及網站。\n\n如需更多資訊,請聯絡您的管理員。"</string>
@@ -493,8 +495,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上快速滑動手勢"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"從 [概覽] 按鈕向上快速滑動,即可使用手勢功能進入分割畫面模式"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index e0162bc..ac6b002 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取額外的連線費用。"</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"你的數據用量已達設定的用量上限,因此系統已停止使用行動數據連線。\n\n如果你繼續使用行動數據連線,可能需要支付相關的數據傳輸費用。"</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"裝置可能會受到監控"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"設定檔可能會受到監控"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"網路可能會受到監控"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"網路可能會受到監控"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"裝置監控"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"設定檔監控"</string>
     <string name="monitoring_title" msgid="169206259253048106">"網路監控"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n詳情請洽您的管理員。"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n同時由於您也連線至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控。"</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"您的裝置由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您的管理員可以監控及管理與裝置相關的設定、企業網路存取權、應用程式和資料,以及裝置的位置資訊。\n\n由於您的裝置已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n如需詳細資訊,請洽您的管理員。"</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"啟用分割畫面向上滑動手勢"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"啟用透過從 [總覽] 按鈕向上滑動的手勢進入分割畫面"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a2c31d6..78e22f1 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -237,7 +237,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string>
+    <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umkhawulo wedatha owusethayo ufikiwe. Awusasebenzisi idatha yeselula.\n\nUma uqalisa kabusha, izindleko zingasebenza ekusetshenzisweni kwedatha."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
@@ -403,6 +403,7 @@
     <string name="device_owned_footer" msgid="3802752663326030053">"Idivayisi inganganyelwa"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Iphrofayela ingaqashwa"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Inethiwekhi kungenzeka iqashiwe"</string>
+    <string name="branded_vpn_footer" msgid="2168111859226496230">"Inethiwekhi kungenzeka iqashiwe"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Ukwengamela idivayisi"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Ukuqapha iphrofayela"</string>
     <string name="monitoring_title" msgid="169206259253048106">"Ukuqashwa kwenethiwekhi"</string>
@@ -415,6 +416,7 @@
     <string name="legacy_vpn_name" msgid="6604123105765737830">"I-VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wakho wenethiwekhi ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
+    <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho womuntu siqu wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yokusebenza, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomsebenzi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu."</string>
     <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Idivayisi yakho iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmqondisi wakho angaqaphela aphinde aphathe izilungiselelo, ukufinyelela kwezinkampani, izinhlelo zokusebenza, idatha ehlotshaniswa nedivayisi yakho, nolwazi lendawo yedivayisi yakho.\n\nUxhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engaqaphela umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
@@ -491,8 +493,6 @@
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
-    <string name="overview_nav_bar_gesture" msgid="8579814204727917764">"Nika amandla ukuthinta kokuswayiphela phezulu ukuhlukanisa isikrini"</string>
-    <string name="overview_nav_bar_gesture_desc" msgid="6329167382305102615">"Nika amandla ukuthinta ukuze ungene ekuhlukaniseni isikrini ngokuswayiphela phezulu kusukela kunkinobho yokubuka konke"</string>
     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index cbaf23f..ad65f82 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -108,5 +108,9 @@
         <attr name="enableAutoSizing" format="boolean" />
         <attr name="itemHeight" format="dimension" />
     </declare-styleable>
+
+    <declare-styleable name="PluginInflateContainer">
+        <attr name="viewType" format="string" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c2897cd..eb1a1eb 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -100,7 +100,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane
     </string>
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
@@ -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>
 
@@ -246,6 +240,9 @@
     -->
     <string name="doze_pickup_subtype_performs_proximity_check"></string>
 
+    <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
+    <string name="doze_double_tap_sensor_type" translatable="false"></string>
+
     <!-- Doze: pulse parameter - how long does it take to fade in? -->
     <integer name="doze_pulse_duration_in">900</integer>
 
@@ -253,7 +250,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/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 75ea585..3f485c3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -567,7 +567,7 @@
     <!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
     <string name="data_usage_disabled_dialog_title">Data is paused</string>
     <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] -->
-    <string name="data_usage_disabled_dialog">Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your carrier.</string>
+    <string name="data_usage_disabled_dialog">The data limit you set has been reached. You are no longer using cellular data.\n\nIf you resume, charges may apply for data usage.</string>
     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
     <string name="data_usage_disabled_dialog_enable">Resume</string>
 
@@ -999,6 +999,9 @@
     <!-- Footer vpn present text [CHAR LIMIT=50] -->
     <string name="vpn_footer">Network may be monitored</string>
 
+    <!-- Footer vpn present text [CHAR LIMIT=50] -->
+    <string name="branded_vpn_footer">Network may be monitored</string>
+
     <!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
     <string name="monitoring_title_device_owned">Device monitoring</string>
 
@@ -1035,6 +1038,9 @@
     <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
 
+    <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
+    <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
+
     <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
 
@@ -1241,11 +1247,6 @@
     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
 
-    <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
-    <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
-    <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
-    <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
-
     <!-- Category in the System UI Tuner settings, where new/experimental
          settings are -->
     <string name="experimental">Experimental</string>
@@ -1666,4 +1667,8 @@
     <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
     <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
 
+    <!-- Plugin control section of the tuner. Non-translatable since it should
+         not appear on production builds ever. -->
+    <string name="plugins" translatable="false">Plugins</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4edeb4c..e5bc8b9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -42,7 +42,7 @@
     </style>
 
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
-    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
         <item name="android:statusBarColor">@color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
@@ -217,7 +217,7 @@
     <style name="Animation.StatusBar">
     </style>
 
-    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
+    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark" />
 
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorAccent">@color/remote_input_accent</item>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index 3c872fa..ce636cd 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -18,11 +18,6 @@
                   xmlns:sysui="http://schemas.android.com/apk/res-auto"
                   android:title="@string/other">
 
-    <com.android.systemui.tuner.TunerSwitch
-            android:key="overview_nav_bar_gesture"
-            android:title="@string/overview_nav_bar_gesture"
-            android:summary="@string/overview_nav_bar_gesture_desc" />
-
     <!-- importance -->
     <Preference
             android:key="power_notification_controls"
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index b46e862..211f8e8 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -133,6 +133,11 @@
             android:title="@string/other"
             android:fragment="com.android.systemui.tuner.OtherPrefs" />
 
+    <Preference
+            android:key="plugins"
+            android:title="@string/plugins"
+            android:fragment="com.android.systemui.tuner.PluginFragment" />
+
     <!-- Warning, this goes last. -->
     <Preference
         android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 2aca788..810dd8c 100644
--- a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -72,9 +72,13 @@
         }
     }
 
-    private void inflateLayout() {
-        removeAllViews();
+    protected void inflateLayoutImpl() {
         LayoutInflater.from(getContext()).inflate(mLayout, this);
+    }
+
+    protected void inflateLayout() {
+        removeAllViews();
+        inflateLayoutImpl();
         final int N = mInflateListeners.size();
         for (int i = 0; i < N; i++) {
             mInflateListeners.get(i).onInflated(getChildAt(0));
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 076b5bc..e1d6a94 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -31,10 +31,9 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
-
 import com.android.systemui.statusbar.policy.BatteryController;
 
 public class BatteryMeterDrawable extends Drawable implements
@@ -92,18 +91,17 @@
     private int mLightModeBackgroundColor;
     private int mLightModeFillColor;
 
-    private final SettingObserver mSettingObserver = new SettingObserver();
+    private final SettingObserver mSettingObserver;
 
     private final Context mContext;
-    private final Handler mHandler;
 
     private int mLevel = -1;
     private boolean mPluggedIn;
     private boolean mListening;
 
-    public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
+    public BatteryMeterDrawable(Context context, int frameColor) {
         mContext = context;
-        mHandler = handler;
+        mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
         final Resources res = context.getResources();
         TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
         TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
@@ -199,12 +197,7 @@
     }
 
     private void postInvalidate() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                invalidateSelf();
-            }
-        });
+        scheduleSelf(this::invalidateSelf, 0);
     }
 
     public void setBatteryController(BatteryController batteryController) {
@@ -506,8 +499,8 @@
     }
 
     private final class SettingObserver extends ContentObserver {
-        public SettingObserver() {
-            super(new Handler());
+        public SettingObserver(Handler handler) {
+            super(handler);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index d8b95cc..4f3ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -49,7 +49,7 @@
                 defStyle, 0);
         final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
                 context.getColor(R.color.batterymeter_frame_color));
-        mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor);
+        mDrawable = new BatteryMeterDrawable(context, frameColor);
         atts.recycle();
 
         mSlotBattery = context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index 1601675..d4149ea 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -60,4 +60,9 @@
 ##       3: USER_SYSTEM_UNBOUND      Secondary user loses connection after system sysui has died
 ##       4: SYSTEM_REGISTER_USER     System sysui registers user's callbacks
 ##       5: SYSTEM_UNREGISTER_USER   System sysui unregisters user's callbacks (after death)
-36060 sysui_recents_connection (type|1),(user|1)
\ No newline at end of file
+36060 sysui_recents_connection (type|1),(user|1)
+
+# ---------------------------
+# LatencyTracker.java
+# ---------------------------
+36070 sysui_latency (action|1|5),(latency|1|3)
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTracker.java b/packages/SystemUI/src/com/android/systemui/LatencyTracker.java
new file mode 100644
index 0000000..0196815
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTracker.java
@@ -0,0 +1,125 @@
+/*
+ * 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.systemui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseLongArray;
+
+/**
+ * Class to track various latencies in SystemUI. It then outputs the latency to logcat so these
+ * latencies can be captured by tests and then used for dashboards.
+ */
+public class LatencyTracker {
+
+    private static final String ACTION_RELOAD_PROPERTY =
+            "com.android.systemui.RELOAD_LATENCY_TRACKER_PROPERTY";
+
+    private static final String TAG = "LatencyTracker";
+
+    /**
+     * Time it takes until the first frame of the notification panel to be displayed while expanding
+     */
+    public static final int ACTION_EXPAND_PANEL = 0;
+
+    /**
+     * Time it takes until the first frame of recents is drawn after invoking it with the button.
+     */
+    public static final int ACTION_TOGGLE_RECENTS = 1;
+
+    /**
+     * Time between we get a fingerprint acquired signal until we start with the unlock animation
+     */
+    public static final int ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 2;
+
+    private static final String[] NAMES = new String[] {
+            "expand panel",
+            "toggle recents",
+            "fingerprint wake-and-unlock" };
+
+    private static LatencyTracker sLatencyTracker;
+
+    private final SparseLongArray mStartRtc = new SparseLongArray();
+    private boolean mEnabled;
+
+    public static LatencyTracker getInstance(Context context) {
+        if (sLatencyTracker == null) {
+            sLatencyTracker = new LatencyTracker(context);
+        }
+        return sLatencyTracker;
+    }
+
+    private LatencyTracker(Context context) {
+        context.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                reloadProperty();
+            }
+        }, new IntentFilter(ACTION_RELOAD_PROPERTY));
+        reloadProperty();
+    }
+
+    private void reloadProperty() {
+        mEnabled = SystemProperties.getBoolean("debug.systemui.latency_tracking", false);
+    }
+
+    public static boolean isEnabled(Context ctx) {
+        return Build.IS_DEBUGGABLE && getInstance(ctx).mEnabled;
+    }
+
+    /**
+     * Notifies that an action is starting. This needs to be called from the main thread.
+     *
+     * @param action The action to start. One of the ACTION_* values.
+     */
+    public void onActionStart(int action) {
+        if (!mEnabled) {
+            return;
+        }
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, NAMES[action], 0);
+        mStartRtc.put(action, SystemClock.elapsedRealtime());
+    }
+
+    /**
+     * Notifies that an action has ended. This needs to be called from the main thread.
+     *
+     * @param action The action to end. One of the ACTION_* values.
+     */
+    public void onActionEnd(int action) {
+        if (!mEnabled) {
+            return;
+        }
+        long endRtc = SystemClock.elapsedRealtime();
+        long startRtc = mStartRtc.get(action, -1);
+        if (startRtc == -1) {
+            return;
+        }
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
+        long duration = endRtc - startRtc;
+        Log.i(TAG, "action=" + action + " latency=" + duration);
+        EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, (int) duration);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
new file mode 100644
index 0000000..efa7cae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -0,0 +1,111 @@
+/*
+ * 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.systemui;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.ViewProvider;
+
+/**
+ * Define an interface or abstract class as follows that includes the
+ * version and action.
+ *
+ * public interface MyInterface {
+ *     public static final String ACTION =
+ *             "com.android.systemui.action.PLUGIN_MYINTERFACE";
+ *
+ *     public static final int VERSION = 1;
+ *
+ *     void myImportantInterface();
+ * }
+ *
+ * Then put in a PluginInflateContainer to use and specify the interface
+ * or class that will be implemented as viewType.  The layout specified
+ * will be used by default and whenever a plugin is not present.
+ *
+ * <com.android.systemui.PluginInflateContainer
+ *     android:id="@+id/some_id"
+ *     android:layout_width="match_parent"
+ *     android:layout_height="match_parent"
+ *     android:layout="@layout/my_default_component"
+ *     systemui:viewType="com.android.systemui.plugins.MyInterface" />
+ */
+public class PluginInflateContainer extends AutoReinflateContainer
+        implements PluginListener<ViewProvider> {
+
+    private static final String TAG = "PluginInflateContainer";
+
+    private String mAction;
+    private int mVersion;
+    private View mPluginView;
+
+    public PluginInflateContainer(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PluginInflateContainer);
+        String viewType = a.getString(R.styleable.PluginInflateContainer_viewType);
+        try {
+            Class c = Class.forName(viewType);
+            mAction = (String) c.getDeclaredField("ACTION").get(null);
+            mVersion = (int) c.getDeclaredField("VERSION").get(null);
+        } catch (Exception e) {
+            Log.d(TAG, "Problem getting class info " + viewType, e);
+            mAction = null;
+            mVersion = 0;
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mAction != null) {
+            PluginManager.getInstance(getContext()).addPluginListener(mAction, this, mVersion);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mAction != null) {
+            PluginManager.getInstance(getContext()).removePluginListener(this);
+        }
+    }
+
+    @Override
+    protected void inflateLayoutImpl() {
+        if (mPluginView != null) {
+            addView(mPluginView);
+        } else {
+            super.inflateLayoutImpl();
+        }
+    }
+
+    @Override
+    public void onPluginConnected(ViewProvider plugin) {
+        mPluginView = plugin.getView();
+        inflateLayout();
+    }
+
+    @Override
+    public void onPluginDisconnected(ViewProvider plugin) {
+        mPluginView = null;
+        inflateLayout();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 52b5a54..e300aff 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,18 +16,24 @@
 
 package com.android.systemui;
 
+import android.app.ActivityThread;
 import android.app.Application;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -106,6 +112,13 @@
                 }
             }, filter);
         } else {
+            // We don't need to startServices for sub-process that is doing some tasks.
+            // (screenshots, sweetsweetdesserts or tuner ..)
+            String processName = ActivityThread.currentProcessName();
+            ApplicationInfo info = getApplicationInfo();
+            if (processName != null && processName.startsWith(info.processName + ":")) {
+                return;
+            }
             // For a secondary user, boot-completed will never be called because it has already
             // been broadcasted on startup for the primary SystemUI process.  Instead, for
             // components which require the SystemUI component to be initialized per-user, we
@@ -174,6 +187,18 @@
                 mServices[i].onBootCompleted();
             }
         }
+        PluginManager.getInstance(this).addPluginListener(OverlayPlugin.ACTION,
+                new PluginListener<OverlayPlugin>() {
+            @Override
+            public void onPluginConnected(OverlayPlugin plugin) {
+                PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
+                if (phoneStatusBar != null) {
+                    plugin.setup(phoneStatusBar.getStatusBarWindow(),
+                            phoneStatusBar.getNavigationBarView());
+                }
+            }
+        }, OverlayPlugin.VERSION, true /* Allow multiple plugins */);
+
         mServicesStarted = true;
     }
 
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..b3038b9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -33,14 +33,15 @@
     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;
+    private static final int PULSE_REASONS = 5;
 
     public static final int PULSE_REASON_INTENT = 0;
     public static final int PULSE_REASON_NOTIFICATION = 1;
     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
+    public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
 
     private static long[] sTimes;
     private static String[] sMessages;
@@ -167,6 +168,7 @@
             case PULSE_REASON_NOTIFICATION: return "notification";
             case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
+            case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index fc0d8bb..261d241 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,14 +16,14 @@
 
 package com.android.systemui.doze;
 
-import android.app.AlarmManager;
-import android.app.PendingIntent;
+import android.app.ActivityManager;
 import android.app.UiModeManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -31,11 +31,15 @@
 import android.hardware.TriggerEvent;
 import android.hardware.TriggerEventListener;
 import android.media.AudioAttributes;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.service.dreams.DreamService;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
 
@@ -43,11 +47,11 @@
 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;
 import java.util.Date;
+import java.util.List;
 
 public class DozeService extends DreamService {
     private static final String TAG = "DozeService";
@@ -55,19 +59,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;
@@ -75,24 +66,19 @@
     private final Handler mHandler = new Handler();
 
     private DozeHost mHost;
-    private SensorManager mSensors;
-    private TriggerSensor mSigMotionSensor;
+    private SensorManager mSensorManager;
+    private TriggerSensor[] mSensors;
     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()");
@@ -107,14 +93,16 @@
         pw.print("  mWakeLock: held="); pw.println(mWakeLock.isHeld());
         pw.print("  mHost: "); pw.println(mHost);
         pw.print("  mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
-        pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
-        pw.print("  mPickupSensor:"); pw.println(mPickupSensor);
+        for (TriggerSensor s : mSensors) {
+            pw.print("  sensor: ");
+            pw.println(s);
+        }
         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);
     }
 
@@ -131,17 +119,28 @@
 
         setWindowless(true);
 
-        mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
-        mSigMotionSensor = new TriggerSensor(Sensor.TYPE_SIGNIFICANT_MOTION,
-                mDozeParameters.getPulseOnSigMotion(), mDozeParameters.getVibrateOnSigMotion(),
-                DozeLog.PULSE_REASON_SENSOR_SIGMOTION);
-        mPickupSensor = new TriggerSensor(Sensor.TYPE_PICK_UP_GESTURE,
-                mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
-                DozeLog.PULSE_REASON_SENSOR_PICKUP);
+        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+        mSensors = new TriggerSensor[] {
+                new TriggerSensor(
+                        mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
+                        null /* setting */,
+                        mDozeParameters.getPulseOnSigMotion(),
+                        mDozeParameters.getVibrateOnSigMotion(),
+                        DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
+                mPickupSensor = new TriggerSensor(
+                        mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
+                        Settings.Secure.DOZE_PULSE_ON_PICK_UP,
+                        mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
+                        DozeLog.PULSE_REASON_SENSOR_PICKUP),
+                new TriggerSensor(
+                        findSensorWithType(mDozeParameters.getDoubleTapSensorType()),
+                        Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
+                        mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
+                        DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
+        };
         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,25 +175,20 @@
         }
 
         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.
         // Once ready, we call startDozing() at which point the CPU may suspend
         // and we will need to acquire a wakelock to do work.
-        mHost.startDozing(new Runnable() {
-            @Override
-            public void run() {
-                if (mDreaming) {
-                    startDozing();
+        mHost.startDozing(mWakeLock.wrap(() -> {
+            if (mDreaming) {
+                startDozing();
 
-                    // From this point until onDreamingStopped we will need to hold a
-                    // wakelock whenever we are doing work.  Note that we never call
-                    // stopDozing because can we just keep dozing until the bitter end.
-                }
+                // From this point until onDreamingStopped we will need to hold a
+                // wakelock whenever we are doing work.  Note that we never call
+                // stopDozing because can we just keep dozing until the bitter end.
             }
-        });
+        }));
     }
 
     @Override
@@ -307,8 +301,9 @@
 
     private void listenForPulseSignals(boolean listen) {
         if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
-        mSigMotionSensor.setListening(listen);
-        mPickupSensor.setListening(listen);
+        for (TriggerSensor s : mSensors) {
+            s.setListening(listen);
+        }
         listenForBroadcasts(listen);
         listenForNotifications(listen);
     }
@@ -316,13 +311,22 @@
     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);
+            filter.addAction(Intent.ACTION_USER_SWITCHED);
             mContext.registerReceiver(mBroadcastReceiver, filter);
+
+            for (TriggerSensor s : mSensors) {
+                if (s.mConfigured && !TextUtils.isEmpty(s.mSetting)) {
+                    mContext.getContentResolver().registerContentObserver(
+                            Settings.Secure.getUriFor(s.mSetting), false /* descendants */,
+                            mSettingsObserver, UserHandle.USER_ALL);
+                }
+            }
             mBroadcastReceiverRegistered = true;
         } else {
             if (mBroadcastReceiverRegistered) {
                 mContext.unregisterReceiver(mBroadcastReceiver);
+                mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
             }
             mBroadcastReceiverRegistered = false;
         }
@@ -330,93 +334,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,19 +367,29 @@
                 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) {
                     finishForCarMode();
                 }
             }
+            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+                for (TriggerSensor s : mSensors) {
+                    s.updateListener();
+                }
+            }
+        }
+    };
+
+    private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            if (userId != ActivityManager.getCurrentUser()) {
+                return;
+            }
+            for (TriggerSensor s : mSensors) {
+                s.updateListener();
+            }
         }
     };
 
@@ -465,17 +403,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
@@ -487,18 +421,34 @@
         }
     };
 
+    private Sensor findSensorWithType(String type) {
+        if (TextUtils.isEmpty(type)) {
+            return null;
+        }
+        List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+        for (Sensor s : sensorList) {
+            if (type.equals(s.getStringType())) {
+                return s;
+            }
+        }
+        return null;
+    }
+
     private class TriggerSensor extends TriggerEventListener {
-        private final Sensor mSensor;
-        private final boolean mConfigured;
-        private final boolean mDebugVibrate;
-        private final int mPulseReason;
+        final Sensor mSensor;
+        final boolean mConfigured;
+        final boolean mDebugVibrate;
+        final int mPulseReason;
+        final String mSetting;
 
         private boolean mRequested;
         private boolean mRegistered;
         private boolean mDisabled;
 
-        public TriggerSensor(int type, boolean configured, boolean debugVibrate, int pulseReason) {
-            mSensor = mSensors.getDefaultSensor(type);
+        public TriggerSensor(Sensor sensor, String setting, boolean configured,
+                boolean debugVibrate, int pulseReason) {
+            mSensor = sensor;
+            mSetting = setting;
             mConfigured = configured;
             mDebugVibrate = debugVibrate;
             mPulseReason = pulseReason;
@@ -516,18 +466,26 @@
             updateListener();
         }
 
-        private void updateListener() {
+        public void updateListener() {
             if (!mConfigured || mSensor == null) return;
-            if (mRequested && !mDisabled && !mRegistered) {
-                mRegistered = mSensors.requestTriggerSensor(this, mSensor);
+            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
+                mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
                 if (DEBUG) Log.d(mTag, "requestTriggerSensor " + mRegistered);
             } else if (mRegistered) {
-                final boolean rt = mSensors.cancelTriggerSensor(this, mSensor);
+                final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
                 if (DEBUG) Log.d(mTag, "cancelTriggerSensor " + rt);
                 mRegistered = false;
             }
         }
 
+        private boolean enabledBySetting() {
+            if (TextUtils.isEmpty(mSetting)) {
+                return true;
+            }
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSetting, 1,
+                    UserHandle.USER_CURRENT) != 0;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("{mRegistered=").append(mRegistered)
@@ -564,17 +522,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);
                 }
@@ -601,7 +554,7 @@
 
         public void check() {
             if (mFinished || mRegistered) return;
-            final Sensor sensor = mSensors.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
             if (sensor == null) {
                 if (DEBUG) Log.d(mTag, "No sensor found");
                 finishWithResult(RESULT_UNKNOWN);
@@ -611,7 +564,8 @@
             mPickupSensor.setDisabled(true);
 
             mMaxRange = sensor.getMaximumRange();
-            mSensors.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, mHandler);
+            mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
+                    mHandler);
             mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
             mRegistered = true;
         }
@@ -638,7 +592,7 @@
             if (mFinished) return;
             if (mRegistered) {
                 mHandler.removeCallbacks(this);
-                mSensors.unregisterListener(this);
+                mSensorManager.unregisterListener(this);
                 // we're done - reenable the pickup sensor
                 mPickupSensor.setDisabled(false);
                 mRegistered = false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 7ec6a03..e05e507 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -90,10 +90,10 @@
         }
 
         @Override // Binder interface
-        public void setOccluded(boolean isOccluded) {
+        public void setOccluded(boolean isOccluded, boolean animate) {
             Trace.beginSection("KeyguardService.mBinder#setOccluded");
             checkPermission();
-            mKeyguardViewMediator.setOccluded(isOccluded);
+            mKeyguardViewMediator.setOccluded(isOccluded, animate);
             Trace.endSection();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c4ef80f..b9e8acb 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() {
@@ -973,6 +976,7 @@
      * if there is a secure lock pattern.
      */
     public void onDreamingStarted() {
+        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStarted();
         synchronized (this) {
             if (mDeviceInteractive
                     && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
@@ -985,6 +989,7 @@
      * A dream stopped.
      */
     public void onDreamingStopped() {
+        KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStopped();
         synchronized (this) {
             if (mDeviceInteractive) {
                 cancelDoKeyguardLaterLocked();
@@ -1123,11 +1128,11 @@
     /**
      * Notify us when the keyguard is occluded by another window
      */
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#setOccluded");
         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
         mHandler.removeMessages(SET_OCCLUDED);
-        Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
+        Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
         mHandler.sendMessage(msg);
         Trace.endSection();
     }
@@ -1135,7 +1140,7 @@
     /**
      * Handles SET_OCCLUDED message sent by setOccluded()
      */
-    private void handleSetOccluded(boolean isOccluded) {
+    private void handleSetOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
         synchronized (KeyguardViewMediator.this) {
             if (mHiding && isOccluded) {
@@ -1146,7 +1151,7 @@
 
             if (mOccluded != isOccluded) {
                 mOccluded = isOccluded;
-                mStatusBarKeyguardViewManager.setOccluded(isOccluded);
+                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
                 updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
@@ -1486,7 +1491,7 @@
                     break;
                 case SET_OCCLUDED:
                     Trace.beginSection("KeyguardViewMediator#handleMessage SET_OCCLUDED");
-                    handleSetOccluded(msg.arg1 != 0);
+                    handleSetOccluded(msg.arg1 != 0, msg.arg2 != 0);
                     Trace.endSection();
                     break;
                 case KEYGUARD_TIMEOUT:
@@ -2035,6 +2040,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 +2064,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/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index b831235..8a500c3 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -73,7 +74,7 @@
     private final Context mContext;
     private final NotificationManager mNoMan;
     private final PowerManager mPowerMan;
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final Receiver mReceiver = new Receiver();
     private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
 
@@ -89,9 +90,10 @@
     private boolean mInvalidCharger;
     private SystemUIDialog mSaverConfirmation;
 
-    public PowerNotificationWarnings(Context context, PhoneStatusBar phoneStatusBar) {
+    public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
+            PhoneStatusBar phoneStatusBar) {
         mContext = context;
-        mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mNoMan = notificationManager;
         mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mReceiver.init();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 109a456..b651f2d9 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.power;
 
+import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,10 +31,8 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
-
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -60,7 +59,10 @@
     public void start() {
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
-        mWarnings = new PowerNotificationWarnings(mContext, getComponent(PhoneStatusBar.class));
+        mWarnings = new PowerNotificationWarnings(
+                mContext,
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE),
+                getComponent(PhoneStatusBar.class));
 
         ContentObserver obs = new ContentObserver(mHandler) {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index afedbe3..1c242e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -88,9 +88,9 @@
         if (mListening == listening) return;
         mListening = listening;
         if (mListening) {
-            mPages.get(mPosition).setListening(listening);
+            setPageListening(mPosition, true);
             if (mOffPage) {
-                mPages.get(mPosition + 1).setListening(listening);
+                setPageListening(mPosition + 1, true);
             }
         } else {
             // Make sure no pages are listening.
@@ -131,6 +131,9 @@
 
     private void setPageListening(int position, boolean listening) {
         if (position >= mPages.size()) return;
+        if (isLayoutRtl()) {
+            position = mPages.size() - 1 - position;
+        }
         mPages.get(position).setListening(listening);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 6104181..e1cd143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,13 +14,13 @@
 
 package com.android.systemui.qs;
 
-import android.graphics.Path;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnLayoutChangeListener;
 import android.widget.TextView;
 
+import com.android.systemui.plugins.qs.QSContainer;
 import com.android.systemui.qs.PagedTileLayout.PageListener;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSTile.Host.Callback;
@@ -160,6 +160,10 @@
 
         for (QSTile<?> tile : tiles) {
             QSTileBaseView tileView = mQsPanel.getTileView(tile);
+            if (tileView == null) {
+                Log.e(TAG, "tileView is null " + tile.getTileSpec());
+                continue;
+            }
             final TextView label = ((QSTileView) tileView).getLabel();
             final View tileIcon = tileView.getIcon().getIconView();
             if (count < mNumQuickTiles && mAllowFancy) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
deleted file mode 100644
index 19a5d52..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.qs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
-
-/**
- * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
- *
- * Also manages animations for the QS Header and Panel.
- */
-public class QSContainer extends FrameLayout {
-    private static final String TAG = "QSContainer";
-    private static final boolean DEBUG = false;
-
-    private final Point mSizePoint = new Point();
-    private final Rect mQsBounds = new Rect();
-
-    private int mHeightOverride = -1;
-    protected QSPanel mQSPanel;
-    private QSDetail mQSDetail;
-    protected BaseStatusBarHeader mHeader;
-    protected float mQsExpansion;
-    private boolean mQsExpanded;
-    private boolean mHeaderAnimating;
-    private boolean mKeyguardShowing;
-    private boolean mStackScrollerOverscrolling;
-
-    private long mDelay;
-    private QSAnimator mQSAnimator;
-    private QSCustomizer mQSCustomizer;
-    private NotificationPanelView mPanelView;
-    private boolean mListening;
-
-    public QSContainer(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
-        mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
-        mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
-        mQSDetail.setQsPanel(mQSPanel, mHeader);
-        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
-                mQSPanel);
-        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
-        mQSCustomizer.setQsContainer(this);
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-        mQSAnimator.onRtlChanged();
-    }
-
-    public void setHost(QSTileHost qsh) {
-        mQSPanel.setHost(qsh, mQSCustomizer);
-        mHeader.setQSPanel(mQSPanel);
-        mQSDetail.setHost(qsh);
-        mQSAnimator.setHost(qsh);
-    }
-
-    public void setPanelView(NotificationPanelView panelView) {
-        mPanelView = panelView;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Since we control our own bottom, be whatever size we want.
-        // Otherwise the QSPanel ends up with 0 height when the window is only the
-        // size of the status bar.
-        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
-                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
-        int width = mQSPanel.getMeasuredWidth();
-        int height = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
-                + mQSPanel.getMeasuredHeight();
-        super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-
-        // QSCustomizer is always be the height of the screen, but do this after
-        // other measuring to avoid changing the height of the QSContainer.
-        getDisplay().getRealSize(mSizePoint);
-        mQSCustomizer.measure(widthMeasureSpec,
-                MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        updateBottom();
-    }
-
-    public boolean isCustomizing() {
-        return mQSCustomizer.isCustomizing();
-    }
-
-    /**
-     * Overrides the height of this view (post-layout), so that the content is clipped to that
-     * height and the background is set to that height.
-     *
-     * @param heightOverride the overridden height
-     */
-    public void setHeightOverride(int heightOverride) {
-        mHeightOverride = heightOverride;
-        updateBottom();
-    }
-
-    /**
-     * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
-     * during closing the detail panel, this already returns the smaller height.
-     */
-    public int getDesiredHeight() {
-        if (isCustomizing()) {
-            return getHeight();
-        }
-        if (mQSDetail.isClosingDetail()) {
-            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
-                    + mQSPanel.getMeasuredHeight();
-            return panelHeight + getPaddingBottom();
-        } else {
-            return getMeasuredHeight();
-        }
-    }
-
-    public void notifyCustomizeChanged() {
-        // The customize state changed, so our height changed.
-        updateBottom();
-        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
-        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
-        // Let the panel know the position changed and it needs to update where notifications
-        // and whatnot are.
-        mPanelView.onQsHeightChanged();
-    }
-
-    private void updateBottom() {
-        int height = calculateContainerHeight();
-        setBottom(getTop() + height);
-        mQSDetail.setBottom(getTop() + height);
-    }
-
-    protected int calculateContainerHeight() {
-        int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
-        return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
-                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
-                + mHeader.getCollapsedHeight();
-    }
-
-    private void updateQsState() {
-        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
-        mQSPanel.setExpanded(mQsExpanded);
-        mQSDetail.setExpanded(mQsExpanded);
-        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
-                ? View.VISIBLE
-                : View.INVISIBLE);
-        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
-                || (mQsExpanded && !mStackScrollerOverscrolling));
-        mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    public BaseStatusBarHeader getHeader() {
-        return mHeader;
-    }
-
-    public QSPanel getQsPanel() {
-        return mQSPanel;
-    }
-
-    public QSCustomizer getCustomizer() {
-        return mQSCustomizer;
-    }
-
-    public boolean isShowingDetail() {
-        return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
-    }
-
-    public void setHeaderClickable(boolean clickable) {
-        if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
-        mHeader.setClickable(clickable);
-    }
-
-    public void setExpanded(boolean expanded) {
-        if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
-        mQsExpanded = expanded;
-        mQSPanel.setListening(mListening && mQsExpanded);
-        updateQsState();
-    }
-
-    public void setKeyguardShowing(boolean keyguardShowing) {
-        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
-        mKeyguardShowing = keyguardShowing;
-        mQSAnimator.setOnKeyguard(keyguardShowing);
-        updateQsState();
-    }
-
-    public void setOverscrolling(boolean stackScrollerOverscrolling) {
-        if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
-        mStackScrollerOverscrolling = stackScrollerOverscrolling;
-        updateQsState();
-    }
-
-    public void setListening(boolean listening) {
-        if (DEBUG) Log.d(TAG, "setListening " + listening);
-        mListening = listening;
-        mHeader.setListening(listening);
-        mQSPanel.setListening(mListening && mQsExpanded);
-    }
-
-    public void setHeaderListening(boolean listening) {
-        mHeader.setListening(listening);
-    }
-
-    public void setQsExpansion(float expansion, float headerTranslation) {
-        if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
-        mQsExpansion = expansion;
-        final float translationScaleY = expansion - 1;
-        if (!mHeaderAnimating) {
-            setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
-                    : headerTranslation);
-        }
-        mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
-        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
-        mQSDetail.setFullyExpanded(expansion == 1);
-        mQSAnimator.setPosition(expansion);
-        updateBottom();
-
-        // Set bounds on the QS panel so it doesn't run over the header.
-        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
-        mQsBounds.right = mQSPanel.getWidth();
-        mQsBounds.bottom = mQSPanel.getHeight();
-        mQSPanel.setClipBounds(mQsBounds);
-    }
-
-    public void animateHeaderSlidingIn(long delay) {
-        if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
-        // If the QS is already expanded we don't need to slide in the header as it's already
-        // visible.
-        if (!mQsExpanded) {
-            mHeaderAnimating = true;
-            mDelay = delay;
-            getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
-        }
-    }
-
-    public void animateHeaderSlidingOut() {
-        if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
-        mHeaderAnimating = true;
-        animate().y(-mHeader.getHeight())
-                .setStartDelay(0)
-                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        animate().setListener(null);
-                        mHeaderAnimating = false;
-                        updateQsState();
-                    }
-                })
-                .start();
-    }
-
-    private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
-            = new ViewTreeObserver.OnPreDrawListener() {
-        @Override
-        public boolean onPreDraw() {
-            getViewTreeObserver().removeOnPreDrawListener(this);
-            animate()
-                    .translationY(0f)
-                    .setStartDelay(mDelay)
-                    .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .setListener(mAnimateHeaderSlidingInListener)
-                    .start();
-            setY(-mHeader.getHeight());
-            return true;
-        }
-    };
-
-    private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
-            = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mHeaderAnimating = false;
-            updateQsState();
-        }
-    };
-
-    public int getQsMinExpansionHeight() {
-        return mHeader.getHeight();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
new file mode 100644
index 0000000..2173922
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+/**
+ * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
+ *
+ * Also manages animations for the QS Header and Panel.
+ */
+public class QSContainerImpl extends QSContainer {
+    private static final String TAG = "QSContainer";
+    private static final boolean DEBUG = false;
+
+    private final Point mSizePoint = new Point();
+    private final Rect mQsBounds = new Rect();
+
+    private int mHeightOverride = -1;
+    protected QSPanel mQSPanel;
+    private QSDetail mQSDetail;
+    protected QuickStatusBarHeader mHeader;
+    protected float mQsExpansion;
+    private boolean mQsExpanded;
+    private boolean mHeaderAnimating;
+    private boolean mKeyguardShowing;
+    private boolean mStackScrollerOverscrolling;
+
+    private long mDelay;
+    private QSAnimator mQSAnimator;
+    private QSCustomizer mQSCustomizer;
+    private HeightListener mPanelView;
+    private boolean mListening;
+
+    public QSContainerImpl(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+        mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
+        mHeader = (QuickStatusBarHeader) findViewById(R.id.header);
+        mQSDetail.setQsPanel(mQSPanel, mHeader);
+        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+                mQSPanel);
+        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
+        mQSCustomizer.setQsContainer(this);
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        mQSAnimator.onRtlChanged();
+    }
+
+    public void setHost(QSTileHost qsh) {
+        mQSPanel.setHost(qsh, mQSCustomizer);
+        mHeader.setQSPanel(mQSPanel);
+        mQSDetail.setHost(qsh);
+        mQSAnimator.setHost(qsh);
+    }
+
+    public void setPanelView(HeightListener panelView) {
+        mPanelView = panelView;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Since we control our own bottom, be whatever size we want.
+        // Otherwise the QSPanel ends up with 0 height when the window is only the
+        // size of the status bar.
+        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
+                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
+        int width = mQSPanel.getMeasuredWidth();
+        int height = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+                + mQSPanel.getMeasuredHeight();
+        super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
+        // QSCustomizer is always be the height of the screen, but do this after
+        // other measuring to avoid changing the height of the QSContainer.
+        getDisplay().getRealSize(mSizePoint);
+        mQSCustomizer.measure(widthMeasureSpec,
+                MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        updateBottom();
+    }
+
+    public boolean isCustomizing() {
+        return mQSCustomizer.isCustomizing();
+    }
+
+    /**
+     * Overrides the height of this view (post-layout), so that the content is clipped to that
+     * height and the background is set to that height.
+     *
+     * @param heightOverride the overridden height
+     */
+    public void setHeightOverride(int heightOverride) {
+        mHeightOverride = heightOverride;
+        updateBottom();
+    }
+
+    @Override
+    public void setContainer(ViewGroup container) {
+        if (container instanceof NotificationsQuickSettingsContainer) {
+            mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
+        }
+    }
+
+    /**
+     * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
+     * during closing the detail panel, this already returns the smaller height.
+     */
+    public int getDesiredHeight() {
+        if (isCustomizing()) {
+            return getHeight();
+        }
+        if (mQSDetail.isClosingDetail()) {
+            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
+                    + mQSPanel.getMeasuredHeight();
+            return panelHeight + getPaddingBottom();
+        } else {
+            return getMeasuredHeight();
+        }
+    }
+
+    public void notifyCustomizeChanged() {
+        // The customize state changed, so our height changed.
+        updateBottom();
+        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        // Let the panel know the position changed and it needs to update where notifications
+        // and whatnot are.
+        mPanelView.onQsHeightChanged();
+    }
+
+    private void updateBottom() {
+        int height = calculateContainerHeight();
+        setBottom(getTop() + height);
+        mQSDetail.setBottom(getTop() + height);
+    }
+
+    protected int calculateContainerHeight() {
+        int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+        return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
+                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+                + mHeader.getCollapsedHeight();
+    }
+
+    private void updateQsState() {
+        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+        mQSPanel.setExpanded(mQsExpanded);
+        mQSDetail.setExpanded(mQsExpanded);
+        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                ? View.VISIBLE
+                : View.INVISIBLE);
+        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+                || (mQsExpanded && !mStackScrollerOverscrolling));
+        mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    public BaseStatusBarHeader getHeader() {
+        return mHeader;
+    }
+
+    public QSPanel getQsPanel() {
+        return mQSPanel;
+    }
+
+    public QSCustomizer getCustomizer() {
+        return mQSCustomizer;
+    }
+
+    public boolean isShowingDetail() {
+        return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
+    }
+
+    public void setHeaderClickable(boolean clickable) {
+        if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+        mHeader.setClickable(clickable);
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+        mQsExpanded = expanded;
+        mQSPanel.setListening(mListening && mQsExpanded);
+        updateQsState();
+    }
+
+    public void setKeyguardShowing(boolean keyguardShowing) {
+        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+        mKeyguardShowing = keyguardShowing;
+        mQSAnimator.setOnKeyguard(keyguardShowing);
+        updateQsState();
+    }
+
+    public void setOverscrolling(boolean stackScrollerOverscrolling) {
+        if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+        mStackScrollerOverscrolling = stackScrollerOverscrolling;
+        updateQsState();
+    }
+
+    public void setListening(boolean listening) {
+        if (DEBUG) Log.d(TAG, "setListening " + listening);
+        mListening = listening;
+        mHeader.setListening(listening);
+        mQSPanel.setListening(mListening && mQsExpanded);
+    }
+
+    public void setHeaderListening(boolean listening) {
+        mHeader.setListening(listening);
+    }
+
+    public void setQsExpansion(float expansion, float headerTranslation) {
+        if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+        mQsExpansion = expansion;
+        final float translationScaleY = expansion - 1;
+        if (!mHeaderAnimating) {
+            setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+                    : headerTranslation);
+        }
+        mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+        mQSDetail.setFullyExpanded(expansion == 1);
+        mQSAnimator.setPosition(expansion);
+        updateBottom();
+
+        // Set bounds on the QS panel so it doesn't run over the header.
+        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
+        mQsBounds.right = mQSPanel.getWidth();
+        mQsBounds.bottom = mQSPanel.getHeight();
+        mQSPanel.setClipBounds(mQsBounds);
+    }
+
+    public void animateHeaderSlidingIn(long delay) {
+        if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+        // If the QS is already expanded we don't need to slide in the header as it's already
+        // visible.
+        if (!mQsExpanded) {
+            mHeaderAnimating = true;
+            mDelay = delay;
+            getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+        }
+    }
+
+    public void animateHeaderSlidingOut() {
+        if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+        mHeaderAnimating = true;
+        animate().y(-mHeader.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        animate().setListener(null);
+                        mHeaderAnimating = false;
+                        updateQsState();
+                    }
+                })
+                .start();
+    }
+
+    @Override
+    public void closeDetail() {
+        mQSPanel.closeDetail();
+    }
+
+    private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+            = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            animate()
+                    .translationY(0f)
+                    .setStartDelay(mDelay)
+                    .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                    .setListener(mAnimateHeaderSlidingInListener)
+                    .start();
+            setY(-mHeader.getHeight());
+            return true;
+        }
+    };
+
+    private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+            = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mHeaderAnimating = false;
+            updateQsState();
+        }
+    };
+
+    public int getQsMinExpansionHeight() {
+        return mHeader.getHeight();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 90b2e90..2b9320b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -35,8 +35,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSTile.DetailAdapter;
-import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QSContainer.Callback;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class QSDetail extends LinearLayout {
@@ -151,7 +152,7 @@
 
 
 
-    public void handleShowingDetail(final QSTile.DetailAdapter adapter, int x, int y,
+    public void handleShowingDetail(final DetailAdapter adapter, int x, int y,
             boolean toggleQs) {
         final boolean showingDetail = adapter != null;
         setClickable(showingDetail);
@@ -287,7 +288,7 @@
                             mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
     }
 
-    protected QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
+    protected Callback mQsPanelCallback = new Callback() {
         @Override
         public void onToggleStateChanged(final boolean state) {
             post(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 15ae4ad..4ac629d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -120,11 +120,10 @@
             mFooterTextId = R.string.device_owned_footer;
             mIsVisible = true;
         } else {
-            mFooterTextId = R.string.vpn_footer;
+            boolean isBranded = mSecurityController.isVpnBranded();
+            mFooterTextId = isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer;
             // Update the VPN footer icon, if needed.
-            int footerIconId = (mSecurityController.isVpnBranded()
-                ? R.drawable.ic_qs_branded_vpn
-                : R.drawable.ic_qs_vpn);
+            int footerIconId = isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn;
             if (mFooterIconId != footerIconId) {
                 mFooterIconId = footerIconId;
                 mMainHandler.post(mUpdateIcon);
@@ -148,11 +147,15 @@
         String primaryVpn = mSecurityController.getPrimaryVpnName();
         String profileVpn = mSecurityController.getProfileVpnName();
         boolean managed = mSecurityController.hasProfileOwner();
+        boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded();
 
         mDialog = new SystemUIDialog(mContext);
-        mDialog.setTitle(getTitle(deviceOwner));
-        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed));
-        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
+        if (!isBranded) {
+            mDialog.setTitle(getTitle(deviceOwner));
+        }
+        mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed,
+                isBranded));
+        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
         if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
         }
@@ -163,12 +166,12 @@
         return mContext.getString(R.string.status_bar_settings_settings_button);
     }
 
-    private String getPositiveButton() {
-        return mContext.getString(R.string.quick_settings_done);
+    private String getPositiveButton(boolean isBranded) {
+        return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
     }
 
     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
-            String profileVpn, boolean primaryUserIsManaged) {
+            String profileVpn, boolean primaryUserIsManaged, boolean isBranded) {
         // Show a special warning when the device has device owner, but --
         // TODO See b/25779452 -- device owner doesn't actually have monitoring power.
         if (deviceOwner != null) {
@@ -184,8 +187,12 @@
                 return mContext.getString(R.string.monitoring_description_app_personal_work,
                         profileOwner, profileVpn, primaryVpn);
             } else {
-                return mContext.getString(R.string.monitoring_description_app_personal,
-                        primaryVpn);
+                if (isBranded) {
+                    return mContext.getString(R.string.branded_monitoring_description_app_personal);
+                } else {
+                    return mContext.getString(R.string.monitoring_description_app_personal,
+                            primaryVpn);
+                }
             }
         } else if (profileVpn != null) {
             return mContext.getString(R.string.monitoring_description_app_work,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ed0fc1f..e1db8c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -30,7 +30,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSTile.DetailAdapter;
+import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.qs.external.CustomTile;
@@ -59,7 +60,7 @@
     protected boolean mExpanded;
     protected boolean mListening;
 
-    private Callback mCallback;
+    private QSContainer.Callback mCallback;
     private BrightnessController mBrightnessController;
     protected QSTileHost mHost;
 
@@ -170,7 +171,7 @@
         return mBrightnessView;
     }
 
-    public void setCallback(Callback callback) {
+    public void setCallback(QSContainer.Callback callback) {
         mCallback = callback;
     }
 
@@ -542,12 +543,6 @@
         public QSTile.Callback callback;
     }
 
-    public interface Callback {
-        void onShowingDetail(DetailAdapter detail, int x, int y);
-        void onToggleStateChanged(boolean state);
-        void onScanStateChanged(boolean state);
-    }
-
     public interface QSTileLayout {
         void addTile(TileRecord tile);
         void removeTile(TileRecord tile);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 6657b62..39ce324 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -27,12 +27,11 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -42,7 +41,6 @@
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.Listenable;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -147,29 +145,6 @@
         return true;
     }
 
-    public interface DetailAdapter {
-        CharSequence getTitle();
-        Boolean getToggleState();
-        default boolean getToggleEnabled() {
-            return true;
-        }
-        View createDetailView(Context context, View convertView, ViewGroup parent);
-        Intent getSettingsIntent();
-        void setToggleState(boolean state);
-        int getMetricsCategory();
-
-        /**
-         * @return the height in px the content of the detail view should take.
-         */
-        default int getDetailViewHeight() { throw new UnsupportedOperationException(); };
-
-        /**
-         * Indicates whether the detail view wants to have its header (back button, title and
-         * toggle) shown.
-         */
-        default boolean hasHeader() { return true; }
-    }
-
     // safe to call from any thread
 
     public void addCallback(Callback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 0de1e30..3493d24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -33,10 +33,11 @@
 import android.widget.LinearLayout;
 import android.widget.Toolbar;
 import android.widget.Toolbar.OnMenuItemClickListener;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSContainer;
+import com.android.systemui.plugins.qs.QSContainer;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java
new file mode 100644
index 0000000..ffe66f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.systemui.qs.external;
+
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+
+// Adapter that wraps calls to PackageManager or IPackageManager for {@link TileLifecycleManager}.
+// TODO: This is very much an intermediate step to allow for PackageManager mocking and should be
+// abstracted into something more useful for other tests in systemui.
+public class PackageManagerAdapter {
+    private static final String TAG = "PackageManagerAdapter";
+
+    private PackageManager mPackageManager;
+    private IPackageManager mIPackageManager;
+
+    // Uses the PackageManager for the provided context.
+    // When necessary, uses the IPackagemanger in AppGlobals.
+    public PackageManagerAdapter(Context context) {
+        mPackageManager = context.getPackageManager();
+        mIPackageManager = AppGlobals.getPackageManager();
+    }
+
+    public ServiceInfo getServiceInfo(ComponentName className, int flags, int userId)
+            throws RemoteException {
+        return mIPackageManager.getServiceInfo(className, flags, userId);
+    }
+
+    public ServiceInfo getServiceInfo(ComponentName component, int flags)
+            throws PackageManager.NameNotFoundException {
+        return mPackageManager.getServiceInfo(component, flags);
+    }
+
+    public PackageInfo getPackageInfoAsUser(String packageName, int flags, @UserIdInt int userId)
+            throws PackageManager.NameNotFoundException {
+        return mPackageManager.getPackageInfoAsUser(packageName, flags, userId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 681005c..867f3b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -21,10 +21,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
+import android.content.ServiceConnection;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
@@ -38,6 +37,7 @@
 import android.support.annotation.VisibleForTesting;
 import android.util.ArraySet;
 import android.util.Log;
+import com.android.systemui.qs.external.PackageManagerAdapter;
 
 import libcore.util.Objects;
 
@@ -63,13 +63,17 @@
 
     // Bind retry control.
     private static final int MAX_BIND_RETRIES = 5;
-    private static final int BIND_RETRY_DELAY = 1000;
+    private static final int DEFAULT_BIND_RETRY_DELAY = 1000;
+
+    // Shared prefs that hold tile lifecycle info.
+    private static final String TILES = "tiles_prefs";
 
     private final Context mContext;
     private final Handler mHandler;
     private final Intent mIntent;
     private final UserHandle mUser;
     private final IBinder mToken = new Binder();
+    private final PackageManagerAdapter mPackageManagerAdapter;
 
     private Set<Integer> mQueuedMessages = new ArraySet<>();
     private QSTileServiceWrapper mWrapper;
@@ -77,22 +81,29 @@
     private IBinder mClickBinder;
 
     private int mBindTryCount;
+    private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
     private boolean mBound;
-    @VisibleForTesting
     boolean mReceiverRegistered;
     private boolean mUnbindImmediate;
     private TileChangeListener mChangeListener;
     // Return value from bindServiceAsUser, determines whether safe to call unbind.
     private boolean mIsBound;
 
-    public TileLifecycleManager(Handler handler, Context context, IQSService service,
-            Tile tile, Intent intent, UserHandle user) {
+    public TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
+            Intent intent, UserHandle user) {
+        this(handler, context, service, tile, intent, user, new PackageManagerAdapter(context));
+    }
+
+    @VisibleForTesting
+    TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
+            Intent intent, UserHandle user, PackageManagerAdapter packageManagerAdapter) {
         mContext = context;
         mHandler = handler;
         mIntent = intent;
         mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder());
         mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
         mUser = user;
+        mPackageManagerAdapter = packageManagerAdapter;
         if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
     }
 
@@ -106,13 +117,17 @@
         }
     }
 
+    public void setBindRetryDelay(int delayMs) {
+        mBindRetryDelay = delayMs;
+    }
+
     public boolean isActiveTile() {
         try {
-            ServiceInfo info = mContext.getPackageManager().getServiceInfo(mIntent.getComponent(),
+            ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
                     PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
             return info.metaData != null
                     && info.metaData.getBoolean(TileService.META_DATA_ACTIVE_TILE, false);
-        } catch (NameNotFoundException e) {
+        } catch (PackageManager.NameNotFoundException e) {
             return false;
         }
     }
@@ -126,6 +141,12 @@
     }
 
     public void setBindService(boolean bind) {
+        if (mBound && mUnbindImmediate) {
+            // If we are already bound and expecting to unbind, this means we should stay bound
+            // because something else wants to hold the connection open.
+            mUnbindImmediate = false;
+            return;
+        }
         mBound = bind;
         if (bind) {
             if (mBindTryCount == MAX_BIND_RETRIES) {
@@ -247,13 +268,12 @@
                         setBindService(true);
                     }
                 }
-            }, BIND_RETRY_DELAY);
+            }, mBindRetryDelay);
         }
     }
 
     private boolean checkComponentState() {
-        PackageManager pm = mContext.getPackageManager();
-        if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+        if (!isPackageAvailable() || !isComponentAvailable()) {
             startPackageListening();
             return false;
         }
@@ -302,10 +322,10 @@
         }
     }
 
-    private boolean isComponentAvailable(PackageManager pm) {
+    private boolean isComponentAvailable() {
         String packageName = mIntent.getComponent().getPackageName();
         try {
-            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+            ServiceInfo si = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
                     0, mUser.getIdentifier());
             if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
             return si != null;
@@ -315,10 +335,10 @@
         return false;
     }
 
-    private boolean isPackageAvailable(PackageManager pm) {
+    private boolean isPackageAvailable() {
         String packageName = mIntent.getComponent().getPackageName();
         try {
-            pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+            mPackageManagerAdapter.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
             return true;
         } catch (PackageManager.NameNotFoundException e) {
             if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
@@ -406,4 +426,13 @@
     public interface TileChangeListener {
         void onTileChanged(ComponentName tile);
     }
+
+    public static boolean isTileAdded(Context context, ComponentName component) {
+        return context.getSharedPreferences(TILES, 0).getBoolean(component.flattenToString(), false);
+    }
+
+    public static void setTileAdded(Context context, ComponentName component, boolean added) {
+        context.getSharedPreferences(TILES, 0).edit().putBoolean(component.flattenToString(),
+                added).commit();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index f3e4d60..91a0eb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -88,8 +88,15 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
-        mServices.getContext().registerReceiverAsUser(mUninstallReceiver,
+        Context context = mServices.getContext();
+        context.registerReceiverAsUser(mUninstallReceiver,
                 new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler);
+        ComponentName component = tileLifecycleManager.getComponent();
+        if (!TileLifecycleManager.isTileAdded(context, component)) {
+            TileLifecycleManager.setTileAdded(context, component, true);
+            mStateManager.onTileAdded();
+            mStateManager.flushMessagesAndUnbind();
+        }
     }
 
     public void setTileChangeListener(TileChangeListener changeListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 985bc9f..d89fbfd3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -40,6 +40,7 @@
 import com.android.settingslib.graph.UsageView;
 import com.android.systemui.BatteryMeterDrawable;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -117,7 +118,7 @@
             @Override
             public Drawable getDrawable(Context context) {
                 BatteryMeterDrawable drawable =
-                        new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+                        new BatteryMeterDrawable(context,
                         context.getColor(R.color.batterymeter_frame_color));
                 drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
                 drawable.onPowerSaveChanged(mPowerSave);
@@ -164,7 +165,7 @@
     private final class BatteryDetail implements DetailAdapter, OnClickListener,
             OnAttachStateChangeListener {
         private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
-                new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
+                mHost.getContext().getColor(R.color.batterymeter_frame_color));
         private View mCurrentView;
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 8d8474a..18bde27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -32,6 +32,7 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index c3e9b6e..61bad77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -28,6 +28,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 0de5105..7de883e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -24,12 +24,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
-import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSIconView;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.SignalTileView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index a63eabc..c7b6aea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -115,6 +115,12 @@
         final TextView infoBottom = (TextView) findViewById(R.id.usage_info_bottom_text);
         infoBottom.setVisibility(bottom != null ? View.VISIBLE : View.GONE);
         infoBottom.setText(bottom);
+        boolean showLevel = info.warningLevel > 0 || info.limitLevel > 0;
+        graph.setVisibility(showLevel ? View.VISIBLE : View.GONE);
+        if (!showLevel) {
+            infoTop.setVisibility(View.GONE);
+        }
+
     }
 
     private String formatBytes(long bytes) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 91821ba..89bb1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -37,6 +37,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.volume.ZenModePanel;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index cc875ac..b5fbfe0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -22,6 +22,7 @@
 import android.util.Pair;
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index ba79a18..27306fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -31,6 +31,7 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index 9403664..9214eef 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -35,4 +35,5 @@
             in Rect initialBounds);
     void onDraggingInRecents(float distanceFromTop);
     void onDraggingInRecentsEnded(float velocity);
+    void showCurrentUserToast(int msgResId, int msgLength);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e117bfe..7207463 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -18,10 +18,12 @@
 
 import android.app.ActivityManager;
 import android.app.UiModeManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -53,6 +55,7 @@
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -96,7 +99,7 @@
     // and does not reside in the home stack.
     private String mOverrideRecentsPackageName;
 
-    private Handler mHandler;
+    private Handler mHandler = new Handler();
     private RecentsImpl mImpl;
     private int mDraggingInRecentsCurrentUser;
 
@@ -162,6 +165,20 @@
         }
     };
 
+
+    private BroadcastReceiver mSystemUserUnlockedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId != UserHandle.USER_NULL) {
+                    mImpl.onUserUnlocked(userId);
+                }
+            }
+        }
+    };
+
+
     /**
      * Returns the callbacks interface that non-system users can call.
      */
@@ -191,7 +208,7 @@
         sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         sTaskLoader = new RecentsTaskLoader(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
-        mHandler = new Handler();
+
         UiModeManager uiModeManager = (UiModeManager) mContext.
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
@@ -221,6 +238,12 @@
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
             mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+
+            // Listen for user-unlocked to kick off preloading recents
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_USER_UNLOCKED);
+            mContext.registerReceiverAsUser(mSystemUserUnlockedReceiver, UserHandle.SYSTEM, filter,
+                    null /* permission */, null /* scheduler */);
         } else {
             // For the secondary user, bind to the primary user's service to get a persistent
             // interface to register its implementation and to later update its state
@@ -455,8 +478,8 @@
                 mDraggingInRecentsCurrentUser = currentUser;
                 return true;
             } else {
-                Toast.makeText(mContext, R.string.recents_incompatible_app_message,
-                        Toast.LENGTH_SHORT).show();
+                EventBus.getDefault().send(new ShowUserToastEvent(
+                        R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT));
                 return false;
             }
         } else {
@@ -674,6 +697,27 @@
         mImpl.onConfigurationChanged();
     }
 
+    public final void onBusEvent(ShowUserToastEvent event) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
     /**
      * Attempts to register with the system user.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 7bdb1c4..e5493b6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.BroadcastReceiver;
@@ -40,7 +41,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
+import com.android.systemui.LatencyTracker;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
@@ -87,6 +90,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
  * The main Recents activity that is started from RecentsComponent.
@@ -165,18 +169,39 @@
      */
     final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
         @Override
-        public void onReceive(Context context, Intent intent) {
+        public void onReceive(Context ctx, Intent intent) {
             String action = intent.getAction();
             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHomeIfVisible(false);
             } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
-                // For the time being, if the time changes, then invalidate the
-                // last-stack-active-time, this ensures that we will just show the last N tasks
-                // the next time that Recents loads, but prevents really old tasks from showing
-                // up if the task time is set forward.
-                Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
-                        0);
+                // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
+                // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
+                // currentTime and remove the old tasks in between which would not be previously
+                // visible, but currently would be in the new currentTime
+                long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this,
+                        Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+                if (oldLastStackActiveTime != -1) {
+                    long currentTime = System.currentTimeMillis();
+                    if (currentTime < oldLastStackActiveTime) {
+                        // We are only removing tasks that are between the new current time
+                        // and the old last stack active time, they were not visible and in the
+                        // TaskStack so we don't need to remove any associated TaskViews but we do
+                        // need to load the task id's from the system
+                        RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
+                        loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
+                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
+                        for (int i = tasks.size() - 1; i >= 0; i--) {
+                            ActivityManager.RecentTaskInfo task = tasks.get(i);
+                            if (currentTime <= task.lastActiveTime && task.lastActiveTime <
+                                    oldLastStackActiveTime) {
+                                Recents.getSystemServices().removeTask(task.persistentId);
+                            }
+                        }
+                        Prefs.putLong(RecentsActivity.this,
+                                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime);
+                    }
+                }
             }
         }
     };
@@ -187,6 +212,11 @@
                 public boolean onPreDraw() {
                     mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
                     EventBus.getDefault().post(new RecentsDrawnEvent());
+                    if (LatencyTracker.isEnabled(getApplicationContext())) {
+                        DejankUtils.postAfterTraversal(() -> LatencyTracker.getInstance(
+                                getApplicationContext()).onActionEnd(
+                                LatencyTracker.ACTION_TOGGLE_RECENTS));
+                    }
                     return true;
                 }
             };
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 20e1665..390ef87 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -41,6 +41,7 @@
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
 
+import android.widget.Toast;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
@@ -187,7 +188,7 @@
         reloadResources();
     }
 
-    public void onBootCompleted() {
+    public void onUserUnlocked(int userId) {
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -200,10 +201,22 @@
         loader.loadTasks(mContext, plan, launchOpts);
     }
 
+    public void onBootCompleted() {
+        // Do nothing
+    }
+
     public void onConfigurationChanged() {
+        Resources res = mContext.getResources();
         reloadResources();
         mDummyStackView.reloadOnConfigurationChange();
+        // Update the header bar direction directly as it is not attached to anything and does not
+        // layout except in updateHeaderBarLayout()
+        mHeaderBar.setLayoutDirection(res.getConfiguration().getLayoutDirection());
         mHeaderBar.onConfigurationChanged();
+        mHeaderBar.forceLayout();
+        mHeaderBar.measure(
+                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredWidth(), MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(mHeaderBar.getMeasuredHeight(), MeasureSpec.EXACTLY));
     }
 
     /**
@@ -212,11 +225,7 @@
      * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
      */
     public void onVisibilityChanged(Context context, boolean visible) {
-        SystemUIApplication app = (SystemUIApplication) context;
-        PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
-        if (statusBar != null) {
-            statusBar.updateRecentsVisibility(visible);
-        }
+        Recents.getSystemServices().setRecentsVisibility(visible);
     }
 
     /**
@@ -393,6 +402,10 @@
         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
     }
 
+    public void onShowCurrentUserToast(int msgResId, int msgLength) {
+        Toast.makeText(mContext, msgResId, msgLength).show();
+    }
+
     /**
      * Transitions to the next recent task in the stack.
      */
@@ -624,6 +637,7 @@
                 synchronized (mHeaderBarLock) {
                     if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
                             mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
+                        mHeaderBar.forceLayout();
                         mHeaderBar.measure(
                                 MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
                                 MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
index 60bf760..ff9e89e9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -38,6 +38,7 @@
     private static final int MSG_DOCK_TOP_TASK = 7;
     private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
     private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
+    private static final int MSG_SHOW_USER_TOAST = 10;
 
     private RecentsImpl mImpl;
 
@@ -109,6 +110,11 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
     }
 
+    @Override
+    public void showCurrentUserToast(int msgResId, int msgLength) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_USER_TOAST, msgResId, msgLength));
+    }
+
     private final Handler mHandler = new Handler() {
 
         @Override
@@ -147,6 +153,9 @@
                 case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
                     mImpl.onDraggingInRecentsEnded((Float) msg.obj);
                     break;
+                case MSG_SHOW_USER_TOAST:
+                    mImpl.onShowCurrentUserToast(msg.arg1, msg.arg2);
+                    break;
                 default:
                     super.handleMessage(msg);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
new file mode 100644
index 0000000..e2b39c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.systemui.recents.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when we want to show a toast for the current user.
+ */
+public class ShowUserToastEvent extends EventBus.Event {
+
+    public final int msgResId;
+    public final int msgLength;
+
+    public ShowUserToastEvent(int msgResId, int msgLength) {
+        this.msgResId = msgResId;
+        this.msgLength = msgLength;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 9d9e27389..e0cdb1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -70,6 +70,7 @@
 import android.view.Display;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
+import android.view.IWindowManager;
 import android.view.WindowManager;
 import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.WindowManagerGlobal;
@@ -121,6 +122,7 @@
     IPackageManager mIpm;
     AssistUtils mAssistUtils;
     WindowManager mWm;
+    IWindowManager mIwm;
     UserManager mUm;
     Display mDisplay;
     String mRecentsPackage;
@@ -208,6 +210,7 @@
         mIpm = AppGlobals.getPackageManager();
         mAssistUtils = new AssistUtils(context);
         mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mIwm = WindowManagerGlobal.getWindowManagerService();
         mUm = UserManager.get(context);
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
@@ -1097,6 +1100,28 @@
         }
     }
 
+    /**
+     * Updates the visibility of recents.
+     */
+    public void setRecentsVisibility(boolean visible) {
+        try {
+            mIwm.setRecentsVisibility(visible);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+    }
+
+    /**
+     * Updates the visibility of the picture-in-picture.
+     */
+    public void setTvPipVisibility(boolean visible) {
+        try {
+            mIwm.setTvPipVisibility(visible);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+    }
+
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_ACTIVITY_PINNED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 1278b73..9b48e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -248,6 +248,13 @@
         return mStack;
     }
 
+    /**
+     * Returns the raw list of recent tasks.
+     */
+    public List<ActivityManager.RecentTaskInfo> getRawTasks() {
+        return mRawTasks;
+    }
+
     /** Returns whether there are any tasks in any stacks. */
     public boolean hasTasks() {
         if (mStack != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index fca8d2d..ef9de53 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -140,10 +140,6 @@
 
     @Override
     public void onVisibilityChanged(Context context, boolean visible) {
-        SystemUIApplication app = (SystemUIApplication) context;
-        TvStatusBar statusBar = app.getComponent(TvStatusBar.class);
-        if (statusBar != null) {
-            statusBar.updateRecentsVisibility(visible);
-        }
+        Recents.getSystemServices().setRecentsVisibility(visible);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 702b076..fce7f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -1258,7 +1258,7 @@
         String innerPrefix = prefix + "  ";
 
         writer.print(prefix); writer.print(TAG);
-        writer.write(" numStackTasks="); writer.write(mNumStackTasks);
+        writer.write(" numStackTasks="); writer.print(mNumStackTasks);
         writer.println();
 
         writer.print(innerPrefix);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index d29fbfd..f7d6183 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -164,6 +164,8 @@
     @ViewDebug.ExportedProperty(category="recents")
     private boolean mAwaitingFirstLayout = true;
     @ViewDebug.ExportedProperty(category="recents")
+    private boolean mLaunchNextAfterFirstMeasure = false;
+    @ViewDebug.ExportedProperty(category="recents")
     @InitialStateAction
     private int mInitialState = INITIAL_STATE_UPDATE_ALL;
     @ViewDebug.ExportedProperty(category="recents")
@@ -339,6 +341,7 @@
         // Since we always animate to the same place in (the initial state), always reset the stack
         // to the initial state when resuming
         mAwaitingFirstLayout = true;
+        mLaunchNextAfterFirstMeasure = false;
         mInitialState = INITIAL_STATE_UPDATE_ALL;
         requestLayout();
     }
@@ -1226,6 +1229,12 @@
                 mInitialState = INITIAL_STATE_UPDATE_NONE;
             }
         }
+        // If we got the launch-next event before the first layout pass, then re-send it after the
+        // initial state has been updated
+        if (mLaunchNextAfterFirstMeasure) {
+            mLaunchNextAfterFirstMeasure = false;
+            EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
+        }
 
         // Rebind all the views, including the ignore ones
         bindVisibleTaskViews(mStackScroller.getStackScroll(), false /* ignoreTaskOverrides */);
@@ -1669,6 +1678,11 @@
     }
 
     public final void onBusEvent(LaunchNextTaskRequestEvent event) {
+        if (mAwaitingFirstLayout) {
+            mLaunchNextAfterFirstMeasure = true;
+            return;
+        }
+
         int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
         if (launchTaskIndex != -1) {
             launchTaskIndex = Math.max(0, launchTaskIndex - 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 67a2595..d44aa84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -634,6 +634,12 @@
             }
 
             int taskIndex = mCurrentTasks.indexOf(task);
+            if (taskIndex == -1) {
+                // If a task was added to the stack view after the start of the dismiss gesture,
+                // just ignore it
+                continue;
+            }
+
             TaskViewTransform fromTransform = mCurrentTaskTransforms.get(taskIndex);
             TaskViewTransform toTransform = mFinalTaskTransforms.get(taskIndex);
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 74dce1c..3ed2698 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -229,6 +229,7 @@
                         break;
                     case MSG_DETACH_LISTENER:
                         mControl.setOnChangedListener(null);
+                        break;
                     default:
                         super.handleMessage(msg);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 5f083d5..5920f46 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -20,12 +20,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.util.ArraySet;
 import android.widget.Toast;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
+import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 import com.android.systemui.stackdivider.events.StartedDragingEvent;
@@ -100,9 +102,8 @@
     }
 
     private void activityDismissingDockedStack() {
-        Toast toast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
-                Toast.LENGTH_SHORT);
-        toast.show();
+        EventBus.getDefault().send(new ShowUserToastEvent(
+                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
     }
 
     private void showPending() {
@@ -112,7 +113,7 @@
             ActivityOptions options = ActivityOptions.makeBasic();
             options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
             options.setTaskOverlay(true);
-            mContext.startActivity(intent, options.toBundle());
+            mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
         }
         mPendingTaskIds.clear();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e35ef44..bc46548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -593,6 +593,9 @@
             public void onAnimationEnd(Animator animation) {
                 updateBackground();
                 mBackgroundAnimator = null;
+                if (mFadeInFromDarkAnimator == null) {
+                    mDimmedBackgroundFadeInAmount = -1;
+                }
             }
         });
         mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a6536a8..7a1ea47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -113,8 +113,11 @@
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 
@@ -158,7 +161,7 @@
             "com.android.systemui.statusbar.banner_action_cancel";
     private static final String BANNER_ACTION_SETUP =
             "com.android.systemui.statusbar.banner_action_setup";
-    private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
+    private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
             = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
 
     protected CommandQueue mCommandQueue;
@@ -214,14 +217,14 @@
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     // public mode, private notifications, etc
-    private boolean mLockscreenPublicMode = false;
+    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
 
     private UserManager mUserManager;
     private int mDensity;
 
-    private KeyguardManager mKeyguardManager;
+    protected KeyguardManager mKeyguardManager;
     private LockPatternUtils mLockPatternUtils;
 
     // UI-specific methods
@@ -268,6 +271,8 @@
 
     protected boolean mVrMode;
 
+    private Set<String> mNonBlockablePkgs;
+
     @Override  // NotificationData.Environment
     public boolean isDeviceProvisioned() {
         return mDeviceProvisioned;
@@ -309,6 +314,7 @@
             mUsersAllowingPrivateNotifications.clear();
             mUsersAllowingNotifications.clear();
             // ... and refresh all the notifications
+            updateLockscreenNotificationSetting();
             updateNotifications();
         }
     };
@@ -459,11 +465,11 @@
             row.setUserExpanded(true);
 
             if (!mAllowLockscreenRemoteInput) {
-                if (isLockscreenPublicMode()) {
+                final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+                if (isLockscreenPublicMode(userId)) {
                     onLockedRemoteInput(row, view);
                     return true;
                 }
-                final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
                 if (mUserManager.getUserInfo(userId).isManagedProfile()
                         && mKeyguardManager.isDeviceLocked(userId)) {
                     onLockedWorkRemoteInput(userId, row, view);
@@ -554,7 +560,7 @@
 
                     );
                 }
-            } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
+            } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
                 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
                 if (intentSender != null) {
@@ -571,7 +577,6 @@
                         /* ignore */
                     }
                 }
-                onWorkChallengeUnlocked();
             }
         }
     };
@@ -579,12 +584,18 @@
     private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
             if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
                     isCurrentProfile(getSendingUserId())) {
                 mUsersAllowingPrivateNotifications.clear();
                 updateLockscreenNotificationSetting();
                 updateNotifications();
+            } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+                if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+                    onWorkChallengeChanged();
+                }
             }
         }
     };
@@ -714,7 +725,7 @@
                 mSettingsObserver);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
-                mSettingsObserver,
+                mLockscreenSettingsObserver,
                 UserHandle.USER_ALL);
         if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
             mContext.getContentResolver().registerContentObserver(
@@ -809,7 +820,7 @@
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         IntentFilter internalFilter = new IntentFilter();
-        internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+        internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         internalFilter.addAction(BANNER_ACTION_CANCEL);
         internalFilter.addAction(BANNER_ACTION_SETUP);
         mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
@@ -817,6 +828,7 @@
         IntentFilter allUsersFilter = new IntentFilter();
         allUsersFilter.addAction(
                 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
         mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
                 null, null);
         updateCurrentProfilesCache();
@@ -828,6 +840,9 @@
             Slog.e(TAG, "Failed to register VR mode state listener: " + e);
         }
 
+        mNonBlockablePkgs = new HashSet<String>();
+        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_nonBlockableNotificationPackages));
     }
 
     protected void notifyUserAboutHiddenNotifications() {
@@ -1108,7 +1123,8 @@
             settingsButton.setVisibility(View.GONE);
         }
 
-        guts.bindImportance(pmUser, sbn, mNotificationData.getImportance(sbn.getKey()));
+        guts.bindImportance(pmUser, sbn, mNonBlockablePkgs,
+                mNotificationData.getImportance(sbn.getKey()));
 
         final TextView doneButton = (TextView) guts.findViewById(R.id.done);
         doneButton.setText(R.string.notification_done);
@@ -1116,9 +1132,10 @@
             @Override
             public void onClick(View v) {
                 // If the user has security enabled, show challenge if the setting is changed.
-                if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
-                        (mState == StatusBarState.KEYGUARD
-                        || mState == StatusBarState.SHADE_LOCKED)) {
+                if (guts.hasImportanceChanged()
+                            && isLockscreenPublicMode(sbn.getUser().getIdentifier())
+                            && (mState == StatusBarState.KEYGUARD
+                                    || mState == StatusBarState.SHADE_LOCKED)) {
                     OnDismissAction dismissAction = new OnDismissAction() {
                         @Override
                         public boolean onDismiss() {
@@ -1420,15 +1437,15 @@
     /**
      * Save the current "public" (locked and secure) state of the lockscreen.
      */
-    public void setLockscreenPublicMode(boolean publicMode) {
-        mLockscreenPublicMode = publicMode;
+    public void setLockscreenPublicMode(boolean publicMode, int userId) {
+        mLockscreenPublicMode.put(userId, publicMode);
     }
 
-    public boolean isLockscreenPublicMode() {
-        return mLockscreenPublicMode;
+    public boolean isLockscreenPublicMode(int userId) {
+        return mLockscreenPublicMode.get(userId, false);
     }
 
-    protected void onWorkChallengeUnlocked() {}
+    protected void onWorkChallengeChanged() {}
 
     /**
      * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
@@ -1486,8 +1503,9 @@
      * If so, notifications should be hidden.
      */
     @Override  // NotificationData.Environment
-    public boolean shouldHideNotifications(int userid) {
-        return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+    public boolean shouldHideNotifications(int userId) {
+        return isLockscreenPublicMode(mCurrentUserId) && !userAllowsNotificationsInPublic(userId)
+                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
     }
 
     /**
@@ -1496,7 +1514,7 @@
      */
     @Override // NotificationDate.Environment
     public boolean shouldHideNotifications(String key) {
-        return isLockscreenPublicMode()
+        return isLockscreenPublicMode(mCurrentUserId)
                 && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
     }
 
@@ -1504,8 +1522,8 @@
      * Returns true if we're on a secure lockscreen.
      */
     @Override  // NotificationData.Environment
-    public boolean onSecureLockScreen() {
-        return isLockscreenPublicMode();
+    public boolean isSecurelyLocked(int userId) {
+        return isLockscreenPublicMode(userId);
     }
 
     public void onNotificationClear(StatusBarNotification notification) {
@@ -1948,9 +1966,18 @@
                                             .getIdentifier();
                                     if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
                                             && mKeyguardManager.isDeviceLocked(userId)) {
-                                        if (startWorkChallengeIfNecessary(userId,
-                                                intent.getIntentSender(), notificationKey)) {
-                                            // Show work challenge, do not run pendingintent and
+                                        boolean canBypass = false;
+                                        try {
+                                            canBypass = ActivityManagerNative.getDefault()
+                                                    .canBypassWorkChallenge(intent);
+                                        } catch (RemoteException e) {
+                                        }
+                                        // For direct-boot aware activities, they can be shown when
+                                        // the device is still locked without triggering the work
+                                        // challenge.
+                                        if ((!canBypass) && startWorkChallengeIfNecessary(userId,
+                                                    intent.getIntentSender(), notificationKey)) {
+                                            // Show work challenge, do not run PendingIntent and
                                             // remove notification
                                             return;
                                         }
@@ -2057,8 +2084,7 @@
         if (newIntent == null) {
             return false;
         }
-        final Intent callBackIntent = new Intent(
-                WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+        final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
         callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
         callBackIntent.setPackage(mContext.getPackageName());
@@ -2257,14 +2283,16 @@
                 entry.row.setOnKeyguard(false);
                 entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
             }
+            int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
             boolean childWithVisibleSummary = childNotification
                     && mGroupManager.getGroupSummary(entry.notification).getVisibility()
                     == View.VISIBLE;
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
-            if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
-                    (onKeyguard && !childWithVisibleSummary
+            if (suppressedSummary
+                    || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
+                    || (onKeyguard && !childWithVisibleSummary
                             && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
                 entry.row.setVisibility(View.GONE);
                 if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 123dc69..e8f0925 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -48,13 +48,30 @@
     }
 
     public static void fadeOut(View view, float fadeOutAmount) {
+        fadeOut(view, fadeOutAmount, true /* remap */);
+    }
+
+    /**
+     * Fade out a view by a given progress amount
+     * @param view the view to fade out
+     * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
+     *                      faded out
+     * @param remap whether the fade amount should be remapped to the shorter duration
+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
+     *
+     * @see #fadeIn(View, float, boolean)
+     */
+    public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
         view.animate().cancel();
         if (fadeOutAmount == 1.0f) {
             view.setVisibility(View.INVISIBLE);
         } else if (view.getVisibility() == View.INVISIBLE) {
             view.setVisibility(View.VISIBLE);
         }
-        fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+        if (remap) {
+            fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+        }
         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
         view.setAlpha(alpha);
         updateLayerType(view, alpha);
@@ -92,11 +109,28 @@
     }
 
     public static void fadeIn(View view, float fadeInAmount) {
+        fadeIn(view, fadeInAmount, true /* remap */);
+    }
+
+    /**
+     * Fade in a view by a given progress amount
+     * @param view the view to fade in
+     * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
+     *                     faded in.
+     * @param remap whether the fade amount should be remapped to the shorter duration
+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
+     *
+     * @see #fadeOut(View, float, boolean)
+     */
+    public static void fadeIn(View view, float fadeInAmount, boolean remap) {
         view.animate().cancel();
         if (view.getVisibility() == View.INVISIBLE) {
             view.setVisibility(View.VISIBLE);
         }
-        fadeInAmount = mapToFadeDuration(fadeInAmount);
+        if (remap) {
+            fadeInAmount = mapToFadeDuration(fadeInAmount);
+        }
         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
         view.setAlpha(alpha);
         updateLayerType(view, alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index 2045ec8..1d7bede 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -56,6 +56,8 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mDismissButton.setText(R.string.clear_all_notifications_text);
+        mDismissButton.setContentDescription(
+                mContext.getString(R.string.accessibility_clear_all));
     }
 
     public boolean isButtonVisible() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 02fdd3f..caf5447 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();
     }
@@ -907,6 +905,9 @@
     }
 
     public void resetTranslation() {
+        if (mTranslateAnim != null) {
+            mTranslateAnim.cancel();
+        }
         if (mTranslateableViews != null) {
             for (int i = 0; i < mTranslateableViews.size(); i++) {
                 mTranslateableViews.get(i).setTranslationX(0);
@@ -1290,7 +1291,7 @@
         }
         mHeadsUpHeight = headsUpChild.getHeight();
         if (intrinsicBefore != getIntrinsicHeight()) {
-            notifyHeightChanged(false  /* needsAnimation */);
+            notifyHeightChanged(true  /* needsAnimation */);
         }
     }
 
@@ -1398,7 +1399,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/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 88f37a3..8b4225a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -174,7 +174,10 @@
 
     private void drawBackgroundCircle(Canvas canvas) {
         if (mCircleRadius > 0 || mFinishing) {
-            if (mFinishing && mSupportHardware) {
+            if (mFinishing && mSupportHardware && mHwCenterX != null) {
+                // Our hardware drawing proparties can be null if the finishing started but we have
+                // never drawn before. In that case we are not doing a render thread animation
+                // anyway, so we need to use the normal drawing.
                 DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
                 displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
                         mHwCirclePaint);
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/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 9fd09d9..58d57f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -116,6 +116,8 @@
     private boolean mForceSelectNextLayout = true;
     private PendingIntent mPreviousExpandedRemoteInputIntent;
     private PendingIntent mPreviousHeadsUpRemoteInputIntent;
+    private RemoteInputView mCachedExpandedRemoteInput;
+    private RemoteInputView mCachedHeadsUpRemoteInput;
 
     private int mContentHeightAtAnimationStart = UNDEFINED;
     private boolean mFocusOnVisibilityChange;
@@ -205,7 +207,7 @@
                     && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
                 singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
                         width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
-                        MeasureSpec.AT_MOST);
+                        MeasureSpec.EXACTLY);
             }
             mSingleLineView.measure(singleLineWidthSpec,
                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
@@ -298,6 +300,9 @@
             mExpandedRemoteInput.onNotificationUpdateOrReset();
             if (mExpandedRemoteInput.isActive()) {
                 mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
+                mCachedExpandedRemoteInput = mExpandedRemoteInput;
+                mExpandedRemoteInput.dispatchStartTemporaryDetach();
+                ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
             }
         }
         if (mExpandedChild != null) {
@@ -310,6 +315,9 @@
             mHeadsUpRemoteInput.onNotificationUpdateOrReset();
             if (mHeadsUpRemoteInput.isActive()) {
                 mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
+                mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
+                mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
+                ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
             }
         }
         if (mHeadsUpChild != null) {
@@ -963,22 +971,35 @@
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
             mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
-                    mPreviousExpandedRemoteInputIntent);
+                    mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput);
         } else {
             mExpandedRemoteInput = null;
         }
+        if (mCachedExpandedRemoteInput != null
+                && mCachedExpandedRemoteInput != mExpandedRemoteInput) {
+            // We had a cached remote input but didn't reuse it. Clean up required.
+            mCachedExpandedRemoteInput.dispatchFinishTemporaryDetach();
+        }
+        mCachedExpandedRemoteInput = null;
 
         View headsUpContentView = mHeadsUpChild;
         if (headsUpContentView != null) {
             mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
-                    mPreviousHeadsUpRemoteInputIntent);
+                    mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput);
         } else {
             mHeadsUpRemoteInput = null;
         }
+        if (mCachedHeadsUpRemoteInput != null
+                && mCachedHeadsUpRemoteInput != mHeadsUpRemoteInput) {
+            // We had a cached remote input but didn't reuse it. Clean up required.
+            mCachedHeadsUpRemoteInput.dispatchFinishTemporaryDetach();
+        }
+        mCachedHeadsUpRemoteInput = null;
     }
 
     private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
-            boolean hasRemoteInput, PendingIntent existingPendingIntent) {
+            boolean hasRemoteInput, PendingIntent existingPendingIntent,
+            RemoteInputView cachedView) {
         View actionContainerCandidate = view.findViewById(
                 com.android.internal.R.id.actions_container);
         if (actionContainerCandidate instanceof FrameLayout) {
@@ -991,15 +1012,22 @@
 
             if (existing == null && hasRemoteInput) {
                 ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
-                RemoteInputView riv = RemoteInputView.inflate(
-                        mContext, actionContainer, entry, mRemoteInputController);
+                if (cachedView == null) {
+                    RemoteInputView riv = RemoteInputView.inflate(
+                            mContext, actionContainer, entry, mRemoteInputController);
 
-                riv.setVisibility(View.INVISIBLE);
-                actionContainer.addView(riv, new LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.MATCH_PARENT)
-                );
-                existing = riv;
+                    riv.setVisibility(View.INVISIBLE);
+                    actionContainer.addView(riv, new LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT)
+                    );
+                    existing = riv;
+                } else {
+                    actionContainer.addView(cachedView);
+                    cachedView.dispatchFinishTemporaryDetach();
+                    cachedView.requestFocus();
+                    existing = cachedView;
+                }
             }
             if (hasRemoteInput) {
                 int color = entry.notification.getNotification().color;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index b6e54af..bae16f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -380,7 +380,7 @@
             return true;
         }
 
-        if (mEnvironment.onSecureLockScreen() &&
+        if (mEnvironment.isSecurelyLocked(sbn.getUserId()) &&
                 (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
                         || mEnvironment.shouldHideNotifications(sbn.getUserId())
                         || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
@@ -463,7 +463,7 @@
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface Environment {
-        public boolean onSecureLockScreen();
+        public boolean isSecurelyLocked(int userId);
         public boolean shouldHideNotifications(int userid);
         public boolean shouldHideNotifications(String key);
         public boolean isDeviceProvisioned();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index c497cfd..62d730a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -50,6 +50,8 @@
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 import com.android.systemui.tuner.TunerService;
 
+import java.util.Set;
+
 /**
  * The guts of a notification revealed when performing a long press.
  */
@@ -173,7 +175,7 @@
     }
 
     void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
-            final int importance) {
+            final Set<String> nonBlockablePkgs, final int importance) {
         mINotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
         mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
@@ -182,24 +184,26 @@
                     mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
         } catch (RemoteException e) {}
         mNotificationImportance = importance;
-        boolean systemApp = false;
+        boolean nonBlockable = false;
         try {
             final PackageInfo info =
                     pm.getPackageInfo(sbn.getPackageName(), PackageManager.GET_SIGNATURES);
-            systemApp = Utils.isSystemPackage(getResources(), pm, info);
+            nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
         } catch (PackageManager.NameNotFoundException e) {
             // unlikely.
         }
+        if (nonBlockablePkgs != null) {
+            nonBlockable |= nonBlockablePkgs.contains(sbn.getPackageName());
+        }
 
         final View importanceSlider = findViewById(R.id.importance_slider);
         final View importanceButtons = findViewById(R.id.importance_buttons);
         if (mShowSlider) {
-            bindSlider(importanceSlider, systemApp);
+            bindSlider(importanceSlider, nonBlockable);
             importanceSlider.setVisibility(View.VISIBLE);
             importanceButtons.setVisibility(View.GONE);
         } else {
-
-            bindToggles(importanceButtons, mStartingUserImportance, systemApp);
+            bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
             importanceButtons.setVisibility(View.VISIBLE);
             importanceSlider.setVisibility(View.GONE);
         }
@@ -239,7 +243,7 @@
     }
 
     private void bindToggles(final View importanceButtons, final int importance,
-            final boolean systemApp) {
+            final boolean nonBlockable) {
         ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
                 new RadioGroup.OnCheckedChangeListener() {
                     @Override
@@ -250,7 +254,7 @@
         mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
         mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
         mReset = (RadioButton) importanceButtons.findViewById(R.id.reset_importance);
-        if (systemApp) {
+        if (nonBlockable) {
             mBlock.setVisibility(View.GONE);
             mReset.setText(mContext.getString(R.string.do_not_silence));
         } else {
@@ -265,7 +269,7 @@
         }
     }
 
-    private void bindSlider(final View importanceSlider, final boolean systemApp) {
+    private void bindSlider(final View importanceSlider, final boolean nonBlockable) {
         mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
         mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color);
 
@@ -273,7 +277,7 @@
         mImportanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
         mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
 
-        final int minProgress = systemApp ?
+        final int minProgress = nonBlockable ?
                 NotificationListenerService.Ranking.IMPORTANCE_MIN
                 : NotificationListenerService.Ranking.IMPORTANCE_NONE;
         mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 6cbacea..66cc15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -21,7 +21,9 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
+import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Pair;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -31,8 +33,9 @@
  */
 public class RemoteInputController {
 
-    private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
-    private final ArraySet<String> mSpinning = new ArraySet<>();
+    private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
+            = new ArrayList<>();
+    private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final HeadsUpManager mHeadsUpManager;
 
@@ -41,36 +44,72 @@
         mHeadsUpManager = headsUpManager;
     }
 
-    public void addRemoteInput(NotificationData.Entry entry) {
+    /**
+     * Adds a currently active remote input.
+     *
+     * @param entry the entry for which a remote input is now active.
+     * @param token a token identifying the view that is managing the remote input
+     */
+    public void addRemoteInput(NotificationData.Entry entry, Object token) {
         Preconditions.checkNotNull(entry);
+        Preconditions.checkNotNull(token);
 
         boolean found = pruneWeakThenRemoveAndContains(
-                entry /* contains */, null /* remove */);
+                entry /* contains */, null /* remove */, token /* removeToken */);
         if (!found) {
-            mOpen.add(new WeakReference<>(entry));
+            mOpen.add(new Pair<>(new WeakReference<>(entry), token));
         }
 
         apply(entry);
     }
 
-    public void removeRemoteInput(NotificationData.Entry entry) {
+    /**
+     * Removes a currently active remote input.
+     *
+     * @param entry the entry for which a remote input should be removed.
+     * @param token a token identifying the view that is requesting the removal. If non-null,
+     *              the entry is only removed if the token matches the last added token for this
+     *              entry. If null, the entry is removed regardless.
+     */
+    public void removeRemoteInput(NotificationData.Entry entry, Object token) {
         Preconditions.checkNotNull(entry);
 
-        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */);
+        pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
 
         apply(entry);
     }
 
-    public void addSpinning(String key) {
-        mSpinning.add(key);
+    /**
+     * Adds a currently spinning (i.e. sending) remote input.
+     *
+     * @param key the key of the entry that's spinning.
+     * @param token the token of the view managing the remote input.
+     */
+    public void addSpinning(String key, Object token) {
+        Preconditions.checkNotNull(key);
+        Preconditions.checkNotNull(token);
+
+        mSpinning.put(key, token);
     }
 
-    public void removeSpinning(String key) {
-        mSpinning.remove(key);
+    /**
+     * Removes a currently spinning remote input.
+     *
+     * @param key the key of the entry for which a remote input should be removed.
+     * @param token a token identifying the view that is requesting the removal. If non-null,
+     *              the entry is only removed if the token matches the last added token for this
+     *              entry. If null, the entry is removed regardless.
+     */
+    public void removeSpinning(String key, Object token) {
+        Preconditions.checkNotNull(key);
+
+        if (token == null || mSpinning.get(key) == token) {
+            mSpinning.remove(key);
+        }
     }
 
     public boolean isSpinning(String key) {
-        return mSpinning.contains(key);
+        return mSpinning.containsKey(key);
     }
 
     private void apply(NotificationData.Entry entry) {
@@ -86,14 +125,16 @@
      * @return true if {@param entry} has an active RemoteInput
      */
     public boolean isRemoteInputActive(NotificationData.Entry entry) {
-        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */);
+        return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
+                null /* removeToken */);
     }
 
     /**
      * @return true if any entry has an active RemoteInput
      */
     public boolean isRemoteInputActive() {
-        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
+        pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */,
+                null /* removeToken */);
         return !mOpen.isEmpty();
     }
 
@@ -101,17 +142,27 @@
      * Prunes dangling weak references, removes entries referring to {@param remove} and returns
      * whether {@param contains} is part of the array in a single loop.
      * @param remove if non-null, removes this entry from the active remote inputs
+     * @param removeToken if non-null, only removes an entry if this matches the token when the
+     *                    entry was added.
      * @return true if {@param contains} is in the set of active remote inputs
      */
     private boolean pruneWeakThenRemoveAndContains(
-            NotificationData.Entry contains, NotificationData.Entry remove) {
+            NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
         boolean found = false;
         for (int i = mOpen.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mOpen.get(i).get();
-            if (item == null || item == remove) {
+            NotificationData.Entry item = mOpen.get(i).first.get();
+            Object itemToken = mOpen.get(i).second;
+            boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
+
+            if (item == null || (item == remove && removeTokenMatches)) {
                 mOpen.remove(i);
             } else if (item == contains) {
-                found = true;
+                if (removeToken != null && removeToken != itemToken) {
+                    // We need to update the token. Remove here and let caller reinsert it.
+                    mOpen.remove(i);
+                } else {
+                    found = true;
+                }
             }
         }
         return found;
@@ -138,7 +189,7 @@
         // Make a copy because closing the remote inputs will modify mOpen.
         ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
         for (int i = mOpen.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mOpen.get(i).get();
+            NotificationData.Entry item = mOpen.get(i).first.get();
             if (item != null && item.row != null) {
                 list.add(item);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 1ff2b13..cd6c31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -116,8 +116,7 @@
                     ownState.transformViewTo(otherState, transformationAmount);
                     otherState.recycle();
                 } else {
-                    // there's no other view available
-                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
+                    ownState.disappear(transformationAmount, notification);
                 }
                 ownState.recycle();
             }
@@ -174,13 +173,7 @@
                     ownState.transformViewFrom(otherState, transformationAmount);
                     otherState.recycle();
                 } else {
-                    // There's no other view, lets fade us in
-                    // Certain views need to prepare the fade in and make sure its children are
-                    // completely visible. An example is the notification header.
-                    if (transformationAmount == 0.0f) {
-                        ownState.prepareFadeIn();
-                    }
-                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
+                    ownState.appear(transformationAmount, notification);
                 }
                 ownState.recycle();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index da57f7a..baff680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -15,17 +15,14 @@
  */
 package com.android.systemui.statusbar.car;
 
-import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
 import android.support.v4.util.SimpleArrayMap;
 import android.util.Log;
 import android.util.SparseBooleanArray;
@@ -33,7 +30,7 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ActivityStarter;
+import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
 
 import java.net.URISyntaxException;
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 6e6ece2..a7331d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -105,7 +105,7 @@
                         R.dimen.status_bar_connected_device_signal_margin_end));
 
         mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
-                mSignalsView);
+                mSignalsView, mBluetoothController);
 
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
@@ -148,7 +148,7 @@
         mController = new CarNavigationBarController(context, mCarNavigationBar,
                 this /* ActivityStarter*/);
         mNavigationBarView = mCarNavigationBar;
-
+        mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index 07856daa9..66030b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -17,11 +17,15 @@
 import android.widget.ImageView;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ScalingDrawableWrapper;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG;
 
 /**
  * Controller that monitors signal strength for a device that is connected via bluetooth.
  */
-public class ConnectedDeviceSignalController extends BroadcastReceiver {
+public class ConnectedDeviceSignalController extends BroadcastReceiver implements
+        BluetoothController.Callback {
     private final static String TAG = "DeviceSignalCtlr";
 
     /**
@@ -54,18 +58,21 @@
 
     private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
     private final Context mContext;
-    private final View mSignalsView;
+    private final BluetoothController mController;
 
+    private final View mSignalsView;
     private final ImageView mNetworkSignalView;
 
     private final float mIconScaleFactor;
 
     private BluetoothHeadsetClient mBluetoothHeadsetClient;
 
-    public ConnectedDeviceSignalController(Context context, View signalsView) {
+    public ConnectedDeviceSignalController(Context context, View signalsView,
+            BluetoothController controller) {
         mContext = context;
-        mSignalsView = signalsView;
+        mController = controller;
 
+        mSignalsView = signalsView;
         mNetworkSignalView = (ImageView)
                 mSignalsView.findViewById(R.id.connected_device_network_signal);
 
@@ -86,22 +93,46 @@
         filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
         mContext.registerReceiver(this, filter);
+
+        mController.addStateChangedCallback(this);
     }
 
     public void stopListening() {
         mContext.unregisterReceiver(this);
+        mController.removeStateChangedCallback(this);
+    }
+
+    @Override
+    public void onBluetoothDevicesChanged() {
+        // Nothing to do here because this Controller is not displaying a list of possible
+        // bluetooth devices.
+    }
+
+    @Override
+    public void onBluetoothStateChange(boolean enabled) {
+        if (DEBUG) {
+            Log.d(TAG, "onBluetoothStateChange(). enabled: " + enabled);
+        }
+
+        // Only need to handle the case if bluetooth has been disabled, in which case the
+        // signal indicators are hidden. If bluetooth has been enabled, then this class should
+        // receive updates to the connection state via onReceive().
+        if (!enabled) {
+            mNetworkSignalView.setVisibility(View.GONE);
+            mSignalsView.setVisibility(View.GONE);
+        }
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
 
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
+        if (DEBUG) {
             Log.d(TAG, "onReceive(). action: " + action);
         }
 
         if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "Received ACTION_AG_EVENT");
             }
 
@@ -109,13 +140,13 @@
         } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
             int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
 
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
                 Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: "
                         + oldState + " -> " + newState);
             }
             BluetoothDevice device =
-                    (BluetoothDevice)intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
+                    (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
             updateViewVisibility(device, newState);
         }
     }
@@ -128,7 +159,7 @@
         int networkStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS,
                 INVALID_SIGNAL);
         if (networkStatus != INVALID_SIGNAL) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "EXTRA_NETWORK_STATUS: " + " " + networkStatus);
             }
 
@@ -140,7 +171,7 @@
         int signalStrength = intent.getIntExtra(
                 BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL);
         if (signalStrength != INVALID_SIGNAL) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength);
             }
 
@@ -150,7 +181,7 @@
         int roamingStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING,
                 INVALID_SIGNAL);
         if (roamingStatus != INVALID_SIGNAL) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "EXTRA_NETWORK_ROAMING: " + roamingStatus);
             }
         }
@@ -169,7 +200,7 @@
 
     private void updateViewVisibility(BluetoothDevice device, int newState) {
         if (newState == BluetoothProfile.STATE_CONNECTED) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "Device connected");
             }
 
@@ -186,14 +217,14 @@
             int signalStrength = featuresBundle.getInt(
                     BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL);
             if (signalStrength != INVALID_SIGNAL) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                if (DEBUG) {
                     Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength);
                 }
 
                 setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]);
             }
         } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (DEBUG) {
                 Log.d(TAG, "Device disconnected");
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 45027c0..e6b3fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,12 +21,17 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * A transform state of a image view.
 */
 public class ImageTransformState extends TransformState {
+    public static final long ANIMATION_DURATION_LENGTH = 210;
 
     public static final int ICON_TAG = R.id.image_icon_tag;
     private static Pools.SimplePool<ImageTransformState> sInstancePool
@@ -49,6 +54,52 @@
         return super.sameAs(otherState);
     }
 
+    @Override
+    public void appear(float transformationAmount, TransformableView otherView) {
+        if (otherView instanceof HybridNotificationView) {
+            if (transformationAmount == 0.0f) {
+                mTransformedView.setPivotY(0);
+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
+                prepareFadeIn();
+            }
+            transformationAmount = mapToDuration(transformationAmount);
+            CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, false /* remap */);
+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
+                    transformationAmount);
+            mTransformedView.setScaleX(transformationAmount);
+            mTransformedView.setScaleY(transformationAmount);
+        } else {
+            super.appear(transformationAmount, otherView);
+        }
+    }
+
+    @Override
+    public void disappear(float transformationAmount, TransformableView otherView) {
+        if (otherView instanceof HybridNotificationView) {
+            if (transformationAmount == 0.0f) {
+                mTransformedView.setPivotY(0);
+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
+            }
+            transformationAmount = mapToDuration(1.0f - transformationAmount);
+            CrossFadeHelper.fadeOut(mTransformedView, 1.0f - transformationAmount,
+                    false /* remap */);
+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
+                    transformationAmount);
+            mTransformedView.setScaleX(transformationAmount);
+            mTransformedView.setScaleY(transformationAmount);
+        } else {
+            super.disappear(transformationAmount, otherView);
+        }
+    }
+
+    private static float mapToDuration(float scaleAmount) {
+        // Assuming a linear interpolator, we can easily map it to our new duration
+        scaleAmount = (scaleAmount * StackStateAnimator.ANIMATION_DURATION_STANDARD
+                - (StackStateAnimator.ANIMATION_DURATION_STANDARD - ANIMATION_DURATION_LENGTH))
+                        / ANIMATION_DURATION_LENGTH;
+        return Math.max(Math.min(scaleAmount, 1.0f), 0.0f);
+    }
+
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index f0f5c8d..770ec95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
 
 /**
@@ -357,6 +358,7 @@
 
     public int[] getLaidOutLocationOnScreen() {
         int[] location = getLocationOnScreen();
+        // remove translation
         location[0] -= mTransformedView.getTranslationX();
         location[1] -= mTransformedView.getTranslationY();
         return location;
@@ -364,6 +366,10 @@
 
     public int[] getLocationOnScreen() {
         mTransformedView.getLocationOnScreen(mOwnPosition);
+
+        // remove scale
+        mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
+        mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
         return mOwnPosition;
     }
 
@@ -371,6 +377,20 @@
         return false;
     }
 
+    public void appear(float transformationAmount, TransformableView otherView) {
+        // There's no other view, lets fade us in
+        // Certain views need to prepare the fade in and make sure its children are
+        // completely visible. An example is the notification header.
+        if (transformationAmount == 0.0f) {
+            prepareFadeIn();
+        }
+        CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
+    }
+
+    public void disappear(float transformationAmount, TransformableView otherView) {
+        CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
+    }
+
     public static TransformState createFrom(View view) {
         if (view instanceof TextView) {
             TextViewTransformState result = TextViewTransformState.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
deleted file mode 100644
index 8f689c6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-
-/**
- * An interface to start activities. This is used to as a callback from the views to
- * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
- * Keyguard.
- */
-public interface ActivityStarter {
-    void startPendingIntentDismissingKeyguard(PendingIntent intent);
-    void startActivity(Intent intent, boolean dismissShade);
-    void startActivity(Intent intent, boolean dismissShade, Callback callback);
-    void preventNextAnimation();
-
-    interface Callback {
-        void onActivityStarted(int resultCode);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
deleted file mode 100644
index 79eef43..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
+++ /dev/null
@@ -1,49 +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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.RelativeLayout;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSPanel.Callback;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-
-public abstract class BaseStatusBarHeader extends RelativeLayout implements
-        NetworkControllerImpl.EmergencyListener {
-
-    public BaseStatusBarHeader(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public abstract int getCollapsedHeight();
-    public abstract int getExpandedHeight();
-
-    public abstract void setExpanded(boolean b);
-    public abstract void setExpansion(float headerExpansionFraction);
-    public abstract void setListening(boolean listening);
-    public abstract void updateEverything();
-    public abstract void setActivityStarter(ActivityStarter activityStarter);
-    public abstract void setQSPanel(QSPanel qSPanel);
-    public abstract void setBatteryController(BatteryController batteryController);
-    public abstract void setNextAlarmController(NextAlarmController nextAlarmController);
-    public abstract void setUserInfoController(UserInfoController userInfoController);
-    public abstract void setCallback(Callback qsPanelCallback);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 95cb672..f6fe176 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,11 +14,11 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.annotation.DrawableRes;
-import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
 import android.view.View;
 
+import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
+
 import java.util.ArrayList;
 
 /**
@@ -186,18 +186,4 @@
         }
     }
 
-    /**
-     * Interface for button actions.
-     */
-    public interface ButtonInterface {
-        void setImageResource(@DrawableRes int resId);
-
-        void setImageDrawable(@Nullable Drawable drawable);
-
-        void abortCurrentGesture();
-
-        void setLandscape(boolean landscape);
-
-        void setCarMode(boolean carMode);
-    }
 }
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..d5bf499 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());
@@ -88,8 +84,8 @@
         return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
     }
 
-    public int getPulseInDuration(boolean pickup) {
-        return pickup
+    public int getPulseInDuration(boolean pickupOrDoubleTap) {
+        return pickupOrDoubleTap
                 ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
                 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
     }
@@ -118,6 +114,10 @@
         return SystemProperties.getBoolean("doze.vibrate.pickup", false);
     }
 
+    public String getDoubleTapSensorType() {
+        return mContext.getString(R.string.doze_double_tap_sensor_type);
+    }
+
     public boolean getProxCheckBeforePulse() {
         return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
     }
@@ -126,18 +126,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 +237,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/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 7d4515e..b44f5f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -109,10 +109,11 @@
 
     public void onScreenTurnedOn() {
         if (isPulsing()) {
-            final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
+            final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
+                    || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
             startScrimAnimation(true /* inFront */, 0f,
-                    mDozeParameters.getPulseInDuration(pickup),
-                    pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
+                    mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
+                    pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
                     mPulseInFinished);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 2c3e805..82867c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -16,7 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -26,6 +30,7 @@
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.LatencyTracker;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 
 /**
@@ -37,6 +42,8 @@
     private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
     private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
     private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+    private static final String ACTION_FINGERPRINT_WAKE_FAKE =
+            "com.android.systemui.ACTION_FINGERPRINT_WAKE_FAKE";
 
     /**
      * Mode in which we don't need to wake up the device when we get a fingerprint.
@@ -94,6 +101,8 @@
     private KeyguardViewMediator mKeyguardViewMediator;
     private ScrimController mScrimController;
     private PhoneStatusBar mPhoneStatusBar;
+    private final UnlockMethodCache mUnlockMethodCache;
+    private final Context mContext;
     private boolean mGoingToSleep;
     private int mPendingAuthenticatedUserId = -1;
 
@@ -102,7 +111,9 @@
             DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator,
             ScrimController scrimController,
-            PhoneStatusBar phoneStatusBar) {
+            PhoneStatusBar phoneStatusBar,
+            UnlockMethodCache unlockMethodCache) {
+        mContext = context;
         mPowerManager = context.getSystemService(PowerManager.class);
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
         mUpdateMonitor.registerCallback(this);
@@ -111,6 +122,15 @@
         mKeyguardViewMediator = keyguardViewMediator;
         mScrimController = scrimController;
         mPhoneStatusBar = phoneStatusBar;
+        mUnlockMethodCache = unlockMethodCache;
+        if (Build.IS_DEBUGGABLE) {
+            context.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    fakeWakeAndUnlock();
+                }
+            }, new IntentFilter(ACTION_FINGERPRINT_WAKE_FAKE));
+        }
     }
 
     public void setStatusBarKeyguardViewManager(
@@ -139,11 +159,20 @@
         }
     }
 
+    public void fakeWakeAndUnlock() {
+        onFingerprintAcquired();
+        onFingerprintAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
+    }
+
     @Override
     public void onFingerprintAcquired() {
         Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
         releaseFingerprintWakeLock();
         if (!mUpdateMonitor.isDeviceInteractive()) {
+            if (LatencyTracker.isEnabled(mContext)) {
+                LatencyTracker.getInstance(mContext).onActionStart(
+                        LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
+            }
             mWakeLock = mPowerManager.newWakeLock(
                     PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
             Trace.beginSection("acquiring wake-and-unlock");
@@ -263,7 +292,7 @@
                 return MODE_ONLY_WAKE;
             } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
                 return MODE_WAKE_AND_UNLOCK_PULSING;
-            } else if (unlockingAllowed) {
+            } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
                 return MODE_WAKE_AND_UNLOCK;
             } else {
                 return MODE_SHOW_BOUNCER;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 8cabfb9..4270147 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -61,6 +61,12 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.plugins.IntentButtonProvider;
+import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
+import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -85,6 +91,11 @@
     public static final String EXTRA_CAMERA_LAUNCH_SOURCE
             = "com.android.systemui.camera_launch_source";
 
+    private static final String LEFT_BUTTON_PLUGIN
+            = "com.android.systemui.action.PLUGIN_LOCKSCREEN_LEFT_BUTTON";
+    private static final String RIGHT_BUTTON_PLUGIN
+            = "com.android.systemui.action.PLUGIN_LOCKSCREEN_RIGHT_BUTTON";
+
     private static final Intent SECURE_CAMERA_INTENT =
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
                     .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -94,7 +105,7 @@
     private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
     private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
 
-    private KeyguardAffordanceView mCameraImageView;
+    private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
     private LockIcon mLockIcon;
     private TextView mIndicationText;
@@ -131,6 +142,9 @@
     private boolean mLeftIsVoiceAssist;
     private AssistManager mAssistManager;
 
+    private IntentButton mRightButton = new DefaultRightButton();
+    private IntentButton mLeftButton = new DefaultLeftButton();
+
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
     }
@@ -155,7 +169,7 @@
             String label = null;
             if (host == mLockIcon) {
                 label = getResources().getString(R.string.unlock_label);
-            } else if (host == mCameraImageView) {
+            } else if (host == mRightAffordanceView) {
                 label = getResources().getString(R.string.camera_label);
             } else if (host == mLeftAffordanceView) {
                 if (mLeftIsVoiceAssist) {
@@ -174,7 +188,7 @@
                     mPhoneStatusBar.animateCollapsePanels(
                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
                     return true;
-                } else if (host == mCameraImageView) {
+                } else if (host == mRightAffordanceView) {
                     launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
                     return true;
                 } else if (host == mLeftAffordanceView) {
@@ -191,7 +205,7 @@
         super.onFinishInflate();
         mLockPatternUtils = new LockPatternUtils(mContext);
         mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
-        mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
+        mRightAffordanceView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
         mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
         mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
         mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
@@ -206,15 +220,31 @@
         inflateCameraPreview();
         mLockIcon.setOnClickListener(this);
         mLockIcon.setOnLongClickListener(this);
-        mCameraImageView.setOnClickListener(this);
+        mRightAffordanceView.setOnClickListener(this);
         mLeftAffordanceView.setOnClickListener(this);
         initAccessibility();
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        PluginManager.getInstance(getContext()).addPluginListener(RIGHT_BUTTON_PLUGIN,
+                mRightListener, IntentButtonProvider.VERSION, false /* Only allow one */);
+        PluginManager.getInstance(getContext()).addPluginListener(LEFT_BUTTON_PLUGIN,
+                mLeftListener, IntentButtonProvider.VERSION, false /* Only allow one */);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        PluginManager.getInstance(getContext()).removePluginListener(mRightListener);
+        PluginManager.getInstance(getContext()).removePluginListener(mLeftListener);
+    }
+
     private void initAccessibility() {
         mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
         mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
-        mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
+        mRightAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
     }
 
     @Override
@@ -233,11 +263,11 @@
                 getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.text_size_small_material));
 
-        ViewGroup.LayoutParams lp = mCameraImageView.getLayoutParams();
+        ViewGroup.LayoutParams lp = mRightAffordanceView.getLayoutParams();
         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
-        mCameraImageView.setLayoutParams(lp);
-        mCameraImageView.setImageDrawable(mContext.getDrawable(R.drawable.ic_camera_alt_24dp));
+        mRightAffordanceView.setLayoutParams(lp);
+        updateRightAffordanceIcon();
 
         lp = mLockIcon.getLayoutParams();
         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
@@ -252,6 +282,13 @@
         updateLeftAffordanceIcon();
     }
 
+    private void updateRightAffordanceIcon() {
+        IconState state = mRightButton.getIcon();
+        mRightAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE);
+        mRightAffordanceView.setImageDrawable(state.drawable);
+        mRightAffordanceView.setContentDescription(state.contentDescription);
+    }
+
     public void setActivityStarter(ActivityStarter activityStarter) {
         mActivityStarter = activityStarter;
     }
@@ -278,11 +315,7 @@
     }
 
     private Intent getCameraIntent() {
-        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-        boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
-                KeyguardUpdateMonitor.getCurrentUser());
-        boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
-        return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+        return mRightButton.getIntent();
     }
 
     /**
@@ -295,33 +328,19 @@
     }
 
     private void updateCameraVisibility() {
-        if (mCameraImageView == null) {
+        if (mRightAffordanceView == null) {
             // Things are not set up yet; reply hazy, ask again later
             return;
         }
-        ResolveInfo resolved = resolveCameraIntent();
-        boolean visible = !isCameraDisabledByDpm() && resolved != null
-                && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
-                && mUserSetupComplete;
-        mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mRightAffordanceView.setVisibility(mRightButton.getIcon().isVisible
+                ? View.VISIBLE : View.GONE);
     }
 
     private void updateLeftAffordanceIcon() {
-        mLeftIsVoiceAssist = canLaunchVoiceAssist();
-        int drawableId;
-        int contentDescription;
-        boolean visible = mUserSetupComplete;
-        if (mLeftIsVoiceAssist) {
-            drawableId = R.drawable.ic_mic_26dp;
-            contentDescription = R.string.accessibility_voice_assist_button;
-        } else {
-            visible &= isPhoneVisible();
-            drawableId = R.drawable.ic_phone_24dp;
-            contentDescription = R.string.accessibility_phone_button;
-        }
-        mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE);
-        mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId));
-        mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription));
+        IconState state = mLeftButton.getIcon();
+        mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE);
+        mLeftAffordanceView.setImageDrawable(state.drawable);
+        mLeftAffordanceView.setContentDescription(state.contentDescription);
     }
 
     public boolean isLeftVoiceAssist() {
@@ -362,16 +381,16 @@
 
     @Override
     public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) {
-        mCameraImageView.setClickable(touchExplorationEnabled);
+        mRightAffordanceView.setClickable(touchExplorationEnabled);
         mLeftAffordanceView.setClickable(touchExplorationEnabled);
-        mCameraImageView.setFocusable(accessibilityEnabled);
+        mRightAffordanceView.setFocusable(accessibilityEnabled);
         mLeftAffordanceView.setFocusable(accessibilityEnabled);
         mLockIcon.update();
     }
 
     @Override
     public void onClick(View v) {
-        if (v == mCameraImageView) {
+        if (v == mRightAffordanceView) {
             launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
         } else if (v == mLeftAffordanceView) {
             launchLeftAffordance();
@@ -540,7 +559,7 @@
                 }
             });
         } else {
-            mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */);
+            mActivityStarter.startActivity(mLeftButton.getIntent(), false /* dismissShade */);
         }
     }
 
@@ -559,7 +578,7 @@
     }
 
     public KeyguardAffordanceView getRightView() {
-        return mCameraImageView;
+        return mRightAffordanceView;
     }
 
     public View getLeftPreview() {
@@ -612,7 +631,7 @@
             mLeftPreview = mPreviewInflater.inflatePreviewFromService(
                     mAssistManager.getVoiceInteractorComponentName());
         } else {
-            mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
+            mLeftPreview = mPreviewInflater.inflatePreview(mLeftButton.getIntent());
         }
         if (mLeftPreview != null) {
             mPreviewContainer.addView(mLeftPreview);
@@ -628,8 +647,8 @@
         }
         startFinishDozeAnimationElement(mLockIcon, delay);
         delay += DOZE_ANIMATION_STAGGER_DELAY;
-        if (mCameraImageView.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mCameraImageView, delay);
+        if (mRightAffordanceView.getVisibility() == View.VISIBLE) {
+            startFinishDozeAnimationElement(mRightAffordanceView, delay);
         }
         mIndicationText.setAlpha(0f);
         mIndicationText.animate()
@@ -663,46 +682,46 @@
 
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            updateCameraVisibility();
-        }
+                @Override
+                public void onUserSwitchComplete(int userId) {
+                    updateCameraVisibility();
+                }
 
-        @Override
-        public void onStartedWakingUp() {
-            mLockIcon.setDeviceInteractive(true);
-        }
+                @Override
+                public void onStartedWakingUp() {
+                    mLockIcon.setDeviceInteractive(true);
+                }
 
-        @Override
-        public void onFinishedGoingToSleep(int why) {
-            mLockIcon.setDeviceInteractive(false);
-        }
+                @Override
+                public void onFinishedGoingToSleep(int why) {
+                    mLockIcon.setDeviceInteractive(false);
+                }
 
-        @Override
-        public void onScreenTurnedOn() {
-            mLockIcon.setScreenOn(true);
-        }
+                @Override
+                public void onScreenTurnedOn() {
+                    mLockIcon.setScreenOn(true);
+                }
 
-        @Override
-        public void onScreenTurnedOff() {
-            mLockIcon.setScreenOn(false);
-        }
+                @Override
+                public void onScreenTurnedOff() {
+                    mLockIcon.setScreenOn(false);
+                }
 
-        @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            mLockIcon.update();
-        }
+                @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    mLockIcon.update();
+                }
 
-        @Override
-        public void onFingerprintRunningStateChanged(boolean running) {
-            mLockIcon.update();
-        }
+                @Override
+                public void onFingerprintRunningStateChanged(boolean running) {
+                    mLockIcon.update();
+                }
 
-        @Override
-        public void onStrongAuthStateChanged(int userId) {
-            mLockIcon.update();
-        }
-    };
+                @Override
+                public void onStrongAuthStateChanged(int userId) {
+                    mLockIcon.update();
+                }
+            };
 
     public void setKeyguardIndicationController(
             KeyguardIndicationController keyguardIndicationController) {
@@ -723,4 +742,96 @@
         updateLeftAffordance();
         inflateCameraPreview();
     }
+
+    private void setRightButton(IntentButton button) {
+        mRightButton = button;
+        updateRightAffordanceIcon();
+        updateCameraVisibility();
+        inflateCameraPreview();
+    }
+
+    private void setLeftButton(IntentButton button) {
+        mLeftButton = button;
+        mLeftIsVoiceAssist = false;
+        updateLeftAffordance();
+    }
+
+    private final PluginListener<IntentButtonProvider> mRightListener =
+            new PluginListener<IntentButtonProvider>() {
+        @Override
+        public void onPluginConnected(IntentButtonProvider plugin) {
+            setRightButton(plugin.getIntentButton());
+        }
+
+        @Override
+        public void onPluginDisconnected(IntentButtonProvider plugin) {
+            setRightButton(new DefaultRightButton());
+        }
+    };
+
+    private final PluginListener<IntentButtonProvider> mLeftListener =
+            new PluginListener<IntentButtonProvider>() {
+        @Override
+        public void onPluginConnected(IntentButtonProvider plugin) {
+            setLeftButton(plugin.getIntentButton());
+        }
+
+        @Override
+        public void onPluginDisconnected(IntentButtonProvider plugin) {
+            setLeftButton(new DefaultLeftButton());
+        }
+    };
+
+    private class DefaultLeftButton implements IntentButton {
+
+        private IconState mIconState = new IconState();
+
+        @Override
+        public IconState getIcon() {
+            mLeftIsVoiceAssist = canLaunchVoiceAssist();
+            if (mLeftIsVoiceAssist) {
+                mIconState.isVisible = mUserSetupComplete;
+                mIconState.drawable = mContext.getDrawable(R.drawable.ic_mic_26dp);
+                mIconState.contentDescription = mContext.getString(
+                        R.string.accessibility_voice_assist_button);
+            } else {
+                mIconState.isVisible = mUserSetupComplete && isPhoneVisible();
+                mIconState.drawable = mContext.getDrawable(R.drawable.ic_phone_24dp);
+                mIconState.contentDescription = mContext.getString(
+                        R.string.accessibility_phone_button);
+            }
+            return mIconState;
+        }
+
+        @Override
+        public Intent getIntent() {
+            return PHONE_INTENT;
+        }
+    }
+
+    private class DefaultRightButton implements IntentButton {
+
+        private IconState mIconState = new IconState();
+
+        @Override
+        public IconState getIcon() {
+            ResolveInfo resolved = resolveCameraIntent();
+            mIconState.isVisible = !isCameraDisabledByDpm() && resolved != null
+                    && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
+                    && mUserSetupComplete;
+            mIconState.drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp);
+            mIconState.contentDescription =
+                    mContext.getString(R.string.accessibility_camera_button);
+            return mIconState;
+        }
+
+        @Override
+        public Intent getIntent() {
+            KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+            boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
+                    KeyguardUpdateMonitor.getCurrentUser());
+            boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+            return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index d4f98c3..d94def9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -308,6 +308,7 @@
         super.setVisibility(visibility);
         if (visibility != View.VISIBLE) {
             mSystemIconsSuperContainer.animate().cancel();
+            mSystemIconsSuperContainer.setTranslationX(0);
             mMultiUserSwitch.animate().cancel();
             mMultiUserSwitch.setAlpha(1f);
         } else {
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/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 0de06c9..af9454c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.ContactsContract;
 import android.text.TextUtils;
@@ -31,8 +30,8 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
@@ -183,7 +182,7 @@
         return false;
     }
 
-    protected QSTile.DetailAdapter getUserDetailAdapter() {
+    protected DetailAdapter getUserDetailAdapter() {
         return mUserSwitcherController.userDetailAdapter;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 06c8b68..c420927 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -28,12 +28,19 @@
 import android.widget.Space;
 
 import com.android.systemui.R;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider;
 import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
-public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
+public class NavigationBarInflaterView extends FrameLayout
+        implements Tunable, PluginListener<NavBarButtonProvider> {
 
     private static final String TAG = "NavBarInflater";
 
@@ -57,6 +64,8 @@
     public static final String KEY_IMAGE_DELIM = ":";
     public static final String KEY_CODE_END = ")";
 
+    private final List<NavBarButtonProvider> mPlugins = new ArrayList<>();
+
     protected LayoutInflater mLayoutInflater;
     protected LayoutInflater mLandscapeInflater;
     private int mDensity;
@@ -129,6 +138,8 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+        PluginManager.getInstance(getContext()).addPluginListener(NavBarButtonProvider.ACTION, this,
+                NavBarButtonProvider.VERSION, true /* Allow multiple */);
     }
 
     @Override
@@ -240,8 +251,36 @@
             int indexInParent) {
         LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
         float size = extractSize(buttonSpec);
-        String button = extractButton(buttonSpec);
+        View v = createView(buttonSpec, parent, inflater, landscape);
+        if (v == null) return null;
+
+        if (size != 0) {
+            ViewGroup.LayoutParams params = v.getLayoutParams();
+            params.width = (int) (params.width * size);
+        }
+        parent.addView(v);
+        addToDispatchers(v, landscape);
+        View lastView = landscape ? mLastRot90 : mLastRot0;
+        if (lastView != null) {
+            v.setAccessibilityTraversalAfter(lastView.getId());
+        }
+        if (landscape) {
+            mLastRot90 = v;
+        } else {
+            mLastRot0 = v;
+        }
+        return v;
+    }
+
+    private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater,
+            boolean landscape) {
         View v = null;
+        String button = extractButton(buttonSpec);
+        // Let plugins go first so they can override a standard view if they want.
+        for (NavBarButtonProvider provider : mPlugins) {
+            v = provider.createView(buttonSpec, parent);
+            if (v != null) return v;
+        }
         if (HOME.equals(button)) {
             v = inflater.inflate(R.layout.home, parent, false);
             if (landscape && isSw600Dp()) {
@@ -271,24 +310,6 @@
             if (uri != null) {
                 ((KeyButtonView) v).loadAsync(uri);
             }
-        } else {
-            return null;
-        }
-
-        if (size != 0) {
-            ViewGroup.LayoutParams params = v.getLayoutParams();
-            params.width = (int) (params.width * size);
-        }
-        parent.addView(v);
-        addToDispatchers(v, landscape);
-        View lastView = landscape ? mLastRot90 : mLastRot0;
-        if (lastView != null) {
-            v.setAccessibilityTraversalAfter(lastView.getId());
-        }
-        if (landscape) {
-            mLastRot90 = v;
-        } else {
-            mLastRot0 = v;
         }
         return v;
     }
@@ -374,4 +395,18 @@
             ((ViewGroup) group.getChildAt(i)).removeAllViews();
         }
     }
+
+    @Override
+    public void onPluginConnected(NavBarButtonProvider plugin) {
+        mPlugins.add(plugin);
+        clearViews();
+        inflateLayout(mCurrentLayout);
+    }
+
+    @Override
+    public void onPluginDisconnected(NavBarButtonProvider plugin) {
+        mPlugins.remove(plugin);
+        clearViews();
+        inflateLayout(mCurrentLayout);
+    }
 }
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..3a0eb94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -43,6 +43,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
@@ -52,13 +53,15 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public class NavigationBarView extends LinearLayout {
+public class NavigationBarView extends FrameLayout {
     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;
 
+    final static boolean ALTERNATE_CAR_MODE_UI = false;
+
     final Display mDisplay;
     View mCurrentView = null;
     View[] mRotatedViews = new View[4];
@@ -94,7 +97,8 @@
     private OnVerticalChangedListener mOnVerticalChangedListener;
     private boolean mLayoutTransitionsEnabled = true;
     private boolean mWakeAndUnlocking;
-    private boolean mCarMode = false;
+    private boolean mUseCarModeUi = false;
+    private boolean mInCarMode = false;
     private boolean mDockedStackExists;
 
     private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
@@ -290,7 +294,9 @@
             mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
             mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
 
-            updateCarModeIcons(ctx);
+            if (ALTERNATE_CAR_MODE_UI) {
+                updateCarModeIcons(ctx);
+            }
         }
     }
 
@@ -341,14 +347,14 @@
         // carmode, respectively. Recents are not available in CarMode in nav bar so change
         // to recent icon is not required.
         Drawable backIcon = (backAlt)
-                ? getBackIconWithAlt(mCarMode, mVertical)
-                : getBackIcon(mCarMode, mVertical);
+                ? getBackIconWithAlt(mUseCarModeUi, mVertical)
+                : getBackIcon(mUseCarModeUi, mVertical);
 
         getBackButton().setImageDrawable(backIcon);
 
         updateRecentsIcon();
 
-        if (mCarMode) {
+        if (mUseCarModeUi) {
             getHomeButton().setImageDrawable(mHomeCarModeIcon);
         } else {
             getHomeButton().setImageDrawable(mHomeDefaultIcon);
@@ -376,9 +382,9 @@
 
         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
 
-        // Disable recents always in car mode.
-        boolean disableRecent = (
-                mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
+        // Always disable recents when alternate car mode UI is active.
+        boolean disableRecent = mUseCarModeUi
+                        || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
@@ -527,8 +533,8 @@
         updateCurrentView();
     }
 
-    public boolean needsReorient() {
-        return mCurrentRotation != mDisplay.getRotation();
+    public boolean needsReorient(int rotation) {
+        return mCurrentRotation != rotation;
     }
 
     private void updateCurrentView() {
@@ -567,7 +573,7 @@
         setMenuVisibility(mShowMenu, true /* force */);
 
         if (DEBUG) {
-            Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
+            Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
         }
 
         updateTaskSwitchHelper();
@@ -626,14 +632,19 @@
         boolean uiCarModeChanged = false;
         if (newConfig != null) {
             int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
-            if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
-                mCarMode = false;
-                uiCarModeChanged = true;
-                getHomeButton().setCarMode(mCarMode);
-            } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
-                mCarMode = true;
-                uiCarModeChanged = true;
-                getHomeButton().setCarMode(mCarMode);
+            final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
+
+            if (isCarMode != mInCarMode) {
+                mInCarMode = isCarMode;
+                getHomeButton().setCarMode(isCarMode);
+
+                if (ALTERNATE_CAR_MODE_UI) {
+                    mUseCarModeUi = isCarMode;
+                    uiCarModeChanged = true;
+                } else {
+                    // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
+                    mUseCarModeUi = false;
+                }
             }
         }
         return uiCarModeChanged;
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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 812c5c1..fb2c335 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -50,7 +50,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.qs.QSContainer;
+import com.android.systemui.plugins.qs.QSContainer;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -70,7 +70,7 @@
         ExpandableView.OnHeightChangedListener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
-        HeadsUpManager.OnHeadsUpChangedListener {
+        HeadsUpManager.OnHeadsUpChangedListener, QSContainer.HeightListener {
 
     private static final boolean DEBUG = false;
 
@@ -242,7 +242,7 @@
             public void onInflated(View v) {
                 mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
                 mQsContainer.setPanelView(NotificationPanelView.this);
-                mQsContainer.getHeader().findViewById(R.id.expand_indicator)
+                mQsContainer.getHeader().getExpandView()
                         .setOnClickListener(NotificationPanelView.this);
 
                 // recompute internal state when qspanel height changes
@@ -328,7 +328,7 @@
         } else if (!mQsExpanded) {
             setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
         }
-        updateStackHeight(getExpandedHeight());
+        updateExpandedHeight(getExpandedHeight());
         updateHeader();
 
         // If we are running a size change animation, the animation takes care of the height of
@@ -376,10 +376,7 @@
         boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         if (mStatusBarState != StatusBarState.KEYGUARD) {
-            int bottom = mQsContainer.getHeader().getHeight();
-            stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
-                    ? bottom + mQsPeekHeight
-                    : mKeyguardStatusBar.getHeight();
+            stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
             mTopPaddingAdjustment = 0;
         } else {
             mClockPositionAlgorithm.setup(
@@ -1166,6 +1163,7 @@
 
     private void updateQsState() {
         mQsContainer.setExpanded(mQsExpanded);
+        mNotificationStackScroller.setQsExpanded(mQsExpanded);
         mNotificationStackScroller.setScrollingEnabled(
                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
                         || mQsExpansionFromOverscroll));
@@ -1427,7 +1425,7 @@
             setQsExpansion(mQsMinExpansionHeight
                     + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
         }
-        updateStackHeight(expandedHeight);
+        updateExpandedHeight(expandedHeight);
         updateHeader();
         updateUnlockIcon();
         updateNotificationTranslucency();
@@ -1487,7 +1485,7 @@
                 maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
                         ? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
                         : 0)
-                + notificationHeight;
+                + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
         if (totalHeight > mNotificationStackScroller.getHeight()) {
             float fullyCollapsedHeight = maxQsHeight
                     + mNotificationStackScroller.getLayoutMinHeight();
@@ -1730,6 +1728,14 @@
         if (view == null && mQsExpanded) {
             return;
         }
+        ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
+        ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
+                ? (ExpandableNotificationRow) firstChildNotGone
+                : null;
+        if (firstRow != null
+                && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
+            requestScrollerTopPaddingUpdate(false);
+        }
         requestPanelHeightUpdate();
     }
 
@@ -2011,7 +2017,7 @@
     }
 
     public void closeQsDetail() {
-        mQsContainer.getQsPanel().closeDetail();
+        mQsContainer.closeDetail();
     }
 
     @Override
@@ -2249,8 +2255,8 @@
         mQsAutoReinflateContainer.setTranslationX(translation);
     }
 
-    protected void updateStackHeight(float stackHeight) {
-        mNotificationStackScroller.setStackHeight(stackHeight);
+    protected void updateExpandedHeight(float expandedHeight) {
+        mNotificationStackScroller.setExpandedHeight(expandedHeight);
         updateKeyguardBottomAreaAlpha();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 36e59db..8b1fcd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,10 +24,10 @@
 import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
+
 import com.android.systemui.AutoReinflateContainer;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSContainer;
-import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.plugins.qs.QSContainer;
 
 /**
  * The container with notification stack scroller and quick settings inside.
@@ -130,8 +130,8 @@
 
     @Override
     public void onInflated(View v) {
-        QSCustomizer customizer = ((QSContainer) v).getCustomizer();
-        customizer.setContainer(this);
+        QSContainer container = (QSContainer) v;
+        container.setContainer(this);
     }
 
     public void setQsExpanded(boolean expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index af85101..c6aec73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -32,9 +33,11 @@
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
+import com.android.systemui.DejankUtils;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
+import com.android.systemui.LatencyTracker;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeLog;
@@ -92,6 +95,7 @@
      * Whether an instant expand request is currently pending and we are just waiting for layout.
      */
     private boolean mInstantExpanding;
+    private boolean mAnimateAfterExpanding;
 
     PanelBar mBar;
 
@@ -114,6 +118,7 @@
     protected boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
     private boolean mIgnoreXTouchSlop;
+    private boolean mExpandLatencyTracking;
     private Runnable mPeekRunnable = new Runnable() {
         @Override
         public void run() {
@@ -214,6 +219,14 @@
         }
     }
 
+    public void startExpandLatencyTracking() {
+        if (LatencyTracker.isEnabled(mContext)) {
+            LatencyTracker.getInstance(mContext).onActionStart(
+                    LatencyTracker.ACTION_EXPAND_PANEL);
+            mExpandLatencyTracking = true;
+        }
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mInstantExpanding || mTouchDisabled
@@ -656,7 +669,7 @@
                 vel = 0;
             }
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
-            if (expandBecauseOfFalsing) {
+            if (vel == 0) {
                 animator.setDuration(350);
             }
         } else {
@@ -738,6 +751,11 @@
     }
 
     public void setExpandedHeightInternal(float h) {
+        if (mExpandLatencyTracking && h != 0f) {
+            DejankUtils.postAfterTraversal(() -> LatencyTracker.getInstance(mContext).onActionEnd(
+                    LatencyTracker.ACTION_EXPAND_PANEL));
+            mExpandLatencyTracking = false;
+        }
         float fhWithoutOverExpansion = getMaxPanelHeight() - getOverExpansionAmount();
         if (mHeightAnimator == null) {
             float overExpansionPixels = Math.max(0, h - fhWithoutOverExpansion);
@@ -870,6 +888,7 @@
         }
 
         mInstantExpanding = true;
+        mAnimateAfterExpanding = animate;
         mUpdateFlingOnLayout = false;
         abortAnimations();
         cancelPeek();
@@ -894,7 +913,7 @@
                         if (mStatusBar.getStatusBarWindow().getHeight()
                                 != mStatusBar.getStatusBarHeight()) {
                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                            if (animate) {
+                            if (mAnimateAfterExpanding) {
                                 notifyExpandingStarted();
                                 fling(0, true /* expand */);
                             } else {
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..a442fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -37,6 +37,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -65,7 +66,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 +100,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;
@@ -132,6 +133,7 @@
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
+import com.android.systemui.LatencyTracker;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
@@ -140,7 +142,10 @@
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.qs.QSContainer;
+import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
+import com.android.systemui.plugins.qs.QSContainer;
+import com.android.systemui.qs.QSContainerImpl;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.recents.events.EventBus;
@@ -174,12 +179,14 @@
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.EncryptionHelper;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.PreviewInflater;
@@ -207,7 +214,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;
@@ -279,6 +286,14 @@
      */
     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
 
+    /**
+     * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
+     * won't draw anything and uninitialized memory will show through
+     * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
+     * libhwui.
+     */
+    private static final float SRC_MIN_ALPHA = 0.002f;
+
     static {
         boolean onlyCoreApps;
         boolean freeformWindowManagement;
@@ -299,7 +314,7 @@
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
-    BluetoothControllerImpl mBluetoothController;
+    protected BluetoothControllerImpl mBluetoothController;
     SecurityControllerImpl mSecurityController;
     protected BatteryController mBatteryController;
     LocationControllerImpl mLocationController;
@@ -657,6 +672,15 @@
     private boolean mNoAnimationOnNextBarModeChange;
     private FalsingManager mFalsingManager;
 
+    private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onDreamingStateChanged(boolean dreaming) {
+            if (dreaming) {
+                maybeEscalateHeadsUp();
+            }
+        }
+    };
+
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -694,10 +718,8 @@
         mUnlockMethodCache.addListener(this);
         startKeyguard();
 
-        mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, null);
-
+        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
         mDozeServiceHost = new DozeServiceHost();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
         putComponent(DozeHost.class, mDozeServiceHost);
         putComponent(PhoneStatusBar.class, this);
 
@@ -881,6 +903,7 @@
 
         initSignalCluster(mStatusBarView);
         initSignalCluster(mKeyguardStatusBar);
+        initEmergencyCryptkeeperText();
 
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
@@ -914,10 +937,12 @@
                 public void onInflated(View v) {
                     QSContainer qsContainer = (QSContainer) v.findViewById(
                             R.id.quick_settings_container);
-                    qsContainer.setHost(qsh);
-                    mQSPanel = qsContainer.getQsPanel();
-                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-                    mKeyguardStatusBar.setQSPanel(mQSPanel);
+                    if (qsContainer instanceof QSContainerImpl) {
+                        ((QSContainerImpl) qsContainer).setHost(qsh);
+                        mQSPanel = ((QSContainerImpl) qsContainer).getQsPanel();
+                        mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+                        mKeyguardStatusBar.setQSPanel(mQSPanel);
+                    }
                     mHeader = qsContainer.getHeader();
                     initSignalCluster(mHeader);
                     mHeader.setActivityStarter(PhoneStatusBar.this);
@@ -998,6 +1023,24 @@
         return mStatusBarView;
     }
 
+    private void initEmergencyCryptkeeperText() {
+        View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
+        if (mNetworkController.hasEmergencyCryptKeeperText()) {
+            if (emergencyViewStub != null) {
+                ((ViewStub) emergencyViewStub).inflate();
+            }
+            mNetworkController.addSignalCallback(new NetworkController.SignalCallback() {
+                @Override
+                public void setIsAirplaneMode(NetworkController.IconState icon) {
+                    recomputeDisableFlags(true /* animate */);
+                }
+            });
+        } else if (emergencyViewStub != null) {
+            ViewGroup parent = (ViewGroup) emergencyViewStub.getParent();
+            parent.removeView(emergencyViewStub);
+        }
+    }
+
     protected BatteryController createBatteryController() {
         return new BatteryControllerImpl(mContext);
     }
@@ -1226,7 +1269,7 @@
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
                 mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
-                mScrimController, this);
+                mScrimController, this, UnlockMethodCache.getInstance(mContext));
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mStatusBarWindowManager, mScrimController,
                 mFingerprintUnlockController);
@@ -1285,6 +1328,10 @@
     private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
+            if (LatencyTracker.isEnabled(mContext)) {
+                LatencyTracker.getInstance(mContext).onActionStart(
+                        LatencyTracker.ACTION_TOGGLE_RECENTS);
+            }
             awakenDreams();
             toggleRecentApps();
         }
@@ -1415,6 +1462,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());
@@ -1595,7 +1663,8 @@
         }
         Entry entry = mNotificationData.get(key);
 
-        if (entry != null && mRemoteInputController.isRemoteInputActive(entry)) {
+        if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
+                && (entry.row != null && !entry.row.isDismissed())) {
             mLatestRankingMap = ranking;
             mRemoteInputEntriesToRemoveOnCollapse.add(entry);
             return;
@@ -1665,7 +1734,7 @@
     protected void performRemoveNotification(StatusBarNotification n, boolean removeView) {
         Entry entry = mNotificationData.get(n.getKey());
         if (mRemoteInputController.isRemoteInputActive(entry)) {
-            mRemoteInputController.removeRemoteInput(entry);
+            mRemoteInputController.removeRemoteInput(entry, null);
         }
         super.performRemoveNotification(n, removeView);
     }
@@ -1697,18 +1766,21 @@
         for (int i=0; i<N; i++) {
             Entry ent = activeNotifications.get(i);
             int vis = ent.notification.getNotification().visibility;
+            int userId = ent.notification.getUserId();
 
             // Display public version of the notification if we need to redact.
-            final boolean hideSensitive =
-                    !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+            boolean deviceSensitive = (isLockscreenPublicMode(mCurrentUserId)
+                    && !userAllowsPrivateNotificationsInPublic(mCurrentUserId));
+            boolean userSensitive = deviceSensitive || (isLockscreenPublicMode(userId)
+                    && !userAllowsPrivateNotificationsInPublic(userId));
             boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
             boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
-            boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
-            boolean showingPublic = sensitive && isLockscreenPublicMode();
+            boolean sensitive = (sensitiveNote && userSensitive) || sensitivePackage;
+            boolean showingPublic = sensitive && isLockscreenPublicMode(userId);
             if (showingPublic) {
                 updatePublicContentView(ent, ent.notification);
             }
-            ent.row.setSensitive(sensitive, hideSensitive);
+            ent.row.setSensitive(sensitive, deviceSensitive);
             if (ent.autoRedacted && ent.legacy) {
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
                 // for legacy auto redacted notifications.
@@ -2193,17 +2265,13 @@
             if (mBackdrop.getVisibility() != View.VISIBLE) {
                 mBackdrop.setVisibility(View.VISIBLE);
                 if (allowEnterAnimation) {
-                    mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mStatusBarWindowManager.setBackdropShowing(true);
-                        }
-                    });
+                    mBackdrop.setAlpha(SRC_MIN_ALPHA);
+                    mBackdrop.animate().alpha(1f);
                 } else {
                     mBackdrop.animate().cancel();
                     mBackdrop.setAlpha(1f);
-                    mStatusBarWindowManager.setBackdropShowing(true);
                 }
+                mStatusBarWindowManager.setBackdropShowing(true);
                 metaDataChanged = true;
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
@@ -2266,11 +2334,7 @@
                 } else {
                     mStatusBarWindowManager.setBackdropShowing(false);
                     mBackdrop.animate()
-                            // Never let the alpha become zero - otherwise the RenderNode
-                            // won't draw anything and uninitialized memory will show through
-                            // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
-                            // libhwui.
-                            .alpha(0.002f)
+                            .alpha(SRC_MIN_ALPHA)
                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
                             .setDuration(300)
                             .setStartDelay(0)
@@ -2285,7 +2349,6 @@
                             });
                     if (mKeyguardFadingAway) {
                         mBackdrop.animate()
-
                                 // Make it disappear faster, as the focus should be on the activity
                                 // behind.
                                 .setDuration(mKeyguardFadingAwayDuration / 2)
@@ -2313,6 +2376,14 @@
             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
         }
+        if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
+            if (mNetworkController.hasEmergencyCryptKeeperText()) {
+                state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+            }
+            if (!mNetworkController.isRadioOn()) {
+                state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+            }
+        }
         return state;
     }
 
@@ -2417,6 +2488,15 @@
         }
     }
 
+    /**
+     * Reapplies the disable flags as last requested by StatusBarManager.
+     *
+     * This needs to be called if state used by {@link #adjustDisableFlags} changes.
+     */
+    private void recomputeDisableFlags(boolean animate) {
+        disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
+    }
+
     @Override
     protected BaseStatusBar.H createHandler() {
         return new PhoneStatusBar.H();
@@ -2520,6 +2600,7 @@
                             mStatusBarWindowManager.setHeadsUpShowing(false);
                             mHeadsUpManager.setHeadsUpGoingAway(false);
                         }
+                        removeRemoteInputEntriesKeptUntilCollapsed();
                     }
                 });
             }
@@ -2604,7 +2685,7 @@
     private void removeRemoteInputEntriesKeptUntilCollapsed() {
         for (int i = 0; i < mRemoteInputEntriesToRemoveOnCollapse.size(); i++) {
             Entry entry = mRemoteInputEntriesToRemoveOnCollapse.valueAt(i);
-            mRemoteInputController.removeRemoteInput(entry);
+            mRemoteInputController.removeRemoteInput(entry, null);
             removeNotification(entry.key, mLatestRankingMap);
         }
         mRemoteInputEntriesToRemoveOnCollapse.clear();
@@ -2709,7 +2790,7 @@
 
         visibilityChanged(true);
         mWaitingForKeyguardExit = false;
-        disable(mDisabledUnmodified1, mDisabledUnmodified2, !force /* animate */);
+        recomputeDisableFlags(!force /* animate */);
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
     }
 
@@ -2851,7 +2932,7 @@
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
         showBouncer();
-        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
+        recomputeDisableFlags(true /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
         // the bouncer appear animation.
@@ -2969,10 +3050,6 @@
                 Integer.toHexString(diff)));
         boolean sbModeChanged = false;
         if (diff != 0) {
-            // we never set the recents bit via this method, so save the prior state to prevent
-            // clobbering the bit below
-            final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
-
             mSystemUiVisibility = newVal;
 
             // update low profile
@@ -3021,11 +3098,6 @@
                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
             }
 
-            // restore the recents bit
-            if (wasRecentsVisible) {
-                mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
-            }
-
             // send updated sysui visibility to window manager
             notifyUiVisibilityChanged(mSystemUiVisibility);
         }
@@ -3599,22 +3671,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);
@@ -4135,6 +4191,15 @@
     }
 
     /**
+     * Plays the animation when an activity that was occluding Keyguard goes away.
+     */
+    public void animateKeyguardUnoccluding() {
+        mScrimController.animateKeyguardUnoccluding(500);
+        mNotificationPanel.setExpandedFraction(0f);
+        animateExpandNotificationsPanel();
+    }
+
+    /**
      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
      * because the launched app crashed or something else went wrong.
@@ -4252,7 +4317,7 @@
                 startTime + fadeoutDuration
                         - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
                 StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
-        disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */);
+        recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
     }
 
     public boolean isKeyguardFadingAway() {
@@ -4272,17 +4337,23 @@
     }
 
     private void updatePublicMode() {
-        boolean isPublic = false;
-        if (mStatusBarKeyguardViewManager.isShowing()) {
-            for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
-                UserInfo userInfo = mCurrentProfiles.valueAt(i);
-                if (mStatusBarKeyguardViewManager.isSecure(userInfo.id)) {
-                    isPublic = true;
-                    break;
+        final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
+        final boolean devicePublic = showingKeyguard
+                && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
+
+        // Look for public mode users. Users are considered public in either case of:
+        //   - device keyguard is shown in secure mode;
+        //   - profile is locked with a work challenge.
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            final int userId = mCurrentProfiles.valueAt(i).id;
+            boolean isProfilePublic = devicePublic;
+            if (!devicePublic && userId != mCurrentUserId) {
+                if (mStatusBarKeyguardViewManager.isSecure(userId)) {
+                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
                 }
             }
+            setLockscreenPublicMode(isProfilePublic, userId);
         }
-        setLockscreenPublicMode(isPublic);
     }
 
     protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -4339,7 +4410,8 @@
     public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
         if (mStackScroller == null) return;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
-        mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
+        boolean publicMode = isAnyProfilePublicMode();
+        mStackScroller.setHideSensitive(publicMode, goingToFullShade);
         mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
         mStackScroller.setExpandingEnabled(!onKeyguard);
         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
@@ -4456,6 +4528,7 @@
         }
         if (state == StatusBarState.KEYGUARD) {
             removeRemoteInputEntriesKeptUntilCollapsed();
+            maybeEscalateHeadsUp();
         }
         mState = state;
         mGroupManager.setStatusBarState(state);
@@ -4588,6 +4661,7 @@
      * @param expandView The view to expand after going to the shade.
      */
     public void goToLockedShade(View expandView) {
+        int userId = mCurrentUserId;
         ExpandableNotificationRow row = null;
         if (expandView instanceof ExpandableNotificationRow) {
             row = (ExpandableNotificationRow) expandView;
@@ -4595,10 +4669,13 @@
             // Indicate that the group expansion is changing at this time -- this way the group
             // and children backgrounds / divider animations will look correct.
             row.setGroupExpansionChanging(true);
+            if (row.getStatusBarNotification() != null) {
+                userId = row.getStatusBarNotification().getUserId();
+            }
         }
         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
                 || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
-        if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
+        if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
             mDraggedDownRow = row;
@@ -4643,52 +4720,65 @@
         mPendingWorkRemoteInputView = clicked;
     }
 
+    private boolean isAnyProfilePublicMode() {
+        for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+            if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
-    protected void onWorkChallengeUnlocked() {
-        if (mPendingWorkRemoteInputView != null) {
-            final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+    protected void onWorkChallengeChanged() {
+        updatePublicMode();
+        updateNotifications();
+        if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
             // Expand notification panel and the notification row, then click on remote input view
             final Runnable clickPendingViewRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    if (mPendingWorkRemoteInputView != null) {
-                        final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
-                        ViewParent p = pendingWorkRemoteInputView.getParent();
-                        while (p != null) {
-                            if (p instanceof ExpandableNotificationRow) {
-                                final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
-                                ViewParent viewParent = row.getParent();
-                                if (viewParent instanceof NotificationStackScrollLayout) {
-                                    final NotificationStackScrollLayout scrollLayout =
-                                            (NotificationStackScrollLayout) viewParent;
-                                    row.makeActionsVisibile();
-                                    row.post(new Runnable() {
-                                        @Override
-                                        public void run() {
-                                            final Runnable finishScrollingCallback = new Runnable()
-                                            {
-                                                @Override
-                                                public void run() {
-                                                    mPendingWorkRemoteInputView.callOnClick();
-                                                    mPendingWorkRemoteInputView = null;
-                                                    scrollLayout.setFinishScrollingCallback(null);
-                                                }
-                                            };
-                                            if (scrollLayout.scrollTo(row)) {
-                                                // It scrolls! So call it when it's finished.
-                                                scrollLayout.setFinishScrollingCallback(
-                                                        finishScrollingCallback);
-                                            } else {
-                                                // It does not scroll, so call it now!
-                                                finishScrollingCallback.run();
-                                            }
-                                        }
-                                    });
-                                }
-                                break;
-                            }
-                            p = p.getParent();
+                    final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+                    if (pendingWorkRemoteInputView == null) {
+                        return;
+                    }
+
+                    // Climb up the hierarchy until we get to the container for this row.
+                    ViewParent p = pendingWorkRemoteInputView.getParent();
+                    while (!(p instanceof ExpandableNotificationRow)) {
+                        if (p == null) {
+                            return;
                         }
+                        p = p.getParent();
+                    }
+
+                    final ExpandableNotificationRow row = (ExpandableNotificationRow) p;
+                    ViewParent viewParent = row.getParent();
+                    if (viewParent instanceof NotificationStackScrollLayout) {
+                        final NotificationStackScrollLayout scrollLayout =
+                                (NotificationStackScrollLayout) viewParent;
+                        row.makeActionsVisibile();
+                        row.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                final Runnable finishScrollingCallback = new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        mPendingWorkRemoteInputView.callOnClick();
+                                        mPendingWorkRemoteInputView = null;
+                                        scrollLayout.setFinishScrollingCallback(null);
+                                    }
+                                };
+                                if (scrollLayout.scrollTo(row)) {
+                                    // It scrolls! So call it when it's finished.
+                                    scrollLayout.setFinishScrollingCallback(
+                                            finishScrollingCallback);
+                                } else {
+                                    // It does not scroll, so call it now!
+                                    finishScrollingCallback.run();
+                                }
+                            }
+                        });
                     }
                 }
             };
@@ -4740,7 +4830,7 @@
     public void setBouncerShowing(boolean bouncerShowing) {
         super.setBouncerShowing(bouncerShowing);
         mStatusBarView.setBouncerShowing(bouncerShowing);
-        disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
+        recomputeDisableFlags(true /* animate */);
     }
 
     public void onStartedGoingToSleep() {
@@ -4817,16 +4907,6 @@
         return false;
     }
 
-    public void updateRecentsVisibility(boolean visible) {
-        // Update the recents visibility flag
-        if (visible) {
-            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
-        } else {
-            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
-        }
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-    }
-
     @Override
     public void showScreenPinningRequest(int taskId) {
         if (mKeyguardMonitor.isShowing()) {
@@ -4975,7 +5055,7 @@
         }
     }
 
-    private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost  {
+    private final class DozeServiceHost implements DozeHost {
         // Amount of time to allow to update the time shown on the screen before releasing
         // the wakelock.  This timeout is design to compensate for the fact that we don't
         // currently have a way to know when time display contents have actually been
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 10facea..da698d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -86,7 +86,7 @@
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final String TILES_SETTING = "sysui_qs_tiles";
+    public static final String TILES_SETTING = Secure.QS_TILES;
 
     private final Context mContext;
     private final PhoneStatusBar mStatusBar;
@@ -407,19 +407,7 @@
                         new UserHandle(ActivityManager.getCurrentUser()));
                 lifecycleManager.onStopListening();
                 lifecycleManager.onTileRemoved();
-                lifecycleManager.flushMessagesAndUnbind();
-            }
-        }
-        for (int i = 0; i < NA; i++) {
-            String tileSpec = newTiles.get(i);
-            if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
-            if (!previousTiles.contains(tileSpec)) {
-                ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
-                Intent intent = new Intent().setComponent(component);
-                TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
-                        mContext, mServices, new Tile(), intent,
-                        new UserHandle(ActivityManager.getCurrentUser()));
-                lifecycleManager.onTileAdded();
+                TileLifecycleManager.setTileAdded(mContext, component, false);
                 lifecycleManager.flushMessagesAndUnbind();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 3ad09d1..b0b86be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -37,12 +37,15 @@
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
+import com.android.systemui.plugins.qs.QSContainer.BaseStatusBarHeader;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSPanel.Callback;
+import com.android.systemui.plugins.qs.QSContainer.Callback;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -50,7 +53,7 @@
 import com.android.systemui.tuner.TunerService;
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
-        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener {
+        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener {
 
     private static final String TAG = "QuickStatusBarHeader";
 
@@ -255,6 +258,11 @@
     }
 
     @Override
+    public View getExpandView() {
+        return findViewById(R.id.expand_indicator);
+    }
+
+    @Override
     public void updateEverything() {
         post(() -> {
             updateVisibilities();
@@ -293,7 +301,6 @@
         mActivityStarter = activityStarter;
     }
 
-    @Override
     public void setQSPanel(final QSPanel qsPanel) {
         mQsPanel = qsPanel;
         setupHost(qsPanel.getHost());
@@ -354,17 +361,14 @@
                 true /* dismissShade */);
     }
 
-    @Override
     public void setNextAlarmController(NextAlarmController nextAlarmController) {
         mNextAlarmController = nextAlarmController;
     }
 
-    @Override
     public void setBatteryController(BatteryController batteryController) {
         // Don't care
     }
 
-    @Override
     public void setUserInfoController(UserInfoController userInfoController) {
         userInfoController.addListener(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 40abaa4..a4b76ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -165,7 +165,7 @@
         mSkipFirstFrame = skipFirstFrame;
         mOnAnimationFinished = onAnimationFinished;
 
-        if (mKeyguardUpdateMonitor.isUserUnlocked()) {
+        if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
             scheduleUpdate();
 
             // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
@@ -185,6 +185,14 @@
         }
     }
 
+    public void animateKeyguardUnoccluding(long duration) {
+        mAnimateChange = false;
+        setScrimBehindColor(0f);
+        mAnimateChange = true;
+        scheduleUpdate();
+        mDurationOverride = duration;
+    }
+
     public void animateGoingToFullShade(long delay, long duration) {
         mDurationOverride = duration;
         mAnimationDelay = delay;
@@ -222,9 +230,9 @@
     }
 
     private float getScrimInFrontAlpha() {
-        return mKeyguardUpdateMonitor.isUserUnlocked()
-                ? SCRIM_IN_FRONT_ALPHA
-                : SCRIM_IN_FRONT_ALPHA_LOCKED;
+        return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
+                ? SCRIM_IN_FRONT_ALPHA_LOCKED
+                : SCRIM_IN_FRONT_ALPHA;
     }
 
     protected void scheduleUpdate() {
@@ -392,7 +400,7 @@
     }
 
     protected Interpolator getInterpolator() {
-        if (mAnimateKeyguardFadingOut && !mKeyguardUpdateMonitor.isUserUnlocked()) {
+        if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
             return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
         } else if (mAnimateKeyguardFadingOut) {
             return KEYGUARD_FADE_OUT_INTERPOLATOR;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 285b9bc..01609e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -30,11 +30,14 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.DejankUtils;
+import com.android.systemui.LatencyTracker;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.RemoteInputController;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.systemui.statusbar.phone.FingerprintUnlockController.*;
 
 /**
  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -242,7 +245,7 @@
         return mStatusBarWindowManager.isShowingWallpaper();
     }
 
-    public void setOccluded(boolean occluded) {
+    public void setOccluded(boolean occluded, boolean animate) {
         if (occluded != mOccluded) {
             mPhoneStatusBar.onKeyguardOccludedChanged(occluded);
         }
@@ -261,9 +264,12 @@
             }
         }
         mOccluded = occluded;
-        mPhoneStatusBar.updateMediaMetaData(false, false);
+        mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
         reset();
+        if (animate && !occluded) {
+            mPhoneStatusBar.animateKeyguardUnoccluding();
+        }
     }
 
     public boolean isOccluded() {
@@ -291,7 +297,7 @@
     public void hide(long startTime, long fadeoutDuration) {
         mShowing = false;
 
-        if (!KeyguardUpdateMonitor.getInstance(mContext).isUserUnlocked()) {
+        if (KeyguardUpdateMonitor.getInstance(mContext).needsSlowUnlockTransition()) {
             fadeoutDuration = KEYGUARD_DISMISS_DURATION_LOCKED;
         }
         long uptimeMillis = SystemClock.uptimeMillis();
@@ -320,8 +326,7 @@
                 }
             });
         } else {
-            if (mFingerprintUnlockController.getMode()
-                    == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
+            if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
                 mFingerprintUnlockController.startKeyguardFadingAway();
                 mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
@@ -338,8 +343,7 @@
                 boolean staying = mPhoneStatusBar.hideKeyguard();
                 if (!staying) {
                     mStatusBarWindowManager.setKeyguardFadingAway(true);
-                    if (mFingerprintUnlockController.getMode()
-                            == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
+                    if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK) {
                         if (!mScreenTurnedOn) {
                             mDeferScrimFadeOut = true;
                         } else {
@@ -393,6 +397,12 @@
                 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0);
             }
         }, skipFirstFrame);
+        if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
+                && LatencyTracker.isEnabled(mContext)) {
+            DejankUtils.postAfterTraversal(() ->
+                    LatencyTracker.getInstance(mContext).onActionEnd(
+                            LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK));
+        }
     }
 
     private void executeAfterKeyguardGoneAction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 47ea59e..4425c5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -33,6 +33,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.view.ActionMode;
 import android.view.InputQueue;
@@ -225,6 +226,10 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
+                && mNotificationPanel.getExpandedHeight() == 0f) {
+            mNotificationPanel.startExpandLatencyTracking();
+        }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
             // Disallow new pointers while the brightness mirror is visible. This is so that you
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index b9c7a4b..6726c92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -53,6 +53,7 @@
     protected boolean mCharged;
     protected boolean mPowerSave;
     private boolean mTestmode = false;
+    private boolean mHasReceivedBattery = false;
 
     public BatteryControllerImpl(Context context) {
         mContext = context;
@@ -92,6 +93,7 @@
         synchronized (mChangeCallbacks) {
             mChangeCallbacks.add(cb);
         }
+        if (!mHasReceivedBattery) return;
         cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
         cb.onPowerSaveChanged(mPowerSave);
     }
@@ -108,6 +110,7 @@
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
             if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
+            mHasReceivedBattery = true;
             mLevel = (int)(100f
                     * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
                     / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
index cc02ece..0fc71d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
@@ -18,13 +18,14 @@
 import android.net.INetworkPolicyListener;
 import android.net.NetworkPolicyManager;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 
 import java.util.ArrayList;
 
 public class DataSaverController {
 
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ArrayList<Listener> mListeners = new ArrayList<>();
     private final NetworkPolicyManager mPolicyManager;
 
@@ -73,7 +74,7 @@
 
     private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
-        public void onUidRulesChanged(int i, int i1) throws RemoteException {
+        public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
         }
 
         @Override
@@ -91,10 +92,7 @@
         }
 
         @Override
-        public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
-        }
-        @Override
-        public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
+        public void onUidPoliciesChanged(int uid, int uidPolicies) throws RemoteException {
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
new file mode 100644
index 0000000..8abfb89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -0,0 +1,124 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.provider.Settings;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+
+import java.util.List;
+
+public class EmergencyCryptkeeperText extends TextView {
+
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onPhoneStateChanged(int phoneState) {
+            update();
+        }
+    };
+
+    public EmergencyCryptkeeperText(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        setVisibility(GONE);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+        mKeyguardUpdateMonitor.registerCallback(mCallback);
+        update();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mKeyguardUpdateMonitor != null) {
+            mKeyguardUpdateMonitor.removeCallback(mCallback);
+        }
+    }
+
+    public void update() {
+        boolean hasMobile = ConnectivityManager.from(mContext)
+                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+
+        if (!hasMobile || airplaneMode) {
+            setText(null);
+            setVisibility(GONE);
+            return;
+        }
+
+        boolean allSimsMissing = true;
+        CharSequence displayText = null;
+
+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+        final int N = subs.size();
+        for (int i = 0; i < N; i++) {
+            int subId = subs.get(i).getSubscriptionId();
+            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+            CharSequence carrierName = subs.get(i).getCarrierName();
+            if (simState.iccCardExist() && !TextUtils.isEmpty(carrierName)) {
+                allSimsMissing = false;
+                displayText = carrierName;
+            }
+        }
+        if (allSimsMissing) {
+            if (N != 0) {
+                // Shows "Emergency calls only" on devices that are voice-capable.
+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
+                // has some connectivity. Otherwise it should show "No service"
+                // Grab the first subscription, because they all should contain the emergency text,
+                // described above.
+                displayText = subs.get(0).getCarrierName();
+            } else {
+                // We don't have a SubscriptionInfo to get the emergency calls only from.
+                // Grab it from the old sticky broadcast if possible instead. We can use it
+                // here because no subscriptions are active, so we don't have
+                // to worry about MSIM clashing.
+                displayText = getContext().getText(
+                        com.android.internal.R.string.emergency_calls_only);
+                Intent i = getContext().registerReceiver(null,
+                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
+                if (i != null) {
+                    displayText = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+                }
+            }
+        }
+
+        setText(displayText);
+        setVisibility(TextUtils.isEmpty(displayText) ? GONE : VISIBLE);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
new file mode 100644
index 0000000..639e50c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EncryptionHelper.java
@@ -0,0 +1,32 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.os.SystemProperties;
+
+/**
+ * Helper for determining whether the phone is decrypted yet.
+ */
+public class EncryptionHelper {
+
+    public static final boolean IS_DATA_ENCRYPTED = isDataEncrypted();
+
+    private static boolean isDataEncrypted() {
+        String voldState = SystemProperties.get("vold.decrypt");
+        return "1".equals(voldState) || "trigger_restart_min_framework".equals(voldState);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index d3ae549..f6c0942 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -381,7 +381,7 @@
     }
 
     public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        if (mIsExpanded) {
+        if (mIsExpanded || mBar.isBouncerShowing()) {
             // The touchable region is always the full area when expanded
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 61bac2d..bcc5a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -44,12 +44,12 @@
 import android.widget.ImageView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ButtonDispatcher;
+import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
-public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonInterface {
+public class KeyButtonView extends ImageView implements ButtonInterface {
 
     private int mContentDescriptionRes;
     private long mDownTime;
@@ -59,6 +59,7 @@
     private AudioManager mAudioManager;
     private boolean mGestureAborted;
     private boolean mLongClicked;
+    private OnClickListener mOnClickListener;
 
     private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
@@ -109,6 +110,12 @@
         mCode = code;
     }
 
+    @Override
+    public void setOnClickListener(OnClickListener onClickListener) {
+        super.setOnClickListener(onClickListener);
+        mOnClickListener = onClickListener;
+    }
+
     public void loadAsync(String uri) {
         new AsyncTask<String, Void, Drawable>() {
             @Override
@@ -190,6 +197,7 @@
                     // Provide the same haptic feedback that the system offers for virtual keys.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                 }
+                playSoundEffect(SoundEffectConstants.CLICK);
                 removeCallbacks(mCheckLongPress);
                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
@@ -215,14 +223,14 @@
                     if (doIt) {
                         sendEvent(KeyEvent.ACTION_UP, 0);
                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-                        playSoundEffect(SoundEffectConstants.CLICK);
                     } else {
                         sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                     }
                 } else {
                     // no key code, just a regular ImageView
-                    if (doIt) {
-                        performClick();
+                    if (doIt && mOnClickListener != null) {
+                        mOnClickListener.onClick(this);
+                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                     }
                 }
                 removeCallbacks(mCheckLongPress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 348e0b0..5f1b871 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -41,20 +41,20 @@
     void removeEmergencyListener(EmergencyListener listener);
 
     public interface SignalCallback {
-        void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description);
+        default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+                boolean activityIn, boolean activityOut, String description) {}
 
-        void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+        default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
                 int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
-                String description, boolean isWide, int subId);
-        void setSubs(List<SubscriptionInfo> subs);
-        void setNoSims(boolean show);
+                String description, boolean isWide, int subId) {}
+        default void setSubs(List<SubscriptionInfo> subs) {}
+        default void setNoSims(boolean show) {}
 
-        void setEthernetIndicators(IconState icon);
+        default void setEthernetIndicators(IconState icon) {}
 
-        void setIsAirplaneMode(IconState icon);
+        default void setIsAirplaneMode(IconState icon) {}
 
-        void setMobileDataEnabled(boolean enabled);
+        default void setMobileDataEnabled(boolean enabled) {}
     }
 
     public interface EmergencyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 7893a1a..37e6a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -819,6 +819,14 @@
         return info;
     }
 
+    public boolean hasEmergencyCryptKeeperText() {
+        return EncryptionHelper.IS_DATA_ENCRYPTED;
+    }
+
+    public boolean isRadioOn() {
+        return !mAirplaneMode;
+    }
+
     private class SubListener extends OnSubscriptionsChangedListener {
         @Override
         public void onSubscriptionsChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 29577ef..7b1f707 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -38,6 +38,7 @@
 import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -68,6 +69,8 @@
     // A marker object that let's us easily find views of this class.
     public static final Object VIEW_TAG = new Object();
 
+    public final Object mToken = new Object();
+
     private RemoteEditText mEditText;
     private ImageButton mSendButton;
     private ProgressBar mProgressBar;
@@ -86,6 +89,8 @@
     private int mRevealCy;
     private int mRevealR;
 
+    private boolean mResetting;
+
     public RemoteInputView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -137,8 +142,8 @@
         mSendButton.setVisibility(INVISIBLE);
         mProgressBar.setVisibility(VISIBLE);
         mEntry.remoteInputText = mEditText.getText();
-        mController.addSpinning(mEntry.key);
-        mController.removeRemoteInput(mEntry);
+        mController.addSpinning(mEntry.key, mToken);
+        mController.removeRemoteInput(mEntry, mToken);
         mEditText.mShowImeOnInputConnection = false;
         mController.remoteInputSent(mEntry);
 
@@ -190,7 +195,7 @@
     }
 
     private void onDefocus(boolean animate) {
-        mController.removeRemoteInput(mEntry);
+        mController.removeRemoteInput(mEntry, mToken);
         mEntry.remoteInputText = mEditText.getText();
 
         // During removal, we get reattached and lose focus. Not hiding in that
@@ -229,11 +234,11 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mEntry.row.isChangingPosition()) {
+        if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) {
             return;
         }
-        mController.removeRemoteInput(mEntry);
-        mController.removeSpinning(mEntry.key);
+        mController.removeRemoteInput(mEntry, mToken);
+        mController.removeSpinning(mEntry.key, mToken);
     }
 
     public void setPendingIntent(PendingIntent pendingIntent) {
@@ -262,7 +267,7 @@
                 mEntry.notification.getPackageName());
 
         setVisibility(VISIBLE);
-        mController.addRemoteInput(mEntry);
+        mController.addRemoteInput(mEntry, mToken);
         mEditText.setInnerFocusable(true);
         mEditText.mShowImeOnInputConnection = true;
         mEditText.setText(mEntry.remoteInputText);
@@ -281,13 +286,28 @@
     }
 
     private void reset() {
+        mResetting = true;
+
         mEditText.getText().clear();
         mEditText.setEnabled(true);
         mSendButton.setVisibility(VISIBLE);
         mProgressBar.setVisibility(INVISIBLE);
-        mController.removeSpinning(mEntry.key);
+        mController.removeSpinning(mEntry.key, mToken);
         updateSendButton();
         onDefocus(false /* animate */);
+
+        mResetting = false;
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (mResetting && child == mEditText) {
+            // Suppress text events if it happens during resetting. Ideally this would be
+            // suppressed by the text view not being shown, but that doesn't work here because it
+            // needs to stay visible for the animation.
+            return false;
+        }
+        return super.onRequestSendAccessibilityEvent(child, event);
     }
 
     private void updateSendButton() {
@@ -348,7 +368,7 @@
     }
 
     public boolean isActive() {
-        return mEditText.isFocused();
+        return mEditText.isFocused() && mEditText.isEnabled();
     }
 
     public void stealFocusFrom(RemoteInputView other) {
@@ -414,6 +434,24 @@
         mRevealR = r;
     }
 
+    @Override
+    public void dispatchStartTemporaryDetach() {
+        super.dispatchStartTemporaryDetach();
+        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
+        // won't lose IME focus.
+        detachViewFromParent(mEditText);
+    }
+
+    @Override
+    public void dispatchFinishTemporaryDetach() {
+        if (isAttachedToWindow()) {
+            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
+        } else {
+            removeDetachedView(mEditText, false /* animate */);
+        }
+        super.dispatchFinishTemporaryDetach();
+    }
+
     /**
      * An EditText that changes appearance based on whether it's focusable and becomes
      * un-focusable whenever the user navigates away from it or it becomes invisible.
@@ -430,7 +468,15 @@
         }
 
         private void defocusIfNeeded(boolean animate) {
-            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
+            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()
+                    || isTemporarilyDetached()) {
+                if (isTemporarilyDetached()) {
+                    // We might get reattached but then the other one of HUN / expanded might steal
+                    // our focus, so we'll need to save our text here.
+                    if (mRemoteInputView != null) {
+                        mRemoteInputView.mEntry.remoteInputText = getText();
+                    }
+                }
                 return;
             }
             if (isFocusable() && isEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index c3becb0..30d1c54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -50,15 +50,14 @@
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.util.UserIcons;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUISecondaryUserService;
-import com.android.systemui.qs.QSTile;
+import com.android.systemui.plugins.qs.QSContainer.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.statusbar.phone.ActivityStarter;
+import com.android.systemui.plugins.qs.QSContainer.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.FileDescriptor;
@@ -793,7 +792,7 @@
         }
     }
 
-    public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
+    public final DetailAdapter userDetailAdapter = new DetailAdapter() {
         private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index b890a30..b1bc2f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -20,6 +20,7 @@
 import android.net.NetworkCapabilities;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.util.Log;
@@ -49,7 +50,7 @@
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         mWifiTracker = new WifiStatusTracker(mWifiManager);
         mHasMobileData = hasMobileData;
-        Handler handler = new WifiHandler();
+        Handler handler = new WifiHandler(Looper.getMainLooper());
         mWifiChannel = new AsyncChannel();
         Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
         if (wifiMessenger != null) {
@@ -121,6 +122,10 @@
      * Handler to receive the data activity on wifi.
      */
     private class WifiHandler extends Handler {
+        WifiHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 50e5b88..81da672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -43,6 +43,7 @@
     private boolean mShadeExpanded;
     private float mMaxHeadsUpTranslation;
     private boolean mDismissAllInProgress;
+    private int mLayoutMinHeight;
 
     public int getScrollY() {
         return mScrollY;
@@ -137,10 +138,6 @@
         mStackTranslation = stackTranslation;
     }
 
-    public int getLayoutHeight() {
-        return mLayoutHeight;
-    }
-
     public void setLayoutHeight(int layoutHeight) {
         mLayoutHeight = layoutHeight;
     }
@@ -154,7 +151,7 @@
     }
 
     public int getInnerHeight() {
-        return mLayoutHeight - mTopPadding;
+        return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
     }
 
     public boolean isShadeExpanded() {
@@ -180,4 +177,8 @@
     public boolean isDismissAllInProgress() {
         return mDismissAllInProgress;
     }
+
+    public void setLayoutMinHeight(int layoutMinHeight) {
+        mLayoutMinHeight = layoutMinHeight;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 3c9373b..d7920a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -123,8 +123,10 @@
             mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
         }
         if (mOverflowNumber != null) {
-            mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
-                    mOverflowNumber.getMeasuredHeight());
+            boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+            int left = (isRtl ? 0 : getWidth() - mOverflowNumber.getMeasuredWidth());
+            int right = left + mOverflowNumber.getMeasuredWidth();
+            mOverflowNumber.layout(left, 0, right, mOverflowNumber.getMeasuredHeight());
         }
         if (mNotificationHeader != null) {
             mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
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..9dc9062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -112,11 +112,7 @@
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
 
-    /**
-     * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
-     * externally from {@link #setStackHeight}
-     */
-    private float mLastSetStackHeight;
+    private float mExpandedHeight;
     private int mOwnScrollY;
     private int mMaxLayoutHeight;
 
@@ -131,7 +127,7 @@
     private boolean mIsBeingDragged;
     private int mLastMotionY;
     private int mDownX;
-    private int mActivePointerId;
+    private int mActivePointerId = INVALID_POINTER;
     private boolean mTouchIsClick;
     private float mInitialTouchX;
     private float mInitialTouchY;
@@ -217,7 +213,6 @@
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
     private boolean mDontClampNextScroll;
-    private boolean mRequestViewResizeAnimationOnLayout;
     private boolean mNeedViewResizeAnimation;
     private View mExpandedGroupView;
     private boolean mEverythingNeedsAnimation;
@@ -356,6 +351,9 @@
                     return object.getBackgroundFadeAmount();
                 }
             };
+    private boolean mQsExpanded;
+    private boolean mForwardScrollable;
+    private boolean mBackwardScrollable;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -519,12 +517,9 @@
         setMaxLayoutHeight(getHeight());
         updateContentHeight();
         clampScrollPosition();
-        if (mRequestViewResizeAnimationOnLayout) {
-            requestAnimationOnViewResize(null);
-            mRequestViewResizeAnimationOnLayout = false;
-        }
         requestChildrenUpdate();
         updateFirstAndLastBackgroundViews();
+        updateAlgorithmLayoutMinHeight();
     }
 
     private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
@@ -566,9 +561,14 @@
 
     private void updateAlgorithmHeightAndPadding() {
         mAmbientState.setLayoutHeight(getLayoutHeight());
+        updateAlgorithmLayoutMinHeight();
         mAmbientState.setTopPadding(mTopPadding);
     }
 
+    private void updateAlgorithmLayoutMinHeight() {
+        mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() ? getLayoutMinHeight() : 0);
+    }
+
     /**
      * Updates the children views according to the stack scroll algorithm. Call this whenever
      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
@@ -599,7 +599,7 @@
                 if (startingPosition < mOwnScrollY) {
                     // This child starts off screen, so let's keep it offscreen to keep the others visible
 
-                    mOwnScrollY += childHeight;
+                    setOwnScrollY(mOwnScrollY + childHeight);
                 }
             }
         }
@@ -622,7 +622,7 @@
             // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
             // that it is not visible anymore.
             if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
-                mOwnScrollY = targetScroll;
+                setOwnScrollY(targetScroll);
             }
         }
     }
@@ -642,7 +642,7 @@
     private void clampScrollPosition() {
         int scrollRange = getScrollRange();
         if (scrollRange < mOwnScrollY) {
-            mOwnScrollY = scrollRange;
+            setOwnScrollY(scrollRange);
         }
     }
 
@@ -665,19 +665,19 @@
     }
 
     /**
-     * Update the height of the stack to a new height.
+     * Update the height of the panel.
      *
-     * @param height the new height of the stack
+     * @param height the expanded height of the panel
      */
-    public void setStackHeight(float height) {
-        mLastSetStackHeight = height;
+    public void setExpandedHeight(float height) {
+        mExpandedHeight = height;
         setIsExpanded(height > 0.0f);
         int stackHeight;
         float translationY;
         float appearEndPosition = getAppearEndPosition();
         float appearStartPosition = getAppearStartPosition();
         if (height >= appearEndPosition) {
-            translationY = mTopPaddingOverflow;
+            translationY = 0;
             stackHeight = (int) height;
         } else {
             float appearFraction = getAppearFraction(height);
@@ -704,8 +704,12 @@
      *         Measured relative to the resting position.
      */
     private float getExpandTranslationStart() {
-        int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
-                ? 0 : -getFirstChildIntrinsicHeight();
+        int startPosition = 0;
+        if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
+            startPosition = - Math.min(getFirstChildIntrinsicHeight(),
+                    mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
+                            - mBottomStackPeekSize);
+        }
         return startPosition - mTopPadding;
     }
 
@@ -728,7 +732,7 @@
                 ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
                         + mBottomStackSlowDownHeight
                 : getLayoutMinHeight();
-        return firstItemHeight + mTopPadding + mTopPaddingOverflow;
+        return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
     }
 
     /**
@@ -1158,6 +1162,10 @@
 
     @Override
     public boolean isAntiFalsingNeeded() {
+        return onKeyguard();
+    }
+
+    private boolean onKeyguard() {
         return mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD;
     }
 
@@ -1267,7 +1275,7 @@
         if (!isScrollingEnabled()) {
             return false;
         }
-        if (isInsideQsContainer(ev)) {
+        if (isInsideQsContainer(ev) && !mIsBeingDragged) {
             return false;
         }
         mForcedScroll = null;
@@ -1436,7 +1444,7 @@
                         false /* onTop */,
                         false /* animate */);
             }
-            mOwnScrollY = range;
+            setOwnScrollY(range);
             scrollAmount = 0.0f;
         }
         return scrollAmount;
@@ -1467,7 +1475,7 @@
             setOverScrolledPixels(currentTopPixels - newScrollY,
                     true /* onTop */,
                     false /* animate */);
-            mOwnScrollY = 0;
+            setOwnScrollY(0);
             scrollAmount = 0.0f;
         }
         return scrollAmount;
@@ -1681,7 +1689,7 @@
     }
 
     private void customScrollTo(int y) {
-        mOwnScrollY = y;
+        setOwnScrollY(y);
         updateChildren();
     }
 
@@ -1692,7 +1700,7 @@
             final int oldX = mScrollX;
             final int oldY = mOwnScrollY;
             mScrollX = scrollX;
-            mOwnScrollY = scrollY;
+            setOwnScrollY(scrollY);
             if (clampedY) {
                 springBack();
             } else {
@@ -1722,12 +1730,12 @@
             if (overScrolledTop) {
                 onTop = true;
                 newAmount = -mOwnScrollY;
-                mOwnScrollY = 0;
+                setOwnScrollY(0);
                 mDontReportNextOverScroll = true;
             } else {
                 onTop = false;
                 newAmount = mOwnScrollY - scrollRange;
-                mOwnScrollY = scrollRange;
+                setOwnScrollY(scrollRange);
             }
             setOverScrollAmount(newAmount, onTop, false);
             setOverScrollAmount(0.0f, onTop, true);
@@ -1855,6 +1863,19 @@
         if (scrollable != mScrollable) {
             mScrollable = scrollable;
             setFocusable(scrollable);
+            updateForwardAndBackwardScrollability();
+        }
+    }
+
+    private void updateForwardAndBackwardScrollability() {
+        boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
+        boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
+        boolean changed = forwardScrollable != mForwardScrollable
+                || backwardsScrollable != mBackwardScrollable;
+        mForwardScrollable = forwardScrollable;
+        mBackwardScrollable = backwardsScrollable;
+        if (changed) {
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         }
     }
 
@@ -2001,9 +2022,9 @@
     }
 
     private void applyCurrentBackgroundBounds() {
-        if (!mFadingOut) {
-            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
-        }
+        mScrimController.setExcludedBackgroundArea(
+                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
+                        : mCurrentBounds);
         invalidate();
     }
 
@@ -2114,13 +2135,13 @@
             float topAmount = getCurrentOverScrollAmount(true);
             float bottomAmount = getCurrentOverScrollAmount(false);
             if (velocityY < 0 && topAmount > 0) {
-                mOwnScrollY -= (int) topAmount;
+                setOwnScrollY(mOwnScrollY - (int) topAmount);
                 mDontReportNextOverScroll = true;
                 setOverScrollAmount(0, true, false);
                 mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
                         * mOverflingDistance + topAmount;
             } else if (velocityY > 0 && bottomAmount > 0) {
-                mOwnScrollY += bottomAmount;
+                setOwnScrollY((int) (mOwnScrollY + bottomAmount));
                 setOverScrollAmount(0, false, false);
                 mMaxOverScroll = Math.abs(velocityY) / 1000f
                         * getRubberBandFactor(false /* onTop */) * mOverflingDistance
@@ -2163,26 +2184,22 @@
      */
     public void updateTopPadding(float qsHeight, boolean animate,
             boolean ignoreIntrinsicPadding) {
-        float start = qsHeight;
-        float stackHeight = getHeight() - start;
+        int topPadding = (int) qsHeight;
         int minStackHeight = getLayoutMinHeight();
-        if (stackHeight <= minStackHeight) {
-            float overflow = minStackHeight - stackHeight;
-            stackHeight = minStackHeight;
-            start = getHeight() - stackHeight;
-            mTopPaddingOverflow = overflow;
+        if (topPadding + minStackHeight > getHeight()) {
+            mTopPaddingOverflow = topPadding + minStackHeight - getHeight();
         } else {
             mTopPaddingOverflow = 0;
         }
-        setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
+        setTopPadding(ignoreIntrinsicPadding ? topPadding : clampPadding(topPadding),
                 animate);
-        setStackHeight(mLastSetStackHeight);
+        setExpandedHeight(mExpandedHeight);
     }
 
     public int getLayoutMinHeight() {
         int firstChildMinHeight = getFirstChildIntrinsicHeight();
         return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
-                mMaxLayoutHeight - mTopPadding);
+                mMaxLayoutHeight - mIntrinsicPadding);
     }
 
     public int getFirstChildIntrinsicHeight() {
@@ -2475,11 +2492,11 @@
         if (endPosition <= mOwnScrollY) {
             // This child is fully scrolled of the top, so we have to deduct its height from the
             // scrollPosition
-            mOwnScrollY -= childHeight;
+            setOwnScrollY(mOwnScrollY - childHeight);
         } else if (startingPosition < mOwnScrollY) {
             // This child is currently being scrolled into, set the scroll position to the start of
             // this child
-            mOwnScrollY = startingPosition;
+            setOwnScrollY(startingPosition);
         }
     }
 
@@ -3064,7 +3081,7 @@
     public void onExpansionStopped() {
         mIsExpansionChanging = false;
         if (!mIsExpanded) {
-            mOwnScrollY = 0;
+            setOwnScrollY(0);
             mPhoneStatusBar.resetUserExpandedStates();
 
             // lets make sure nothing is in the overlay / transient anymore
@@ -3097,7 +3114,7 @@
 
     public void resetScrollPosition() {
         mScroller.abortAnimation();
-        mOwnScrollY = 0;
+        setOwnScrollY(0);
     }
 
     private void setIsExpanded(boolean isExpanded) {
@@ -3133,10 +3150,14 @@
         updateScrollPositionOnExpandInBottom(view);
         clampScrollPosition();
         notifyHeightChangeListener(view);
+        ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
+                ? (ExpandableNotificationRow) view
+                : null;
+        if (row != null && (row == mFirstVisibleBackgroundChild
+                || row.getNotificationParent() == mFirstVisibleBackgroundChild)) {
+            updateAlgorithmLayoutMinHeight();
+        }
         if (needsAnimation) {
-            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
-                    ? (ExpandableNotificationRow) view
-                    : null;
             requestAnimationOnViewResize(row);
         }
         requestChildrenUpdate();
@@ -3144,9 +3165,6 @@
 
     @Override
     public void onReset(ExpandableView view) {
-        if (mIsExpanded && mAnimationsEnabled) {
-            mRequestViewResizeAnimationOnLayout = true;
-        }
         updateAnimationState(view);
         updateChronometerForChild(view);
     }
@@ -3165,7 +3183,7 @@
                 }
                 int stackEnd = getStackEndPosition();
                 if (endPosition > stackEnd) {
-                    mOwnScrollY += endPosition - stackEnd;
+                    setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
                     mDisallowScrollingInThisMotion = true;
                 }
             }
@@ -3422,7 +3440,7 @@
     }
 
     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
-        if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) {
+        if (screenLocation == null || screenLocation.y < mTopPadding) {
             return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
         }
         if (screenLocation.y > getBottomMostNotificationBottom()) {
@@ -3495,7 +3513,7 @@
                         notifyHeightChangeListener(mEmptyShadeView);
                     }
                 };
-                if (mAnimationsEnabled) {
+                if (mAnimationsEnabled && mIsExpanded) {
                     mEmptyShadeView.setWillBeGone(true);
                     mEmptyShadeView.performVisibilityAnimation(false, onFinishedRunnable);
                 } else {
@@ -3727,15 +3745,14 @@
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
-        final int scrollRange = getScrollRange();
-        if (scrollRange > 0) {
+        if (mScrollable) {
             info.setScrollable(true);
-            if (mScrollY > 0) {
+            if (mBackwardScrollable) {
                 info.addAction(
                         AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
             }
-            if (mScrollY < scrollRange) {
+            if (mForwardScrollable) {
                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
             }
@@ -3887,11 +3904,7 @@
     }
 
     private void updateFadingState() {
-        if (mFadingOut || mParentFadingOut || mAmbientState.isDark()) {
-            mScrimController.setExcludedBackgroundArea(null);
-        } else {
-            applyCurrentBackgroundBounds();
-        }
+        applyCurrentBackgroundBounds();
         updateSrcDrawing();
     }
 
@@ -3910,6 +3923,18 @@
         mCurrentStackScrollState.removeViewStateForView(view);
     }
 
+    public void setQsExpanded(boolean qsExpanded) {
+        mQsExpanded = qsExpanded;
+        updateAlgorithmLayoutMinHeight();
+    }
+
+    public void setOwnScrollY(int ownScrollY) {
+        if (ownScrollY != mOwnScrollY) {
+            mOwnScrollY = ownScrollY;
+            updateForwardAndBackwardScrollability();
+        }
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
@@ -3952,6 +3977,7 @@
     private class NotificationSwipeHelper extends SwipeHelper {
         private static final long SHOW_GEAR_DELAY = 60;
         private static final long COVER_GEAR_DELAY = 4000;
+        private static final long SWIPE_GEAR_TIMING = 200;
         private CheckForDrag mCheckForDrag;
         private Runnable mFalsingCheck;
         private Handler mHandler;
@@ -4068,6 +4094,9 @@
 
             boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
             boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
+            final double timeForGesture = ev.getEventTime() - ev.getDownTime();
+            final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView)
+                && timeForGesture >= SWIPE_GEAR_TIMING;
 
             if (mGearSnappedTo && mCurrIconRow.isVisible()) {
                 if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
@@ -4092,7 +4121,8 @@
                 } else {
                     dismissOrSnapBack(animView, velocity, ev);
                 }
-            } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
+            } else if (((!gestureFastEnough || showGearForSlowOnGoing)
+                    && swipedEnoughToShowGear(animView))
                     || gestureTowardsGear) {
                 // Gear has not been snapped to previously and this is gear revealing gesture
                 snapToGear(animView, velocity);
@@ -4128,7 +4158,7 @@
             onDragCancelled(animView);
 
             // If we're on the lockscreen we want to false this.
-            if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+            if (isAntiFalsingNeeded()) {
                 mHandler.removeCallbacks(mFalsingCheck);
                 mHandler.postDelayed(mFalsingCheck, COVER_GEAR_DELAY);
             }
@@ -4144,13 +4174,9 @@
             final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
             final float snapBackThreshold = getSpaceForGear(animView) * multiplier;
             final float translation = getTranslation(animView);
-            final boolean fromLeft = translation > 0;
-            final float absTrans = Math.abs(translation);
-            final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
-
-            return mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
-                    ? (translation > snapBackThreshold && translation <= notiThreshold)
-                    : (translation < -snapBackThreshold && translation >= -notiThreshold));
+            return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
+                    ? translation > snapBackThreshold
+                    : translation < -snapBackThreshold);
         }
 
         @Override
@@ -4191,13 +4217,11 @@
                 final int rx = (int) ev.getRawX();
                 final int ry = (int) ev.getRawY();
 
-                getLocationOnScreen(mTempInt2);
-                int[] location = new int[2];
-                view.getLocationOnScreen(location);
-                final int x = location[0] - mTempInt2[0];
-                final int y = location[1] - mTempInt2[1];
+                view.getLocationOnScreen(mTempInt2);
+                final int x = mTempInt2[0];
+                final int y = mTempInt2[1];
                 Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
-                if (!rect.contains((int) rx, (int) ry)) {
+                if (!rect.contains(rx, ry)) {
                     // Touch was outside visible guts / gear notification, close what's visible
                     mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2d4900b..3c83921 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -19,7 +19,6 @@
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.view.View;
@@ -36,16 +35,6 @@
 
 public class TvStatusBar extends BaseStatusBar {
 
-    /**
-     * Tracking calls to View.setSystemUiVisibility().
-     */
-    int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
-
-    /**
-     * Last value sent to window manager.
-     */
-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
     @Override
     public void setIcon(String slot, StatusBarIcon icon) {
     }
@@ -224,40 +213,6 @@
         putComponent(TvStatusBar.class, this);
     }
 
-    /**
-     * Updates the visibility of the picture-in-picture.
-     */
-    public void updatePipVisibility(boolean visible) {
-        if (visible) {
-            mSystemUiVisibility |= View.TV_PICTURE_IN_PICTURE_VISIBLE;
-        } else {
-            mSystemUiVisibility &= ~View.TV_PICTURE_IN_PICTURE_VISIBLE;
-        }
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-    }
-
-    /**
-     * Updates the visibility of the Recents
-     */
-    public void updateRecentsVisibility(boolean visible) {
-        if (visible) {
-            mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
-        } else {
-            mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
-        }
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-    }
-
-    private void notifyUiVisibilityChanged(int vis) {
-        try {
-            if (mLastDispatchedSystemUiVisibility != vis) {
-                mWindowManagerService.statusBarVisibilityChanged(vis);
-                mLastDispatchedSystemUiVisibility = vis;
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     @Override
     public void handleSystemNavigationKey(int arg1) {
         // Not implemented
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
new file mode 100644
index 0000000..132a6dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -0,0 +1,111 @@
+/*
+ * 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.systemui.tuner;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.view.View;
+
+import com.android.systemui.plugins.PluginPrefs;
+import com.android.systemui.R;
+
+import java.util.List;
+import java.util.Set;
+
+public class PluginFragment extends PreferenceFragment {
+
+    public static final String ACTION_PLUGIN_SETTINGS
+            = "com.android.systemui.action.PLUGIN_SETTINGS";
+
+    private PluginPrefs mPluginPrefs;
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext());
+        screen.setOrderingAsAdded(false);
+        Context prefContext = getPreferenceManager().getContext();
+        mPluginPrefs = new PluginPrefs(getContext());
+        Set<String> pluginActions = mPluginPrefs.getPluginList();
+        for (String action : pluginActions) {
+            String name = action.replace("com.android.systemui.action.PLUGIN_", "");
+            PreferenceCategory category = new PreferenceCategory(prefContext);
+            category.setTitle(name);
+
+            List<ResolveInfo> result = getContext().getPackageManager().queryIntentServices(
+                    new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
+            if (result.size() > 0) {
+                screen.addPreference(category);
+            }
+            for (ResolveInfo info : result) {
+                category.addPreference(new PluginPreference(prefContext, info));
+            }
+        }
+        setPreferenceScreen(screen);
+    }
+
+    private static class PluginPreference extends SwitchPreference {
+        private final ComponentName mComponent;
+        private final boolean mHasSettings;
+
+        public PluginPreference(Context prefContext, ResolveInfo info) {
+            super(prefContext);
+            mComponent = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
+            PackageManager pm = prefContext.getPackageManager();
+            mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
+                    .setPackage(mComponent.getPackageName()), 0) != null;
+            setTitle(info.serviceInfo.loadLabel(pm));
+            setChecked(pm.getComponentEnabledSetting(mComponent)
+                    != PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+            setWidgetLayoutResource(R.layout.tuner_widget_settings_switch);
+        }
+
+        @Override
+        protected boolean persistBoolean(boolean value) {
+            getContext().getPackageManager().setComponentEnabledSetting(mComponent,
+                    value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                            : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                    PackageManager.DONT_KILL_APP);
+            return true;
+        }
+
+        @Override
+        public void onBindViewHolder(PreferenceViewHolder holder) {
+            super.onBindViewHolder(holder);
+            holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
+                    : View.GONE);
+            holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
+                    : View.GONE);
+            holder.findViewById(R.id.settings).setOnClickListener(v -> {
+                ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
+                        new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
+                                mComponent.getPackageName()), 0);
+                if (result != null) {
+                    v.getContext().startActivity(new Intent().setComponent(
+                            new ComponentName(result.activityInfo.packageName,
+                                    result.activityInfo.name)));
+                }
+            });
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 70f2fdc..7f63418 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -19,16 +19,9 @@
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.content.DialogInterface;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.provider.Settings;
-import android.provider.Settings.System;
 import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -36,12 +29,14 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.plugins.PluginPrefs;
 
 public class TunerFragment extends PreferenceFragment {
 
     private static final String TAG = "TunerFragment";
 
     private static final String KEY_BATTERY_PCT = "battery_pct";
+    private static final String KEY_PLUGINS = "plugins";
 
     public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
 
@@ -65,6 +60,9 @@
     @Override
     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         addPreferencesFromResource(R.xml.tuner_prefs);
+        if (!PluginPrefs.hasPlugins(getContext())) {
+            getPreferenceScreen().removePreference(findPreference(KEY_PLUGINS));
+        }
 
         if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
                 0) == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 5e4854c..085e003 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -78,6 +78,18 @@
         sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
                 "com.google.android.leanbacklauncher",
                 "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.apps.mediashell",
+                "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.katniss",
+                "com.google.android.katniss.setting.SpeechSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.katniss",
+                "com.google.android.katniss.setting.SearchSettingsActivity"));
+        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
+                "com.google.android.gsf.notouch",
+                "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
     }
 
     /**
@@ -711,10 +723,7 @@
         return mPipRecentsOverlayManager;
     }
 
-    private void updatePipVisibility(boolean visible) {
-        TvStatusBar statusBar = ((SystemUIApplication) mContext).getComponent(TvStatusBar.class);
-        if (statusBar != null) {
-            statusBar.updatePipVisibility(visible);
-        }
+    private void updatePipVisibility(final boolean visible) {
+        SystemServicesProxy.getInstance(mContext).setTvPipVisibility(visible);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index ca32567..cd465ac 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -36,16 +36,26 @@
 import com.android.systemui.R;
 
 import java.util.ArrayList;
+import java.util.Iterator;
+
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 
 /* Activity for choosing an application for a USB device or accessory */
 public class UsbResolverActivity extends ResolverActivity {
     public static final String TAG = "UsbResolverActivity";
     public static final String EXTRA_RESOLVE_INFOS = "rlist";
+    public static final String EXTRA_RESOLVE_INFO = "rinfo";
 
     private UsbDevice mDevice;
     private UsbAccessory mAccessory;
     private UsbDisconnectedReceiver mDisconnectedReceiver;
 
+    /** Resolve info that switches user profiles */
+    private ResolveInfo mForwardResolveInfo;
+
+    /** The intent that should be started when the profile is switched */
+    private Intent mOtherProfileIntent;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Intent intent = getIntent();
@@ -56,17 +66,22 @@
             return;
         }
         Intent target = (Intent)targetParcelable;
-        ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
-        CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
-        super.onCreate(savedInstanceState, target, title, null, rList,
-                true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
+        ArrayList<ResolveInfo> rList = new ArrayList<>(
+                intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS));
 
-        CheckBox alwaysUse = (CheckBox)findViewById(com.android.internal.R.id.alwaysUse);
-        if (alwaysUse != null) {
-            if (mDevice == null) {
-                alwaysUse.setText(R.string.always_use_accessory);
-            } else {
-                alwaysUse.setText(R.string.always_use_device);
+        // The rList contains the apps for all profiles of this users. Separate those. We currently
+        // only support two profiles, i.e. one forward resolve info.
+        ArrayList<ResolveInfo> rListOtherProfile = new ArrayList<>();
+        mForwardResolveInfo = null;
+        for (Iterator<ResolveInfo> iterator = rList.iterator(); iterator.hasNext();) {
+            ResolveInfo ri = iterator.next();
+
+            if (ri.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+                mForwardResolveInfo = ri;
+            } else if (UserHandle.getUserId(ri.activityInfo.applicationInfo.uid)
+                    != UserHandle.myUserId()) {
+                iterator.remove();
+                rListOtherProfile.add(ri);
             }
         }
 
@@ -82,6 +97,40 @@
             }
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
         }
+
+        // Create intent that will be used when switching to other profile. Emulate the behavior of
+        // UsbProfileGroupSettingsManager#resolveActivity
+        if (mForwardResolveInfo != null) {
+            if (rListOtherProfile.size() > 1) {
+                mOtherProfileIntent = new Intent(intent);
+                mOtherProfileIntent.putParcelableArrayListExtra(EXTRA_RESOLVE_INFOS,
+                        rListOtherProfile);
+            } else {
+                mOtherProfileIntent = new Intent(this, UsbConfirmActivity.class);
+                mOtherProfileIntent.putExtra(EXTRA_RESOLVE_INFO, rListOtherProfile.get(0));
+
+                if (mDevice != null) {
+                    mOtherProfileIntent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+                }
+
+                if (mAccessory != null) {
+                    mOtherProfileIntent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+                }
+            }
+        }
+
+        CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
+        super.onCreate(savedInstanceState, target, title, null, rList,
+                true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
+
+        CheckBox alwaysUse = (CheckBox)findViewById(com.android.internal.R.id.alwaysUse);
+        if (alwaysUse != null) {
+            if (mDevice == null) {
+                alwaysUse.setText(R.string.always_use_accessory);
+            } else {
+                alwaysUse.setText(R.string.always_use_device);
+            }
+        }
     }
 
     @Override
@@ -95,6 +144,12 @@
     @Override
     protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
         final ResolveInfo ri = target.getResolveInfo();
+        if (ri == mForwardResolveInfo) {
+            startActivityAsUser(mOtherProfileIntent, null,
+                    UserHandle.of(mForwardResolveInfo.targetUserId));
+            return true;
+        }
+
         try {
             IBinder b = ServiceManager.getService(USB_SERVICE);
             IUsbManager service = IUsbManager.Stub.asInterface(b);
@@ -122,7 +177,7 @@
             }
 
             try {
-                target.startAsUser(this, null, new UserHandle(userId));
+                target.startAsUser(this, null, UserHandle.of(userId));
             } catch (ActivityNotFoundException e) {
                 Log.e(TAG, "startActivity failed", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 047085d..8ca277e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -558,35 +558,7 @@
         final VolumeRow activeRow = getActiveRow();
         if (!dismissing) {
             mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT);
-            AutoTransition transition = new AutoTransition();
-            transition.setDuration(mExpandButtonAnimationDuration);
-            transition.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-            transition.addListener(new Transition.TransitionListener() {
-                @Override
-                public void onTransitionStart(Transition transition) {
-                }
-
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    mWindow.setLayout(
-                            mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
-                }
-
-                @Override
-                public void onTransitionCancel(Transition transition) {
-                }
-
-                @Override
-                public void onTransitionPause(Transition transition) {
-                    mWindow.setLayout(
-                            mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
-                }
-
-                @Override
-                public void onTransitionResume(Transition transition) {
-                }
-            });
-            TransitionManager.beginDelayedTransition(mDialogView, transition);
+            TransitionManager.beginDelayedTransition(mDialogView, getTransistion());
         }
         updateRowsH(activeRow);
         rescheduleTimeoutH();
@@ -702,6 +674,7 @@
         final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
                 && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
                 && !mZenPanel.isEditing();
+        TransitionManager.beginDelayedTransition(mDialogView, getTransistion());
         if (wasVisible != visible && !visible) {
             prepareForCollapse();
         }
@@ -897,7 +870,7 @@
                 if (row.anim != null) {
                     row.anim.cancel();
                 }
-                row.slider.setProgress(newProgress);
+                row.slider.setProgress(newProgress, true);
             }
         }
     }
@@ -947,6 +920,38 @@
         rescheduleTimeoutH();
     }
 
+    private AutoTransition getTransistion() {
+        AutoTransition transition = new AutoTransition();
+        transition.setDuration(mExpandButtonAnimationDuration);
+        transition.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        transition.addListener(new Transition.TransitionListener() {
+            @Override
+            public void onTransitionStart(Transition transition) {
+            }
+
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                mWindow.setLayout(
+                        mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
+            }
+
+            @Override
+            public void onTransitionCancel(Transition transition) {
+            }
+
+            @Override
+            public void onTransitionPause(Transition transition) {
+                mWindow.setLayout(
+                        mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
+            }
+
+            @Override
+            public void onTransitionResume(Transition transition) {
+            }
+        });
+        return transition;
+    }
+
     private boolean hasTouchFeature() {
         final PackageManager pm = mContext.getPackageManager();
         return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 2020abb..23967aa 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -34,6 +34,7 @@
     frameworks/base/packages/SystemUI/res \
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
+    SystemUIPluginLib \
     Keyguard \
     android-support-v7-recyclerview \
     android-support-v7-preference \
@@ -42,7 +43,8 @@
     android-support-v17-leanback
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    mockito-target \
+    android-support-test \
+    mockito-target-minus-junit4 \
     SystemUI-proto-tags
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
@@ -53,6 +55,42 @@
 # UI it doesn't own. This is necessary to allow screenshots to be taken
 LOCAL_CERTIFICATE := platform
 
+# Provide jack a list of classes to exclude from code coverage.
+# This is needed because the SystemUITests compile SystemUI source directly, rather than using
+# LOCAL_INSTRUMENTATION_FOR := SystemUI.
+#
+# We want to exclude the test classes from code coverage measurements, but they share the same
+# package as the rest of SystemUI so they can't be easily filtered by package name.
+#
+# Generate a comma separated list of patterns based on the test source files under src/
+# SystemUI classes are in ../src/ so they won't be excluded.
+# Example:
+#   Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java
+#   Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest*
+
+# Filter all src files under src/ to just java files
+local_java_files := $(filter %.java,$(call all-java-files-under, src))
+# Transform java file names into full class names.
+# This only works if the class name matches the file name and the directory structure
+# matches the package.
+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
+local_comma := ,
+local_empty :=
+local_space := $(local_empty) $(local_empty)
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude)
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
+
+# Reset variables
+local_java_files :=
+local_classes :=
+local_comma :=
+local_space :=
+jacoco_exclude :=
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 53a9976..b5584f3 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -35,7 +35,7 @@
             android:process=":killable" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.systemui.tests"
         android:label="Tests for SystemUI">
     </instrumentation>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
new file mode 100644
index 0000000..5cb5e68
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.systemui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryMeterDrawableTest {
+
+    private Context mContext;
+    private Resources mResources;
+    private BatteryMeterDrawable mBatteryMeter;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mResources = mContext.getResources();
+        mBatteryMeter = new BatteryMeterDrawable(mContext, 0);
+    }
+
+    @Test
+    public void testGetIntrinsicSize() {
+        assertEquals(
+                mResources.getDimensionPixelSize(R.dimen.battery_width),
+                mBatteryMeter.getIntrinsicWidth());
+        assertEquals(
+                mResources.getDimensionPixelSize(R.dimen.battery_height),
+                mBatteryMeter.getIntrinsicHeight());
+    }
+
+    @Test
+    public void testDrawNothingBeforeOnBatteryLevelChanged() {
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        verify(canvas, never()).drawPath(any(), any());
+        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawImageButNoTextIfPluggedIn() {
+        mBatteryMeter.onBatteryLevelChanged(0, true, true);
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        verify(canvas, atLeastOnce()).drawPath(any(), any());
+        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawTextIfNotPluggedIn() {
+        mBatteryMeter.onBatteryLevelChanged(0, false, false);
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        verify(canvas, times(1)).drawText(anyString(), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawNoTextIfPowerSaveEnabled() {
+        mBatteryMeter.onBatteryLevelChanged(0, false, false);
+        mBatteryMeter.onPowerSaveChanged(true);
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawTextWarningAtCriticalLevel() {
+        int criticalLevel = mResources.getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+        mBatteryMeter.onBatteryLevelChanged(criticalLevel, false, false);
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        String warningString = mResources.getString(R.string.battery_meter_very_low_overlay_symbol);
+        verify(canvas, times(1)).drawText(eq(warningString), anyFloat(), anyFloat(), any());
+    }
+
+    @Test
+    public void testDrawTextNoWarningAboveCriticalLevel() {
+        int criticalLevel = mResources.getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+        mBatteryMeter.onBatteryLevelChanged(criticalLevel + 1, false, false);
+        final Canvas canvas = mock(Canvas.class);
+        mBatteryMeter.draw(canvas);
+        String warningString = mResources.getString(R.string.battery_meter_very_low_overlay_symbol);
+        verify(canvas, never()).drawText(eq(warningString), anyFloat(), anyFloat(), any());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 3fdb3d2..d943eb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -15,17 +15,88 @@
  */
 package com.android.systemui;
 
-import android.test.AndroidTestCase;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.MessageQueue;
+import org.junit.Before;
 
 /**
  * Base class that does System UI specific setup.
  */
-public class SysuiTestCase extends AndroidTestCase {
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // Mockito stuff.
-        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
-        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+public class SysuiTestCase {
+
+    private Handler mHandler;
+    protected Context mContext;
+
+    @Before
+    public void SysuiSetup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    protected Context getContext() {
+        return mContext;
+    }
+
+    protected void waitForIdleSync() {
+        if (mHandler == null) {
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+        waitForIdleSync(mHandler);
+    }
+
+    protected void waitForIdleSync(Handler h) {
+        validateThread(h.getLooper());
+        Idler idler = new Idler(null);
+        h.getLooper().getQueue().addIdleHandler(idler);
+        // Ensure we are non-idle, so the idle handler can run.
+        h.post(new EmptyRunnable());
+        idler.waitForIdle();
+    }
+
+    private static final void validateThread(Looper l) {
+        if (Looper.myLooper() == l) {
+            throw new RuntimeException(
+                "This method can not be called from the looper being synced");
+        }
+    }
+
+    public static final class EmptyRunnable implements Runnable {
+        public void run() {
+        }
+    }
+
+    public static final class Idler implements MessageQueue.IdleHandler {
+        private final Runnable mCallback;
+        private boolean mIdle;
+
+        public Idler(Runnable callback) {
+            mCallback = callback;
+            mIdle = false;
+        }
+
+        @Override
+        public boolean queueIdle() {
+            if (mCallback != null) {
+                mCallback.run();
+            }
+            synchronized (this) {
+                mIdle = true;
+                notifyAll();
+            }
+            return false;
+        }
+
+        public void waitForIdle() {
+            synchronized (this) {
+                while (!mIdle) {
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java b/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
deleted file mode 100644
index 07334f3..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/phone/DozeParametersTests.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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.systemui.phone;
-
-import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-@SmallTest
-public class DozeParametersTests extends AndroidTestCase {
-
-    public void test_inOutMatcher_defaultIn() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("*");
-
-        assertTrue(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(-1));
-        assertTrue(intInOutMatcher.isIn(0));
-    }
-
-    public void test_inOutMatcher_defaultOut() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertFalse(intInOutMatcher.isIn(-1));
-        assertFalse(intInOutMatcher.isIn(0));
-    }
-
-    public void test_inOutMatcher_someIn() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("1,2,3,!*");
-
-        assertTrue(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(2));
-        assertTrue(intInOutMatcher.isIn(3));
-
-        assertFalse(intInOutMatcher.isIn(0));
-        assertFalse(intInOutMatcher.isIn(4));
-    }
-
-    public void test_inOutMatcher_someOut() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,!2,!3,*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertFalse(intInOutMatcher.isIn(2));
-        assertFalse(intInOutMatcher.isIn(3));
-
-        assertTrue(intInOutMatcher.isIn(0));
-        assertTrue(intInOutMatcher.isIn(4));
-    }
-
-    public void test_inOutMatcher_mixed() {
-        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,2,!3,*");
-
-        assertFalse(intInOutMatcher.isIn(1));
-        assertTrue(intInOutMatcher.isIn(2));
-        assertFalse(intInOutMatcher.isIn(3));
-
-        assertTrue(intInOutMatcher.isIn(0));
-        assertTrue(intInOutMatcher.isIn(4));
-    }
-
-    public void test_inOutMatcher_failEmpty() {
-        try {
-            new IntInOutMatcher("");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failNull() {
-        try {
-            new IntInOutMatcher(null);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failEmptyClause() {
-        try {
-            new IntInOutMatcher("!1,*,");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failDuplicate() {
-        try {
-            new IntInOutMatcher("!1,*,!1");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failDuplicateDefault() {
-        try {
-            new IntInOutMatcher("!1,*,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failMalformedNot() {
-        try {
-            new IntInOutMatcher("!,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failText() {
-        try {
-            new IntInOutMatcher("!abc,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failContradiction() {
-        try {
-            new IntInOutMatcher("1,!1,*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failContradictionDefault() {
-        try {
-            new IntInOutMatcher("1,*,!*");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    public void test_inOutMatcher_failMissingDefault() {
-        try {
-            new IntInOutMatcher("1");
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
new file mode 100644
index 0000000..9050b83
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.systemui.plugins;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.HandlerThread;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PluginInstanceManagerTest extends SysuiTestCase {
+
+    // Static since the plugin needs to be generated by the PluginInstanceManager using newInstance.
+    private static Plugin sMockPlugin;
+
+    private HandlerThread mHandlerThread;
+    private Context mContextWrapper;
+    private PackageManager mMockPm;
+    private PluginListener mMockListener;
+    private PluginInstanceManager mPluginInstanceManager;
+    private PluginManager mMockManager;
+
+    @Before
+    public void setup() throws Exception {
+        mHandlerThread = new HandlerThread("test_thread");
+        mHandlerThread.start();
+        mContextWrapper = new MyContextWrapper(getContext());
+        mMockPm = mock(PackageManager.class);
+        mMockListener = mock(PluginListener.class);
+        mMockManager = mock(PluginManager.class);
+        when(mMockManager.getClassLoader(Mockito.any(), Mockito.any()))
+                .thenReturn(getClass().getClassLoader());
+        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
+                mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, true);
+        sMockPlugin = mock(Plugin.class);
+        when(sMockPlugin.getVersion()).thenReturn(1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        sMockPlugin = null;
+    }
+
+    @Test
+    public void testNoPlugins() {
+        when(mMockPm.queryIntentServices(Mockito.any(), Mockito.anyInt())).thenReturn(
+                Collections.emptyList());
+        mPluginInstanceManager.loadAll();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+        verify(mMockListener, Mockito.never()).onPluginConnected(
+                ArgumentCaptor.forClass(Plugin.class).capture());
+    }
+
+    @Test
+    public void testPluginCreate() {
+        createPlugin();
+
+        // Verify startup lifecycle
+        verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
+                ArgumentCaptor.forClass(Context.class).capture());
+        verify(mMockListener).onPluginConnected(ArgumentCaptor.forClass(Plugin.class).capture());
+    }
+
+    @Test
+    public void testPluginDestroy() {
+        createPlugin(); // Get into valid created state.
+
+        mPluginInstanceManager.destroy();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+        // Verify shutdown lifecycle
+        verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(sMockPlugin).onDestroy();
+    }
+
+    @Test
+    public void testIncorrectVersion() {
+        setupFakePmQuery();
+        when(sMockPlugin.getVersion()).thenReturn(2);
+
+        mPluginInstanceManager.loadAll();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+        // Plugin shouldn't be connected because it is the wrong version.
+        verify(mMockListener, Mockito.never()).onPluginConnected(
+                ArgumentCaptor.forClass(Plugin.class).capture());
+    }
+
+    @Test
+    public void testReloadOnChange() {
+        createPlugin(); // Get into valid created state.
+
+        mPluginInstanceManager.onPackageChange("com.android.systemui");
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+        // Verify the old one was destroyed.
+        verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(sMockPlugin).onDestroy();
+        // Also verify we got a second onCreate.
+        verify(sMockPlugin, Mockito.times(2)).onCreate(
+                ArgumentCaptor.forClass(Context.class).capture(),
+                ArgumentCaptor.forClass(Context.class).capture());
+        verify(mMockListener, Mockito.times(2)).onPluginConnected(
+                ArgumentCaptor.forClass(Plugin.class).capture());
+    }
+
+    @Test
+    public void testNonDebuggable() {
+        // Create a version that thinks the build is not debuggable.
+        mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
+                mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, false);
+        setupFakePmQuery();
+
+        mPluginInstanceManager.loadAll();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);;
+
+        // Non-debuggable build should receive no plugins.
+        verify(mMockListener, Mockito.never()).onPluginConnected(
+                ArgumentCaptor.forClass(Plugin.class).capture());
+    }
+
+    @Test
+    public void testCheckAndDisable() {
+        createPlugin(); // Get into valid created state.
+
+        // Start with an unrelated class.
+        boolean result = mPluginInstanceManager.checkAndDisable(Activity.class.getName());
+        assertFalse(result);
+        verify(mMockPm, Mockito.never()).setComponentEnabledSetting(
+                ArgumentCaptor.forClass(ComponentName.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture());
+
+        // Now hand it a real class and make sure it disables the plugin.
+        result = mPluginInstanceManager.checkAndDisable(TestPlugin.class.getName());
+        assertTrue(result);
+        verify(mMockPm).setComponentEnabledSetting(
+                ArgumentCaptor.forClass(ComponentName.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture());
+    }
+
+    @Test
+    public void testDisableAll() {
+        createPlugin(); // Get into valid created state.
+
+        mPluginInstanceManager.disableAll();
+
+        verify(mMockPm).setComponentEnabledSetting(
+                ArgumentCaptor.forClass(ComponentName.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture(),
+                ArgumentCaptor.forClass(int.class).capture());
+    }
+
+    private void setupFakePmQuery() {
+        List<ResolveInfo> list = new ArrayList<>();
+        ResolveInfo info = new ResolveInfo();
+        info.serviceInfo = new ServiceInfo();
+        info.serviceInfo.packageName = "com.android.systemui";
+        info.serviceInfo.name = TestPlugin.class.getName();
+        list.add(info);
+        when(mMockPm.queryIntentServices(Mockito.any(), Mockito.anyInt())).thenReturn(list);
+
+        when(mMockPm.checkPermission(Mockito.anyString(), Mockito.anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        try {
+            ApplicationInfo appInfo = getContext().getApplicationInfo();
+            when(mMockPm.getApplicationInfo(Mockito.anyString(), Mockito.anyInt())).thenReturn(
+                    appInfo);
+        } catch (NameNotFoundException e) {
+            // Shouldn't be possible, but if it is, we want to fail.
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void createPlugin() {
+        setupFakePmQuery();
+
+        mPluginInstanceManager.loadAll();
+
+        waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+        waitForIdleSync(mPluginInstanceManager.mMainHandler);
+    }
+
+    // Real context with no registering/unregistering of receivers.
+    private static class MyContextWrapper extends ContextWrapper {
+        public MyContextWrapper(Context base) {
+            super(base);
+        }
+
+        @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+            return null;
+        }
+
+        @Override
+        public void unregisterReceiver(BroadcastReceiver receiver) {
+        }
+    }
+
+    public static class TestPlugin implements Plugin {
+        @Override
+        public int getVersion() {
+            return sMockPlugin.getVersion();
+        }
+
+        @Override
+        public void onCreate(Context sysuiContext, Context pluginContext) {
+            sMockPlugin.onCreate(sysuiContext, pluginContext);
+        }
+
+        @Override
+        public void onDestroy() {
+            sMockPlugin.onDestroy();
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
new file mode 100644
index 0000000..4b1827d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.systemui.plugins;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.PluginManager.PluginInstanceManagerFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PluginManagerTest extends SysuiTestCase {
+
+    private PluginInstanceManagerFactory mMockFactory;
+    private PluginInstanceManager mMockPluginInstance;
+    private PluginManager mPluginManager;
+    private PluginListener mMockListener;
+
+    private UncaughtExceptionHandler mRealExceptionHandler;
+    private UncaughtExceptionHandler mMockExceptionHandler;
+    private UncaughtExceptionHandler mPluginExceptionHandler;
+
+    @Before
+    public void setup() throws Exception {
+        mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+        mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
+        mMockFactory = mock(PluginInstanceManagerFactory.class);
+        mMockPluginInstance = mock(PluginInstanceManager.class);
+        when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
+                Mockito.anyBoolean(), Mockito.any(), Mockito.anyInt(), Mockito.any()))
+                .thenReturn(mMockPluginInstance);
+        mPluginManager = new PluginManager(getContext(), mMockFactory, true, mMockExceptionHandler);
+        resetExceptionHandler();
+        mMockListener = mock(PluginListener.class);
+    }
+
+    @Test
+    public void testAddListener() {
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
+
+        verify(mMockPluginInstance).loadAll();
+    }
+
+    @Test
+    public void testRemoveListener() {
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
+
+        mPluginManager.removePluginListener(mMockListener);
+        verify(mMockPluginInstance).destroy();
+    }
+
+    @Test
+    public void testNonDebuggable() {
+        mPluginManager = new PluginManager(getContext(), mMockFactory, false,
+                mMockExceptionHandler);
+        resetExceptionHandler();
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
+
+        verify(mMockPluginInstance, Mockito.never()).loadAll();
+    }
+
+    @Test
+    public void testExceptionHandler_foundPlugin() {
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
+        when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(true);
+
+        mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
+
+        verify(mMockPluginInstance, Mockito.atLeastOnce()).checkAndDisable(
+                ArgumentCaptor.forClass(String.class).capture());
+        verify(mMockPluginInstance, Mockito.never()).disableAll();
+        verify(mMockExceptionHandler).uncaughtException(
+                ArgumentCaptor.forClass(Thread.class).capture(),
+                ArgumentCaptor.forClass(Throwable.class).capture());
+    }
+
+    @Test
+    public void testExceptionHandler_noFoundPlugin() {
+        mPluginManager.addPluginListener("myAction", mMockListener, 1);
+        when(mMockPluginInstance.checkAndDisable(Mockito.any())).thenReturn(false);
+
+        mPluginExceptionHandler.uncaughtException(Thread.currentThread(), new Throwable());
+
+        verify(mMockPluginInstance, Mockito.atLeastOnce()).checkAndDisable(
+                ArgumentCaptor.forClass(String.class).capture());
+        verify(mMockPluginInstance).disableAll();
+        verify(mMockExceptionHandler).uncaughtException(
+                ArgumentCaptor.forClass(Thread.class).capture(),
+                ArgumentCaptor.forClass(Throwable.class).capture());
+    }
+
+    private void resetExceptionHandler() {
+        mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+        // Set back the real exception handler so the test can crash if it wants to.
+        Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
new file mode 100644
index 0000000..39b6412
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.systemui.power;
+
+import static android.test.MoreAsserts.assertNotEqual;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PowerNotificationWarningsTest {
+    private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
+    private PowerNotificationWarnings mPowerNotificationWarnings;
+
+    @Before
+    public void setUp() throws Exception {
+        // Test Instance.
+        mPowerNotificationWarnings = new PowerNotificationWarnings(
+                InstrumentationRegistry.getTargetContext(), mMockNotificationManager, null);
+    }
+
+    @Test
+    public void testIsInvalidChargerWarningShowing_DefaultsToFalse() {
+        assertFalse(mPowerNotificationWarnings.isInvalidChargerWarningShowing());
+    }
+
+    @Test
+    public void testIsInvalidChargerWarningShowing_TrueAfterShow() {
+        mPowerNotificationWarnings.showInvalidChargerWarning();
+        assertTrue(mPowerNotificationWarnings.isInvalidChargerWarningShowing());
+    }
+
+    @Test
+    public void testIsInvalidChargerWarningShowing_FalseAfterDismiss() {
+        mPowerNotificationWarnings.showInvalidChargerWarning();
+        mPowerNotificationWarnings.dismissInvalidChargerWarning();
+        assertFalse(mPowerNotificationWarnings.isInvalidChargerWarningShowing());
+    }
+
+    @Test
+    public void testShowInvalidChargerNotification_NotifyAsUser() {
+        mPowerNotificationWarnings.showInvalidChargerWarning();
+        verify(mMockNotificationManager, times(1))
+                .notifyAsUser(anyString(), anyInt(), any(), any());
+    }
+
+    @Test
+    public void testDismissInvalidChargerNotification_CancelAsUser() {
+        mPowerNotificationWarnings.showInvalidChargerWarning();
+        mPowerNotificationWarnings.dismissInvalidChargerWarning();
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+    }
+
+    @Test
+    public void testShowLowBatteryNotification_NotifyAsUser() {
+        mPowerNotificationWarnings.showLowBatteryWarning(false);
+        verify(mMockNotificationManager, times(1))
+                .notifyAsUser(anyString(), anyInt(), any(), any());
+    }
+
+    @Test
+    public void testDismissLowBatteryNotification_CancelAsUser() {
+        mPowerNotificationWarnings.showLowBatteryWarning(false);
+        mPowerNotificationWarnings.dismissLowBatteryWarning();
+        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+    }
+
+    @Test
+    public void testShowLowBatteryNotification_Silent() {
+        mPowerNotificationWarnings.showLowBatteryWarning(false);
+        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
+        verify(mMockNotificationManager)
+                .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+        assertEquals(null, captor.getValue().sound);
+    }
+
+    @Test
+    public void testShowLowBatteryNotification_Sound() {
+        mPowerNotificationWarnings.showLowBatteryWarning(true);
+        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
+        verify(mMockNotificationManager)
+                .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+        assertNotEqual(null, captor.getValue().sound);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
new file mode 100644
index 0000000..8eecfcf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.systemui.qs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileLayoutTest {
+    private Context mContext = InstrumentationRegistry.getTargetContext();
+    private final TileLayout mTileLayout = new TileLayout(mContext);
+    private int mLayoutSizeForOneTile;
+
+    @Before
+    public void setUp() throws Exception {
+        // Layout needs to leave space for the tile margins. Three times the margin size is
+        // sufficient for any number of columns.
+        mLayoutSizeForOneTile =
+                mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin) * 3;
+    }
+
+    private QSPanel.TileRecord createTileRecord() {
+        QSPanel.TileRecord tileRecord = new QSPanel.TileRecord();
+        tileRecord.tile = mock(QSTile.class);
+        tileRecord.tileView = spy(new QSTileBaseView(mContext, new QSIconView(mContext)));
+        return tileRecord;
+    }
+
+    @Test
+    public void testAddTile_CallsSetListeningOnTile() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.addTile(tileRecord);
+        verify(tileRecord.tile, times(1)).setListening(mTileLayout, false);
+    }
+
+    @Test
+    public void testSetListening_CallsSetListeningOnTile() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.addTile(tileRecord);
+        mTileLayout.setListening(true);
+        verify(tileRecord.tile, times(1)).setListening(mTileLayout, true);
+    }
+
+    @Test
+    public void testSetListening_SameValueIsNoOp() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.addTile(tileRecord);
+        mTileLayout.setListening(false);
+        verify(tileRecord.tile, times(1)).setListening(any(), anyBoolean());
+    }
+
+    @Test
+    public void testSetListening_ChangesValueForAddingFutureTiles() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.setListening(true);
+        mTileLayout.addTile(tileRecord);
+        verify(tileRecord.tile, times(1)).setListening(mTileLayout, true);
+    }
+
+    @Test
+    public void testRemoveTile_CallsSetListeningFalseOnTile() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.setListening(true);
+        mTileLayout.addTile(tileRecord);
+        mTileLayout.removeTile(tileRecord);
+        verify(tileRecord.tile, times(1)).setListening(mTileLayout, false);
+    }
+
+    @Test
+    public void testRemoveAllViews_CallsSetListeningFalseOnAllTiles() {
+        QSPanel.TileRecord tileRecord1 = createTileRecord();
+        QSPanel.TileRecord tileRecord2 = createTileRecord();
+        mTileLayout.setListening(true);
+        mTileLayout.addTile(tileRecord1);
+        mTileLayout.addTile(tileRecord2);
+        mTileLayout.removeAllViews();
+        verify(tileRecord1.tile, times(1)).setListening(mTileLayout, false);
+        verify(tileRecord2.tile, times(1)).setListening(mTileLayout, false);
+    }
+
+    @Test
+    public void testMeasureLayout_CallsLayoutOnTile() {
+        QSPanel.TileRecord tileRecord = createTileRecord();
+        mTileLayout.addTile(tileRecord);
+        mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+        mTileLayout.layout(0, 0, mLayoutSizeForOneTile, mLayoutSizeForOneTile);
+        verify(tileRecord.tileView, times(1)).layout(anyInt(), anyInt(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testMeasureLayout_CallsLayoutOnTilesWithNeighboredBounds() {
+        QSPanel.TileRecord tileRecord1 = createTileRecord();
+        QSPanel.TileRecord tileRecord2 = createTileRecord();
+        mTileLayout.addTile(tileRecord1);
+        mTileLayout.addTile(tileRecord2);
+        mTileLayout.measure(mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
+        mTileLayout.layout(0, 0, mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
+
+        // Capture the layout calls for both tiles.
+        ArgumentCaptor<Integer> left1 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> top1 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> right1 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> bottom1 = ArgumentCaptor.forClass(Integer.class);
+        verify(tileRecord1.tileView, times(1))
+                .layout(left1.capture(), top1.capture(), right1.capture(), bottom1.capture());
+        ArgumentCaptor<Integer> left2 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> top2 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> right2 = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> bottom2 = ArgumentCaptor.forClass(Integer.class);
+        verify(tileRecord2.tileView, times(1))
+                .layout(left2.capture(), top2.capture(), right2.capture(), bottom2.capture());
+
+        // We assume two tiles will always fit side-by-side.
+        assertTrue(mContext.getResources().getInteger(R.integer.quick_settings_num_columns) > 1);
+
+        // left <= right, top <= bottom
+        assertTrue(left1.getValue() <= right1.getValue());
+        assertTrue(top1.getValue() <= bottom1.getValue());
+        assertTrue(left2.getValue() <= right2.getValue());
+        assertTrue(top2.getValue() <= bottom2.getValue());
+
+        // The tiles' left and right should describe discrete ranges.
+        // Agnostic of Layout direction.
+        assertTrue(left1.getValue() > right2.getValue() || right1.getValue() < left2.getValue());
+
+        // The tiles' Top and Bottom should be the same.
+        assertEquals(top1.getValue().intValue(), top2.getValue().intValue());
+        assertEquals(bottom1.getValue().intValue(), bottom2.getValue().intValue());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
new file mode 100644
index 0000000..641cdc7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.systemui.qs;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.SysuiTestCase;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static junit.framework.Assert.assertEquals;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TouchAnimatorTest extends SysuiTestCase {
+
+    private Listener mTouchListener;
+    private View mTestView;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestView = new View(getContext());
+        mTouchListener = Mockito.mock(Listener.class);
+    }
+
+    @Test
+    public void testSetValueFloat() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    @Test
+    public void testSetValueInt() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addInt(mTestView, "top", 0, 50)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0, mTestView.getTop());
+
+        animator.setPosition(.5f);
+        assertEquals(25, mTestView.getTop());
+
+        animator.setPosition(1);
+        assertEquals(50, mTestView.getTop());
+    }
+
+    @Test
+    public void testStartDelay() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .setStartDelay(.5f)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.75f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    @Test
+    public void testEndDelay() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .addFloat(mTestView, "x", 0, 50)
+                .setEndDelay(.5f)
+                .build();
+
+        animator.setPosition(0);
+        assertEquals(0f, mTestView.getX());
+
+        animator.setPosition(.25f);
+        assertEquals(25f, mTestView.getX());
+
+        animator.setPosition(.5f);
+        assertEquals(50f, mTestView.getX());
+
+        animator.setPosition(1);
+        assertEquals(50f, mTestView.getX());
+    }
+
+    @Test
+    public void testOnAnimationAtStartCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(1);
+
+        // Not called from same state.
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(1);
+
+        // Called after starting and moving back to start.
+        animator.setPosition(.5f);
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(2);
+
+        // Called when move from end to end.
+        animator.setPosition(1);
+        animator.setPosition(0);
+        verifyOnAnimationAtStart(3);
+    }
+
+    @Test
+    public void testOnAnimationAtEndCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(1);
+
+        // Not called from same state.
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(1);
+
+        // Called after starting and moving back to end.
+        animator.setPosition(.5f);
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(2);
+
+        // Called when move from end to end.
+        animator.setPosition(0);
+        animator.setPosition(1);
+        verifyOnAnimationAtEnd(3);
+    }
+
+    @Test
+    public void testOnAnimationStartedCallback() {
+        TouchAnimator animator = new TouchAnimator.Builder()
+                .setListener(mTouchListener)
+                .build();
+
+        // Called on init.
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(1);
+
+        // Not called from same state.
+        animator.setPosition(.6f);
+        verifyOnAnimationStarted(1);
+
+        // Called after going to end then moving again.
+        animator.setPosition(1);
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(2);
+
+        // Called after moving to start then moving again.
+        animator.setPosition(0);
+        animator.setPosition(.5f);
+        verifyOnAnimationStarted(3);
+    }
+
+    // TODO: Add test for interpolator.
+
+    private void verifyOnAnimationAtStart(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtStart();
+    }
+
+    private void verifyOnAnimationAtEnd(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtEnd();
+    }
+
+    private void verifyOnAnimationStarted(int times) {
+        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationStarted();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
deleted file mode 100644
index e9b85b9..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.systemui.qs;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.qs.TouchAnimator.Listener;
-import org.mockito.Mockito;
-
-@SmallTest
-public class TouchAnimatorTests extends SysuiTestCase {
-
-    private Listener mTouchListener;
-    private View mTestView;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mTestView = new View(getContext());
-        mTouchListener = Mockito.mock(Listener.class);
-    }
-
-    public void testSetValueFloat() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .addFloat(mTestView, "x", 0, 50)
-                .build();
-
-        animator.setPosition(0);
-        assertEquals(0f, mTestView.getX());
-
-        animator.setPosition(.5f);
-        assertEquals(25f, mTestView.getX());
-
-        animator.setPosition(1);
-        assertEquals(50f, mTestView.getX());
-    }
-
-    public void testSetValueInt() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .addInt(mTestView, "top", 0, 50)
-                .build();
-
-        animator.setPosition(0);
-        assertEquals(0, mTestView.getTop());
-
-        animator.setPosition(.5f);
-        assertEquals(25, mTestView.getTop());
-
-        animator.setPosition(1);
-        assertEquals(50, mTestView.getTop());
-    }
-
-    public void testStartDelay() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .addFloat(mTestView, "x", 0, 50)
-                .setStartDelay(.5f)
-                .build();
-
-        animator.setPosition(0);
-        assertEquals(0f, mTestView.getX());
-
-        animator.setPosition(.5f);
-        assertEquals(0f, mTestView.getX());
-
-        animator.setPosition(.75f);
-        assertEquals(25f, mTestView.getX());
-
-        animator.setPosition(1);
-        assertEquals(50f, mTestView.getX());
-    }
-
-    public void testEndDelay() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .addFloat(mTestView, "x", 0, 50)
-                .setEndDelay(.5f)
-                .build();
-
-        animator.setPosition(0);
-        assertEquals(0f, mTestView.getX());
-
-        animator.setPosition(.25f);
-        assertEquals(25f, mTestView.getX());
-
-        animator.setPosition(.5f);
-        assertEquals(50f, mTestView.getX());
-
-        animator.setPosition(1);
-        assertEquals(50f, mTestView.getX());
-    }
-
-    public void testOnAnimationAtStartCallback() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .setListener(mTouchListener)
-                .build();
-
-        // Called on init.
-        animator.setPosition(0);
-        verifyOnAnimationAtStart(1);
-
-        // Not called from same state.
-        animator.setPosition(0);
-        verifyOnAnimationAtStart(1);
-
-        // Called after starting and moving back to start.
-        animator.setPosition(.5f);
-        animator.setPosition(0);
-        verifyOnAnimationAtStart(2);
-
-        // Called when move from end to end.
-        animator.setPosition(1);
-        animator.setPosition(0);
-        verifyOnAnimationAtStart(3);
-    }
-
-    public void testOnAnimationAtEndCallback() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .setListener(mTouchListener)
-                .build();
-
-        // Called on init.
-        animator.setPosition(1);
-        verifyOnAnimationAtEnd(1);
-
-        // Not called from same state.
-        animator.setPosition(1);
-        verifyOnAnimationAtEnd(1);
-
-        // Called after starting and moving back to end.
-        animator.setPosition(.5f);
-        animator.setPosition(1);
-        verifyOnAnimationAtEnd(2);
-
-        // Called when move from end to end.
-        animator.setPosition(0);
-        animator.setPosition(1);
-        verifyOnAnimationAtEnd(3);
-    }
-
-    public void testOnAnimationStartedCallback() {
-        TouchAnimator animator = new TouchAnimator.Builder()
-                .setListener(mTouchListener)
-                .build();
-
-        // Called on init.
-        animator.setPosition(.5f);
-        verifyOnAnimationStarted(1);
-
-        // Not called from same state.
-        animator.setPosition(.6f);
-        verifyOnAnimationStarted(1);
-
-        // Called after going to end then moving again.
-        animator.setPosition(1);
-        animator.setPosition(.5f);
-        verifyOnAnimationStarted(2);
-
-        // Called after moving to start then moving again.
-        animator.setPosition(0);
-        animator.setPosition(.5f);
-        verifyOnAnimationStarted(3);
-    }
-
-    // TODO: Add test for interpolator.
-
-    private void verifyOnAnimationAtStart(int times) {
-        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtStart();
-    }
-
-    private void verifyOnAnimationAtEnd(int times) {
-        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtEnd();
-    }
-
-    private void verifyOnAnimationStarted(int times) {
-        Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationStarted();
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
new file mode 100644
index 0000000..d7ff04f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -0,0 +1,265 @@
+/*
+ * 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.qs.external;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+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 android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageInfo;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
+import android.util.Log;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileLifecycleManagerTest {
+    private static final int TEST_FAIL_TIMEOUT = 5000;
+
+    private final Context mMockContext = Mockito.mock(Context.class);
+    private final PackageManagerAdapter mMockPackageManagerAdapter =
+            Mockito.mock(PackageManagerAdapter.class);
+    private final IQSTileService.Stub mMockTileService = Mockito.mock(IQSTileService.Stub.class);
+    private ComponentName mTileServiceComponentName;
+    private Intent mTileServiceIntent;
+    private UserHandle mUser;
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileLifecycleManager mStateManager;
+
+    @Before
+    public void setUp() throws Exception {
+        setPackageEnabled(true);
+        mTileServiceComponentName = new ComponentName(
+                InstrumentationRegistry.getTargetContext(), "FakeTileService.class");
+
+        // Stub.asInterface will just return itself.
+        when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
+
+        // Default behavior for bind is success and connects as mMockTileService.
+        when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any()))
+                .thenAnswer(
+                        new Answer<Boolean>() {
+                            @Override
+                            public Boolean answer(InvocationOnMock invocation) {
+                                ServiceConnection connection =
+                                        (ServiceConnection) invocation.getArguments()[1];
+                                connection.onServiceConnected(
+                                        mTileServiceComponentName, mMockTileService);
+                                return true;
+                            }
+                        });
+
+
+        mTileServiceIntent = new Intent().setComponent(mTileServiceComponentName);
+        mUser = new UserHandle(UserHandle.myUserId());
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mStateManager = new TileLifecycleManager(mHandler, mMockContext,
+                Mockito.mock(IQSService.class), new Tile(),
+                mTileServiceIntent,
+                mUser,
+                mMockPackageManagerAdapter);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mThread.quit();
+    }
+
+    private void setPackageEnabled(boolean enabled) throws Exception {
+        ServiceInfo defaultServiceInfo = null;
+        if (enabled) {
+            defaultServiceInfo = new ServiceInfo();
+            defaultServiceInfo.metaData = new Bundle();
+            defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true);
+        }
+        when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt()))
+                .thenReturn(defaultServiceInfo);
+        when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt()))
+                .thenReturn(defaultServiceInfo);
+        PackageInfo defaultPackageInfo = new PackageInfo();
+        when(mMockPackageManagerAdapter.getPackageInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(defaultPackageInfo);
+    }
+
+    private void verifyBind(int times) {
+        verify(mMockContext, times(times)).bindServiceAsUser(
+                mTileServiceIntent,
+                mStateManager,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                mUser);
+    }
+
+    @Test
+    public void testBind() {
+        mStateManager.setBindService(true);
+        verifyBind(1);
+    }
+
+    @Test
+    public void testUnbind() {
+        mStateManager.setBindService(true);
+        mStateManager.setBindService(false);
+        verify(mMockContext).unbindService(mStateManager);
+    }
+
+    @Test
+    public void testTileServiceCallbacks() throws Exception {
+        mStateManager.setBindService(true);
+        mStateManager.onTileAdded();
+        verify(mMockTileService).onTileAdded();
+        mStateManager.onStartListening();
+        verify(mMockTileService).onStartListening();
+        mStateManager.onClick(null);
+        verify(mMockTileService).onClick(null);
+        mStateManager.onStopListening();
+        verify(mMockTileService).onStopListening();
+        mStateManager.onTileRemoved();
+        verify(mMockTileService).onTileRemoved();
+    }
+
+    @Test
+    public void testAddedBeforeBind() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.setBindService(true);
+
+        verifyBind(1);
+        verify(mMockTileService).onTileAdded();
+    }
+
+    @Test
+    public void testListeningBeforeBind() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.setBindService(true);
+
+        verifyBind(1);
+        verify(mMockTileService).onTileAdded();
+        verify(mMockTileService).onStartListening();
+    }
+
+    @Test
+    public void testClickBeforeBind() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+        mStateManager.setBindService(true);
+
+        verifyBind(1);
+        verify(mMockTileService).onTileAdded();
+        verify(mMockTileService).onStartListening();
+        verify(mMockTileService).onClick(null);
+    }
+
+    @Test
+    public void testListeningNotListeningBeforeBind() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onStopListening();
+        mStateManager.setBindService(true);
+
+        verifyBind(1);
+        mStateManager.setBindService(false);
+        verify(mMockContext).unbindService(mStateManager);
+        verify(mMockTileService, never()).onStartListening();
+    }
+
+    @Test
+    public void testNoClickOfNotListeningAnymore() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+        mStateManager.onStopListening();
+        mStateManager.setBindService(true);
+
+        verifyBind(1);
+        mStateManager.setBindService(false);
+        verify(mMockContext).unbindService(mStateManager);
+        verify(mMockTileService, never()).onClick(null);
+    }
+
+    @Test
+    public void testComponentEnabling() throws Exception {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        setPackageEnabled(false);
+        mStateManager.setBindService(true);
+        // Package not available, not yet created.
+        verifyBind(0);
+
+        // Package is re-enabled.
+        setPackageEnabled(true);
+        mStateManager.onReceive(
+                mMockContext,
+                new Intent(
+                        Intent.ACTION_PACKAGE_CHANGED,
+                        Uri.fromParts(
+                                "package", mTileServiceComponentName.getPackageName(), null)));
+        verifyBind(1);
+    }
+
+    @Test
+    public void testKillProcess() throws Exception {
+        mStateManager.onStartListening();
+        mStateManager.setBindService(true);
+        mStateManager.setBindRetryDelay(0);
+        mStateManager.onServiceDisconnected(mTileServiceComponentName);
+
+        // Guarantees mHandler has processed all messages.
+        assertTrue(mHandler.runWithScissors(()->{}, TEST_FAIL_TIMEOUT));
+
+        // Two calls: one for the first bind, one for the restart.
+        verifyBind(2);
+        verify(mMockTileService, times(2)).onStartListening();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
deleted file mode 100644
index 7703c58..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
+++ /dev/null
@@ -1,320 +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.qs.external;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
-import android.util.Log;
-
-import org.mockito.Mockito;
-
-@SmallTest
-public class TileLifecycleManagerTests extends AndroidTestCase {
-    public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
-    public static final String EXTRA_CALLBACK = "callback";
-
-    private HandlerThread mThread;
-    private Handler mHandler;
-    private TileLifecycleManager mStateManager;
-    private final Object mBroadcastLock = new Object();
-    private final ArraySet<String> mCallbacks = new ArraySet<>();
-    private boolean mBound;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mThread = new HandlerThread("TestThread");
-        mThread.start();
-        mHandler = new Handler(mThread.getLooper());
-        ComponentName component = new ComponentName(mContext, FakeTileService.class);
-        mStateManager = new TileLifecycleManager(mHandler, getContext(),
-                Mockito.mock(IQSService.class), new Tile(),
-                new Intent().setComponent(component),
-                new UserHandle(UserHandle.myUserId()));
-        mCallbacks.clear();
-        getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        if (mBound) {
-            unbindService();
-        }
-        mThread.quit();
-        getContext().unregisterReceiver(mReceiver);
-    }
-
-    public void testSync() {
-        syncWithHandler();
-    }
-
-    public void testBind() {
-        bindService();
-        waitForCallback("onCreate");
-    }
-
-    public void testUnbind() {
-        bindService();
-        waitForCallback("onCreate");
-        unbindService();
-        waitForCallback("onDestroy");
-    }
-
-    public void testTileServiceCallbacks() {
-        bindService();
-        waitForCallback("onCreate");
-
-        mStateManager.onTileAdded();
-        waitForCallback("onTileAdded");
-        mStateManager.onStartListening();
-        waitForCallback("onStartListening");
-        mStateManager.onClick(null);
-        waitForCallback("onClick");
-        mStateManager.onStopListening();
-        waitForCallback("onStopListening");
-        mStateManager.onTileRemoved();
-        waitForCallback("onTileRemoved");
-
-        unbindService();
-    }
-
-    public void testAddedBeforeBind() {
-        mStateManager.onTileAdded();
-
-        bindService();
-        waitForCallback("onCreate");
-        waitForCallback("onTileAdded");
-    }
-
-    public void testListeningBeforeBind() {
-        mStateManager.onTileAdded();
-        mStateManager.onStartListening();
-
-        bindService();
-        waitForCallback("onCreate");
-        waitForCallback("onTileAdded");
-        waitForCallback("onStartListening");
-    }
-
-    public void testClickBeforeBind() {
-        mStateManager.onTileAdded();
-        mStateManager.onStartListening();
-        mStateManager.onClick(null);
-
-        bindService();
-        waitForCallback("onCreate");
-        waitForCallback("onTileAdded");
-        waitForCallback("onStartListening");
-        waitForCallback("onClick");
-    }
-
-    public void testListeningNotListeningBeforeBind() {
-        mStateManager.onTileAdded();
-        mStateManager.onStartListening();
-        mStateManager.onStopListening();
-
-        bindService();
-        waitForCallback("onCreate");
-        unbindService();
-        waitForCallback("onDestroy");
-        assertFalse(mCallbacks.contains("onStartListening"));
-    }
-
-    public void testNoClickOfNotListeningAnymore() {
-        mStateManager.onTileAdded();
-        mStateManager.onStartListening();
-        mStateManager.onClick(null);
-        mStateManager.onStopListening();
-
-        bindService();
-        waitForCallback("onCreate");
-        unbindService();
-        waitForCallback("onDestroy");
-        assertFalse(mCallbacks.contains("onClick"));
-    }
-
-    public void testComponentEnabling() {
-        mStateManager.onTileAdded();
-        mStateManager.onStartListening();
-
-        PackageManager pm = getContext().getPackageManager();
-        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
-
-        bindService();
-        assertTrue(mStateManager.mReceiverRegistered);
-
-        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
-        waitForCallback("onCreate");
-    }
-
-    public void testKillProcess() {
-        mStateManager.onStartListening();
-        bindService();
-        waitForCallback("onCreate");
-        waitForCallback("onStartListening");
-
-        getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
-
-        waitForCallback("onCreate");
-        waitForCallback("onStartListening");
-    }
-
-    private void bindService() {
-        mBound = true;
-        mStateManager.setBindService(true);
-    }
-
-    private void unbindService() {
-        mBound = false;
-        mStateManager.setBindService(false);
-    }
-
-    private void waitForCallback(String callback) {
-        for (int i = 0; i < 50; i++) {
-            if (mCallbacks.contains(callback)) {
-                mCallbacks.remove(callback);
-                return;
-            }
-            synchronized (mBroadcastLock) {
-                try {
-                    mBroadcastLock.wait(500);
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-        if (mCallbacks.contains(callback)) {
-            mCallbacks.remove(callback);
-            return;
-        }
-        fail("Didn't receive callback: " + callback);
-    }
-
-    private void syncWithHandler() {
-        final Object lock = new Object();
-        synchronized (lock) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (lock) {
-                        lock.notify();
-                    }
-                }
-            });
-            try {
-                lock.wait(10000);
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
-            synchronized (mBroadcastLock) {
-                mBroadcastLock.notify();
-            }
-        }
-    };
-
-    public static class FakeTileService extends Service {
-        public static final String ACTION_KILL = "com.android.systemui.test.KILL";
-
-        @Override
-        public IBinder onBind(Intent intent) {
-            return new IQSTileService.Stub() {
-                @Override
-                public void onTileAdded() throws RemoteException {
-                    sendCallback("onTileAdded");
-                }
-
-                @Override
-                public void onTileRemoved() throws RemoteException {
-                    sendCallback("onTileRemoved");
-                }
-
-                @Override
-                public void onStartListening() throws RemoteException {
-                    sendCallback("onStartListening");
-                }
-
-                @Override
-                public void onStopListening() throws RemoteException {
-                    sendCallback("onStopListening");
-                }
-
-                @Override
-                public void onClick(IBinder iBinder) throws RemoteException {
-                    sendCallback("onClick");
-                }
-
-                @Override
-                public void onUnlockComplete() throws RemoteException {
-                    sendCallback("onUnlockComplete");
-                }
-            };
-        }
-
-        @Override
-        public void onCreate() {
-            super.onCreate();
-            registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
-            sendCallback("onCreate");
-        }
-
-        @Override
-        public void onDestroy() {
-            super.onDestroy();
-            unregisterReceiver(mReceiver);
-            sendCallback("onDestroy");
-        }
-
-        private void sendCallback(String callback) {
-            Log.d("TileLifecycleManager", "Relaying: " + callback);
-            sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
-                    .putExtra(EXTRA_CALLBACK, callback));
-        }
-
-        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (ACTION_KILL.equals(intent.getAction())) {
-                    Process.killProcess(Process.myPid());
-                }
-            }
-        };
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
new file mode 100644
index 0000000..c2237c9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.qs.external;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileServiceManagerTest extends SysuiTestCase {
+
+    private TileServices mTileServices;
+    private TileLifecycleManager mTileLifecycle;
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileServiceManager mTileServiceManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mTileServices = Mockito.mock(TileServices.class);
+        Mockito.when(mTileServices.getContext()).thenReturn(mContext);
+        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+        Mockito.when(mTileLifecycle.isActiveTile()).thenReturn(false);
+        ComponentName componentName = new ComponentName(mContext,
+                TileServiceManagerTest.class);
+        Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+        mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mThread.quit();
+    }
+
+    @Test
+    public void testSetBindRequested() {
+        // Request binding.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setLastUpdate(0);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        assertEquals(5, mTileServiceManager.getBindPriority());
+
+        // Verify same state doesn't trigger recalculating for no reason.
+        mTileServiceManager.setBindRequested(true);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+        assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    @Test
+    public void testPendingClickPriority() {
+        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+        mTileServiceManager.calculateBindPriority(0);
+        assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    @Test
+    public void testBind() {
+        // Trigger binding requested and allowed.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setBindAllowed(true);
+
+        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+        assertTrue((boolean) captor.getValue());
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(0);
+        // Priority shouldn't disappear after the request goes away if we just bound, instead
+        // it sticks around to avoid thrashing a bunch of processes.
+        assertEquals(Integer.MAX_VALUE - 2, mTileServiceManager.getBindPriority());
+
+        mTileServiceManager.setBindAllowed(false);
+        captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+        assertFalse((boolean) captor.getValue());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
deleted file mode 100644
index 1e27603..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
+++ /dev/null
@@ -1,101 +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.qs.external;
-
-import android.content.ComponentName;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.test.suitebuilder.annotation.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
-@SmallTest
-public class TileServiceManagerTests extends SysuiTestCase {
-
-    private TileServices mTileServices;
-    private TileLifecycleManager mTileLifecycle;
-    private HandlerThread mThread;
-    private Handler mHandler;
-    private TileServiceManager mTileServiceManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mThread = new HandlerThread("TestThread");
-        mThread.start();
-        mHandler = new Handler(mThread.getLooper());
-        mTileServices = Mockito.mock(TileServices.class);
-        Mockito.when(mTileServices.getContext()).thenReturn(mContext);
-        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
-        Mockito.when(mTileLifecycle.isActiveTile()).thenReturn(false);
-        ComponentName componentName = new ComponentName(mContext,
-                TileServiceManagerTests.class);
-        Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
-        mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mThread.quit();
-    }
-
-    public void testSetBindRequested() {
-        // Request binding.
-        mTileServiceManager.setBindRequested(true);
-        mTileServiceManager.setLastUpdate(0);
-        mTileServiceManager.calculateBindPriority(5);
-        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
-        assertEquals(5, mTileServiceManager.getBindPriority());
-
-        // Verify same state doesn't trigger recalculating for no reason.
-        mTileServiceManager.setBindRequested(true);
-        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
-
-        mTileServiceManager.setBindRequested(false);
-        mTileServiceManager.calculateBindPriority(5);
-        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
-        assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
-    }
-
-    public void testPendingClickPriority() {
-        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
-        mTileServiceManager.calculateBindPriority(0);
-        assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
-    }
-
-    public void testBind() {
-        // Trigger binding requested and allowed.
-        mTileServiceManager.setBindRequested(true);
-        mTileServiceManager.setBindAllowed(true);
-
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
-        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
-        assertTrue((boolean) captor.getValue());
-
-        mTileServiceManager.setBindRequested(false);
-        mTileServiceManager.calculateBindPriority(0);
-        // Priority shouldn't disappear after the request goes away if we just bound, instead
-        // it sticks around to avoid thrashing a bunch of processes.
-        assertEquals(Integer.MAX_VALUE - 2, mTileServiceManager.getBindPriority());
-
-        mTileServiceManager.setBindAllowed(false);
-        captor = ArgumentCaptor.forClass(Boolean.class);
-        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
-        assertFalse((boolean) captor.getValue());
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
new file mode 100644
index 0000000..3ee1372
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.qs.external;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Looper;
+import android.service.quicksettings.Tile;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import java.util.ArrayList;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TileServicesTest extends SysuiTestCase {
+    private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+    private TileServices mTileService;
+    private ArrayList<TileServiceManager> mManagers;
+
+    @Before
+    public void setUp() throws Exception {
+        mManagers = new ArrayList<>();
+        final NetworkController networkController = Mockito.mock(NetworkController.class);
+        Mockito.when(networkController.getDataSaverController()).thenReturn(
+                Mockito.mock(DataSaverController.class));
+        QSTileHost host = new QSTileHost(mContext, null, null, null, null,
+                networkController, null,
+                Mockito.mock(HotspotController.class), null,
+                null, null, null, null, null, null, null, null);
+        mTileService = new TestTileServices(host, Looper.getMainLooper());
+    }
+
+    @Test
+    public void testRecalculateBindAllowance() {
+        // Add some fake tiles.
+        for (int i = 0; i < NUM_FAKES; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        assertEquals(NUM_FAKES, mManagers.size());
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+        }
+        mTileService.recalculateBindAllowance();
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+                    Mockito.anyLong());
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    @Test
+    public void testSetMemoryPressure() {
+        testRecalculateBindAllowance();
+        mTileService.setMemoryPressure(true);
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    @Test
+    public void testCalcFew() {
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        mTileService.recalculateBindAllowance();
+
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            // Shouldn't get bind prioirities calculated when there are less than the max services.
+            Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+                    Mockito.anyLong());
+
+            // All should be bound since there are less than the max services.
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertTrue(captor.getValue());
+        }
+    }
+
+    private class TestTileServices extends TileServices {
+        public TestTileServices(QSTileHost host, Looper looper) {
+            super(host, looper);
+        }
+
+        @Override
+        protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
+            TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+            mManagers.add(manager);
+            return manager;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
deleted file mode 100644
index de3864d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ /dev/null
@@ -1,119 +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.qs.external;
-
-import android.content.ComponentName;
-import android.os.Looper;
-import android.service.quicksettings.Tile;
-import android.test.suitebuilder.annotation.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-
-@SmallTest
-public class TileServicesTests extends SysuiTestCase {
-    private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
-
-    private TileServices mTileService;
-    private ArrayList<TileServiceManager> mManagers;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mManagers = new ArrayList<>();
-        final NetworkController networkController = Mockito.mock(NetworkController.class);
-        Mockito.when(networkController.getDataSaverController()).thenReturn(
-                Mockito.mock(DataSaverController.class));
-        QSTileHost host = new QSTileHost(mContext, null, null, null, null,
-                networkController, null,
-                Mockito.mock(HotspotController.class), null,
-                null, null, null, null, null, null, null, null);
-        mTileService = new TestTileServices(host, Looper.myLooper());
-    }
-
-    public void testRecalculateBindAllowance() {
-        // Add some fake tiles.
-        for (int i = 0; i < NUM_FAKES; i++) {
-            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
-        }
-        assertEquals(NUM_FAKES, mManagers.size());
-
-        for (int i = 0; i < NUM_FAKES; i++) {
-            Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
-        }
-        mTileService.recalculateBindAllowance();
-        for (int i = 0; i < NUM_FAKES; i++) {
-            Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
-                    Mockito.anyLong());
-            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
-            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
-
-            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
-                    (boolean) captor.getValue());
-        }
-    }
-
-    public void testSetMemoryPressure() {
-        testRecalculateBindAllowance();
-        mTileService.setMemoryPressure(true);
-
-        for (int i = 0; i < NUM_FAKES; i++) {
-            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
-            Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
-
-            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
-                    (boolean) captor.getValue());
-        }
-    }
-
-    public void testCalcFew() {
-        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
-            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
-        }
-        mTileService.recalculateBindAllowance();
-
-        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
-            // Shouldn't get bind prioirities calculated when there are less than the max services.
-            Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
-                    Mockito.anyLong());
-
-            // All should be bound since there are less than the max services.
-            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
-            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
-
-            assertTrue(captor.getValue());
-        }
-    }
-
-    private class TestTileServices extends TileServices {
-        public TestTileServices(QSTileHost host, Looper looper) {
-            super(host, looper);
-        }
-
-        @Override
-        protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
-            TileServiceManager manager = Mockito.mock(TileServiceManager.class);
-            mManagers.add(manager);
-            return manager;
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotTest.java
deleted file mode 100644
index 5e5c284..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2011 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.screenshot;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Environment;
-import android.os.FileObserver;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import java.io.File;
-
-/**
- * Functional tests for the global screenshot feature.
- */
-@LargeTest
-public class ScreenshotTest extends ActivityInstrumentationTestCase2<ScreenshotStubActivity> {
-
-    private static final String LOG_TAG = "ScreenshotTest";
-    private static final int SCREEN_WAIT_TIME_SEC = 5;
-
-    public ScreenshotTest() {
-        super(ScreenshotStubActivity.class);
-    }
-
-    /**
-     * A simple test for screenshots that launches an Activity, injects the key event combo
-     * to trigger the screenshot, and verifies the screenshot was taken successfully.
-     */
-    public void testScreenshot() throws Exception {
-        if (true) {
-            // Disable until this works again.
-            return;
-        }
-        Log.d(LOG_TAG, "starting testScreenshot");
-        // launch the activity.
-        ScreenshotStubActivity activity = getActivity();
-        assertNotNull(activity);
-
-        File screenshotDir = getScreenshotDir();
-        NewScreenshotObserver observer = new NewScreenshotObserver(
-                screenshotDir.getAbsolutePath());
-        observer.startWatching();
-        takeScreenshot();
-        // unlikely, but check if a new screenshot file was already created
-        if (observer.getCreatedPath() == null) {
-            // wait for screenshot to be created
-            synchronized(observer) {
-                observer.wait(SCREEN_WAIT_TIME_SEC*1000);
-            }
-        }
-        assertNotNull(String.format("Could not find screenshot after %d seconds",
-                SCREEN_WAIT_TIME_SEC), observer.getCreatedPath());
-
-        File screenshotFile = new File(screenshotDir, observer.getCreatedPath());
-        try {
-            assertTrue(String.format("Detected new screenshot %s but its not a file",
-                    screenshotFile.getName()), screenshotFile.isFile());
-            assertTrue(String.format("Detected new screenshot %s but its not an image",
-                    screenshotFile.getName()), isValidImage(screenshotFile));
-        } finally {
-            // delete the file to prevent external storage from filing up
-            screenshotFile.delete();
-        }
-    }
-
-    private static class NewScreenshotObserver extends FileObserver {
-        private String mAddedPath = null;
-
-        NewScreenshotObserver(String path) {
-            super(path, FileObserver.CREATE);
-        }
-
-        synchronized String getCreatedPath() {
-            return mAddedPath;
-        }
-
-        @Override
-        public void onEvent(int event, String path) {
-            Log.d(LOG_TAG, String.format("Detected new file added %s", path));
-            synchronized (this) {
-                mAddedPath = path;
-                notify();
-            }
-        }
-    }
-
-    /**
-     * Inject the key sequence to take a screenshot.
-     */
-    private void takeScreenshot() {
-        getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_POWER));
-        getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_VOLUME_DOWN));
-        // the volume down key event will cause the 'volume adjustment' UI to appear in the
-        // foreground, and steal UI focus
-        // unfortunately this means the next key event will get directed to the
-        // 'volume adjustment' UI, instead of this test's activity
-        // for this reason this test must be signed with platform certificate, to grant this test
-        // permission to inject key events to another process
-        getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_VOLUME_DOWN));
-        getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_POWER));
-    }
-
-    /**
-     * Get the directory where screenshot images are stored.
-     */
-    private File getScreenshotDir() {
-        // TODO: get this dir location from a constant
-        return new File(Environment.getExternalStorageDirectory(), "Pictures" + File.separator +
-                "Screenshots");
-    }
-
-    /**
-     * Return true if file is valid image file
-     */
-    private boolean isValidImage(File screenshotFile) {
-        Bitmap b = BitmapFactory.decodeFile(screenshotFile.getAbsolutePath());
-        // TODO: do more checks on image
-        return b != null;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java
new file mode 100644
index 0000000..2792d8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconListTest.java
@@ -0,0 +1,85 @@
+package com.android.systemui.statusbar;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Mockito.mock;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.StatusBarIconList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StatusBarIconListTest extends SysuiTestCase {
+
+    private final static String[] STATUS_BAR_SLOTS = {"aaa", "bbb", "ccc"};
+
+    @Test
+    public void testGetExistingSlot() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        assertEquals(1, statusBarIconList.getSlotIndex("bbb"));
+        assertEquals(2, statusBarIconList.getSlotIndex("ccc"));
+    }
+
+    @Test
+    public void testGetNonexistingSlot() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        assertEquals(0, statusBarIconList.getSlotIndex("aaa"));
+        assertEquals(3, statusBarIconList.size());
+        assertEquals(0, statusBarIconList.getSlotIndex("zzz")); // new content added in front
+        assertEquals(1, statusBarIconList.getSlotIndex("aaa")); // slid back
+        assertEquals(4, statusBarIconList.size());
+    }
+
+    @Test
+    public void testAddSlotSlidesIcons() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        StatusBarIcon sbIcon = mock(StatusBarIcon.class);
+        statusBarIconList.setIcon(0, sbIcon);
+        statusBarIconList.getSlotIndex("zzz"); // new content added in front
+        assertNull(statusBarIconList.getIcon(0));
+        assertEquals(sbIcon, statusBarIconList.getIcon(1));
+    }
+
+    @Test
+    public void testGetAndSetIcon() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        StatusBarIcon sbIconA = mock(StatusBarIcon.class);
+        StatusBarIcon sbIconB = mock(StatusBarIcon.class);
+        statusBarIconList.setIcon(0, sbIconA);
+        statusBarIconList.setIcon(1, sbIconB);
+        assertEquals(sbIconA, statusBarIconList.getIcon(0));
+        assertEquals(sbIconB, statusBarIconList.getIcon(1));
+        assertNull(statusBarIconList.getIcon(2)); // icon not set
+    }
+
+    @Test
+    public void testRemoveIcon() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        StatusBarIcon sbIconA = mock(StatusBarIcon.class);
+        StatusBarIcon sbIconB = mock(StatusBarIcon.class);
+        statusBarIconList.setIcon(0, sbIconA);
+        statusBarIconList.setIcon(1, sbIconB);
+        statusBarIconList.removeIcon(0);
+        assertNull(statusBarIconList.getIcon(0)); // icon not set
+    }
+
+    @Test
+    public void testGetViewIndex() {
+        StatusBarIconList statusBarIconList = new StatusBarIconList(STATUS_BAR_SLOTS);
+        StatusBarIcon sbIcon = mock(StatusBarIcon.class);
+        statusBarIconList.setIcon(2, sbIcon);
+        assertEquals(0, statusBarIconList.getViewIndex(2)); // Icon for item 2 is 0th child view.
+        statusBarIconList.setIcon(0, sbIcon);
+        assertEquals(0, statusBarIconList.getViewIndex(0)); // Icon for item 0 is 0th child view,
+        assertEquals(1, statusBarIconList.getViewIndex(2)); // and item 2 is now 1st child view.
+    }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
new file mode 100644
index 0000000..ee10440
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.fail;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DozeParametersTest {
+
+    @Test
+    public void test_inOutMatcher_defaultIn() {
+        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("*");
+
+        assertTrue(intInOutMatcher.isIn(1));
+        assertTrue(intInOutMatcher.isIn(-1));
+        assertTrue(intInOutMatcher.isIn(0));
+    }
+
+    @Test
+    public void test_inOutMatcher_defaultOut() {
+        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!*");
+
+        assertFalse(intInOutMatcher.isIn(1));
+        assertFalse(intInOutMatcher.isIn(-1));
+        assertFalse(intInOutMatcher.isIn(0));
+    }
+
+    @Test
+    public void test_inOutMatcher_someIn() {
+        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("1,2,3,!*");
+
+        assertTrue(intInOutMatcher.isIn(1));
+        assertTrue(intInOutMatcher.isIn(2));
+        assertTrue(intInOutMatcher.isIn(3));
+
+        assertFalse(intInOutMatcher.isIn(0));
+        assertFalse(intInOutMatcher.isIn(4));
+    }
+
+    @Test
+    public void test_inOutMatcher_someOut() {
+        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,!2,!3,*");
+
+        assertFalse(intInOutMatcher.isIn(1));
+        assertFalse(intInOutMatcher.isIn(2));
+        assertFalse(intInOutMatcher.isIn(3));
+
+        assertTrue(intInOutMatcher.isIn(0));
+        assertTrue(intInOutMatcher.isIn(4));
+    }
+
+    @Test
+    public void test_inOutMatcher_mixed() {
+        IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,2,!3,*");
+
+        assertFalse(intInOutMatcher.isIn(1));
+        assertTrue(intInOutMatcher.isIn(2));
+        assertFalse(intInOutMatcher.isIn(3));
+
+        assertTrue(intInOutMatcher.isIn(0));
+        assertTrue(intInOutMatcher.isIn(4));
+    }
+
+    @Test
+    public void test_inOutMatcher_failEmpty() {
+        try {
+            new IntInOutMatcher("");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failNull() {
+        try {
+            new IntInOutMatcher(null);
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failEmptyClause() {
+        try {
+            new IntInOutMatcher("!1,*,");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failDuplicate() {
+        try {
+            new IntInOutMatcher("!1,*,!1");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failDuplicateDefault() {
+        try {
+            new IntInOutMatcher("!1,*,*");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failMalformedNot() {
+        try {
+            new IntInOutMatcher("!,*");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failText() {
+        try {
+            new IntInOutMatcher("!abc,*");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failContradiction() {
+        try {
+            new IntInOutMatcher("1,!1,*");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failContradictionDefault() {
+        try {
+            new IntInOutMatcher("1,*,!*");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void test_inOutMatcher_failMissingDefault() {
+        try {
+            new IntInOutMatcher("1");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 19cb243..7b56ea3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -16,6 +16,7 @@
 package com.android.systemui.statusbar.policy;
 
 import android.os.HandlerThread;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.SubscriptionInfo;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -23,16 +24,22 @@
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-import java.util.List;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertEquals;
 
 @SmallTest
-public class CallbackHandlerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CallbackHandlerTest {
 
     private CallbackHandler mHandler;
     private HandlerThread mHandlerThread;
@@ -42,10 +49,8 @@
     @Mock
     private SignalCallback mSignalCallback;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setUp() throws Exception {
         mHandlerThread = new HandlerThread("TestThread");
         mHandlerThread.start();
         mHandler = new CallbackHandler(mHandlerThread.getLooper());
@@ -55,6 +60,7 @@
         mHandler.setListening(mSignalCallback, true);
     }
 
+    @Test
     public void testEmergencyListener() {
         mHandler.setEmergencyCallsOnly(true);
         waitForCallbacks();
@@ -64,6 +70,7 @@
         assertTrue(captor.getValue());
     }
 
+    @Test
     public void testSignalCallback_setWifiIndicators() {
         boolean enabled = true;
         IconState status = new IconState(true, 0, "");
@@ -91,6 +98,7 @@
         assertEquals(description, descArg.getValue());
     }
 
+    @Test
     public void testSignalCallback_setMobileDataIndicators() {
         IconState status = new IconState(true, 0, "");
         IconState qs = new IconState(true, 1, "");
@@ -133,6 +141,7 @@
     }
 
     @SuppressWarnings("unchecked")
+    @Test
     public void testSignalCallback_setSubs() {
         List<SubscriptionInfo> subs = new ArrayList<>();
         mHandler.setSubs(subs);
@@ -143,6 +152,7 @@
         assertTrue(subs == subsArg.getValue());
     }
 
+    @Test
     public void testSignalCallback_setNoSims() {
         boolean noSims = true;
         mHandler.setNoSims(noSims);
@@ -153,6 +163,7 @@
         assertEquals(noSims, (boolean) noSimsArg.getValue());
     }
 
+    @Test
     public void testSignalCallback_setEthernetIndicators() {
         IconState state = new IconState(true, R.drawable.stat_sys_ethernet, "Test Description");
         mHandler.setEthernetIndicators(state);
@@ -163,6 +174,7 @@
         assertEquals(state, iconArg.getValue());
     }
 
+    @Test
     public void testSignalCallback_setIsAirplaneMode() {
         IconState state = new IconState(true, R.drawable.stat_sys_airplane_mode, "Test Description");
         mHandler.setIsAirplaneMode(state);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 38cac1e..6c9cfe0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -30,11 +30,16 @@
 import android.util.Log;
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
+import com.android.systemui.SysuiTestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
@@ -43,6 +48,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static junit.framework.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -73,10 +79,21 @@
 
     private NetworkCapabilities mNetCapabilities;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Rule
+    public TestWatcher failWatcher = new TestWatcher() {
+        @Override
+        protected void failed(Throwable e, Description description) {
+            // Print out mNetworkController state if the test fails.
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            mNetworkController.dump(null, pw, null);
+            pw.flush();
+            Log.d(TAG, sw.toString());
+        }
+    };
 
+    @Before
+    public void setUp() throws Exception {
         mMockWm = mock(WifiManager.class);
         mMockTm = mock(TelephonyManager.class);
         mMockSm = mock(SubscriptionManager.class);
@@ -136,7 +153,7 @@
       when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
       NetworkControllerImpl networkControllerNoMobile
               = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
-                        mConfig, Looper.getMainLooper(), mCallbackHandler,
+                        mConfig, mContext.getMainLooper(), mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults);
 
@@ -146,16 +163,6 @@
 
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        mNetworkController.dump(null, pw, null);
-        pw.flush();
-        Log.d(TAG, sw.toString());
-        super.tearDown();
-    }
-
     // 2 Bars 3G GSM.
     public void setupDefaultSignal() {
         setIsGsm(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 542c390..55ec572 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -2,14 +2,19 @@
 
 import android.net.NetworkCapabilities;
 import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import com.android.settingslib.net.DataUsageController;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class NetworkControllerDataTest extends NetworkControllerBaseTest {
 
+    @Test
     public void test3gDataIcon() {
         setupDefaultSignal();
 
@@ -17,6 +22,7 @@
                 TelephonyIcons.QS_DATA_3G);
     }
 
+    @Test
     public void testRoamingDataIcon() {
         setupDefaultSignal();
         setGsmRoaming(true);
@@ -29,6 +35,7 @@
                 TelephonyIcons.QS_DATA_R, false, false);
     }
 
+    @Test
     public void test2gDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -38,6 +45,7 @@
                 TelephonyIcons.QS_DATA_G);
     }
 
+    @Test
     public void testCdmaDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -47,6 +55,7 @@
                 TelephonyIcons.QS_DATA_1X);
     }
 
+    @Test
     public void testEdgeDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -56,6 +65,7 @@
                 TelephonyIcons.QS_DATA_E);
     }
 
+    @Test
     public void testLteDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -65,6 +75,7 @@
                 TelephonyIcons.QS_DATA_LTE);
     }
 
+    @Test
     public void testHspaDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -74,6 +85,7 @@
                 TelephonyIcons.QS_DATA_H);
     }
 
+    @Test
     public void testWfcNoDataIcon() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -82,6 +94,7 @@
         verifyDataIndicators(0, 0);
     }
 
+    @Test
     public void test4gDataIcon() {
         // Switch to showing 4g icon and re-initialize the NetworkController.
         mConfig.show4gForLte = true;
@@ -99,6 +112,7 @@
                 TelephonyIcons.QS_DATA_4G);
     }
 
+    @Test
     public void testDataDisabledIcon() {
         setupNetworkController();
         Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
@@ -110,6 +124,7 @@
                 TelephonyIcons.QS_ICON_DATA_DISABLED);
     }
 
+    @Test
     public void testDataDisabledIcon_UserNotSetup() {
         setupNetworkController();
         Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
@@ -122,6 +137,7 @@
         verifyDataIndicators(0, 0);
     }
 
+    @Test
     public void test4gDataIconConfigChange() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -138,6 +154,7 @@
                 TelephonyIcons.QS_DATA_4G);
     }
 
+    @Test
     public void testDataChangeWithoutConnectionState() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -153,6 +170,7 @@
                 TelephonyIcons.QS_DATA_H);
     }
 
+    @Test
     public void testDataActivity() {
         setupDefaultSignal();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
index b2fedfa..9ac51b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
@@ -1,16 +1,23 @@
 package com.android.systemui.statusbar.policy;
 
 import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+import static junit.framework.Assert.assertEquals;
+
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class NetworkControllerEthernetTest extends NetworkControllerBaseTest {
 
+    @Test
     public void testEthernetIcons() {
         verifyLastEthernetIcon(false, 0);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 08da382..4560aa7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -15,12 +15,11 @@
  */
 package com.android.systemui.statusbar.policy;
 
-import static org.mockito.Mockito.mock;
-
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -32,15 +31,24 @@
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
 
+    @Test
     public void testNoIconWithoutMobile() {
         // Turn off mobile network support.
         Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
@@ -54,6 +62,7 @@
         verifyLastMobileDataIndicators(false, 0, 0);
     }
 
+    @Test
     public void testNoSimsIconPresent() {
         // No Subscriptions.
         mNetworkController.mMobileSignalControllers.clear();
@@ -62,6 +71,7 @@
         verifyHasNoSims(true);
     }
 
+    @Test
     public void testEmergencyOnly() {
         setupDefaultSignal();
         mNetworkController.recalculateEmergency();
@@ -72,6 +82,7 @@
         verifyEmergencyOnly(true);
     }
 
+    @Test
     public void testEmergencyOnlyNoSubscriptions() {
         setupDefaultSignal();
         setSubscriptions();
@@ -81,6 +92,7 @@
         verifyEmergencyOnly(true);
     }
 
+    @Test
     public void testNoEmengencyNoSubscriptions() {
         setupDefaultSignal();
         setSubscriptions();
@@ -90,6 +102,7 @@
         verifyEmergencyOnly(false);
     }
 
+    @Test
     public void testNoSimlessIconWithoutMobile() {
         // Turn off mobile network support.
         Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
@@ -107,6 +120,7 @@
         verifyHasNoSims(false);
     }
 
+    @Test
     public void testSignalStrength() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -123,6 +137,7 @@
         }
     }
 
+    @Test
     public void testCdmaSignalStrength() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -136,6 +151,7 @@
         }
     }
 
+    @Test
     public void testSignalRoaming() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -150,6 +166,7 @@
         }
     }
 
+    @Test
     public void testCdmaSignalRoaming() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -164,6 +181,7 @@
         }
     }
 
+    @Test
     public void testQsSignalStrength() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -176,6 +194,7 @@
         }
     }
 
+    @Test
     public void testCdmaQsSignalStrength() {
         for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
@@ -189,6 +208,7 @@
         }
     }
 
+    @Test
     public void testNoBangWithWifi() {
         setupDefaultSignal();
         setConnectivity(mMobileSignalController.mTransportType, false, false);
@@ -199,6 +219,7 @@
 
     // Some tests of actual NetworkController code, just internals not display stuff
     // TODO: Put this somewhere else, maybe in its own file.
+    @Test
     public void testHasCorrectMobileControllers() {
         int[] testSubscriptions = new int[] { 1, 5, 3 };
         int notTestSubscription = 0;
@@ -225,6 +246,7 @@
         assertFalse(mNetworkController.hasCorrectMobileControllers(subscriptions));
     }
 
+    @Test
     public void testSetCurrentSubscriptions() {
         // We will not add one controller to make sure it gets created.
         int indexToSkipController = 0;
@@ -277,6 +299,7 @@
         }
     }
 
+    @Test
     public void testHistorySize() {
         // Verify valid history size, otherwise it gits printed out the wrong order and whatnot.
         assertEquals(0, SignalController.HISTORY_SIZE & (SignalController.HISTORY_SIZE - 1));
@@ -289,6 +312,7 @@
         setCdmaRoaming(false);
     }
 
+    @Test
     public void testOnReceive_stringsUpdatedAction_spn() {
         String expectedMNetworkName = "Test";
         Intent intent = createStringsUpdatedIntent(true /* showSpn */,
@@ -301,6 +325,7 @@
         assertNetworkNameEquals(expectedMNetworkName);
     }
 
+    @Test
     public void testOnReceive_stringsUpdatedAction_plmn() {
         String expectedMNetworkName = "Test";
 
@@ -314,6 +339,7 @@
         assertNetworkNameEquals(expectedMNetworkName);
     }
 
+    @Test
     public void testOnReceive_stringsUpdatedAction_bothFalse() {
         Intent intent = createStringsUpdatedIntent(false /* showSpn */,
               "Irrelevant" /* spn */,
@@ -328,6 +354,7 @@
         assertNetworkNameEquals(defaultNetworkName);
     }
 
+    @Test
     public void testOnReceive_stringsUpdatedAction_bothTrueAndNull() {
         Intent intent = createStringsUpdatedIntent(true /* showSpn */,
             null /* spn */,
@@ -341,6 +368,7 @@
         assertNetworkNameEquals(defaultNetworkName);
     }
 
+    @Test
     public void testOnReceive_stringsUpdatedAction_bothTrueAndNonNull() {
         String spn = "Test1";
         String plmn = "Test2";
@@ -374,6 +402,7 @@
         return intent;
     }
 
+    @Test
     public void testOnUpdateDataActivity_dataIn() {
         setupDefaultSignal();
 
@@ -387,6 +416,7 @@
 
     }
 
+    @Test
     public void testOnUpdateDataActivity_dataOut() {
       setupDefaultSignal();
 
@@ -400,6 +430,7 @@
 
     }
 
+    @Test
     public void testOnUpdateDataActivity_dataInOut() {
       setupDefaultSignal();
 
@@ -413,6 +444,7 @@
 
     }
 
+    @Test
     public void testOnUpdateDataActivity_dataActivityNone() {
       setupDefaultSignal();
 
@@ -426,6 +458,7 @@
 
     }
 
+    @Test
     public void testCarrierNetworkChange_carrierNetworkChange() {
       int strength = SignalStrength.SIGNAL_STRENGTH_GREAT;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index d7c4e1e..fc7f942 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -5,19 +5,26 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+import static junit.framework.Assert.assertEquals;
+
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
     // These match the constants in WifiManager and need to be kept up to date.
     private static final int MIN_RSSI = -100;
     private static final int MAX_RSSI = -55;
 
+    @Test
     public void testWifiIcon() {
         String testSsid = "Test SSID";
         setWifiEnabled(true);
@@ -36,6 +43,7 @@
         }
     }
 
+    @Test
     public void testQsWifiIcon() {
         String testSsid = "Test SSID";
 
@@ -58,6 +66,7 @@
         }
     }
 
+    @Test
     public void testQsDataDirection() {
         // Setup normal connection
         String testSsid = "Test SSID";
@@ -79,6 +88,7 @@
         verifyLastQsDataDirection(true, true);
     }
 
+    @Test
     public void testRoamingIconDuringWifi() {
         // Setup normal connection
         String testSsid = "Test SSID";
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 242eca8..ff934ef 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -19,17 +19,22 @@
 import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.app.WallpaperManager.FLAG_SYSTEM;
 
+import android.app.AppGlobals;
 import android.app.WallpaperManager;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.FullBackupDataOutput;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.graphics.Rect;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
 import android.util.Xml;
@@ -142,11 +147,12 @@
             }
 
             // only back up the wallpapers if we've been told they're eligible
-            if ((sysEligible || lockEligible) && mWallpaperInfo.exists()) {
+            if (mWallpaperInfo.exists()) {
                 if (sysChanged || lockChanged || !infoStage.exists()) {
                     if (DEBUG) Slog.v(TAG, "New wallpaper configuration; copying");
                     FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
                 }
+                if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
                 fullBackupFile(infoStage, data);
             }
             if (sysEligible && mWallpaperFile.exists()) {
@@ -154,6 +160,7 @@
                     if (DEBUG) Slog.v(TAG, "New system wallpaper; copying");
                     FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
                 }
+                if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
                 fullBackupFile(imageStage, data);
                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
             }
@@ -164,6 +171,7 @@
                     if (DEBUG) Slog.v(TAG, "New lock wallpaper; copying");
                     FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
                 }
+                if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
                 fullBackupFile(lockImageStage, data);
                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
             }
@@ -217,6 +225,19 @@
             // wallpaper image present.
             restoreFromStage(imageStage, infoStage, "wp", sysWhich);
             restoreFromStage(lockImageStage, infoStage, "kwp", FLAG_LOCK);
+
+            // And reset to the wallpaper service we should be using
+            ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
+            if (servicePackageExists(wpService)) {
+                if (DEBUG) {
+                    Slog.i(TAG, "Using wallpaper service " + wpService);
+                }
+                mWm.setWallpaperComponent(wpService, UserHandle.USER_SYSTEM);
+            } else {
+                if (DEBUG) {
+                    Slog.v(TAG, "Can't use wallpaper service " + wpService);
+                }
+            }
         } catch (Exception e) {
             Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
         } finally {
@@ -274,18 +295,60 @@
             } while (type != XmlPullParser.END_DOCUMENT);
         } catch (Exception e) {
             // Whoops; can't process the info file at all.  Report failure.
-            Slog.w(TAG, "Failed to parse restored metadata: " + e.getMessage());
+            Slog.w(TAG, "Failed to parse restored crop: " + e.getMessage());
             return null;
         }
 
         return cropHint;
     }
 
+    private ComponentName parseWallpaperComponent(File wallpaperInfo, String sectionTag) {
+        ComponentName name = null;
+        try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+            int type;
+            do {
+                type = parser.next();
+                if (type == XmlPullParser.START_TAG) {
+                    String tag = parser.getName();
+                    if (sectionTag.equals(tag)) {
+                        final String parsedName = parser.getAttributeValue(null, "component");
+                        name = (parsedName != null)
+                                ? ComponentName.unflattenFromString(parsedName)
+                                : null;
+                        break;
+                    }
+                }
+            } while (type != XmlPullParser.END_DOCUMENT);
+        } catch (Exception e) {
+            // Whoops; can't process the info file at all.  Report failure.
+            Slog.w(TAG, "Failed to parse restored component: " + e.getMessage());
+            return null;
+        }
+        return name;
+    }
+
     private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
         final String value = parser.getAttributeValue(null, name);
         return (value == null) ? defValue : Integer.parseInt(value);
     }
 
+    private boolean servicePackageExists(ComponentName comp) {
+        try {
+            if (comp != null) {
+                final IPackageManager pm = AppGlobals.getPackageManager();
+                final PackageInfo info = pm.getPackageInfo(comp.getPackageName(),
+                        0, UserHandle.USER_SYSTEM);
+                return (info != null);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to contact package manager");
+        }
+        return false;
+    }
+
     //
     // Key/value API: abstract, therefore required; but not used
     //
diff --git a/preloaded-classes b/preloaded-classes
index 805a1c9..42f290e 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -2542,6 +2542,7 @@
 com.android.internal.os.RuntimeInit$Arguments
 com.android.internal.os.RuntimeInit$KillApplicationHandler
 com.android.internal.os.RuntimeInit$LoggingHandler
+com.android.internal.os.RoSystemProperties
 com.android.internal.os.SamplingProfilerIntegration
 com.android.internal.os.SomeArgs
 com.android.internal.os.Zygote
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8c8b391..815978e 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2270,6 +2270,308 @@
     //   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;
+
+    // ACTION: Managed provisioning was launched to set this package as DPC app.
+    // PACKAGE: DPC's package name.
+    PROVISIONING_DPC_PACKAGE_NAME = 517;
+
+    // ACTION: Managed provisioning triggered DPC installation.
+    // PACKAGE: Package name of package which installed DPC.
+    PROVISIONING_DPC_INSTALLED_BY_PACKAGE = 518;
+
+    // ACTION: Logged when provisioning activity finishes.
+    // TIME: Indicates time taken by provisioning activity to finish in MS.
+    PROVISIONING_PROVISIONING_ACTIVITY_TIME_MS = 519;
+
+    // ACTION: Logged when preprovisioning activity finishes.
+    // TIME: Indicates time taken by preprovisioning activity to finish in MS.
+    PROVISIONING_PREPROVISIONING_ACTIVITY_TIME_MS = 520;
+
+    // ACTION: Logged when encrypt device activity finishes.
+    // TIME: Indicates time taken by encrypt device activity to finish in MS.
+    PROVISIONING_ENCRYPT_DEVICE_ACTIVITY_TIME_MS = 521;
+
+    // ACTION: Logged when web activity finishes.
+    // TIME: Indicates total time taken by web activity to finish in MS.
+    PROVISIONING_WEB_ACTIVITY_TIME_MS = 522;
+
+    // ACTION: Logged when trampoline activity finishes.
+    // TIME: Indicates total time taken by trampoline activity to finish in MS.
+    PROVISIONING_TRAMPOLINE_ACTIVITY_TIME_MS = 523;
+
+    // ACTION: Logged when encryption activity finishes.
+    // TIME: Indicates total time taken by post encryption activity to finish in MS.
+    PROVISIONING_POST_ENCRYPTION_ACTIVITY_TIME_MS = 524;
+
+    // ACTION: Logged when finalization activity finishes.
+    // TIME: Indicates time taken by finalization activity to finish in MS.
+    PROVISIONING_FINALIZATION_ACTIVITY_TIME_MS = 525;
+
+    // OPEN: Settings Support > Phone/Chat -> Disclaimer
+    DIALOG_SUPPORT_DISCLAIMER = 526;
+
+    // OPEN: Settings Support > Travel abroad
+    DIALOG_SUPPORT_PHONE = 527;
+
+    // OPEN: Settings > Security > Factory Reset Protection dialog
+    DIALOG_FRP = 528;
+
+    // OPEN: Settings > Custom list preference with confirmation message
+    DIALOG_CUSTOM_LIST_CONFIRMATION = 529;
+
+    // OPEN: Settings > APN Editor > Error dialog
+    DIALOG_APN_EDITOR_ERROR = 530;
+
+    // OPEN: Settings > Users > Edit owner info dialog
+    DIALOG_OWNER_INFO_SETTINGS = 531;
+
+    // OPEN: Settings > Security > Use one lock dialog
+    DIALOG_UNIFICATION_CONFIRMATION = 532;
+
+    // OPEN: Settings > Security > User Credential
+    DIALOG_USER_CREDENTIAL = 533;
+
+    // OPEN: Settings > Accounts > Remove account
+    DIALOG_REMOVE_USER = 534;
+
+    // OPEN: Settings > Accounts > Confirm auto sync dialog
+    DIALOG_CONFIRM_AUTO_SYNC_CHANGE = 535;
+
+    // OPEN: Settings > Apps > Dialog for running service details
+    DIALOG_RUNNIGN_SERVICE = 536;
+
+    // OPEN: Settings > Dialog for hiding home settings
+    DIALOG_NO_HOME = 537;
+
+    // OPEN: Settings > Bluetooth > Rename this device
+    DIALOG_BLUETOOTH_RENAME = 538;
+
+    // OPEN: Settings > Bluetooth > Paired device profile
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_PROFILE = 539;
+
+    // OPEN: Settings > Battery optimization > details for app
+    DIALOG_HIGH_POWER_DETAILS = 540;
+
+    // OPEN: Settings > Keyboard > Show keyboard layout dialog
+    DIALOG_KEYBOARD_LAYOUT = 541;
+
+    // OPEN: Settings > Wifi > WPS Setup dialog
+    DIALOG_WPS_SETUP = 542;
+
+    // OPEN: Settings > WIFI Scan permission dialog
+    DIALOG_WIFI_SCAN_MODE = 543;
+
+    // OPEN: Settings > WIFI Setup > Skip Wifi dialog
+    DIALOG_WIFI_SKIP = 544;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog
+    DIALOG_LEGACY_VPN_CONFIG = 545;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog for app
+    DIALOG_VPN_APP_CONFIG = 546;
+
+    // OPEN: Settings > Wireless > VPN > Cannot connect dialog
+    DIALOG_VPN_CANNOT_CONNECT = 547;
+
+    // OPEN: Settings > Wireless > VPN > Replace existing VPN dialog
+    DIALOG_VPN_REPLACE_EXISTING = 548;
+
+    // OPEN: Settings > Billing cycle > Edit billing cycle dates dialog
+    DIALOG_BILLING_CYCLE = 549;
+
+    // OPEN: Settings > Billing cycle > Edit data limit/warning dialog
+    DIALOG_BILLING_BYTE_LIMIT = 550;
+
+    // OPEN: Settings > Billing cycle > turn on data limit dialog
+    DIALOG_BILLING_CONFIRM_LIMIT = 551;
+
+    // OPEN: Settings > Service > Turn off notification access dialog
+    DIALOG_DISABLE_NOTIFICATION_ACCESS = 552;
+
+    // OPEN: Settings > Sound > Use personal sound for work profile dialog
+    DIALOG_UNIFY_SOUND_SETTINGS = 553;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being granted.
+    DIALOG_ZEN_ACCESS_GRANT = 554;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being revoked.
+    DIALOG_ZEN_ACCESS_REVOKE = 555;
+
+    // OPEN: Settings > Zen mode > Dialog that picks time for zen mode.
+    DIALOG_ZEN_TIMEPICKER = 556;
+
+    // OPEN: Settings > Apps > Dialog that informs user to allow service access for app.
+    DIALOG_SERVICE_ACCESS_WARNING = 557;
+
+    // OPEN: Settings > Apps > Dialog for app actions (such as force stop/clear data)
+    DIALOG_APP_INFO_ACTION = 558;
+
+    // OPEN: Settings > Storage > Dialog for forgetting a storage device
+    DIALOG_VOLUME_FORGET = 559;
+
+    // OPEN: Settings > Storage > Dialog warning that a volume is slow
+    DIALOG_VOLUME_SLOW_WARNING = 560;
+
+    // OPEN: Settings > Storage > Dialog for initializing a volume
+    DIALOG_VOLUME_INIT = 561;
+
+    // OPEN: Settings > Storage > Dialog for unmounting a volume
+    DIALOG_VOLUME_UNMOUNT = 562;
+
+    // OPEN: Settings > Storage > Dialog for renaming a volume
+    DIALOG_VOLUME_RENAME = 563;
+
+    // OPEN: Settings > Storage > Dialog for clear cache
+    DIALOG_STORAGE_CLEAR_CACHE = 564;
+
+    // OPEN: Settings > Storage > Dialog for system info
+    DIALOG_STORAGE_SYSTEM_INFO = 565;
+
+    // OPEN: Settings > Storage > Dialog for other info
+    DIALOG_STORAGE_OTHER_INFO = 566;
+
+    // OPEN: Settings > Storage > Dialog for user info
+    DIALOG_STORAGE_USER_INFO = 567;
+
+    // OPEN: Settings > Add fingerprint > Dialog when user touches fingerprint icon.
+    DIALOG_FINGERPRINT_ICON_TOUCH = 568;
+
+    // OPEN: Settings > Add fingerprint > Error dialog
+    DIALOG_FINGERPINT_ERROR = 569;
+
+    // OPEN: Settings > Fingerprint > Rename or delete dialog
+    DIALOG_FINGERPINT_EDIT = 570;
+
+    // OPEN: Settings > Fingerprint > Dialog for deleting last fingerprint
+    DIALOG_FINGERPINT_DELETE_LAST = 571;
+
+    // OPEN: SUW > Fingerprint > Dialog to confirm cancel fingerprint setup.
+    DIALOG_FINGERPRINT_CANCEL_SETUP = 572;
+
+    // OPEN: SUW > Fingerprint > Dialog to confirm skip fingerprint setup entirely.
+    DIALOG_FINGERPRINT_SKIP_SETUP = 573;
+
+    // OPEN: Settings > Proxy Selector error dialog
+    DIALOG_PROXY_SELECTOR_ERROR = 574;
+
+    // OPEN: Settings > Wifi > P2P Settings > Disconnect dialog
+    DIALOG_WIFI_P2P_DISCONNECT = 575;
+
+    // OPEN: Settings > Wifi > P2P Settings > Cancel connection dialog
+    DIALOG_WIFI_P2P_CANCEL_CONNECT = 576;
+
+    // OPEN: Settings > Wifi > P2P Settings > Rename dialog
+    DIALOG_WIFI_P2P_RENAME = 577;
+
+    // OPEN: Settings > Wifi > P2P Settings > Forget group dialog
+    DIALOG_WIFI_P2P_DELETE_GROUP = 578;
+
+    // OPEN: Settings > APN > Restore default dialog
+    DIALOG_APN_RESTORE_DEFAULT = 579;
+
+    // OPEN: Settings > Dream > When to dream dialog
+    DIALOG_DREAM_START_DELAY = 580;
+
+    // OPEN: Settings > Encryption interstitial accessibility warning dialog
+    DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY = 581;
+
+    // OPEN: Settings > Tether > AP setting dialog
+    DIALOG_AP_SETTINGS = 582;
+
+    // OPEN: Settings > Acessibility > Enable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_ENABLE = 583;
+
+    // OPEN: Settings > Acessibility > Disable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_DISABLE = 584;
+
+    // OPEN: Settings > Account > Remove account dialog
+    DIALOG_ACCOUNT_SYNC_REMOVE = 585;
+
+    // OPEN: Settings > Account > Remove account failed dialog
+    DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL = 586;
+
+    // OPEN: Settings > Account > Cannot do onetime sync dialog
+    DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC = 587;
+
+    // OPEN: Settings > Display > Night light > Set start time dialog
+    DIALOG_NIGHT_DISPLAY_SET_START_TIME = 588;
+
+    // OPEN: Settings > Display > Night light > Set end time dialog
+    DIALOG_NIGHT_DISPLAY_SET_END_TIME = 589;
+
+    // OPEN: Settings > User > Edit info dialog
+    DIALOG_USER_EDIT = 590;
+
+    // OPEN: Settings > User > Confirm remove dialog
+    DIALOG_USER_REMOVE = 591;
+
+    // OPEN: Settings > User > Enable calling dialog
+    DIALOG_USER_ENABLE_CALLING = 592;
+
+    // OPEN: Settings > User > Enable calling and sms dialog
+    DIALOG_USER_ENABLE_CALLING_AND_SMS = 593;
+
+    // OPEN: Settings > User > Cannot manage device message dialog
+    DIALOG_USER_CANNOT_MANAGE = 594;
+
+    // OPEN: Settings > User > Add user dialog
+    DIALOG_USER_ADD = 595;
+
+    // OPEN: Settings > User > Setup user dialog
+    DIALOG_USER_SETUP = 596;
+
+    // OPEN: Settings > User > Setup profile dialog
+    DIALOG_USER_SETUP_PROFILE = 597;
+
+    // OPEN: Settings > User > Choose user type dialog
+    DIALOG_USER_CHOOSE_TYPE = 598;
+
+    // OPEN: Settings > User > Need lockscreen dialog
+    DIALOG_USER_NEED_LOCKSCREEN = 599;
+
+    // OPEN: Settings > User > Confirm exit guest mode dialog
+    DIALOG_USER_CONFIRM_EXIT_GUEST = 600;
+
+    // OPEN: Settings > User > Edit user profile dialog
+    DIALOG_USER_EDIT_PROFILE = 601;
+
+    // OPEN: Settings > Wifi > Saved AP > Edit dialog
+    DIALOG_WIFI_SAVED_AP_EDIT = 602;
+
+    // OPEN: Settings > Wifi > Edit AP dialog
+    DIALOG_WIFI_AP_EDIT = 603;
+
+    // OPEN: Settings > Wifi > PBC Config dialog
+    DIALOG_WIFI_PBC = 604;
+
+    // OPEN: Settings > Wifi > Display pin dialog
+    DIALOG_WIFI_PIN = 605;
+
+    // OPEN: Settings > Wifi > Write config to NFC dialog
+    DIALOG_WIFI_WRITE_NFC = 606;
+    // OPEN: Settings > Date > Date picker dialog
+    DIALOG_DATE_PICKER = 607;
+
+    // OPEN: Settings > Date > Time picker dialog
+    DIALOG_TIME_PICKER = 608;
+
+    // OPEN: Settings > Wireless > Manage wireless plan dialog
+    DIALOG_MANAGE_MOBILE_PLAN = 609;
+
+    // ACTION: Logs network type of the device while provisioning
+    PROVISIONING_NETWORK_TYPE = 610;
+
+    // ACTION: Logs action which triggered provisioning.
+    PROVISIONING_ACTION = 611;
+
     // ---- 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/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index 562d950..582b19b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -341,6 +341,8 @@
         mDoubleTapDetected = false;
         mSecondFingerDoubleTap = false;
         mGestureStarted = false;
+        mGestureDetector.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL,
+                0.0f, 0.0f, 0));
         cancelGesture();
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ea25f74..0b83e66 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
@@ -1275,8 +1315,14 @@
     private void updateServicesLocked(UserState userState) {
         Map<ComponentName, Service> componentNameToServiceMap =
                 userState.mComponentNameToServiceMap;
-        boolean isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class)
-                .isUserUnlockingOrUnlocked(userState.mUserId);
+        boolean isUnlockingOrUnlocked;
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class)
+                    .isUserUnlockingOrUnlocked(userState.mUserId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
 
         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
@@ -2201,6 +2247,8 @@
 
         AccessibilityServiceInfo mAccessibilityServiceInfo;
 
+        // The service that's bound to this instance. Whenever this value is non-null, this
+        // object is registered as a death recipient
         IBinder mService;
 
         IAccessibilityServiceClient mServiceInterface;
@@ -2281,7 +2329,7 @@
 
         @Override
         public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
-            if (!mRequestFilterKeyEvents) {
+            if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
                 return false;
             }
             if((mAccessibilityServiceInfo.getCapabilities()
@@ -2352,14 +2400,14 @@
                 }
             } else {
                 userState.mBindingServices.add(mComponentName);
-                mService = userState.mUiAutomationServiceClient.asBinder();
                 mMainHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         // Simulate asynchronous connection since in onServiceConnected
                         // we may modify the state data in case of an error but bind is
                         // called while iterating over the data and bad things can happen.
-                        onServiceConnected(mComponentName, mService);
+                        onServiceConnected(mComponentName,
+                                userState.mUiAutomationServiceClient.asBinder());
                     }
                 });
                 userState.mUiAutomationService = this;
@@ -2451,7 +2499,19 @@
         @Override
         public void onServiceConnected(ComponentName componentName, IBinder service) {
             synchronized (mLock) {
-                mService = service;
+                if (mService != service) {
+                    if (mService != null) {
+                        mService.unlinkToDeath(this, 0);
+                    }
+                    mService = service;
+                    try {
+                        mService.linkToDeath(this, 0);
+                    } catch (RemoteException re) {
+                        Slog.e(LOG_TAG, "Failed registering death link");
+                        binderDied();
+                        return;
+                    }
+                }
                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
                 UserState userState = getUserStateLocked(mUserId);
                 addServiceLocked(this, userState);
@@ -2477,7 +2537,7 @@
             // share the accessibility state of the parent. The call below
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
-                    .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
+                    .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.getCallingUserId());
             return resolvedUserId == mCurrentUserId;
         }
 
@@ -3085,7 +3145,6 @@
         }
 
         public void onAdded() throws RemoteException {
-            linkToOwnDeathLocked();
             final long identity = Binder.clearCallingIdentity();
             try {
                 mWindowManagerService.addWindowToken(mOverlayWindowToken,
@@ -3102,17 +3161,6 @@
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
-            unlinkToOwnDeathLocked();
-        }
-
-        public void linkToOwnDeathLocked() throws RemoteException {
-            mService.linkToDeath(this, 0);
-        }
-
-        public void unlinkToOwnDeathLocked() {
-            if (mService != null) {
-                mService.unlinkToDeath(this, 0);
-            }
         }
 
         public void resetLocked() {
@@ -3125,7 +3173,10 @@
             } catch (RemoteException re) {
                 /* ignore */
             }
-            mService = null;
+            if (mService != null) {
+                mService.unlinkToDeath(this, 0);
+                mService = null;
+            }
             mServiceInterface = null;
         }
 
@@ -3603,6 +3654,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:
@@ -3687,13 +3739,6 @@
                 Rect boundsInScreen = mTempRect;
                 focus.getBoundsInScreen(boundsInScreen);
 
-                // Clip to the window bounds.
-                Rect windowBounds = mTempRect1;
-                getWindowBounds(focus.getWindowId(), windowBounds);
-                if (!boundsInScreen.intersect(windowBounds)) {
-                    return false;
-                }
-
                 // Apply magnification if needed.
                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
                 if (spec != null && !spec.isNop()) {
@@ -3701,6 +3746,13 @@
                     boundsInScreen.scale(1 / spec.scale);
                 }
 
+                // Clip to the window bounds.
+                Rect windowBounds = mTempRect1;
+                getWindowBounds(focus.getWindowId(), windowBounds);
+                if (!boundsInScreen.intersect(windowBounds)) {
+                    return false;
+                }
+
                 // Clip to the screen bounds.
                 Point screenSize = mTempPoint;
                 mDefaultDisplay.getRealSize(screenSize);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 1532946..c81a876 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.Binder;
 import android.provider.Settings.Secure;
 import android.view.accessibility.AccessibilityManager;
 
@@ -60,10 +61,15 @@
         final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
 
         int daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
-        if (Secure.getIntForUser(cr,
-                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
-            daltonizerMode = Secure.getIntForUser(cr,
-                    Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (Secure.getIntForUser(cr,
+                    Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
+                daltonizerMode = Secure.getIntForUser(cr,
+                        Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
 
         float[] grayscaleMatrix = null;
@@ -83,9 +89,14 @@
         final ContentResolver cr = context.getContentResolver();
         final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
 
-        final boolean invertColors = Secure.getIntForUser(cr,
-                Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0;
-        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
-                invertColors ? MATRIX_INVERT_COLOR : null);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            final boolean invertColors = Secure.getIntForUser(cr,
+                    Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0;
+            dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
+                    invertColors ? MATRIX_INVERT_COLOR : null);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 5ec3f2b..bf60e47 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2269,6 +2269,7 @@
         pw.print(info.updatePeriodMillis);
         pw.print(" resizeMode=");
         pw.print(info.resizeMode);
+        pw.print(" widgetCategory=");
         pw.print(info.widgetCategory);
         pw.print(" autoAdvanceViewId=");
         pw.print(info.autoAdvanceViewId);
diff --git a/services/core/Android.mk b/services/core/Android.mk
index b965ce3..58f2074 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -8,16 +8,18 @@
 
 LOCAL_SRC_FILES += \
     $(call all-java-files-under,java) \
+    $(call all-proto-files-under, proto) \
     java/com/android/server/EventLogTags.logtags \
     java/com/android/server/am/EventLogTags.logtags \
     ../../../../system/netd/server/binder/android/net/INetd.aidl \
-    ../../../../system/netd/server/binder/android/net/metrics/IDnsEventListener.aidl \
+    ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
 
 LOCAL_AIDL_INCLUDES += \
     system/netd/server/binder
 
 LOCAL_JAVA_LIBRARIES := services.net telephony-common
 LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
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..7c2eea3f 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -51,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.os.storage.MountServiceInternal;
@@ -875,7 +876,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 +1025,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 +1083,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 +1309,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();
 
@@ -1787,8 +1788,9 @@
     }
 
     @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
-        (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver);
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     static void dumpCommandHelp(PrintWriter pw) {
@@ -2210,25 +2212,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 +2273,22 @@
     @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);
+            }
+            removeUidsForUserLocked(userHandle);
+        }
+    }
+
+    private void removeUidsForUserLocked(int userHandle) {
+        for (int i = mUidStates.size() - 1; i >= 0; --i) {
+            final int uid = mUidStates.keyAt(i);
+            if (UserHandle.getUserId(uid) == userHandle) {
+                mUidStates.removeAt(i);
+            }
         }
     }
 
@@ -2386,6 +2408,12 @@
                     perUserExcludedPackages = null;
                 }
             }
+            if (perUserRestrictions != null) {
+                perUserRestrictions.remove(userId);
+                if (perUserRestrictions.size() <= 0) {
+                    perUserRestrictions = null;
+                }
+            }
         }
 
         public boolean isDefault() {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 6b51721..d2cfb6d 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -20,6 +20,7 @@
 import android.os.BatteryStats;
 
 import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
@@ -789,7 +790,7 @@
                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
             } else {
                 Shell shell = new Shell();
-                shell.exec(mBinderService, null, fd, null, args, new ResultReceiver(null));
+                shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
             }
         }
     }
@@ -875,8 +876,9 @@
         }
 
         @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
-                FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
-            (new Shell()).exec(this, in, out, err, args, resultReceiver);
+                FileDescriptor err, String[] args, ShellCallback callback,
+                ResultReceiver resultReceiver) {
+            (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
         }
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8b243e7..3ad71ea 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;
@@ -302,7 +302,7 @@
      */
     private final boolean isBluetoothPersistedStateOn() {
         return Settings.Global.getInt(mContentResolver,
-                Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
+                Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) != BLUETOOTH_OFF;
     }
 
     /**
@@ -310,7 +310,7 @@
      */
     private final boolean isBluetoothPersistedStateOnBluetooth() {
         return Settings.Global.getInt(mContentResolver,
-                Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
+                Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
     }
 
     /**
@@ -742,7 +742,16 @@
             // 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.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+                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) {
@@ -762,6 +771,7 @@
             if (mUnbinding) return;
             mUnbinding = true;
             mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+            mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
             if (mBluetooth != null) {
                 //Unregister callback object
                 try {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 70f39db..fa2f6ac 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -24,6 +24,7 @@
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
@@ -38,7 +39,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;
@@ -132,9 +132,12 @@
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.KeepaliveTracker;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.LingerMonitor;
 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;
@@ -260,6 +263,11 @@
         DONT_REAP
     };
 
+    private enum UnneededFor {
+        LINGER,    // Determine whether this network is unneeded and should be lingered.
+        TEARDOWN,  // Determine whether this network is unneeded and should be torn down.
+    }
+
     /**
      * used internally to change our mobile data enabled flag
      */
@@ -364,6 +372,11 @@
     private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
 
     /**
+     * used to specify whether a network should not be penalized when it becomes unvalidated.
+     */
+    private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
+
+    /**
      * used to ask the user to confirm a connection to an unvalidated network.
      * obj  = network
      */
@@ -390,6 +403,11 @@
     private static final int EVENT_REQUEST_LINKPROPERTIES  = 32;
     private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
 
+    /**
+     * Used internally to (re)configure avoid bad wifi setting.
+     */
+    private static final int EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI = 34;
+
     /** Handler thread used for both of the handlers below. */
     @VisibleForTesting
     protected final HandlerThread mHandlerThread;
@@ -436,6 +454,8 @@
     TelephonyManager mTelephonyManager;
 
     private KeepaliveTracker mKeepaliveTracker;
+    private NetworkNotificationManager mNotifier;
+    private LingerMonitor mLingerMonitor;
 
     // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
     private final static int MIN_NET_ID = 100; // some reserved marks
@@ -687,13 +707,13 @@
         if (DBG) log("ConnectivityService starting up");
 
         mMetricsLog = logger;
-        mDefaultRequest = createInternetRequestForTransport(-1);
+        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
         mNetworkRequests.put(mDefaultRequest, defaultNRI);
         mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
 
         mDefaultMobileDataRequest = createInternetRequestForTransport(
-                NetworkCapabilities.TRANSPORT_CELLULAR);
+                NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
 
         mHandlerThread = createHandlerThread();
         mHandlerThread.start();
@@ -796,7 +816,7 @@
         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
                 && SystemProperties.get("ro.build.type").equals("eng");
 
-        mTethering = new Tethering(mContext, mNetd, statsService);
+        mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager);
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
@@ -832,17 +852,36 @@
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
         mKeepaliveTracker = new KeepaliveTracker(mHandler);
+        mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
+                mContext.getSystemService(NotificationManager.class));
+
+        final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+                LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
+        final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+                LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
+        mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
+
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
+            }
+        }, UserHandle.ALL, intentFilter, null, null);
+        updateAvoidBadWifi();
     }
 
-    private NetworkRequest createInternetRequestForTransport(int transportType) {
+    private NetworkRequest createInternetRequestForTransport(
+            int transportType, NetworkRequest.Type type) {
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
         netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
         if (transportType > -1) {
             netCap.addTransportType(transportType);
         }
-        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(),
-                NetworkRequest.Type.REQUEST);
+        return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
     }
 
     // Used only for testing.
@@ -882,6 +921,12 @@
         mSettingsObserver.observe(
                 Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
                 EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
+
+        // Watch for whether to automatically switch away from wifi networks that lose Internet
+        // access.
+        mSettingsObserver.observe(
+                Settings.Global.getUriFor(Settings.Global.NETWORK_AVOID_BAD_WIFI),
+                EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
     }
 
     private synchronized int nextNetworkRequestId() {
@@ -1524,19 +1569,10 @@
         }
 
         @Override
-        public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
+        public void onUidPoliciesChanged(int uid, int uidPolicies) {
+            // caller is NPMS, since we only register with them
             if (LOGD_RULES) {
-                // caller is NPMS, since we only register with them
-                log("onRestrictBackgroundWhitelistChanged(uid=" + uid + ", whitelisted="
-                        + whitelisted + ")");
-            }
-        }
-        @Override
-        public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
-            if (LOGD_RULES) {
-                // caller is NPMS, since we only register with them
-                log("onRestrictBackgroundBlacklistChanged(uid=" + uid + ", blacklisted="
-                        + blacklisted + ")");
+                log("onUidRulesChanged(uid=" + uid + ", uidPolicies=" + uidPolicies + ")");
             }
         }
     };
@@ -1959,8 +1995,12 @@
         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
             pw.println(nai.toString());
             pw.increaseIndent();
-            pw.println(String.format("Requests: %d request/%d total",
-                    nai.numRequestNetworkRequests(), nai.numNetworkRequests()));
+            pw.println(String.format(
+                    "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d",
+                    nai.numForegroundNetworkRequests(),
+                    nai.numNetworkRequests() - nai.numRequestNetworkRequests(),
+                    nai.numBackgroundNetworkRequests(),
+                    nai.numNetworkRequests()));
             pw.increaseIndent();
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
                 pw.println(nai.requestAt(i).toString());
@@ -2029,7 +2069,9 @@
         mKeepaliveTracker.dump(pw);
 
         pw.println();
+        dumpAvoidBadWifiSettings(pw);
 
+        pw.println();
         if (mInetLog != null && mInetLog.size() > 0) {
             pw.println();
             pw.println("Inet condition reports:");
@@ -2119,15 +2161,11 @@
                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
                     final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
                     if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
-                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
+                            networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
                         Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                     }
-                    if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
-                            networkCapabilities)) {
-                        Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
-                                + nai.networkCapabilities + " -> " + networkCapabilities);
-                    }
-                    updateCapabilities(nai, networkCapabilities);
+                    updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
                     break;
                 }
                 case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
@@ -2198,13 +2236,14 @@
                     if (nai != null) {
                         final boolean valid =
                                 (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                        final boolean wasValidated = nai.lastValidated;
                         if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
                                 (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
                         if (valid != nai.lastValidated) {
                             final int oldScore = nai.getCurrentScore();
                             nai.lastValidated = valid;
                             nai.everValidated |= valid;
-                            updateCapabilities(nai, nai.networkCapabilities);
+                            updateCapabilities(oldScore, nai, nai.networkCapabilities);
                             // If score has changed, rebroadcast to NetworkFactories. b/17726566
                             if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
                         }
@@ -2216,6 +2255,9 @@
                                 NetworkAgent.CMD_REPORT_NETWORK_STATUS,
                                 (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                                 0, redirectUrlBundle);
+                         if (wasValidated && !nai.lastValidated) {
+                             handleNetworkUnvalidated(nai);
+                         }
                     }
                     break;
                 }
@@ -2228,21 +2270,21 @@
                     }
                     // If captive portal status has changed, update capabilities.
                     if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
+                        final int oldScore = nai.getCurrentScore();
                         nai.lastCaptivePortalDetected = visible;
                         nai.everCaptivePortalDetected |= visible;
-                        updateCapabilities(nai, nai.networkCapabilities);
+                        updateCapabilities(oldScore, 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, null,
+                                    (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
                         }
                     }
                     break;
@@ -2282,15 +2324,13 @@
         // 3. If this network is unneeded (which implies it is not lingering), and there is at least
         //    one lingered request, start lingering.
         nai.updateLingerTimer();
-        if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) {
+        if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
             if (DBG) log("Unlingering " + nai.name());
             nai.unlinger();
             logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
-        } else if (unneeded(nai) && nai.getLingerExpiry() > 0) {  // unneeded() calls isLingering()
+        } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
             int lingerTime = (int) (nai.getLingerExpiry() - now);
-            if (DBG) {
-                Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms");
-            }
+            if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms");
             nai.linger();
             logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
@@ -2392,6 +2432,7 @@
             }
             mLegacyTypeTracker.remove(nai, wasDefault);
             rematchAllNetworksAndRequests(null, 0);
+            mLingerMonitor.noteDisconnect(nai);
             if (nai.created) {
                 // Tell netd to clean up the configuration for this network
                 // (routing rules, DNS, etc).
@@ -2468,15 +2509,37 @@
         }
     }
 
-    // Is nai unneeded by all NetworkRequests (and should be disconnected)?
-    // This is whether it is satisfying any NetworkRequests or were it to become validated,
-    // would it have a chance of satisfying any NetworkRequests.
-    private boolean unneeded(NetworkAgentInfo nai) {
-        if (!nai.everConnected || nai.isVPN() ||
-               nai.isLingering() || nai.numRequestNetworkRequests() > 0) {
+    // Determines whether the network is the best (or could become the best, if it validated), for
+    // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends
+    // on the value of reason:
+    //
+    // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason,
+    //   then it should be torn down.
+    // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
+    //   then it should be lingered.
+    private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
+        final int numRequests;
+        switch (reason) {
+            case TEARDOWN:
+                numRequests = nai.numRequestNetworkRequests();
+                break;
+            case LINGER:
+                numRequests = nai.numForegroundNetworkRequests();
+                break;
+            default:
+                Slog.wtf(TAG, "Invalid reason. Cannot happen.");
+                return true;
+        }
+
+        if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
             return false;
         }
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
+                // Background requests don't affect lingering.
+                continue;
+            }
+
             // If this Network is already the highest scoring Network for a request, or if
             // there is hope for it to become one if it validated, then it is needed.
             if (nri.request.isRequest() && nai.satisfies(nri.request) &&
@@ -2539,14 +2602,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) {
@@ -2564,6 +2641,7 @@
             boolean wasKept = false;
             NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
             if (nai != null) {
+                boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
                 nai.removeRequest(nri.request.requestId);
                 if (VDBG) {
                     log(" Removing from current network " + nai.name() +
@@ -2572,13 +2650,17 @@
                 // If there are still lingered requests on this network, don't tear it down,
                 // but resume lingering instead.
                 updateLingerState(nai, SystemClock.elapsedRealtime());
-                if (unneeded(nai)) {
+                if (unneeded(nai, UnneededFor.TEARDOWN)) {
                     if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
                     teardownUnneededNetwork(nai);
                 } else {
                     wasKept = true;
                 }
                 mNetworkForRequestId.remove(nri.request.requestId);
+                if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
+                    // Went from foreground to background.
+                    updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+                }
             }
 
             // TODO: remove this code once we know that the Slog.wtf is never hit.
@@ -2635,7 +2717,7 @@
                 }
             }
         }
-        callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
+        callCallbackForRequest(nri, null, whichCallback, 0);
     }
 
     @Override
@@ -2645,6 +2727,12 @@
                 accept ? 1 : 0, always ? 1: 0, network));
     }
 
+    @Override
+    public void setAvoidUnvalidated(Network network) {
+        enforceConnectivityInternalPermission();
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
+    }
+
     private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
         if (DBG) log("handleSetAcceptUnvalidated network=" + network +
                 " accept=" + accept + " always=" + always);
@@ -2685,6 +2773,20 @@
 
     }
 
+    private void handleSetAvoidUnvalidated(Network network) {
+        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai == null || nai.lastValidated) {
+            // Nothing to do. The network either disconnected or revalidated.
+            return;
+        }
+        if (!nai.avoidUnvalidated) {
+            int oldScore = nai.getCurrentScore();
+            nai.avoidUnvalidated = true;
+            rematchAllNetworksAndRequests(nai, oldScore);
+            sendUpdatedScoreToFactories(nai);
+        }
+    }
+
     private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) {
         if (VDBG) log("scheduleUnvalidatedPrompt " + nai.network);
         mHandler.sendMessageDelayed(
@@ -2692,6 +2794,95 @@
                 PROMPT_UNVALIDATED_DELAY_MS);
     }
 
+    private boolean mAvoidBadWifi = true;
+
+    public boolean avoidBadWifi() {
+        return mAvoidBadWifi;
+    }
+
+    @VisibleForTesting
+    /** Whether the device or carrier configuration disables avoiding bad wifi by default. */
+    public boolean configRestrictsAvoidBadWifi() {
+        return mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0;
+    }
+
+    /** Whether we should display a notification when wifi becomes unvalidated. */
+    public boolean shouldNotifyWifiUnvalidated() {
+        return configRestrictsAvoidBadWifi() &&
+                Settings.Global.getString(mContext.getContentResolver(),
+                        Settings.Global.NETWORK_AVOID_BAD_WIFI) == null;
+    }
+
+    private boolean updateAvoidBadWifi() {
+        boolean settingAvoidBadWifi = "1".equals(Settings.Global.getString(
+                mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI));
+
+        boolean prev = mAvoidBadWifi;
+        mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
+        return mAvoidBadWifi != prev;
+    }
+
+    private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
+        boolean configRestrict = configRestrictsAvoidBadWifi();
+        if (!configRestrict) {
+            pw.println("Bad Wi-Fi avoidance: unrestricted");
+            return;
+        }
+
+        pw.println("Bad Wi-Fi avoidance: " + avoidBadWifi());
+        pw.increaseIndent();
+        pw.println("Config restrict:   " + configRestrict);
+
+        String value = Settings.Global.getString(
+                mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI);
+        String description;
+        // Can't use a switch statement because strings are legal case labels, but null is not.
+        if ("0".equals(value)) {
+            description = "get stuck";
+        } else if (value == null) {
+            description = "prompt";
+        } else if ("1".equals(value)) {
+            description = "avoid";
+        } else {
+            description = value + " (?)";
+        }
+        pw.println("User setting:      " + description);
+        pw.println("Network overrides:");
+        pw.increaseIndent();
+        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            if (nai.avoidUnvalidated) {
+                pw.println(nai.name());
+            }
+        }
+        pw.decreaseIndent();
+        pw.decreaseIndent();
+    }
+
+    private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
+        final String action;
+        switch (type) {
+            case NO_INTERNET:
+                action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
+                break;
+            case LOST_INTERNET:
+                action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
+                break;
+            default:
+                Slog.wtf(TAG, "Unknown notification type " + type);
+                return;
+        }
+
+        Intent intent = new Intent(action);
+        intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName("com.android.settings",
+                "com.android.settings.wifi.WifiNoInternetDialog");
+
+        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
+                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+        mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true);
+    }
+
     private void handlePromptUnvalidated(Network network) {
         if (VDBG) log("handlePromptUnvalidated " + network);
         NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -2703,18 +2894,22 @@
                 !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
             return;
         }
+        showValidationNotification(nai, NotificationType.NO_INTERNET);
+    }
 
-        Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED);
-        intent.setData(Uri.fromParts("netId", Integer.toString(network.netId), null));
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClassName("com.android.settings",
-                "com.android.settings.wifi.WifiNoInternetDialog");
+    // TODO: Delete this like updateMobileDataAlwaysOn above.
+    @VisibleForTesting
+    void updateNetworkAvoidBadWifi() {
+        mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
+    }
 
-        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
+        NetworkCapabilities nc = nai.networkCapabilities;
+        if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
 
-        setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
-                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
+        if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && shouldNotifyWifiUnvalidated()) {
+            showValidationNotification(nai, NotificationType.LOST_INTERNET);
+        }
     }
 
     private class InternalHandler extends Handler {
@@ -2778,6 +2973,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;
@@ -2790,6 +2990,10 @@
                     handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0);
                     break;
                 }
+                case EVENT_SET_AVOID_UNVALIDATED: {
+                    handleSetAvoidUnvalidated((Network) msg.obj);
+                    break;
+                }
                 case EVENT_PROMPT_UNVALIDATED: {
                     handlePromptUnvalidated((Network) msg.obj);
                     break;
@@ -2798,6 +3002,18 @@
                     handleMobileDataAlwaysOn();
                     break;
                 }
+                case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
+                    if (updateAvoidBadWifi()) {
+                        rematchAllNetworksAndRequests(null, 0);
+                        for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
+                            if (nai.networkCapabilities.hasTransport(
+                                    NetworkCapabilities.TRANSPORT_WIFI)) {
+                                sendUpdatedScoreToFactories(nai);
+                            }
+                        }
+                    }
+                    break;
+                }
                 case EVENT_REQUEST_LINKPROPERTIES:
                     handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
                     break;
@@ -2833,12 +3049,6 @@
         ConnectivityManager.enforceTetherChangePermission(mContext);
         if (isTetheringSupported()) {
             final int status = mTethering.tether(iface);
-            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
-                try {
-                    mPolicyManager.onTetheringChanged(iface, true);
-                } catch (RemoteException e) {
-                }
-            }
             return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
@@ -2852,12 +3062,6 @@
 
         if (isTetheringSupported()) {
             final int status = mTethering.untether(iface);
-            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
-                try {
-                    mPolicyManager.onTetheringChanged(iface, false);
-                } catch (RemoteException e) {
-                }
-            }
             return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
@@ -3620,118 +3824,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 +3927,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);
         }
@@ -4237,8 +4331,17 @@
             enforceAccessPermission();
         }
 
-        NetworkRequest networkRequest = new NetworkRequest(
-                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
+        NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        if (!ConnectivityManager.checkChangePermission(mContext)) {
+            // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
+            // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
+            // onLost and onAvailable callbacks when networks move in and out of the background.
+            // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
+            // can't request networks.
+            nc.addCapability(NET_CAPABILITY_FOREGROUND);
+        }
+
+        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
         if (VDBG) log("listenForNetwork for " + nri);
@@ -4359,6 +4462,10 @@
         return nai == getDefaultNetwork();
     }
 
+    private boolean isDefaultRequest(NetworkRequestInfo nri) {
+        return nri.request.requestId == mDefaultRequest.requestId;
+    }
+
     public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkMisc networkMisc) {
@@ -4549,15 +4656,35 @@
         mNumDnsEntries = last;
     }
 
+    private String getNetworkPermission(NetworkCapabilities nc) {
+        // TODO: make these permission strings AIDL constants instead.
+        if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+            return NetworkManagementService.PERMISSION_SYSTEM;
+        }
+        if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
+            return NetworkManagementService.PERMISSION_NETWORK;
+        }
+        return null;
+    }
+
     /**
      * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
      * augmented with any stateful capabilities implied from {@code networkAgent}
      * (e.g., validated status and captive portal status).
      *
+     * @param oldScore score of the network before any of the changes that prompted us
+     *                 to call this function.
      * @param nai the network having its capabilities updated.
      * @param networkCapabilities the new network capabilities.
      */
-    private void updateCapabilities(NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
+    private void updateCapabilities(
+            int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
+        if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities(
+                networkCapabilities)) {
+            Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: "
+                    + nai.networkCapabilities + " -> " + networkCapabilities);
+        }
+
         // Don't modify caller's NetworkCapabilities.
         networkCapabilities = new NetworkCapabilities(networkCapabilities);
         if (nai.lastValidated) {
@@ -4570,21 +4697,38 @@
         } else {
             networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
         }
-        if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
-            final int oldScore = nai.getCurrentScore();
-            if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) !=
-                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
-                try {
-                    mNetd.setNetworkPermission(nai.network.netId,
-                            networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ?
-                                    null : NetworkManagementService.PERMISSION_SYSTEM);
-                } catch (RemoteException e) {
-                    loge("Exception in setNetworkPermission: " + e);
-                }
+        if (nai.isBackgroundNetwork()) {
+            networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND);
+        } else {
+            networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
+        }
+
+        if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;
+
+        final String oldPermission = getNetworkPermission(nai.networkCapabilities);
+        final String newPermission = getNetworkPermission(networkCapabilities);
+        if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
+            try {
+                mNetd.setNetworkPermission(nai.network.netId, newPermission);
+            } catch (RemoteException e) {
+                loge("Exception in setNetworkPermission: " + e);
             }
-            synchronized (nai) {
-                nai.networkCapabilities = networkCapabilities;
-            }
+        }
+
+        final NetworkCapabilities prevNc = nai.networkCapabilities;
+        synchronized (nai) {
+            nai.networkCapabilities = networkCapabilities;
+        }
+        if (nai.getCurrentScore() == oldScore &&
+                networkCapabilities.equalRequestableCapabilities(prevNc)) {
+            // If the requestable capabilities haven't changed, and the score hasn't changed, then
+            // the change we're processing can't affect any requests, it can only affect the listens
+            // on this network. We might have been called by rematchNetworkAndRequests when a
+            // network changed foreground state.
+            processListenRequests(nai, true);
+        } else {
+            // If the requestable capabilities have changed or the score changed, we can't have been
+            // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests(nai, oldScore);
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
@@ -4707,8 +4851,13 @@
         // must be no other active linger timers, and we must stop lingering.
         oldNetwork.clearLingerState();
 
-        if (unneeded(oldNetwork)) {
+        if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
+            // Tear the network down.
             teardownUnneededNetwork(oldNetwork);
+        } else {
+            // Put the network in the background.
+            updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
+                    oldNetwork.networkCapabilities);
         }
     }
 
@@ -4726,6 +4875,31 @@
         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
     }
 
+    private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
+        // For consistency with previous behaviour, send onLost callbacks before onAvailable.
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            NetworkRequest nr = nri.request;
+            if (!nr.isListen()) continue;
+            if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
+                nai.removeRequest(nri.request.requestId);
+                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
+            }
+        }
+
+        if (capabilitiesChanged) {
+            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+        }
+
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            NetworkRequest nr = nri.request;
+            if (!nr.isListen()) continue;
+            if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
+                nai.addRequest(nr);
+                notifyNetworkCallback(nai, nri);
+            }
+        }
+    }
+
     // Handles a network appearing or improving its score.
     //
     // - Evaluates all current NetworkRequests that can be
@@ -4759,13 +4933,25 @@
         boolean keep = newNetwork.isVPN();
         boolean isNewDefault = false;
         NetworkAgentInfo oldDefaultNetwork = null;
+
+        final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
+        final int score = newNetwork.getCurrentScore();
+
         if (VDBG) log("rematching " + newNetwork.name());
+
         // Find and migrate to this Network any NetworkRequests for
         // which this network is now the best.
         ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
         ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
-        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
+        NetworkCapabilities nc = newNetwork.networkCapabilities;
+        if (VDBG) log(" network has: " + nc);
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            // Process requests in the first pass and listens in the second pass. This allows us to
+            // change a network's capabilities depending on which requests it has. This is only
+            // correct if the change in capabilities doesn't affect whether the network satisfies
+            // requests or not, and doesn't affect the network's score.
+            if (nri.request.isListen()) continue;
+
             final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
             final boolean satisfies = newNetwork.satisfies(nri.request);
             if (newNetwork == currentNetwork && satisfies) {
@@ -4780,22 +4966,14 @@
             // check if it satisfies the NetworkCapabilities
             if (VDBG) log("  checking if request is satisfied: " + nri.request);
             if (satisfies) {
-                if (nri.request.isListen()) {
-                    // This is not a request, it's a callback listener.
-                    // Add it to newNetwork regardless of score.
-                    if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
-                    continue;
-                }
-
                 // next check if it's better than any current network we're using for
                 // this request
                 if (VDBG) {
                     log("currentScore = " +
                             (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
-                            ", newScore = " + newNetwork.getCurrentScore());
+                            ", newScore = " + score);
                 }
-                if (currentNetwork == null ||
-                        currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
+                if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
                     if (VDBG) log("rematch for " + newNetwork.name());
                     if (currentNetwork != null) {
                         if (VDBG) log("   accepting network in place of " + currentNetwork.name());
@@ -4817,16 +4995,19 @@
                     // TODO - this could get expensive if we have alot of requests for this
                     // network.  Think about if there is a way to reduce this.  Push
                     // netid->request mapping to each factory?
-                    sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
-                    if (mDefaultRequest.requestId == nri.request.requestId) {
+                    sendUpdatedScoreToFactories(nri.request, score);
+                    if (isDefaultRequest(nri)) {
                         isNewDefault = true;
                         oldDefaultNetwork = currentNetwork;
+                        if (currentNetwork != null) {
+                            mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);
+                        }
                     }
                 }
             } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
                 // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
                 // mark it as no longer satisfying "nri".  Because networks are processed by
-                // rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
+                // rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
                 // match "newNetwork" before this loop will encounter a "currentNetwork" with higher
                 // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
                 // This means this code doesn't have to handle the case where "currentNetwork" no
@@ -4840,16 +5021,14 @@
                     mNetworkForRequestId.remove(nri.request.requestId);
                     sendUpdatedScoreToFactories(nri.request, 0);
                 } else {
-                    if (nri.request.isRequest()) {
-                        Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
-                                newNetwork.name() +
-                                " without updating mNetworkForRequestId or factories!");
-                    }
+                    Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
+                            newNetwork.name() +
+                            " without updating mNetworkForRequestId or factories!");
                 }
-                // TODO: technically, sending CALLBACK_LOST here is
-                // incorrect if nri is a request (not a listen) and there
-                // is a replacement network currently connected that can
-                // satisfy it. However, the only capability that can both
+                // TODO: Technically, sending CALLBACK_LOST here is
+                // incorrect if there is a replacement network currently
+                // connected that can satisfy nri, which is a request
+                // (not a listen). However, the only capability that can both
                 // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
                 // so this code is only incorrect for a network that loses
                 // the TRUSTED capability, which is a rare case.
@@ -4874,6 +5053,28 @@
             }
         }
 
+        if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
+            Slog.wtf(TAG, String.format(
+                    "BUG: %s changed requestable capabilities during rematch: %s -> %s",
+                    nc, newNetwork.networkCapabilities));
+        }
+        if (newNetwork.getCurrentScore() != score) {
+            Slog.wtf(TAG, String.format(
+                    "BUG: %s changed score during rematch: %d -> %d",
+                    score, newNetwork.getCurrentScore()));
+        }
+
+        // Second pass: process all listens.
+        if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
+            // If the network went from background to foreground or vice versa, we need to update
+            // its foreground state. It is safe to do this after rematching the requests because
+            // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
+            // capability and does not affect the network's score (see the Slog.wtf call above).
+            updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
+        } else {
+            processListenRequests(newNetwork, false);
+        }
+
         // do this after the default net is switched, but
         // before LegacyTypeTracker sends legacy broadcasts
         for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
@@ -4951,7 +5152,7 @@
         }
         if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
             for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                if (unneeded(nai)) {
+                if (unneeded(nai, UnneededFor.TEARDOWN)) {
                     if (nai.getLingerExpiry() > 0) {
                         // This network has active linger timers and no requests, but is not
                         // lingering. Linger it.
@@ -5065,6 +5266,10 @@
         if (!networkAgent.created
                 && (state == NetworkInfo.State.CONNECTED
                 || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
+
+            // A network that has just connected has zero requests and is thus a foreground network.
+            networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
+
             try {
                 // This should never fail.  Specifying an already in use NetID will cause failure.
                 if (networkAgent.isVPN()) {
@@ -5074,9 +5279,7 @@
                                 !networkAgent.networkMisc.allowBypass));
                 } else {
                     mNetd.createPhysicalNetwork(networkAgent.network.netId,
-                            networkAgent.networkCapabilities.hasCapability(
-                                    NET_CAPABILITY_NOT_RESTRICTED) ?
-                                    null : NetworkManagementService.PERMISSION_SYSTEM);
+                            getNetworkPermission(networkAgent.networkCapabilities));
                 }
             } catch (Exception e) {
                 loge("Error creating network " + networkAgent.network.netId + ": "
@@ -5226,6 +5429,8 @@
             NetworkRequest nr = networkAgent.requestAt(i);
             NetworkRequestInfo nri = mNetworkRequests.get(nr);
             if (VDBG) log(" sending notification for " + nr);
+            // TODO: if we're in the middle of a rematch, can we send a CAP_CHANGED callback for
+            // a network that no longer satisfies the listen?
             if (nri.mPendingIntent == null) {
                 callCallbackForRequest(nri, networkAgent, notifyType, arg1);
             } else {
@@ -5297,7 +5502,7 @@
 
     @Override
     public String getCaptivePortalServerUrl() {
-        return NetworkMonitor.getCaptivePortalServerUrl(mContext);
+        return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
     }
 
     @Override
@@ -5360,6 +5565,9 @@
                 }
             }
         }
+
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 6b73fec..dbc1f31 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -60,6 +60,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -1232,8 +1233,8 @@
         }
 
         @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
-                FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
-            (new Shell()).exec(this, in, out, err, args, resultReceiver);
+                FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
         }
     }
 
@@ -2838,7 +2839,8 @@
                     shell.userId = userId;
                     String[] newArgs = new String[args.length-i];
                     System.arraycopy(args, i, newArgs, 0, args.length-i);
-                    shell.exec(mBinderService, null, fd, null, newArgs, new ResultReceiver(null));
+                    shell.exec(mBinderService, null, fd, null, newArgs, null,
+                            new ResultReceiver(null));
                     return;
                 }
             }
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/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 71ac544..df1b6f5 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -822,7 +822,7 @@
         public void onUnlockUser(final @UserIdInt int userHandle) {
             // Called on ActivityManager thread.
             mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
-                    userHandle));
+                    userHandle /* arg1 */, 0 /* arg2 */));
         }
     }
 
@@ -3077,8 +3077,8 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Found an input method " + p);
                 }
-            } catch (XmlPullParserException | IOException e) {
-                Slog.w(TAG, "Unable to load input method " + compName, e);
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Unable to load input method " + compName, e);
             }
         }
 
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 3fdcceb..83d374c 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -364,6 +364,7 @@
             buildResolveList(intent, categories, debug, defaultOnly,
                     resolvedType, scheme, listCut.get(i), resultList, userId);
         }
+        filterResults(resultList);
         sortResults(resultList);
         return resultList;
     }
@@ -457,6 +458,7 @@
             buildResolveList(intent, categories, debug, defaultOnly,
                     resolvedType, scheme, schemeCut, finalList, userId);
         }
+        filterResults(finalList);
         sortResults(finalList);
 
         if (debug) {
@@ -521,6 +523,12 @@
         Collections.sort(results, mResolvePrioritySorter);
     }
 
+    /**
+     * Apply filtering to the results. This happens before the results are sorted.
+     */
+    protected void filterResults(List<R> results) {
+    }
+
     protected void dumpFilter(PrintWriter out, String prefix, F filter) {
         out.print(prefix); out.println(filter);
     }
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..b9a4831 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -922,7 +922,7 @@
 
         // Record user as started so newly mounted volumes kick off events
         // correctly, then synthesize events for any already-mounted volumes.
-        synchronized (mVolumes) {
+        synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
@@ -945,7 +945,7 @@
         } catch (NativeDaemonConnectorException ignored) {
         }
 
-        synchronized (mVolumes) {
+        synchronized (mLock) {
             mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
         }
     }
@@ -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;
             }
@@ -1433,13 +1437,22 @@
      * Decide if volume is mountable per device policies.
      */
     private boolean isMountDisallowed(VolumeInfo vol) {
-        if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
-            final UserManager userManager = mContext.getSystemService(UserManager.class);
-            return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+
+        boolean isUsbRestricted = false;
+        if (vol.disk != null && vol.disk.isUsb()) {
+            isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
                     Binder.getCallingUserHandle());
-        } else {
-            return false;
         }
+
+        boolean isTypeRestricted = false;
+        if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
+            isTypeRestricted = userManager
+                    .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
+                    Binder.getCallingUserHandle());
+        }
+
+        return isUsbRestricted || isTypeRestricted;
     }
 
     private void enforceAdminUser() {
@@ -1985,6 +1998,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..e64aa16 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -77,6 +77,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.provider.Settings;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
@@ -1310,8 +1311,9 @@
             mConnector.execute("tether", "interface", "remove", iface);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
+        } finally {
+            removeInterfaceFromLocalNetwork(iface);
         }
-        removeInterfaceFromLocalNetwork(iface);
     }
 
     @Override
@@ -1698,6 +1700,7 @@
                 return;
             }
 
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
             try {
                 mConnector.execute("bandwidth", suffix + chain, uid);
                 if (enable) {
@@ -1707,6 +1710,8 @@
                 }
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
         }
     }
@@ -1729,6 +1734,7 @@
                 Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
                 return true;
             }
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "bandwidthEnableDataSaver");
             try {
                 final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
                 if (changed) {
@@ -1740,6 +1746,8 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
                 return false;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
         }
     }
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 276687f..3c8c699 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -21,6 +21,7 @@
 import android.net.LocalSocketAddress;
 import android.os.IRecoverySystem;
 import android.os.IRecoverySystemProgressListener;
+import android.os.PowerManager;
 import android.os.RecoverySystem;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -50,8 +51,15 @@
     // The socket at /dev/socket/uncrypt to communicate with uncrypt.
     private static final String UNCRYPT_SOCKET = "uncrypt";
 
+    // The init services that communicate with /system/bin/uncrypt.
+    private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+    private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+    private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+
     private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
 
+    private static final Object sRequestLock = new Object();
+
     private Context mContext;
 
     public RecoverySystemService(Context context) {
@@ -69,95 +77,155 @@
         public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
             if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
 
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+            synchronized (sRequestLock) {
+                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
 
-            // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
-            // uncrypt.
-            RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
-
-            try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
-                uncryptFile.write(filename + "\n");
-            } catch (IOException e) {
-                Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
-                        "\": ", e);
-                return false;
-            }
-
-            // Trigger uncrypt via init.
-            SystemProperties.set("ctl.start", "uncrypt");
-
-            // Connect to the uncrypt service socket.
-            LocalSocket socket = connectService();
-            if (socket == null) {
-                Slog.e(TAG, "Failed to connect to uncrypt socket");
-                return false;
-            }
-
-            // Read the status from the socket.
-            DataInputStream dis = null;
-            DataOutputStream dos = null;
-            try {
-                dis = new DataInputStream(socket.getInputStream());
-                dos = new DataOutputStream(socket.getOutputStream());
-                int lastStatus = Integer.MIN_VALUE;
-                while (true) {
-                    int status = dis.readInt();
-                    // Avoid flooding the log with the same message.
-                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
-                        continue;
-                    }
-                    lastStatus = status;
-
-                    if (status >= 0 && status <= 100) {
-                        // Update status
-                        Slog.i(TAG, "uncrypt read status: " + status);
-                        if (listener != null) {
-                            try {
-                                listener.onProgress(status);
-                            } catch (RemoteException ignored) {
-                                Slog.w(TAG, "RemoteException when posting progress");
-                            }
-                        }
-                        if (status == 100) {
-                            Slog.i(TAG, "uncrypt successfully finished.");
-                            // Ack receipt of the final status code. uncrypt
-                            // waits for the ack so the socket won't be
-                            // destroyed before we receive the code.
-                            dos.writeInt(0);
-                            break;
-                        }
-                    } else {
-                        // Error in /system/bin/uncrypt.
-                        Slog.e(TAG, "uncrypt failed with status: " + status);
-                        // Ack receipt of the final status code. uncrypt waits
-                        // for the ack so the socket won't be destroyed before
-                        // we receive the code.
-                        dos.writeInt(0);
-                        return false;
-                    }
+                final boolean available = checkAndWaitForUncryptService();
+                if (!available) {
+                    Slog.e(TAG, "uncrypt service is unavailable.");
+                    return false;
                 }
-            } catch (IOException e) {
-                Slog.e(TAG, "IOException when reading status: ", e);
-                return false;
-            } finally {
-                IoUtils.closeQuietly(dis);
-                IoUtils.closeQuietly(dos);
-                IoUtils.closeQuietly(socket);
-            }
 
-            return true;
+                // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
+                // uncrypt.
+                RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+
+                try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
+                    uncryptFile.write(filename + "\n");
+                } catch (IOException e) {
+                    Slog.e(TAG, "IOException when writing \"" +
+                            RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
+                    return false;
+                }
+
+                // Trigger uncrypt via init.
+                SystemProperties.set("ctl.start", "uncrypt");
+
+                // Connect to the uncrypt service socket.
+                LocalSocket socket = connectService();
+                if (socket == null) {
+                    Slog.e(TAG, "Failed to connect to uncrypt socket");
+                    return false;
+                }
+
+                // Read the status from the socket.
+                DataInputStream dis = null;
+                DataOutputStream dos = null;
+                try {
+                    dis = new DataInputStream(socket.getInputStream());
+                    dos = new DataOutputStream(socket.getOutputStream());
+                    int lastStatus = Integer.MIN_VALUE;
+                    while (true) {
+                        int status = dis.readInt();
+                        // Avoid flooding the log with the same message.
+                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+                            continue;
+                        }
+                        lastStatus = status;
+
+                        if (status >= 0 && status <= 100) {
+                            // Update status
+                            Slog.i(TAG, "uncrypt read status: " + status);
+                            if (listener != null) {
+                                try {
+                                    listener.onProgress(status);
+                                } catch (RemoteException ignored) {
+                                    Slog.w(TAG, "RemoteException when posting progress");
+                                }
+                            }
+                            if (status == 100) {
+                                Slog.i(TAG, "uncrypt successfully finished.");
+                                // Ack receipt of the final status code. uncrypt
+                                // waits for the ack so the socket won't be
+                                // destroyed before we receive the code.
+                                dos.writeInt(0);
+                                break;
+                            }
+                        } else {
+                            // Error in /system/bin/uncrypt.
+                            Slog.e(TAG, "uncrypt failed with status: " + status);
+                            // Ack receipt of the final status code. uncrypt waits
+                            // for the ack so the socket won't be destroyed before
+                            // we receive the code.
+                            dos.writeInt(0);
+                            return false;
+                        }
+                    }
+                } catch (IOException e) {
+                    Slog.e(TAG, "IOException when reading status: ", e);
+                    return false;
+                } finally {
+                    IoUtils.closeQuietly(dis);
+                    IoUtils.closeQuietly(dos);
+                    IoUtils.closeQuietly(socket);
+                }
+
+                return true;
+            }
         }
 
         @Override // Binder call
         public boolean clearBcb() {
             if (DEBUG) Slog.d(TAG, "clearBcb");
-            return setupOrClearBcb(false, null);
+            synchronized (sRequestLock) {
+                return setupOrClearBcb(false, null);
+            }
         }
 
         @Override // Binder call
         public boolean setupBcb(String command) {
             if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
-            return setupOrClearBcb(true, command);
+            synchronized (sRequestLock) {
+                return setupOrClearBcb(true, command);
+            }
+        }
+
+        @Override // Binder call
+        public void rebootRecoveryWithCommand(String command) {
+            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+            synchronized (sRequestLock) {
+                if (!setupOrClearBcb(true, command)) {
+                    return;
+                }
+
+                // Having set up the BCB, go ahead and reboot.
+                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+                pm.reboot(PowerManager.REBOOT_RECOVERY);
+            }
+        }
+
+        /**
+         * Check if any of the init services is still running. If so, we cannot
+         * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+         * it may break the socket communication since init creates / deletes
+         * the socket (/dev/socket/uncrypt) on service start / exit.
+         */
+        private boolean checkAndWaitForUncryptService() {
+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+                final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
+                final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
+                final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
+                final boolean busy = "running".equals(uncryptService) ||
+                        "running".equals(setupBcbService) || "running".equals(clearBcbService);
+                if (DEBUG) {
+                    Slog.i(TAG, "retry: " + retry + " busy: " + busy +
+                            " uncrypt: [" + uncryptService + "]" +
+                            " setupBcb: [" + setupBcbService + "]" +
+                            " clearBcb: [" + clearBcbService + "]");
+                }
+
+                if (!busy) {
+                    return true;
+                }
+
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    Slog.w(TAG, "Interrupted:", e);
+                }
+            }
+
+            return false;
         }
 
         private LocalSocket connectService() {
@@ -176,7 +244,7 @@
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
-                        Slog.w(TAG, "Interrupted: ", e);
+                        Slog.w(TAG, "Interrupted:", e);
                     }
                 }
             }
@@ -190,6 +258,12 @@
         private boolean setupOrClearBcb(boolean isSetup, String command) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
 
+            final boolean available = checkAndWaitForUncryptService();
+            if (!available) {
+                Slog.e(TAG, "uncrypt service is unavailable.");
+                return false;
+            }
+
             if (isSetup) {
                 SystemProperties.set("ctl.start", "setup-bcb");
             } else {
@@ -232,7 +306,7 @@
                     return false;
                 }
             } catch (IOException e) {
-                Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
+                Slog.e(TAG, "IOException when communicating with uncrypt:", e);
                 return false;
             } finally {
                 IoUtils.closeQuietly(dis);
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 383e25a..2ff036b 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -141,8 +141,12 @@
      * <p>
      * Note that if there are no matching encryption-aware services, we may not
      * bind to a real service until after the current user is unlocked.
+     *
+     * @returns {@code true} if a potential service implementation was found.
      */
     public boolean start() {
+        if (isServiceMissing()) return false;
+
         synchronized (mLock) {
             bindBestPackageLocked(mServicePackageName, false);
         }
@@ -174,6 +178,17 @@
     }
 
     /**
+     * Check if any instance of this service is present on the device,
+     * regardless of it being encryption-aware or not.
+     */
+    private boolean isServiceMissing() {
+        final Intent intent = new Intent(mAction);
+        final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+        return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
+    }
+
+    /**
      * Searches and binds to the best package, or do nothing if the best package
      * is already bound, unless force rebinding is requested.
      *
@@ -181,7 +196,7 @@
      *            packages if it is {@code null}.
      * @param forceRebind Force a rebinding to the best package if it's already
      *            bound.
-     * @return {@code true} if a valid package was found to bind to.
+     * @returns {@code true} if a valid package was found to bind to.
      */
     private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
         Intent intent = new Intent(mAction);
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/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 4b0d4be..4f02a23 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -459,71 +459,75 @@
         if (!calledFromValidUser()) {
             return null;
         }
+        final int subtypeHashCode;
+        final SpellCheckerInfo sci;
+        final Locale systemLocale;
         synchronized (mSpellCheckerMap) {
-            final int subtypeHashCode =
+            subtypeHashCode =
                     mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
             if (DBG) {
                 Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
             }
-            final SpellCheckerInfo sci = getCurrentSpellChecker(null);
-            if (sci == null || sci.getSubtypeCount() == 0) {
-                if (DBG) {
-                    Slog.w(TAG, "Subtype not found.");
-                }
-                return null;
-            }
-            if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
-                    && !allowImplicitlySelectedSubtype) {
-                return null;
-            }
-            String candidateLocale = null;
-            if (subtypeHashCode == 0) {
-                // Spell checker language settings == "auto"
-                final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
-                if (imm != null) {
-                    final InputMethodSubtype currentInputMethodSubtype =
-                            imm.getCurrentInputMethodSubtype();
-                    if (currentInputMethodSubtype != null) {
-                        final String localeString = currentInputMethodSubtype.getLocale();
-                        if (!TextUtils.isEmpty(localeString)) {
-                            // 1. Use keyboard locale if available in the spell checker
-                            candidateLocale = localeString;
-                        }
-                    }
-                }
-                if (candidateLocale == null) {
-                    // 2. Use System locale if available in the spell checker
-                    candidateLocale = mContext.getResources().getConfiguration().locale.toString();
-                }
-            }
-            SpellCheckerSubtype candidate = null;
-            for (int i = 0; i < sci.getSubtypeCount(); ++i) {
-                final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
-                if (subtypeHashCode == 0) {
-                    final String scsLocale = scs.getLocale();
-                    if (candidateLocale.equals(scsLocale)) {
-                        return scs;
-                    } else if (candidate == null) {
-                        if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
-                                && candidateLocale.startsWith(scsLocale)) {
-                            // Fall back to the applicable language
-                            candidate = scs;
-                        }
-                    }
-                } else if (scs.hashCode() == subtypeHashCode) {
-                    if (DBG) {
-                        Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
-                                + ", " + scs.getLocale());
-                    }
-                    // 3. Use the user specified spell check language
-                    return scs;
-                }
-            }
-            // 4. Fall back to the applicable language and return it if not null
-            // 5. Simply just return it even if it's null which means we could find no suitable
-            // spell check languages
-            return candidate;
+            sci = getCurrentSpellChecker(null);
+            systemLocale = mContext.getResources().getConfiguration().locale;
         }
+        if (sci == null || sci.getSubtypeCount() == 0) {
+            if (DBG) {
+                Slog.w(TAG, "Subtype not found.");
+            }
+            return null;
+        }
+        if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
+                && !allowImplicitlySelectedSubtype) {
+            return null;
+        }
+        String candidateLocale = null;
+        if (subtypeHashCode == 0) {
+            // Spell checker language settings == "auto"
+            final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+            if (imm != null) {
+                final InputMethodSubtype currentInputMethodSubtype =
+                        imm.getCurrentInputMethodSubtype();
+                if (currentInputMethodSubtype != null) {
+                    final String localeString = currentInputMethodSubtype.getLocale();
+                    if (!TextUtils.isEmpty(localeString)) {
+                        // 1. Use keyboard locale if available in the spell checker
+                        candidateLocale = localeString;
+                    }
+                }
+            }
+            if (candidateLocale == null) {
+                // 2. Use System locale if available in the spell checker
+                candidateLocale = systemLocale.toString();
+            }
+        }
+        SpellCheckerSubtype candidate = null;
+        for (int i = 0; i < sci.getSubtypeCount(); ++i) {
+            final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
+            if (subtypeHashCode == 0) {
+                final String scsLocale = scs.getLocale();
+                if (candidateLocale.equals(scsLocale)) {
+                    return scs;
+                } else if (candidate == null) {
+                    if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
+                            && candidateLocale.startsWith(scsLocale)) {
+                        // Fall back to the applicable language
+                        candidate = scs;
+                    }
+                }
+            } else if (scs.hashCode() == subtypeHashCode) {
+                if (DBG) {
+                    Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
+                            + ", " + scs.getLocale());
+                }
+                // 3. Use the user specified spell check language
+                return scs;
+            }
+        }
+        // 4. Fall back to the applicable language and return it if not null
+        // 5. Simply just return it even if it's null which means we could find no suitable
+        // spell check languages
+        return candidate;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
new file mode 100644
index 0000000..c3b7e15
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -0,0 +1,294 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PackageUtils;
+import android.util.Pair;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for backup and restore of account access grants.
+ */
+public final class AccountManagerBackupHelper {
+    private static final String TAG = "AccountManagerBackupHelper";
+
+    private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+
+    private static final String TAG_PERMISSIONS = "permissions";
+    private static final String TAG_PERMISSION = "permission";
+    private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_DIGEST = "digest";
+
+    private final Object mLock = new Object();
+
+    private final AccountManagerService mAccountManagerService;
+    private final AccountManagerInternal mAccountManagerInternal;
+
+    @GuardedBy("mLock")
+    private List<PendingAppPermission> mRestorePendingAppPermissions;
+
+    @GuardedBy("mLock")
+    private RestorePackageMonitor mRestorePackageMonitor;
+
+    @GuardedBy("mLock")
+    private Runnable mRestoreCancelCommand;
+
+    public AccountManagerBackupHelper(AccountManagerService accountManagerService,
+            AccountManagerInternal accountManagerInternal) {
+        mAccountManagerService = accountManagerService;
+        mAccountManagerInternal = accountManagerInternal;
+    }
+
+    private final class PendingAppPermission {
+        private final @NonNull String accountDigest;
+        private final @NonNull String packageName;
+        private final @NonNull String certDigest;
+        private final @IntRange(from = 0) int userId;
+
+        public PendingAppPermission(String accountDigest, String packageName,
+                String certDigest, int userId) {
+            this.accountDigest = accountDigest;
+            this.packageName = packageName;
+            this.certDigest = certDigest;
+            this.userId = userId;
+        }
+
+        public boolean apply(PackageManager packageManager) {
+            Account account = null;
+            AccountManagerService.UserAccounts accounts = mAccountManagerService
+                    .getUserAccounts(userId);
+            synchronized (accounts.cacheLock) {
+                for (Account[] accountsPerType : accounts.accountCache.values()) {
+                    for (Account accountPerType : accountsPerType) {
+                        if (accountDigest.equals(PackageUtils.computeSha256Digest(
+                                accountPerType.name.getBytes()))) {
+                            account = accountPerType;
+                            break;
+                        }
+                    }
+                    if (account != null) {
+                        break;
+                    }
+                }
+            }
+            if (account == null) {
+                return false;
+            }
+            final PackageInfo packageInfo;
+            try {
+                packageInfo = packageManager.getPackageInfoAsUser(packageName,
+                        PackageManager.GET_SIGNATURES, userId);
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+            String currentCertDigest = PackageUtils.computeCertSha256Digest(
+                    packageInfo.signatures[0]);
+            if (!certDigest.equals(currentCertDigest)) {
+                return false;
+            }
+            final int uid = packageInfo.applicationInfo.uid;
+            if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
+                mAccountManagerService.grantAppPermission(account,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
+            }
+            return true;
+        }
+    }
+
+    public byte[] backupAccountAccessPermissions(int userId) {
+        final AccountManagerService.UserAccounts accounts = mAccountManagerService
+                .getUserAccounts(userId);
+        synchronized (accounts.cacheLock) {
+            List<Pair<String, Integer>> allAccountGrants = accounts.accountsDb
+                    .findAllAccountGrants();
+            if (allAccountGrants.isEmpty()) {
+                return null;
+            }
+            try {
+                ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+                final XmlSerializer serializer = new FastXmlSerializer();
+                serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
+                serializer.startDocument(null, true);
+                serializer.startTag(null, TAG_PERMISSIONS);
+
+                PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
+                for (Pair<String, Integer> grant : allAccountGrants) {
+                    final String accountName = grant.first;
+                    final int uid = grant.second;
+
+                    final String[] packageNames = packageManager.getPackagesForUid(uid);
+                    if (packageNames == null) {
+                        continue;
+                    }
+
+                    for (String packageName : packageNames) {
+                        String digest = PackageUtils.computePackageCertSha256Digest(
+                                packageManager, packageName, userId);
+                        if (digest != null) {
+                            serializer.startTag(null, TAG_PERMISSION);
+                            serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
+                                    PackageUtils.computeSha256Digest(accountName.getBytes()));
+                            serializer.attribute(null, ATTR_PACKAGE, packageName);
+                            serializer.attribute(null, ATTR_DIGEST, digest);
+                            serializer.endTag(null, TAG_PERMISSION);
+                        }
+                    }
+                }
+                serializer.endTag(null, TAG_PERMISSIONS);
+                serializer.endDocument();
+                serializer.flush();
+                return dataStream.toByteArray();
+            } catch (IOException e) {
+                Log.e(TAG, "Error backing up account access grants", e);
+                return null;
+            }
+        }
+    }
+
+    public void restoreAccountAccessPermissions(byte[] data, int userId) {
+        try {
+            ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(dataStream, StandardCharsets.UTF_8.name());
+            PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
+
+            final int permissionsOuterDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
+                if (!TAG_PERMISSIONS.equals(parser.getName())) {
+                    continue;
+                }
+                final int permissionOuterDepth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
+                    if (!TAG_PERMISSION.equals(parser.getName())) {
+                        continue;
+                    }
+                    String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
+                    if (TextUtils.isEmpty(accountDigest)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    if (TextUtils.isEmpty(packageName)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+                    String digest =  parser.getAttributeValue(null, ATTR_DIGEST);
+                    if (TextUtils.isEmpty(digest)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+
+                    PendingAppPermission pendingAppPermission = new PendingAppPermission(
+                            accountDigest, packageName, digest, userId);
+
+                    if (!pendingAppPermission.apply(packageManager)) {
+                        synchronized (mLock) {
+                            // Start watching before add pending to avoid a missed signal
+                            if (mRestorePackageMonitor == null) {
+                                mRestorePackageMonitor = new RestorePackageMonitor();
+                                mRestorePackageMonitor.register(mAccountManagerService.mContext,
+                                        mAccountManagerService.mHandler.getLooper(), true);
+                            }
+                            if (mRestorePendingAppPermissions == null) {
+                                mRestorePendingAppPermissions = new ArrayList<>();
+                            }
+                            mRestorePendingAppPermissions.add(pendingAppPermission);
+                        }
+                    }
+                }
+            }
+
+            // Make sure we eventually prune the in-memory pending restores
+            mRestoreCancelCommand = new CancelRestoreCommand();
+            mAccountManagerService.mHandler.postDelayed(mRestoreCancelCommand,
+                    PENDING_RESTORE_TIMEOUT_MILLIS);
+        } catch (XmlPullParserException | IOException e) {
+            Log.e(TAG, "Error restoring app permissions", e);
+        }
+    }
+
+    private final class RestorePackageMonitor extends PackageMonitor {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            synchronized (mLock) {
+                if (mRestorePendingAppPermissions == null) {
+                    return;
+                }
+                if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
+                    return;
+                }
+                final int count = mRestorePendingAppPermissions.size();
+                for (int i = count - 1; i >= 0; i--) {
+                    PendingAppPermission pendingAppPermission =
+                            mRestorePendingAppPermissions.get(i);
+                    if (!pendingAppPermission.packageName.equals(packageName)) {
+                        continue;
+                    }
+                    if (pendingAppPermission.apply(
+                            mAccountManagerService.mContext.getPackageManager())) {
+                        mRestorePendingAppPermissions.remove(i);
+                    }
+                }
+                if (mRestorePendingAppPermissions.isEmpty()
+                        && mRestoreCancelCommand != null) {
+                    mAccountManagerService.mHandler.removeCallbacks(mRestoreCancelCommand);
+                    mRestoreCancelCommand.run();
+                    mRestoreCancelCommand = null;
+                }
+            }
+        }
+    }
+
+    private final class CancelRestoreCommand implements Runnable {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                mRestorePendingAppPermissions = null;
+                if (mRestorePackageMonitor != null) {
+                    mRestorePackageMonitor.unregister();
+                    mRestorePackageMonitor = null;
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index acab1af..7802576 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,15 @@
 import android.accounts.IAccountAuthenticatorResponse;
 import android.accounts.IAccountManager;
 import android.accounts.IAccountManagerResponse;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 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;
@@ -42,13 +47,14 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentValues;
 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;
@@ -58,20 +64,18 @@
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
-import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -85,12 +89,14 @@
 import android.util.SparseBooleanArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 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;
-import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 
 import com.google.android.collect.Lists;
@@ -98,7 +104,6 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
@@ -110,13 +115,14 @@
 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;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -142,95 +148,31 @@
 
         @Override
         public void onStart() {
-            mService = new AccountManagerService(getContext());
+            mService = new AccountManagerService(new Injector(getContext()));
             publishBinderService(Context.ACCOUNT_SERVICE, mService);
         }
 
         @Override
-        public void onBootPhase(int phase) {
-            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
-                mService.systemReady();
-            }
-        }
-
-        @Override
         public void onUnlockUser(int userHandle) {
             mService.onUnlockUser(userHandle);
         }
     }
 
-    private static final String DATABASE_NAME = "accounts.db";
-    private static final int PRE_N_DATABASE_VERSION = 9;
-    private static final int CE_DATABASE_VERSION = 10;
-    private static final int DE_DATABASE_VERSION = 1;
-
-    private static final int MAX_DEBUG_DB_SIZE = 64;
-
-    private final Context mContext;
+    final Context mContext;
 
     private final PackageManager mPackageManager;
     private final AppOpsManager mAppOpsManager;
     private UserManager mUserManager;
+    private final Injector mInjector;
 
-    private final MessageHandler mMessageHandler;
-
-    /**
-     * Used to keep data read/write operations for logging purposes in a separate thread
-     * from main thread
-     */
-    private final LinkedList<Runnable> mLogRecordRunnables = new LinkedList<Runnable>();
-    private Thread mLogRecordThread;
+    final MessageHandler mHandler;
 
     // Messages that can be sent on mHandler
     private static final int MESSAGE_TIMED_OUT = 3;
     private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
 
     private final IAccountAuthenticatorCache mAuthenticatorCache;
-
-    private static final String TABLE_ACCOUNTS = "accounts";
-    private static final String ACCOUNTS_ID = "_id";
-    private static final String ACCOUNTS_NAME = "name";
-    private static final String ACCOUNTS_TYPE = "type";
-    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
-    private static final String ACCOUNTS_PASSWORD = "password";
-    private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
-    private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
-            "last_password_entry_time_millis_epoch";
-
-    private static final String TABLE_AUTHTOKENS = "authtokens";
-    private static final String AUTHTOKENS_ID = "_id";
-    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
-    private static final String AUTHTOKENS_TYPE = "type";
-    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
-
-    private static final String TABLE_GRANTS = "grants";
-    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
-    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
-    private static final String GRANTS_GRANTEE_UID = "uid";
-
-    private static final String TABLE_EXTRAS = "extras";
-    private static final String EXTRAS_ID = "_id";
-    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
-    private static final String EXTRAS_KEY = "key";
-    private static final String EXTRAS_VALUE = "value";
-
-    private static final String TABLE_META = "meta";
-    private static final String META_KEY = "key";
-    private static final String META_VALUE = "value";
-
-    private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
-    private static final String SHARED_ACCOUNTS_ID = "_id";
-
     private static final String PRE_N_DATABASE_NAME = "accounts.db";
-    private static final String CE_DATABASE_NAME = "accounts_ce.db";
-    private static final String DE_DATABASE_NAME = "accounts_de.db";
-    private static final String CE_DB_PREFIX = "ceDb.";
-    private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
-    private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
-    private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
-
-    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
-            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
     private static final Intent ACCOUNTS_CHANGED_INTENT;
 
     static {
@@ -238,28 +180,6 @@
         ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
     }
 
-    private static final String COUNT_OF_MATCHING_GRANTS = ""
-            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
-            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
-            + " AND " + GRANTS_GRANTEE_UID + "=?"
-            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
-            + " 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=?)";
-
-    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
-            AUTHTOKENS_AUTHTOKEN};
-
-    private static final String SELECTION_USERDATA_BY_ACCOUNT =
-            EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
-    private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
-
-    private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
-            "auth_uid_for_type:";
-    private static final String META_KEY_DELIMITER = ":";
-    private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
 
     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
     private final AtomicInteger mNotificationIds = new AtomicInteger(1);
@@ -268,22 +188,20 @@
 
     static class UserAccounts {
         private final int userId;
-        private final DeDatabaseHelper openHelper;
+        final AccountsDb accountsDb;
         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
                 credentialsPermissionNotificationIds =
                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
         private final HashMap<Account, Integer> signinRequiredNotificationIds =
                 new HashMap<Account, Integer>();
-        private final Object cacheLock = new Object();
+        final Object cacheLock = new Object();
         /** protected by the {@link #cacheLock} */
-        private final HashMap<String, Account[]> accountCache =
-                new LinkedHashMap<String, Account[]>();
+        final HashMap<String, Account[]> accountCache =
+                new LinkedHashMap<>();
         /** 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();
@@ -319,18 +237,22 @@
                 new HashMap<Account, AtomicReference<String>>();
 
         private int debugDbInsertionPoint = -1;
-        private SQLiteStatement statementForLogging;
+        private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
 
         UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
             this.userId = userId;
             synchronized (cacheLock) {
-                openHelper = DeDatabaseHelper.create(context, userId, preNDbFile, deDbFile);
+                accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
             }
         }
     }
 
     private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
     private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
+    // Not thread-safe. Only use in synchronized context
+    private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
+            mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
 
     private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
@@ -345,19 +267,13 @@
         return sThis.get();
     }
 
-    public AccountManagerService(Context context) {
-        this(context, context.getPackageManager(), new AccountAuthenticatorCache(context));
-    }
-
-    public AccountManagerService(Context context, PackageManager packageManager,
-            IAccountAuthenticatorCache authenticatorCache) {
-        mContext = context;
-        mPackageManager = packageManager;
+    public AccountManagerService(Injector injector) {
+        mInjector = injector;
+        mContext = injector.getContext();
+        mPackageManager = mContext.getPackageManager();
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
-
-        mMessageHandler = new MessageHandler(FgThread.get().getLooper());
-
-        mAuthenticatorCache = authenticatorCache;
+        mHandler = new MessageHandler(injector.getMessageHandlerLooper());
+        mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
         mAuthenticatorCache.setListener(this, null /* Handler */);
 
         sThis.set(this);
@@ -382,7 +298,7 @@
                      * and then rebuild the cache. All under the cache lock. But that change is too
                      * large at this point.
                      */
-                    Runnable r = new Runnable() {
+                    Runnable purgingRunnable = new Runnable() {
                         @Override
                         public void run() {
                             purgeOldGrantsAll();
@@ -402,7 +318,7 @@
                                         uidOfUninstalledApplication)));
                         }
                     };
-                    new Thread(r).start();
+                    mHandler.post(purgingRunnable);
                 }
 
             }
@@ -415,7 +331,7 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context1, Intent intent) {
-                mMessageHandler.post(new Runnable() {
+                mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         int uidOfInstalledApplication =
@@ -442,6 +358,118 @@
                 }
             }
         }, UserHandle.ALL, userFilter, null, null);
+
+        injector.addLocalService(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, mHandler.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 (mPackageManager.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_TYPE, uid), packageName,
+                    UserHandle.getUserHandleForUid(uid));
+        }
     }
 
     @Override
@@ -668,8 +696,7 @@
      * installed on the device.
      */
     private void addRequestsForPreInstalledApplications() {
-        List<PackageInfo> allInstalledPackages = mContext.getPackageManager().
-                getInstalledPackages(0);
+        List<PackageInfo> allInstalledPackages = mPackageManager.getInstalledPackages(0);
         for(PackageInfo pi : allInstalledPackages) {
             int currentUid = pi.applicationInfo.uid;
             if(currentUid != -1) {
@@ -807,14 +834,16 @@
         String interestedPackages = null;
         try {
             String[] allPackages = mPackageManager.getPackagesForUid(uid);
-            for(String aPackage : allPackages) {
-                ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
-                        PackageManager.GET_META_DATA);
-                Bundle b = ai.metaData;
-                if(b == null) {
-                    return;
+            if (allPackages != null) {
+                for(String aPackage : allPackages) {
+                    ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
+                            PackageManager.GET_META_DATA);
+                    Bundle b = ai.metaData;
+                    if(b == null) {
+                        return;
+                    }
+                    interestedPackages = b.getString("android.accounts.SupportedLoginTypes");
                 }
-                interestedPackages = b.getString("android.accounts.SupportedLoginTypes");
             }
         } catch (PackageManager.NameNotFoundException e) {
             Log.d("NameNotFoundException", e.getMessage());
@@ -933,9 +962,6 @@
         }
     }
 
-    public void systemReady() {
-    }
-
     private UserManager getUserManager() {
         if (mUserManager == null) {
             mUserManager = UserManager.get(mContext);
@@ -962,7 +988,7 @@
             UserAccounts accounts, boolean invalidateAuthenticatorCache) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "validateAccountsInternal " + accounts.userId
-                    + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+                    + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
                     + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
         }
 
@@ -975,130 +1001,96 @@
         boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
 
         synchronized (accounts.cacheLock) {
-            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
+            final AccountsDb accountsDb = accounts.accountsDb;
+            Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
             // 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
+                        accountsDb.deleteMetaByAuthTypeAndUid(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()) {
+                accountsDb.insertOrReplaceMetaAuthTypeAndUid(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 = accountsDb.findAllDeAccounts();
             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.");
-                        db.beginTransaction();
+                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.");
+                        accountsDb.beginTransaction();
                         try {
-                            db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
+                            accountsDb.deleteDeAccount(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);
+                                accountsDb.deleteCeAccount(accountId);
                             }
-                            db.setTransactionSuccessful();
+                            accountsDb.setTransactionSuccessful();
                         } finally {
-                            db.endTransaction();
+                            accountsDb.endTransaction();
                         }
                         accountDeleted = true;
 
-                        logRecord(db, DebugDbHelper.ACTION_AUTHENTICATOR_REMOVE, TABLE_ACCOUNTS,
-                                accountId, accounts);
+                        logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE,
+                                AccountsDb.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()) {
@@ -1106,12 +1098,12 @@
                     final ArrayList<String> accountNames = cur.getValue();
                     final Account[] accountsForType = new Account[accountNames.size()];
                     for (int i = 0; i < accountsForType.length; i++) {
-                        accountsForType[i] = new Account(accountNames.get(i), accountType);
+                        accountsForType[i] = new Account(accountNames.get(i), accountType,
+                                UUID.randomUUID().toString());
                     }
                     accounts.accountCache.put(accountType, accountsForType);
                 }
             } finally {
-                cursor.close();
                 if (accountDeleted) {
                     sendAccountsChangedBroadcast(accounts.userId);
                 }
@@ -1135,7 +1127,7 @@
         return knownUids;
     }
 
-    private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
+    static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
             Context context,
             int userId) {
         AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
@@ -1162,23 +1154,20 @@
             UserAccounts accounts = mUsers.get(userId);
             boolean validateAccounts = false;
             if (accounts == null) {
-                File preNDbFile = new File(getPreNDatabaseName(userId));
-                File deDbFile = new File(getDeDatabaseName(userId));
+                File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
+                File deDbFile = new File(mInjector.getDeDatabaseName(userId));
                 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
-                initializeDebugDbSizeAndCompileSqlStatementForLogging(
-                        accounts.openHelper.getWritableDatabase(), accounts);
+                initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
                 mUsers.append(userId, accounts);
                 purgeOldGrants(accounts);
                 validateAccounts = true;
             }
             // open CE database if necessary
-            if (!accounts.openHelper.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
+            if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
                 Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
                 synchronized (accounts.cacheLock) {
-                    File preNDatabaseFile = new File(getPreNDatabaseName(userId));
-                    File ceDatabaseFile = new File(getCeDatabaseName(userId));
-                    CeDatabaseHelper.create(mContext, userId, preNDatabaseFile, ceDatabaseFile);
-                    accounts.openHelper.attachCeDatabase(ceDatabaseFile);
+                    File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
+                    accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
                 }
                 syncDeCeAccountsLocked(accounts);
             }
@@ -1191,12 +1180,12 @@
 
     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 = accounts.accountsDb.findCeAccountsNotInDe();
         if (!accountsToRemove.isEmpty()) {
             Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
                     + accounts.userId + " was locked. Removing accounts from CE tables");
-            logRecord(accounts, DebugDbHelper.ACTION_SYNC_DE_CE_ACCOUNTS, TABLE_ACCOUNTS);
+            logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
+                    AccountsDb.TABLE_ACCOUNTS);
 
             for (Account account : accountsToRemove) {
                 removeAccountInternal(accounts, account, Process.myUid());
@@ -1214,24 +1203,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 = accounts.accountsDb.findAllUidGrants();
+            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");
+                accounts.accountsDb.deleteGrantsByUid(uid);
             }
         }
     }
@@ -1250,29 +1230,23 @@
         }
         if (accounts != null) {
             synchronized (accounts.cacheLock) {
-                accounts.openHelper.close();
+                accounts.accountsDb.close();
             }
         }
         Log.i(TAG, "Removing database files for user " + userId);
-        File dbFile = new File(getDeDatabaseName(userId));
+        File dbFile = new File(mInjector.getDeDatabaseName(userId));
 
-        deleteDbFileWarnIfFailed(dbFile);
+        AccountsDb.deleteDbFileWarnIfFailed(dbFile);
         // Remove CE file if user is unlocked, or FBE is not enabled
         boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
         if (!fbeEnabled || userUnlocked) {
-            File ceDb = new File(getCeDatabaseName(userId));
+            File ceDb = new File(mInjector.getCeDatabaseName(userId));
             if (ceDb.exists()) {
-                deleteDbFileWarnIfFailed(ceDb);
+                AccountsDb.deleteDbFileWarnIfFailed(ceDb);
             }
         }
     }
 
-    private static void deleteDbFileWarnIfFailed(File dbFile) {
-        if (!SQLiteDatabase.deleteDatabase(dbFile)) {
-            Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
-        }
-    }
-
     @VisibleForTesting
     void onUserUnlocked(Intent intent) {
         onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
@@ -1349,9 +1323,7 @@
         }
 
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
-            return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
-                    account.type);
+            return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
         }
     }
 
@@ -1380,27 +1352,10 @@
         synchronized (accounts.cacheLock) {
             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 = accounts.accountsDb.findDeAccountPreviousName(account);
+                previousNameRef = new AtomicReference<>(previousName);
+                accounts.previousNameCache.put(account, previousNameRef);
+                return previousName;
             } else {
                 return previousNameRef.get();
             }
@@ -1474,6 +1429,7 @@
      * Should only be called inside of a clearCallingIdentity block.
      */
     private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
+        mAuthenticatorCache.updateServices(userId);
         Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
                 authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
         AuthenticatorDescription[] types =
@@ -1487,8 +1443,6 @@
         return types;
     }
 
-
-
     private boolean isCrossUser(int callingUid, int userId) {
         return (userId != UserHandle.getCallingUserId()
                 && callingUid != Process.myUid()
@@ -1634,21 +1588,8 @@
     private boolean updateLastAuthenticatedTime(Account account) {
         final UserAccounts accounts = getUserAccountsForCaller();
         synchronized (accounts.cacheLock) {
-            final ContentValues values = new ContentValues();
-            values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            int i = db.update(
-                    TABLE_ACCOUNTS,
-                    values,
-                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                    new String[] {
-                            account.name, account.type
-                    });
-            if (i > 0) {
-                return true;
-            }
+            return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
         }
-        return false;
     }
 
     private void completeCloningAccount(IAccountManagerResponse response,
@@ -1716,36 +1657,21 @@
             return false;
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             try {
-                long numMatches = DatabaseUtils.longForQuery(db,
-                        "select count(*) from " + CE_TABLE_ACCOUNTS
-                                + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                        new String[]{account.name, account.type});
-                if (numMatches > 0) {
+                if (accounts.accountsDb.findCeAccountId(account) >= 0) {
                     Log.w(TAG, "insertAccountIntoDatabase: " + account
                             + ", skipping since the account already exists");
                     return false;
                 }
-                ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_NAME, account.name);
-                values.put(ACCOUNTS_TYPE, account.type);
-                values.put(ACCOUNTS_PASSWORD, password);
-                long accountId = db.insert(CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+                long accountId = accounts.accountsDb.insertCeAccount(account, password);
                 if (accountId < 0) {
                     Log.w(TAG, "insertAccountIntoDatabase: " + account
                             + ", skipping the DB insert failed");
                     return false;
                 }
                 // Insert into DE table
-                values = new ContentValues();
-                values.put(ACCOUNTS_ID, accountId);
-                values.put(ACCOUNTS_NAME, account.name);
-                values.put(ACCOUNTS_TYPE, account.type);
-                values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS,
-                        System.currentTimeMillis());
-                if (db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values) < 0) {
+                if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
                     Log.w(TAG, "insertAccountIntoDatabase: " + account
                             + ", skipping the DB insert failed");
                     return false;
@@ -1753,21 +1679,21 @@
                 if (extras != null) {
                     for (String key : extras.keySet()) {
                         final String value = extras.getString(key);
-                        if (insertExtraLocked(db, accountId, key, value) < 0) {
+                        if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
                             Log.w(TAG, "insertAccountIntoDatabase: " + account
                                     + ", skipping since insertExtra failed for key " + key);
                             return false;
                         }
                     }
                 }
-                db.setTransactionSuccessful();
+                accounts.accountsDb.setTransactionSuccessful();
 
-                logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_ACCOUNTS, accountId,
-                        accounts, callingUid);
+                logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+                        accountId, accounts, callingUid);
 
                 insertAccountIntoCacheLocked(accounts, account);
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
             }
         }
         if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
@@ -1797,21 +1723,13 @@
             if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
                 addSharedAccountAsUser(account, user.id);
                 if (isLocalUnlockedUser(user.id)) {
-                    mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
+                    mHandler.sendMessage(mHandler.obtainMessage(
                             MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
                 }
             }
         }
     }
 
-    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) {
@@ -1819,7 +1737,7 @@
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "hasFeatures: " + account
                     + ", response " + response
-                    + ", features " + stringArrayToString(features)
+                    + ", features " + Arrays.toString(features)
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
@@ -1921,6 +1839,8 @@
             Bundle result = new Bundle();
             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
+            result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID,
+                    resultingAccount.getAccessId());
             try {
                 response.onResult(result);
             } catch (RemoteException e) {
@@ -1956,38 +1876,29 @@
             }
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             Account renamedAccount = new Account(newName, accountToRename.type);
             try {
-                final long accountId = getAccountIdLocked(db, accountToRename);
+                final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
                 if (accountId >= 0) {
-                    final ContentValues values = new ContentValues();
-                    values.put(ACCOUNTS_NAME, newName);
-                    final String[] argsAccountId = { String.valueOf(accountId) };
-                    db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
-                    // Update NAME/PREVIOUS_NAME in DE accounts table
-                    values.put(ACCOUNTS_PREVIOUS_NAME, accountToRename.name);
-                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
-                    db.setTransactionSuccessful();
-                    logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_ACCOUNTS, accountId,
-                            accounts);
+                    accounts.accountsDb.renameCeAccount(accountId, newName);
+                    accounts.accountsDb.renameDeAccount(accountId, newName, accountToRename.name);
                 }
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
             }
             /*
              * Database transaction was successful. Clean up cached
              * data associated with the account in the user profile.
              */
-            insertAccountIntoCacheLocked(accounts, renamedAccount);
+            renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount);
             /*
              * Extract the data and token caches before removing the
              * 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 +1908,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;
@@ -2097,12 +2008,10 @@
                 }
             }
         }
-        SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-        final long accountId = getAccountIdLocked(db, account);
+        final long accountId = accounts.accountsDb.findDeAccountId(account);
         logRecord(
-                db,
-                DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
-                TABLE_ACCOUNTS,
+                AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
+                AccountsDb.TABLE_ACCOUNTS,
                 accountId,
                 accounts,
                 callingUid);
@@ -2138,12 +2047,10 @@
         }
         removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
         UserAccounts accounts = getUserAccountsForCaller();
-        SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-        final long accountId = getAccountIdLocked(db, account);
+        final long accountId = accounts.accountsDb.findDeAccountId(account);
         logRecord(
-                db,
-                DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
-                TABLE_ACCOUNTS,
+                AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
+                AccountsDb.TABLE_ACCOUNTS,
                 accountId,
                 accounts,
                 callingUid);
@@ -2217,40 +2124,31 @@
                     + " is still locked. CE data will be removed later");
         }
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = userUnlocked
-                    ? accounts.openHelper.getWritableDatabaseUserIsUnlocked()
-                    : accounts.openHelper.getWritableDatabase();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             // Set to a dummy value, this will only be used if the database
             // transaction succeeds.
             long accountId = -1;
             try {
-                accountId = getAccountIdLocked(db, account);
+                accountId = accounts.accountsDb.findDeAccountId(account);
                 if (accountId >= 0) {
-                    db.delete(
-                            TABLE_ACCOUNTS,
-                            ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                            new String[]{ account.name, account.type });
+                    accounts.accountsDb.deleteDeAccount(accountId);
                     if (userUnlocked) {
                         // Delete from CE table
-                        db.delete(
-                                CE_TABLE_ACCOUNTS,
-                                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                                new String[]{ account.name, account.type });
+                        accounts.accountsDb.deleteCeAccount(accountId);
                     }
-                    db.setTransactionSuccessful();
+                    accounts.accountsDb.setTransactionSuccessful();
                     isChanged = true;
                 }
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
             }
             if (isChanged) {
                 removeAccountFromCacheLocked(accounts, account);
                 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
                 sendAccountsChangedBroadcast(accounts.userId);
-                String action = userUnlocked ? DebugDbHelper.ACTION_ACCOUNT_REMOVE
-                        : DebugDbHelper.ACTION_ACCOUNT_REMOVE_DE;
-                logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts);
+                String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
+                        : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
+                logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
             }
         }
         long id = Binder.clearCallingIdentity();
@@ -2268,6 +2166,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_TYPE.equals(key.first.second)) {
+                        final int uid = (Integer) key.second;
+                        mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
+                                account, uid, false));
+                    }
+                }
+            }
+        }
+
         return isChanged;
     }
 
@@ -2286,14 +2199,13 @@
         try {
             UserAccounts accounts = getUserAccounts(userId);
             synchronized (accounts.cacheLock) {
-                final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
-                db.beginTransaction();
+                accounts.accountsDb.beginTransaction();
                 try {
-                    invalidateAuthTokenLocked(accounts, db, accountType, authToken);
+                    invalidateAuthTokenLocked(accounts, accountType, authToken);
                     invalidateCustomTokenLocked(accounts, accountType, authToken);
-                    db.setTransactionSuccessful();
+                    accounts.accountsDb.setTransactionSuccessful();
                 } finally {
-                    db.endTransaction();
+                    accounts.accountsDb.endTransaction();
                 }
             }
         } finally {
@@ -2312,31 +2224,20 @@
         accounts.accountTokenCaches.remove(accountType, authToken);
     }
 
-    private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
-            String accountType, String authToken) {
+    private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
+            String authToken) {
         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 = accounts.accountsDb.findAuthtokenForAllAccounts(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);
+                accounts.accountsDb.deleteAuthToken(authTokenId);
                 writeAuthTokenIntoCacheLocked(
                         accounts,
-                        db,
                         new Account(accountName, accountType),
                         authTokenType,
                         null);
@@ -2374,28 +2275,21 @@
         cancelNotification(getSigninRequiredNotificationId(accounts, account),
                 UserHandle.of(accounts.userId));
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             try {
-                long accountId = getAccountIdLocked(db, account);
+                long accountId = accounts.accountsDb.findDeAccountId(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) {
-                    db.setTransactionSuccessful();
-                    writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
+                accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
+                if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
+                    accounts.accountsDb.setTransactionSuccessful();
+                    writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
                     return true;
                 }
                 return false;
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
             }
         }
     }
@@ -2494,32 +2388,26 @@
         }
         boolean isChanged = false;
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             try {
-                final ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_PASSWORD, password);
-                final long accountId = getAccountIdLocked(db, account);
+                final long accountId = accounts.accountsDb.findDeAccountId(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);
+                    accounts.accountsDb.updateCeAccountPassword(accountId, password);
+                    accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
                     accounts.authTokenCache.remove(account);
                     accounts.accountTokenCaches.remove(account);
-                    db.setTransactionSuccessful();
+                    accounts.accountsDb.setTransactionSuccessful();
                     // If there is an account whose password will be updated and the database
                     // transactions succeed, then we say that a change has occured. Even if the
                     // new password is the same as the old and there were no authtokens to delete.
                     isChanged = true;
                     String action = (password == null || password.length() == 0) ?
-                            DebugDbHelper.ACTION_CLEAR_PASSWORD
-                            : DebugDbHelper.ACTION_SET_PASSWORD;
-                    logRecord(db, action, TABLE_ACCOUNTS, accountId, accounts, callingUid);
+                            AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD
+                            : AccountsDb.DEBUG_ACTION_SET_PASSWORD;
+                    logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
                 }
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
                 if (isChanged) {
                     // Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
                     sendAccountsChangedBroadcast(accounts.userId);
@@ -2609,30 +2497,25 @@
         if (account == null || key == null) {
             return;
         }
-        final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        db.beginTransaction();
+        accounts.accountsDb.beginTransaction();
         try {
-            long accountId = getAccountIdLocked(db, account);
+            long accountId = accounts.accountsDb.findDeAccountId(account);
             if (accountId < 0) {
                 return;
             }
-            long extrasId = getExtrasIdLocked(db, accountId, key);
+            long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
             if (extrasId < 0) {
-                extrasId = insertExtraLocked(db, accountId, key, value);
+                extrasId = accounts.accountsDb.insertExtra(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 (!accounts.accountsDb.updateExtra(extrasId, value)) {
+                return;
             }
-            writeUserDataIntoCacheLocked(accounts, db, account, key, value);
-            db.setTransactionSuccessful();
+            writeUserDataIntoCacheLocked(accounts, account, key, value);
+            accounts.accountsDb.setTransactionSuccessful();
         } finally {
-            db.endTransaction();
+            accounts.accountsDb.endTransaction();
         }
     }
 
@@ -2664,7 +2547,7 @@
 
         final int callingUid = getCallingUid();
         clearCallingIdentity();
-        if (callingUid != Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
             throw new SecurityException("can only call from system");
         }
         int userId = UserHandle.getUserId(callingUid);
@@ -2864,9 +2747,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 +2802,7 @@
                                     intent);
                             doNotification(mAccounts,
                                     account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
-                                    intent, accounts.userId);
+                                    intent, "android", accounts.userId);
                         }
                     }
                     super.onResult(result);
@@ -2948,7 +2833,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 +2848,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 +2861,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);
@@ -3036,7 +2924,7 @@
             Log.v(TAG, "addAccount: accountType " + accountType
                     + ", response " + response
                     + ", authTokenType " + authTokenType
-                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+                    + ", requiredFeatures " + Arrays.toString(requiredFeatures)
                     + ", expectActivityLaunch " + expectActivityLaunch
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
@@ -3077,7 +2965,8 @@
         try {
             UserAccounts accounts = getUserAccounts(usrId);
             logRecordWithUid(
-                    accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, uid);
+                    accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+                    uid);
             new Session(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */, null /* accountName */,
                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -3091,10 +2980,7 @@
                 protected String toDebugString(long now) {
                     return super.toDebugString(now) + ", addAccount"
                             + ", accountType " + accountType
-                            + ", requiredFeatures "
-                            + (requiredFeatures != null
-                              ? TextUtils.join(",", requiredFeatures)
-                              : null);
+                            + ", requiredFeatures " + Arrays.toString(requiredFeatures);
                 }
             }.bind();
         } finally {
@@ -3112,7 +2998,7 @@
             Log.v(TAG, "addAccount: accountType " + accountType
                     + ", response " + response
                     + ", authTokenType " + authTokenType
-                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+                    + ", requiredFeatures " + Arrays.toString(requiredFeatures)
                     + ", expectActivityLaunch " + expectActivityLaunch
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid()
@@ -3160,7 +3046,8 @@
         try {
             UserAccounts accounts = getUserAccounts(userId);
             logRecordWithUid(
-                    accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, userId);
+                    accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
+                    userId);
             new Session(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */, null /* accountName */,
                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -3199,7 +3086,7 @@
                     "startAddAccountSession: accountType " + accountType
                     + ", response " + response
                     + ", authTokenType " + authTokenType
-                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+                    + ", requiredFeatures " + Arrays.toString(requiredFeatures)
                     + ", expectActivityLaunch " + expectActivityLaunch
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
@@ -3242,12 +3129,11 @@
         boolean isPasswordForwardingAllowed = isPermitted(
                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
 
-        int usrId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(usrId);
-            logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
-                    TABLE_ACCOUNTS, uid);
+            UserAccounts accounts = getUserAccounts(userId);
+            logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
+                    AccountsDb.TABLE_ACCOUNTS, uid);
             new StartAccountSession(
                     accounts,
                     response,
@@ -3306,10 +3192,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 +3221,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);
 
@@ -3487,8 +3374,8 @@
             UserAccounts accounts = getUserAccounts(userId);
             logRecordWithUid(
                     accounts,
-                    DebugDbHelper.ACTION_CALLED_ACCOUNT_SESSION_FINISH,
-                    TABLE_ACCOUNTS,
+                    AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH,
+                    AccountsDb.TABLE_ACCOUNTS,
                     callingUid);
             new Session(
                     accounts,
@@ -3520,7 +3407,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 +3715,137 @@
     }
 
     @Override
+    public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
+            @NonNull UserHandle userHandle) {
+        if (UserHandle.getAppId(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);
+            return hasAccountAccess(account, packageName, uid);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
+            int uid) {
+        if (packageName == null) {
+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
+            if (ArrayUtils.isEmpty(packageNames)) {
+                return false;
+            }
+            // For app op checks related to permissions all packages in the UID
+            // have the same app op state, so doesn't matter which one we pick.
+            packageName = packageNames[0];
+        }
+
+        // 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, UserHandle.getUserId(uid))) {
+            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);
+    }
+
+    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 (UserHandle.getAppId(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);
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return PendingIntent.getActivityAsUser(
+                    mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                            | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                    null, new UserHandle(userId)).getIntentSender();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    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_TYPE, 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_TYPE, 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");
@@ -4124,19 +4144,15 @@
     private boolean addSharedAccountAsUser(Account account, int userId) {
         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);
+        accounts.accountsDb.deleteSharedAccount(account);
+        long accountId = accounts.accountsDb.insertSharedAccount(account);
         if (accountId < 0) {
             Log.w(TAG, "insertAccountIntoDatabase: " + account
                     + ", skipping the DB insert failed");
             return false;
         }
-        logRecord(db, DebugDbHelper.ACTION_ACCOUNT_ADD, TABLE_SHARED_ACCOUNTS, accountId, accounts);
+        logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId,
+                accounts);
         return true;
     }
 
@@ -4144,18 +4160,11 @@
     public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
         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 = accounts.accountsDb.findSharedAccountId(account);
+        int r = accounts.accountsDb.renameSharedAccount(account, newName);
         if (r > 0) {
             int callingUid = getCallingUid();
-            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_SHARED_ACCOUNTS,
+            logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
                     sharedTableAccountId, accounts, callingUid);
             // Recursively rename the account.
             renameAccountInternal(accounts, account, newName);
@@ -4171,41 +4180,21 @@
     private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
         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) {
-            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
+        long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
+        boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
+        if (deleted) {
+            logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.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();
-            }
-        }
+        List<Account> accountList = accounts.accountsDb.getSharedAccounts();
         Account[] accountArray = new Account[accountList.size()];
         accountList.toArray(accountArray);
         return accountArray;
@@ -4256,7 +4245,7 @@
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAccounts: accountType " + type
                     + ", response " + response
-                    + ", features " + stringArrayToString(features)
+                    + ", features " + Arrays.toString(features)
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
@@ -4301,43 +4290,27 @@
         }
     }
 
-    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();
+    @Override
+    public void onAccountAccessed(String token) throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
+            return;
         }
-    }
-
-    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);
+        final int userId = UserHandle.getCallingUserId();
+        final long identity = Binder.clearCallingIdentity();
         try {
-            if (cursor.moveToNext()) {
-                return cursor.getLong(0);
+            for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
+                if (Objects.equals(account.getAccessId(), token)) {
+                    // An app just accessed the account. At this point it knows about
+                    // it and there is not need to hide this account from the app.
+                    if (!hasAccountAccess(account, null, uid)) {
+                        updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
+                                uid, true);
+                    }
+                }
             }
-            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();
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -4500,7 +4473,7 @@
         }
 
         public void cancelTimeout() {
-            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
+            mHandler.removeMessages(MESSAGE_TIMED_OUT, this);
         }
 
         @Override
@@ -4572,15 +4545,9 @@
                     if (mAuthDetailsRequired) {
                         long lastAuthenticatedTime = -1;
                         if (accountPresent) {
-                            lastAuthenticatedTime = DatabaseUtils.longForQuery(
-                                    mAccounts.openHelper.getReadableDatabase(),
-                                    "SELECT " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
-                                            + " FROM " +
-                                            TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
-                                            + ACCOUNTS_TYPE + "=?",
-                                    new String[] {
-                                            mAccountName, mAccountType
-                                    });
+                            lastAuthenticatedTime = mAccounts.accountsDb
+                                    .findAccountLastAuthenticatedTime(
+                                            new Account(mAccountName, mAccountType));
                         }
                         result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
                                 lastAuthenticatedTime);
@@ -4714,7 +4681,7 @@
         }
     }
 
-    private class MessageHandler extends Handler {
+    class MessageHandler extends Handler {
         MessageHandler(Looper looper) {
             super(looper);
         }
@@ -4737,122 +4704,26 @@
         }
     }
 
-    @VisibleForTesting
-    String getPreNDatabaseName(int userId) {
-        File systemDir = Environment.getDataSystemDirectory();
-        File databaseFile = new File(Environment.getUserSystemDirectory(userId),
-                PRE_N_DATABASE_NAME);
-        if (userId == 0) {
-            // Migrate old file, if it exists, to the new location.
-            // Make sure the new file doesn't already exist. A dummy file could have been
-            // accidentally created in the old location, causing the new one to become corrupted
-            // as well.
-            File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
-            if (oldFile.exists() && !databaseFile.exists()) {
-                // Check for use directory; create if it doesn't exist, else renameTo will fail
-                File userDir = Environment.getUserSystemDirectory(userId);
-                if (!userDir.exists()) {
-                    if (!userDir.mkdirs()) {
-                        throw new IllegalStateException("User dir cannot be created: " + userDir);
-                    }
-                }
-                if (!oldFile.renameTo(databaseFile)) {
-                    throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
-                }
-            }
-        }
-        return databaseFile.getPath();
-    }
-
-    @VisibleForTesting
-    String getDeDatabaseName(int userId) {
-        File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
-                DE_DATABASE_NAME);
-        return databaseFile.getPath();
-    }
-
-    @VisibleForTesting
-    String getCeDatabaseName(int userId) {
-        File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
-                CE_DATABASE_NAME);
-        return databaseFile.getPath();
-    }
-
-    private static class DebugDbHelper{
-        private DebugDbHelper() {
-        }
-
-        private static String TABLE_DEBUG = "debug_table";
-
-        // Columns for the table
-        private static String ACTION_TYPE = "action_type";
-        private static String TIMESTAMP = "time";
-        private static String CALLER_UID = "caller_uid";
-        private static String TABLE_NAME = "table_name";
-        private static String KEY = "primary_key";
-
-        // These actions correspond to the occurrence of real actions. Since
-        // these are called by the authenticators, the uid associated will be
-        // of the authenticator.
-        private static String ACTION_SET_PASSWORD = "action_set_password";
-        private static String ACTION_CLEAR_PASSWORD = "action_clear_password";
-        private static String ACTION_ACCOUNT_ADD = "action_account_add";
-        private static String ACTION_ACCOUNT_REMOVE = "action_account_remove";
-        private static String ACTION_ACCOUNT_REMOVE_DE = "action_account_remove_de";
-        private static String ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
-        private static String ACTION_ACCOUNT_RENAME = "action_account_rename";
-
-        // These actions don't necessarily correspond to any action on
-        // accountDb taking place. As an example, there might be a request for
-        // addingAccount, which might not lead to addition of account on grounds
-        // of bad authentication. We will still be logging it to keep track of
-        // who called.
-        private static String ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
-        private static String ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
-        private static String ACTION_SYNC_DE_CE_ACCOUNTS = "action_sync_de_ce_accounts";
-
-        //This action doesn't add account to accountdb. Account is only
-        // added in finishSession which may be in a different user profile.
-        private static String ACTION_CALLED_START_ACCOUNT_ADD = "action_called_start_account_add";
-        private static String ACTION_CALLED_ACCOUNT_SESSION_FINISH =
-                "action_called_account_session_finish";
-
-        private static SimpleDateFormat dateFromat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-        private static void createDebugTable(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
-                    + ACCOUNTS_ID + " INTEGER,"
-                    + ACTION_TYPE + " TEXT NOT NULL, "
-                    + TIMESTAMP + " DATETIME,"
-                    + CALLER_UID + " INTEGER NOT NULL,"
-                    + TABLE_NAME + " TEXT NOT NULL,"
-                    + KEY + " INTEGER PRIMARY KEY)");
-            db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " (" + TIMESTAMP + ")");
-        }
-    }
-
     private void logRecord(UserAccounts accounts, String action, String tableName) {
-        SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        logRecord(db, action, tableName, -1, accounts);
+        logRecord(action, tableName, -1, accounts);
     }
 
     private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
-        SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        logRecord(db, action, tableName, -1, accounts, uid);
+        logRecord(action, tableName, -1, accounts, uid);
     }
 
     /*
      * This function receives an opened writable database.
      */
-    private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+    private void logRecord(String action, String tableName, long accountId,
             UserAccounts userAccount) {
-        logRecord(db, action, tableName, accountId, userAccount, getCallingUid());
+        logRecord(action, tableName, accountId, userAccount, getCallingUid());
     }
 
     /*
      * This function receives an opened writable database and writes to it in a separate thread.
      */
-    private void logRecord(SQLiteDatabase db, String action, String tableName, long accountId,
+    private void logRecord(String action, String tableName, long accountId,
             UserAccounts userAccount, int callingUid) {
 
         class LogRecordTask implements Runnable {
@@ -4881,7 +4752,7 @@
                 SQLiteStatement logStatement = userAccount.statementForLogging;
                 logStatement.bindLong(1, accountId);
                 logStatement.bindString(2, action);
-                logStatement.bindString(3, DebugDbHelper.dateFromat.format(new Date()));
+                logStatement.bindString(3, mDateFormat.format(new Date()));
                 logStatement.bindLong(4, callingUid);
                 logStatement.bindString(5, tableName);
                 logStatement.bindLong(6, userDebugDbInsertionPoint);
@@ -4890,534 +4761,21 @@
             }
         }
 
-        mLogRecordRunnables.add(new LogRecordTask(action, tableName, accountId, userAccount,
-                callingUid, userAccount.debugDbInsertionPoint));
+        LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
+                callingUid, userAccount.debugDbInsertionPoint);
         userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
-                % MAX_DEBUG_DB_SIZE;
-
-
-        if(mLogRecordThread == null || !mLogRecordThread.isAlive()) {
-            mLogRecordThread = new Thread(new Runnable() {
-                public void run() {
-                    while(mLogRecordRunnables.size() > 0) {
-                        mLogRecordRunnables.pollFirst().run();
-                    }
-                }
-            });
-            mLogRecordThread.start();
-        }
-
+                % AccountsDb.MAX_DEBUG_DB_SIZE;
+        mHandler.post(logTask);
     }
 
     /*
      * This should only be called once to compile the sql statement for logging
      * and to find the insertion point.
      */
-    private void initializeDebugDbSizeAndCompileSqlStatementForLogging(SQLiteDatabase db,
-            UserAccounts userAccount) {
-        // Initialize the count if not done earlier.
-        int size = (int) getDebugTableRowCount(db);
-        if (size >= MAX_DEBUG_DB_SIZE) {
-            // Table is full, and we need to find the point where to insert.
-            userAccount.debugDbInsertionPoint = (int) getDebugTableInsertionPoint(db);
-        } else {
-            userAccount.debugDbInsertionPoint = size;
-        }
-        compileSqlStatementForLogging(db, userAccount);
-    }
-
-    private void compileSqlStatementForLogging(SQLiteDatabase db, UserAccounts userAccount) {
-        String sql = "INSERT OR REPLACE INTO " + DebugDbHelper.TABLE_DEBUG
-                + " VALUES (?,?,?,?,?,?)";
-        userAccount.statementForLogging = db.compileStatement(sql);
-    }
-
-    private long getDebugTableRowCount(SQLiteDatabase db) {
-        String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + DebugDbHelper.TABLE_DEBUG;
-        return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
-    }
-
-    /*
-     * Finds the row key where the next insertion should take place. This should
-     * be invoked only if the table has reached its full capacity.
-     */
-    private long getDebugTableInsertionPoint(SQLiteDatabase db) {
-        // This query finds the smallest timestamp value (and if 2 records have
-        // same timestamp, the choose the lower id).
-        String queryCountDebugDbRows = new StringBuilder()
-                .append("SELECT ").append(DebugDbHelper.KEY)
-                .append(" FROM ").append(DebugDbHelper.TABLE_DEBUG)
-                .append(" ORDER BY ")
-                .append(DebugDbHelper.TIMESTAMP).append(",").append(DebugDbHelper.KEY)
-                .append(" LIMIT 1")
-                .toString();
-        return DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
-    }
-
-    static class PreNDatabaseHelper extends SQLiteOpenHelper {
-        private final Context mContext;
-        private final int mUserId;
-
-        public PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
-            super(context, preNDatabaseName, null, PRE_N_DATABASE_VERSION);
-            mContext = context;
-            mUserId = userId;
-        }
-
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            // We use PreNDatabaseHelper only if pre-N db exists
-            throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
-        }
-
-        private void createSharedAccountsTable(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-        }
-
-        private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
-            db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
-                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
-        }
-
-        private void addOldAccountNameColumn(SQLiteDatabase db) {
-            db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
-        }
-
-        private void addDebugTable(SQLiteDatabase db) {
-            DebugDbHelper.createDebugTable(db);
-        }
-
-        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
-            db.execSQL(""
-                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
-                    + " BEGIN"
-                    + "   DELETE FROM " + TABLE_AUTHTOKENS
-                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + "   DELETE FROM " + TABLE_EXTRAS
-                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + "   DELETE FROM " + TABLE_GRANTS
-                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + " END");
-        }
-
-        private void createGrantsTable(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
-                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
-                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
-                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
-                    +   "," + GRANTS_GRANTEE_UID + "))");
-        }
-
-        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);
-            }
-        }
-
-        /**
-         * Pre-N database may need an upgrade before splitting
-         */
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
-
-            if (oldVersion == 1) {
-                // no longer need to do anything since the work is done
-                // when upgrading from version 2
-                oldVersion++;
-            }
-
-            if (oldVersion == 2) {
-                createGrantsTable(db);
-                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
-                createAccountsDeletionTrigger(db);
-                oldVersion++;
-            }
-
-            if (oldVersion == 3) {
-                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
-                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
-                oldVersion++;
-            }
-
-            if (oldVersion == 4) {
-                createSharedAccountsTable(db);
-                oldVersion++;
-            }
-
-            if (oldVersion == 5) {
-                addOldAccountNameColumn(db);
-                oldVersion++;
-            }
-
-            if (oldVersion == 6) {
-                addLastSuccessfullAuthenticatedTimeColumn(db);
-                oldVersion++;
-            }
-
-            if (oldVersion == 7) {
-                addDebugTable(db);
-                oldVersion++;
-            }
-
-            if (oldVersion == 8) {
-                populateMetaTableWithAuthTypeAndUID(
-                        db,
-                        AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
-                oldVersion++;
-            }
-
-            if (oldVersion != newVersion) {
-                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
-            }
-        }
-
-        @Override
-        public void onOpen(SQLiteDatabase db) {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
-        }
-    }
-
-    static class DeDatabaseHelper extends SQLiteOpenHelper {
-
-        private final int mUserId;
-        private volatile boolean mCeAttached;
-
-        private DeDatabaseHelper(Context context, int userId, String deDatabaseName) {
-            super(context, deDatabaseName, null, DE_DATABASE_VERSION);
-            mUserId = userId;
-        }
-
-        /**
-         * This call needs to be made while the mCacheLock is held. The way to
-         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
-         * @param db The database.
-         */
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            Log.i(TAG, "Creating DE database for user " + mUserId);
-            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
-                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
-                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
-                    + META_VALUE + " TEXT)");
-
-            createGrantsTable(db);
-            createSharedAccountsTable(db);
-            createAccountsDeletionTrigger(db);
-            DebugDbHelper.createDebugTable(db);
-        }
-
-        private void createSharedAccountsTable(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-        }
-
-        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
-            db.execSQL(""
-                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
-                    + " BEGIN"
-                    + "   DELETE FROM " + TABLE_GRANTS
-                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + " END");
-        }
-
-        private void createGrantsTable(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
-                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
-                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
-                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
-                    +   "," + GRANTS_GRANTEE_UID + "))");
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
-
-            if (oldVersion != newVersion) {
-                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
-            }
-        }
-
-        public void attachCeDatabase(File ceDbFile) {
-            SQLiteDatabase db = getWritableDatabase();
-            db.execSQL("ATTACH DATABASE '" +  ceDbFile.getPath()+ "' AS ceDb");
-            mCeAttached = true;
-        }
-
-        public boolean isCeDatabaseAttached() {
-            return mCeAttached;
-        }
-
-
-        public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
-            if(!mCeAttached) {
-                Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user " + mUserId
-                        + " is still locked. CE database is not yet available.", new Throwable());
-            }
-            return super.getReadableDatabase();
-        }
-
-        public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
-            if(!mCeAttached) {
-                Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
-                        + " is still locked. CE database is not yet available.", new Throwable());
-            }
-            return super.getWritableDatabase();
-        }
-
-        @Override
-        public void onOpen(SQLiteDatabase db) {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
-        }
-
-        private void migratePreNDbToDe(File preNDbFile) {
-            Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
-            SQLiteDatabase db = getWritableDatabase();
-            db.execSQL("ATTACH DATABASE '" +  preNDbFile.getPath() + "' AS preNDb");
-            db.beginTransaction();
-            // Copy accounts fields
-            db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
-                    + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
-                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
-                    + ") "
-                    + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
-                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
-                    + " FROM preNDb." + TABLE_ACCOUNTS);
-            // Copy SHARED_ACCOUNTS
-            db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
-                    + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
-                    "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
-                    + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
-            // Copy DEBUG_TABLE
-            db.execSQL("INSERT INTO " + DebugDbHelper.TABLE_DEBUG
-                    + "(" + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
-                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
-                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY + ") " +
-                    "SELECT " + ACCOUNTS_ID + "," + DebugDbHelper.ACTION_TYPE + ","
-                    + DebugDbHelper.TIMESTAMP + "," + DebugDbHelper.CALLER_UID + ","
-                    + DebugDbHelper.TABLE_NAME + "," + DebugDbHelper.KEY
-                    + " FROM preNDb." + DebugDbHelper.TABLE_DEBUG);
-            // Copy GRANTS
-            db.execSQL("INSERT INTO " + TABLE_GRANTS
-                    + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
-                    + GRANTS_GRANTEE_UID + ") " +
-                    "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
-                    + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
-            // Copy META
-            db.execSQL("INSERT INTO " + TABLE_META
-                    + "(" + META_KEY + "," + META_VALUE + ") "
-                    + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
-            db.setTransactionSuccessful();
-            db.endTransaction();
-
-            db.execSQL("DETACH DATABASE preNDb");
-        }
-
-        static DeDatabaseHelper create(
-                Context context,
-                int userId,
-                File preNDatabaseFile,
-                File deDatabaseFile) {
-            boolean newDbExists = deDatabaseFile.exists();
-            DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
-                    deDatabaseFile.getPath());
-            // If the db just created, and there is a legacy db, migrate it
-            if (!newDbExists && preNDatabaseFile.exists()) {
-                // Migrate legacy db to the latest version -  PRE_N_DATABASE_VERSION
-                PreNDatabaseHelper preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
-                        preNDatabaseFile.getPath());
-                // Open the database to force upgrade if required
-                preNDatabaseHelper.getWritableDatabase();
-                preNDatabaseHelper.close();
-                // Move data without SPII to DE
-                deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
-            }
-            return deDatabaseHelper;
-        }
-    }
-
-    static class CeDatabaseHelper extends SQLiteOpenHelper {
-
-        public CeDatabaseHelper(Context context, String ceDatabaseName) {
-            super(context, ceDatabaseName, null, CE_DATABASE_VERSION);
-        }
-
-        /**
-         * This call needs to be made while the mCacheLock is held.
-         * @param db The database.
-         */
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            Log.i(TAG, "Creating CE database " + getDatabaseName());
-            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
-                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
-                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
-                    + ACCOUNTS_PASSWORD + " TEXT, "
-                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
-                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
-                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
-                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
-                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
-                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
-
-            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
-                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
-                    + EXTRAS_KEY + " TEXT NOT NULL, "
-                    + EXTRAS_VALUE + " TEXT, "
-                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
-
-            createAccountsDeletionTrigger(db);
-        }
-
-        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
-            db.execSQL(""
-                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
-                    + " BEGIN"
-                    + "   DELETE FROM " + TABLE_AUTHTOKENS
-                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + "   DELETE FROM " + TABLE_EXTRAS
-                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
-                    + " END");
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
-
-            if (oldVersion == 9) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "onUpgrade upgrading to v10");
-                }
-                db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
-                db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
-                // Recreate the trigger, since the old one references the table to be removed
-                db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
-                createAccountsDeletionTrigger(db);
-                db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
-                db.execSQL("DROP TABLE IF EXISTS " + DebugDbHelper.TABLE_DEBUG);
-                oldVersion ++;
-            }
-
-            if (oldVersion != newVersion) {
-                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
-            }
-        }
-
-        @Override
-        public void onOpen(SQLiteDatabase db) {
-            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,
-         * it also performs migration to the new CE database.
-         * @param context
-         * @param userId id of the user where the database is located
-         */
-        static CeDatabaseHelper create(
-                Context context,
-                int userId,
-                File preNDatabaseFile,
-                File ceDatabaseFile) {
-            boolean newDbExists = ceDatabaseFile.exists();
-            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
-                        + preNDatabaseFile.exists() + " newDbExists=" + newDbExists);
-            }
-            boolean removeOldDb = false;
-            if (!newDbExists && preNDatabaseFile.exists()) {
-                removeOldDb = migratePreNDbToCe(preNDatabaseFile, ceDatabaseFile);
-            }
-            // Try to open and upgrade if necessary
-            CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, ceDatabaseFile.getPath());
-            ceHelper.getWritableDatabase();
-            ceHelper.close();
-            if (removeOldDb) {
-                Slog.i(TAG, "Migration complete - removing pre-N db " + preNDatabaseFile);
-                if (!SQLiteDatabase.deleteDatabase(preNDatabaseFile)) {
-                    Slog.e(TAG, "Cannot remove pre-N db " + preNDatabaseFile);
-                }
-            }
-            return ceHelper;
-        }
-
-        private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
-            Slog.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
-            try {
-                FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
-            } catch (IOException e) {
-                Slog.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
-                // Try to remove potentially damaged file if I/O error occurred
-                deleteDbFileWarnIfFailed(ceDbFile);
-                return false;
-            }
-            return true;
-        }
+    private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
+        userAccount.debugDbInsertionPoint = userAccount.accountsDb
+                .calculateDebugTableInsertionPoint();
+        userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
     }
 
     public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
@@ -5466,22 +4824,9 @@
     private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
             String[] args, boolean isCheckinRequest) {
         synchronized (userAccounts.cacheLock) {
-            final SQLiteDatabase db = userAccounts.openHelper.getReadableDatabase();
-
             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();
-                    }
-                }
+                userAccounts.accountsDb.dumpDeAccountsTable(fout);
             } else {
                 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
                         Process.myUid(), null);
@@ -5492,21 +4837,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();
-                }
-
+                userAccounts.accountsDb.dumpDebugTable(fout);
                 fout.println();
                 synchronized (mSessions) {
                     final long now = SystemClock.elapsedRealtime();
@@ -5523,7 +4854,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 +4864,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,28 +4881,42 @@
                         .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);
         }
     }
 
-    @VisibleForTesting
-    protected void installNotification(final int notificationId, final Notification n,
-            UserHandle user) {
-        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .notifyAsUser(null, notificationId, n, user);
+    private void installNotification(int notificationId, final Notification notification,
+            String packageName, int userId) {
+        final long token = clearCallingIdentity();
+        try {
+            INotificationManager notificationManager = mInjector.getNotificationManager();
+            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) {
+    private void cancelNotification(int id, UserHandle user) {
+        cancelNotification(id, mContext.getPackageName(), user);
+    }
+
+    private void cancelNotification(int id, String packageName, UserHandle user) {
         long identityToken = clearCallingIdentity();
         try {
-            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .cancelAsUser(null, id, user);
+            INotificationManager service = mInjector.getNotificationManager();
+            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
+        } catch (RemoteException e) {
+            /* ignore - local call */
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -5632,18 +4977,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,
@@ -5727,16 +5094,21 @@
 
     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
             int callerUid) {
-        if (callerUid == Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
             return true;
         }
-        UserAccounts accounts = getUserAccountsForCaller();
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
         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;
+            long grantsCount;
+            if (authTokenType != null) {
+                grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
+                        account);
+            } else {
+                grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
+                        account);
+            }
+            final boolean permissionGranted = grantsCount > 0;
+
             if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
                 // TODO: Skip this check when running automated tests. Replace this
                 // with a more general solution.
@@ -5835,7 +5207,7 @@
             throws RemoteException {
         final int callingUid = getCallingUid();
 
-        if (callingUid != Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
             throw new SecurityException();
         }
 
@@ -5853,30 +5225,27 @@
      * which is in the system. This means we don't need to protect it with permissions.
      * @hide
      */
-    private void grantAppPermission(Account account, String authTokenType, int uid) {
+    void grantAppPermission(Account account, String authTokenType, int uid) {
         if (account == null || authTokenType == null) {
             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
             return;
         }
         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 = accounts.accountsDb.findDeAccountId(account);
+            if (accountId >= 0) {
+                accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
             }
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
                     UserHandle.of(accounts.userId));
+
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
+        }
+
+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
+                : mAppPermissionChangeListeners) {
+            mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
         }
     }
 
@@ -5895,28 +5264,27 @@
         }
         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.cacheLock) {
-            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            db.beginTransaction();
+            accounts.accountsDb.beginTransaction();
             try {
-                long accountId = getAccountIdLocked(db, account);
+                long accountId = accounts.accountsDb.findDeAccountId(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)});
-                    db.setTransactionSuccessful();
+                    accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
+                            accountId, authTokenType, uid);
+                    accounts.accountsDb.setTransactionSuccessful();
                 }
             } finally {
-                db.endTransaction();
+                accounts.accountsDb.endTransaction();
             }
+
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
                     new UserHandle(accounts.userId));
         }
-    }
 
-    static final private String stringArrayToString(String[] value) {
-        return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
+                : mAppPermissionChangeListeners) {
+            mHandler.post(() -> listener.onAppPermissionChanged(account, uid));
+        }
     }
 
     private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
@@ -5943,16 +5311,22 @@
 
     /**
      * This assumes that the caller has already checked that the account is not already present.
+     * IMPORTANT: The account being inserted will begin to be tracked for access in remote
+     * processes and if you will return this account to apps you should return the result.
+     * @return The inserted account which is a new instance that is being tracked.
      */
-    private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
+    private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
         Account[] accountsForType = accounts.accountCache.get(account.type);
         int oldLength = (accountsForType != null) ? accountsForType.length : 0;
         Account[] newAccountsForType = new Account[oldLength + 1];
         if (accountsForType != null) {
             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
         }
-        newAccountsForType[oldLength] = account;
+        String token = account.getAccessId() != null ? account.getAccessId()
+                : UUID.randomUUID().toString();
+        newAccountsForType[oldLength] = new Account(account, token);
         accounts.accountCache.put(account.type, newAccountsForType);
+        return newAccountsForType[oldLength];
     }
 
     private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
@@ -6055,11 +5429,11 @@
         }
     }
 
-    protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
+    protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
             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 = accounts.accountsDb.findUserExtrasForAccount(account);
             accounts.userDataCache.put(account, userDataForAccount);
         }
         if (value == null) {
@@ -6081,11 +5455,11 @@
         }
     }
 
-    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
+    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
             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 = accounts.accountsDb.findAuthTokensByAccount(account);
             accounts.authTokenCache.put(account, authTokensForAccount);
         }
         if (value == null) {
@@ -6098,11 +5472,10 @@
     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 = accounts.accountsDb.findAuthTokensByAccount(account);
                 accounts.authTokenCache.put(account, authTokensForAccount);
             }
             return authTokensForAccount.get(authTokenType);
@@ -6111,56 +5484,15 @@
 
     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 = accounts.accountsDb.findUserExtrasForAccount(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 +5526,158 @@
             }
         }
     }
+
+    private final class AccountManagerInternalImpl extends AccountManagerInternal {
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private AccountManagerBackupHelper mBackupHelper;
+
+        @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 (AccountManagerService.this.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);
+            final UserAccounts userAccounts;
+            synchronized (mUsers) {
+                userAccounts = mUsers.get(userId);
+            }
+            doNotification(userAccounts, account, null, intent, packageName, userId);
+        }
+
+        @Override
+        public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
+            // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+            mAppPermissionChangeListeners.add(listener);
+        }
+
+        @Override
+        public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
+            return AccountManagerService.this.hasAccountAccess(account, null, uid);
+        }
+
+        @Override
+        public byte[] backupAccountAccessPermissions(int userId) {
+            synchronized (mLock) {
+                if (mBackupHelper == null) {
+                    mBackupHelper = new AccountManagerBackupHelper(
+                            AccountManagerService.this, this);
+                }
+                return mBackupHelper.backupAccountAccessPermissions(userId);
+            }
+        }
+
+        @Override
+        public void restoreAccountAccessPermissions(byte[] data, int userId) {
+            synchronized (mLock) {
+                if (mBackupHelper == null) {
+                    mBackupHelper = new AccountManagerBackupHelper(
+                            AccountManagerService.this, this);
+                }
+                mBackupHelper.restoreAccountAccessPermissions(data, userId);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    static class Injector {
+        private final Context mContext;
+
+        public Injector(Context context) {
+            mContext = context;
+        }
+
+        Looper getMessageHandlerLooper() {
+            ServiceThread serviceThread = new ServiceThread(TAG,
+                    android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+            serviceThread.start();
+            return serviceThread.getLooper();
+        }
+
+        Context getContext() {
+            return mContext;
+        }
+
+        void addLocalService(AccountManagerInternal service) {
+            LocalServices.addService(AccountManagerInternal.class, service);
+        }
+
+        String getDeDatabaseName(int userId) {
+            File databaseFile = new File(Environment.getDataSystemDeDirectory(userId),
+                    AccountsDb.DE_DATABASE_NAME);
+            return databaseFile.getPath();
+        }
+
+        String getCeDatabaseName(int userId) {
+            File databaseFile = new File(Environment.getDataSystemCeDirectory(userId),
+                    AccountsDb.CE_DATABASE_NAME);
+            return databaseFile.getPath();
+        }
+
+        String getPreNDatabaseName(int userId) {
+            File systemDir = Environment.getDataSystemDirectory();
+            File databaseFile = new File(Environment.getUserSystemDirectory(userId),
+                    PRE_N_DATABASE_NAME);
+            if (userId == 0) {
+                // Migrate old file, if it exists, to the new location.
+                // Make sure the new file doesn't already exist. A dummy file could have been
+                // accidentally created in the old location, causing the new one to become corrupted
+                // as well.
+                File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
+                if (oldFile.exists() && !databaseFile.exists()) {
+                    // Check for use directory; create if it doesn't exist, else renameTo will fail
+                    File userDir = Environment.getUserSystemDirectory(userId);
+                    if (!userDir.exists()) {
+                        if (!userDir.mkdirs()) {
+                            throw new IllegalStateException("User dir cannot be created: " + userDir);
+                        }
+                    }
+                    if (!oldFile.renameTo(databaseFile)) {
+                        throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
+                    }
+                }
+            }
+            return databaseFile.getPath();
+        }
+
+        IAccountAuthenticatorCache getAccountAuthenticatorCache() {
+            return new AccountAuthenticatorCache(mContext);
+        }
+
+        INotificationManager getNotificationManager() {
+            return NotificationManager.getService();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
new file mode 100644
index 0000000..cb594f6
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -0,0 +1,1202 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.os.FileUtils;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Persistence layer abstraction for accessing accounts_ce/accounts_de databases.
+ *
+ * <p>At first, CE database needs to be {@link #attachCeDatabase(File) attached to DE},
+ * in order for the tables to be available. All operations with CE database are done through the
+ * connection to the DE database, to which it is attached. This approach allows atomic
+ * transactions across two databases</p>
+ */
+class AccountsDb implements AutoCloseable {
+    private static final String TAG = "AccountsDb";
+
+    private static final String DATABASE_NAME = "accounts.db";
+    private static final int PRE_N_DATABASE_VERSION = 9;
+    private static final int CE_DATABASE_VERSION = 10;
+    private static final int DE_DATABASE_VERSION = 1;
+
+
+    static final String TABLE_ACCOUNTS = "accounts";
+    private static final String ACCOUNTS_ID = "_id";
+    private static final String ACCOUNTS_NAME = "name";
+    private static final String ACCOUNTS_TYPE = "type";
+    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
+    private static final String ACCOUNTS_PASSWORD = "password";
+    private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
+    private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
+            "last_password_entry_time_millis_epoch";
+
+    private static final String TABLE_AUTHTOKENS = "authtokens";
+    private static final String AUTHTOKENS_ID = "_id";
+    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
+    private static final String AUTHTOKENS_TYPE = "type";
+    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
+
+    private static final String TABLE_GRANTS = "grants";
+    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
+    private static final String GRANTS_GRANTEE_UID = "uid";
+
+    private static final String TABLE_EXTRAS = "extras";
+    private static final String EXTRAS_ID = "_id";
+    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
+    private static final String EXTRAS_KEY = "key";
+    private static final String EXTRAS_VALUE = "value";
+
+    private static final String TABLE_META = "meta";
+    private static final String META_KEY = "key";
+    private static final String META_VALUE = "value";
+
+    static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+    private static final String SHARED_ACCOUNTS_ID = "_id";
+
+    private static String TABLE_DEBUG = "debug_table";
+
+    // Columns for debug_table table
+    private static String DEBUG_TABLE_ACTION_TYPE = "action_type";
+    private static String DEBUG_TABLE_TIMESTAMP = "time";
+    private static String DEBUG_TABLE_CALLER_UID = "caller_uid";
+    private static String DEBUG_TABLE_TABLE_NAME = "table_name";
+    private static String DEBUG_TABLE_KEY = "primary_key";
+
+    // These actions correspond to the occurrence of real actions. Since
+    // these are called by the authenticators, the uid associated will be
+    // of the authenticator.
+    static String DEBUG_ACTION_SET_PASSWORD = "action_set_password";
+    static String DEBUG_ACTION_CLEAR_PASSWORD = "action_clear_password";
+    static String DEBUG_ACTION_ACCOUNT_ADD = "action_account_add";
+    static String DEBUG_ACTION_ACCOUNT_REMOVE = "action_account_remove";
+    static String DEBUG_ACTION_ACCOUNT_REMOVE_DE = "action_account_remove_de";
+    static String DEBUG_ACTION_AUTHENTICATOR_REMOVE = "action_authenticator_remove";
+    static String DEBUG_ACTION_ACCOUNT_RENAME = "action_account_rename";
+
+    // These actions don't necessarily correspond to any action on
+    // accountDb taking place. As an example, there might be a request for
+    // addingAccount, which might not lead to addition of account on grounds
+    // of bad authentication. We will still be logging it to keep track of
+    // who called.
+    static String DEBUG_ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
+    static String DEBUG_ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
+    static String DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS = "action_sync_de_ce_accounts";
+
+    //This action doesn't add account to accountdb. Account is only
+    // added in finishSession which may be in a different user profile.
+    static String DEBUG_ACTION_CALLED_START_ACCOUNT_ADD = "action_called_start_account_add";
+    static String DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH =
+            "action_called_account_session_finish";
+
+    static final String CE_DATABASE_NAME = "accounts_ce.db";
+    static final String DE_DATABASE_NAME = "accounts_de.db";
+    private static final String CE_DB_PREFIX = "ceDb.";
+    private static final String CE_TABLE_ACCOUNTS = CE_DB_PREFIX + TABLE_ACCOUNTS;
+    private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
+    private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
+
+    static final int MAX_DEBUG_DB_SIZE = 64;
+
+    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
+            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
+
+    private static final String COUNT_OF_MATCHING_GRANTS = ""
+            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+            + " AND " + GRANTS_GRANTEE_UID + "=?"
+            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
+            + " 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=?)";
+
+    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
+            AUTHTOKENS_AUTHTOKEN};
+
+    private static final String SELECTION_USERDATA_BY_ACCOUNT =
+            EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
+    private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
+
+    private static final String ACCOUNT_ACCESS_GRANTS = ""
+            + "SELECT " + AccountsDb.ACCOUNTS_NAME + ", "
+            + AccountsDb.GRANTS_GRANTEE_UID
+            + " FROM " + AccountsDb.TABLE_ACCOUNTS
+            + ", " + AccountsDb.TABLE_GRANTS
+            + " WHERE " + AccountsDb.GRANTS_ACCOUNTS_ID
+            + "=" + AccountsDb.ACCOUNTS_ID;
+
+    private static final String META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX =
+            "auth_uid_for_type:";
+    private static final String META_KEY_DELIMITER = ":";
+    private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
+
+    private final DeDatabaseHelper mDeDatabase;
+    private final Context mContext;
+    private final File mPreNDatabaseFile;
+
+    AccountsDb(DeDatabaseHelper deDatabase, Context context, File preNDatabaseFile) {
+        mDeDatabase = deDatabase;
+        mContext = context;
+        mPreNDatabaseFile = preNDatabaseFile;
+    }
+
+    private static class CeDatabaseHelper extends SQLiteOpenHelper {
+
+        CeDatabaseHelper(Context context, String ceDatabaseName) {
+            super(context, ceDatabaseName, null, CE_DATABASE_VERSION);
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held.
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating CE database " + getDatabaseName());
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PASSWORD + " TEXT, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
+                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
+                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
+                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+                    + EXTRAS_KEY + " TEXT NOT NULL, "
+                    + EXTRAS_VALUE + " TEXT, "
+                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+            createAccountsDeletionTrigger(db);
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_AUTHTOKENS
+                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_EXTRAS
+                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "Upgrade CE from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion == 9) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "onUpgrade upgrading to v10");
+                }
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_META);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_SHARED_ACCOUNTS);
+                // Recreate the trigger, since the old one references the table to be removed
+                db.execSQL("DROP TRIGGER IF EXISTS " + TABLE_ACCOUNTS + "Delete");
+                createAccountsDeletionTrigger(db);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_GRANTS);
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_DEBUG);
+                oldVersion ++;
+            }
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
+        }
+
+
+        /**
+         * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
+         * it also performs migration to the new CE database.
+         */
+        static CeDatabaseHelper create(
+                Context context,
+                File preNDatabaseFile,
+                File ceDatabaseFile) {
+            boolean newDbExists = ceDatabaseFile.exists();
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "CeDatabaseHelper.create ceDatabaseFile=" + ceDatabaseFile
+                        + " oldDbExists=" + preNDatabaseFile.exists()
+                        + " newDbExists=" + newDbExists);
+            }
+            boolean removeOldDb = false;
+            if (!newDbExists && preNDatabaseFile.exists()) {
+                removeOldDb = migratePreNDbToCe(preNDatabaseFile, ceDatabaseFile);
+            }
+            // Try to open and upgrade if necessary
+            CeDatabaseHelper ceHelper = new CeDatabaseHelper(context, ceDatabaseFile.getPath());
+            ceHelper.getWritableDatabase();
+            ceHelper.close();
+            if (removeOldDb) {
+                Slog.i(TAG, "Migration complete - removing pre-N db " + preNDatabaseFile);
+                if (!SQLiteDatabase.deleteDatabase(preNDatabaseFile)) {
+                    Slog.e(TAG, "Cannot remove pre-N db " + preNDatabaseFile);
+                }
+            }
+            return ceHelper;
+        }
+
+        private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
+            Slog.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+            try {
+                FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
+            } catch (IOException e) {
+                Slog.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+                // Try to remove potentially damaged file if I/O error occurred
+                deleteDbFileWarnIfFailed(ceDbFile);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    /**
+     * 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>
+     */
+    Cursor findAuthtokenForAllAccounts(String accountType, String authToken) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        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});
+    }
+
+    Map<String, String> findAuthTokensByAccount(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        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;
+    }
+
+    boolean deleteAuthtokensByAccountIdAndType(long accountId, String authtokenType) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        return db.delete(CE_TABLE_AUTHTOKENS,
+                AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+                new String[]{String.valueOf(accountId), authtokenType}) > 0;
+    }
+
+    boolean deleteAuthToken(String authTokenId) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        return db.delete(
+                CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
+                new String[]{authTokenId}) > 0;
+    }
+
+    long insertAuthToken(long accountId, String authTokenType, String authToken) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        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);
+    }
+
+    int updateCeAccountPassword(long accountId, String password) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        final ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_PASSWORD, password);
+        return db.update(
+                CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
+                new String[] {String.valueOf(accountId)});
+    }
+
+    boolean renameCeAccount(long accountId, String newName) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        final ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_NAME, newName);
+        final String[] argsAccountId = {String.valueOf(accountId)};
+        return db.update(
+                CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+    }
+
+    boolean deleteAuthTokensByAccountId(long accountId) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
+                new String[] {String.valueOf(accountId)}) > 0;
+    }
+
+    long findExtrasIdByAccountId(long accountId, String key) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        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();
+        }
+    }
+
+    boolean updateExtra(long extrasId, String value) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        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;
+    }
+
+    long insertExtra(long accountId, String key, String value) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        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);
+    }
+
+    Map<String, String> findUserExtrasForAccount(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        Map<String, String> userExtrasForAccount = new HashMap<>();
+        String[] selectionArgs = {account.name, account.type};
+        try (Cursor cursor = db.query(CE_TABLE_EXTRAS,
+                COLUMNS_EXTRAS_KEY_AND_VALUE,
+                SELECTION_USERDATA_BY_ACCOUNT,
+                selectionArgs,
+                null, null, null)) {
+            while (cursor.moveToNext()) {
+                final String tmpkey = cursor.getString(0);
+                final String value = cursor.getString(1);
+                userExtrasForAccount.put(tmpkey, value);
+            }
+        }
+        return userExtrasForAccount;
+    }
+
+    long findCeAccountId(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        String[] columns = { ACCOUNTS_ID };
+        String selection = "name=? AND type=?";
+        String[] selectionArgs = {account.name, account.type};
+        try (Cursor cursor = db.query(CE_TABLE_ACCOUNTS, columns, selection, selectionArgs,
+                null, null, null)) {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+            return -1;
+        }
+    }
+
+    String findAccountPasswordByNameAndType(String name, String type) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        String selection = ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?";
+        String[] selectionArgs = {name, type};
+        String[] columns = {ACCOUNTS_PASSWORD};
+        try (Cursor cursor = db.query(CE_TABLE_ACCOUNTS, columns, selection, selectionArgs,
+                null, null, null)) {
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
+            }
+            return null;
+        }
+    }
+
+    long insertCeAccount(Account account, String password) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+        ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_NAME, account.name);
+        values.put(ACCOUNTS_TYPE, account.type);
+        values.put(ACCOUNTS_PASSWORD, password);
+        return db.insert(
+                CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+    }
+
+
+    static class DeDatabaseHelper extends SQLiteOpenHelper {
+
+        private final int mUserId;
+        private volatile boolean mCeAttached;
+
+        private DeDatabaseHelper(Context context, int userId, String deDatabaseName) {
+            super(context, deDatabaseName, null, DE_DATABASE_VERSION);
+            mUserId = userId;
+        }
+
+        /**
+         * This call needs to be made while the mCacheLock is held. The way to
+         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
+         * @param db The database.
+         */
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            Log.i(TAG, "Creating DE database for user " + mUserId);
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+                    + META_VALUE + " TEXT)");
+
+            createGrantsTable(db);
+            createSharedAccountsTable(db);
+            createAccountsDeletionTrigger(db);
+            createDebugTable(db);
+        }
+
+        private void createSharedAccountsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_GRANTS
+                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        private void createGrantsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
+                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
+                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
+                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+                    +   "," + GRANTS_GRANTEE_UID + "))");
+        }
+
+        static void createDebugTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
+                    + ACCOUNTS_ID + " INTEGER,"
+                    + DEBUG_TABLE_ACTION_TYPE + " TEXT NOT NULL, "
+                    + DEBUG_TABLE_TIMESTAMP + " DATETIME,"
+                    + DEBUG_TABLE_CALLER_UID + " INTEGER NOT NULL,"
+                    + DEBUG_TABLE_TABLE_NAME + " TEXT NOT NULL,"
+                    + DEBUG_TABLE_KEY + " INTEGER PRIMARY KEY)");
+            db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " ("
+                    + DEBUG_TABLE_TIMESTAMP + ")");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user " + mUserId
+                        + " is still locked. CE database is not yet available.", new Throwable());
+            }
+            return super.getReadableDatabase();
+        }
+
+        public SQLiteDatabase getWritableDatabaseUserIsUnlocked() {
+            if(!mCeAttached) {
+                Log.wtf(TAG, "getWritableDatabaseUserIsUnlocked called while user " + mUserId
+                        + " is still locked. CE database is not yet available.", new Throwable());
+            }
+            return super.getWritableDatabase();
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DE_DATABASE_NAME);
+        }
+
+        private void migratePreNDbToDe(File preNDbFile) {
+            Log.i(TAG, "Migrate pre-N database to DE preNDbFile=" + preNDbFile);
+            SQLiteDatabase db = getWritableDatabase();
+            db.execSQL("ATTACH DATABASE '" +  preNDbFile.getPath() + "' AS preNDb");
+            db.beginTransaction();
+            // Copy accounts fields
+            db.execSQL("INSERT INTO " + TABLE_ACCOUNTS
+                    + "(" + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + ") "
+                    + "SELECT " + ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ", "
+                    + ACCOUNTS_PREVIOUS_NAME + ", " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                    + " FROM preNDb." + TABLE_ACCOUNTS);
+            // Copy SHARED_ACCOUNTS
+            db.execSQL("INSERT INTO " + TABLE_SHARED_ACCOUNTS
+                    + "(" + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + ") " +
+                    "SELECT " + SHARED_ACCOUNTS_ID + "," + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+                    + " FROM preNDb." + TABLE_SHARED_ACCOUNTS);
+            // Copy DEBUG_TABLE
+            db.execSQL("INSERT INTO " + TABLE_DEBUG
+                    + "(" + ACCOUNTS_ID + "," + DEBUG_TABLE_ACTION_TYPE + ","
+                    + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_CALLER_UID + ","
+                    + DEBUG_TABLE_TABLE_NAME + "," + DEBUG_TABLE_KEY + ") " +
+                    "SELECT " + ACCOUNTS_ID + "," + DEBUG_TABLE_ACTION_TYPE + ","
+                    + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_CALLER_UID + ","
+                    + DEBUG_TABLE_TABLE_NAME + "," + DEBUG_TABLE_KEY
+                    + " FROM preNDb." + TABLE_DEBUG);
+            // Copy GRANTS
+            db.execSQL("INSERT INTO " + TABLE_GRANTS
+                    + "(" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + ") " +
+                    "SELECT " + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE + ","
+                    + GRANTS_GRANTEE_UID + " FROM preNDb." + TABLE_GRANTS);
+            // Copy META
+            db.execSQL("INSERT INTO " + TABLE_META
+                    + "(" + META_KEY + "," + META_VALUE + ") "
+                    + "SELECT " + META_KEY + "," + META_VALUE + " FROM preNDb." + TABLE_META);
+            db.setTransactionSuccessful();
+            db.endTransaction();
+
+            db.execSQL("DETACH DATABASE preNDb");
+        }
+    }
+
+    boolean deleteDeAccount(long accountId) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+    }
+
+    long insertSharedAccount(Account account) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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);
+    }
+
+    boolean deleteSharedAccount(Account account) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        return db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                new String[]{account.name, account.type}) > 0;
+    }
+
+    int renameSharedAccount(Account account, String newName) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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});
+    }
+
+    List<Account> getSharedAccounts() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        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;
+    }
+
+    long findSharedAccountId(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        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();
+        }
+    }
+
+    long findAccountLastAuthenticatedTime(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        return DatabaseUtils.longForQuery(db,
+                "SELECT " + AccountsDb.ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+                        + " FROM " + TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+                        + ACCOUNTS_TYPE + "=?",
+                new String[] {account.name, account.type});
+    }
+
+    boolean updateAccountLastAuthenticatedTime(Account account) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        final ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+        int rowCount = db.update(TABLE_ACCOUNTS,
+                values,
+                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                new String[] { account.name, account.type });
+        return rowCount > 0;
+    }
+
+    void dumpDeAccountsTable(PrintWriter pw) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        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();
+            }
+        }
+    }
+
+    long findDeAccountId(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        String[] columns = {ACCOUNTS_ID};
+        String selection = "name=? AND type=?";
+        String[] selectionArgs = {account.name, account.type};
+        try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns, selection, selectionArgs,
+                null, null, null)) {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+            return -1;
+        }
+    }
+
+    Map<Long, Account> findAllDeAccounts() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
+        String[] columns = {ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME};
+        try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns,
+                null, null, null, null, ACCOUNTS_ID)) {
+            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);
+            }
+        }
+        return map;
+    }
+
+    String findDeAccountPreviousName(Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        String[] columns = {ACCOUNTS_PREVIOUS_NAME};
+        String selection = ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?";
+        String[] selectionArgs = {account.name, account.type};
+        try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns, selection, selectionArgs,
+                null, null, null)) {
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
+            }
+        }
+        return null;
+    }
+
+    long insertDeAccount(Account account, long accountId) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_ID, accountId);
+        values.put(ACCOUNTS_NAME, account.name);
+        values.put(ACCOUNTS_TYPE, account.type);
+        values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+        return db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+    }
+
+    boolean renameDeAccount(long accountId, String newName, String previousName) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        final ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_NAME, newName);
+        values.put(ACCOUNTS_PREVIOUS_NAME, previousName);
+        final String[] argsAccountId = {String.valueOf(accountId)};
+        return db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+    }
+
+    boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(long accountId,
+            String authTokenType, long uid) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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;
+    }
+
+    List<Integer> findAllUidGrants() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        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;
+    }
+
+    long findMatchingGrantsCount(int uid, String authTokenType, Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        String[] args = {String.valueOf(uid), authTokenType, account.name, account.type};
+        return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
+    }
+
+    long findMatchingGrantsCountAnyToken(int uid, Account account) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        String[] args = {String.valueOf(uid), account.name, account.type};
+        return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS_ANY_TOKEN, args);
+    }
+
+    long insertGrant(long accountId, String authTokenType, int uid) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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);
+    }
+
+    boolean deleteGrantsByUid(int uid) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        return db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
+                new String[] {Integer.toString(uid)}) > 0;
+    }
+
+    long insertOrReplaceMetaAuthTypeAndUid(String authenticatorType, int uid) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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);
+    }
+
+    Map<String, Integer> findMetaAuthUid() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        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;
+    }
+
+    boolean deleteMetaByAuthTypeAndUid(String type, int uid) {
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        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;
+    }
+
+    /**
+     * Returns list of all grants as {@link Pair pairs} of account name and UID.
+     */
+    List<Pair<String, Integer>> findAllAccountGrants() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        try (Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null)) {
+            if (cursor == null || !cursor.moveToFirst()) {
+                return Collections.emptyList();
+            }
+            List<Pair<String, Integer>> results = new ArrayList<>();
+            do {
+                final String accountName = cursor.getString(0);
+                final int uid = cursor.getInt(1);
+                results.add(Pair.create(accountName, uid));
+            } while (cursor.moveToNext());
+            return results;
+        }
+    }
+
+    private static class PreNDatabaseHelper extends SQLiteOpenHelper {
+        private final Context mContext;
+        private final int mUserId;
+
+        PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
+            super(context, preNDatabaseName, null, PRE_N_DATABASE_VERSION);
+            mContext = context;
+            mUserId = userId;
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            // We use PreNDatabaseHelper only if pre-N db exists
+            throw new IllegalStateException("Legacy database cannot be created - only upgraded!");
+        }
+
+        private void createSharedAccountsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+        }
+
+        private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
+            db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
+                    + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
+        }
+
+        private void addOldAccountNameColumn(SQLiteDatabase db) {
+            db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
+        }
+
+        private void addDebugTable(SQLiteDatabase db) {
+            DeDatabaseHelper.createDebugTable(db);
+        }
+
+        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_AUTHTOKENS
+                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_EXTRAS
+                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_GRANTS
+                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        private void createGrantsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
+                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
+                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
+                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+                    +   "," + GRANTS_GRANTEE_UID + "))");
+        }
+
+        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);
+        }
+
+        private void populateMetaTableWithAuthTypeAndUID(SQLiteDatabase db,
+                Map<String, Integer> authTypeAndUIDMap) {
+            for (Map.Entry<String, Integer> entry : authTypeAndUIDMap.entrySet()) {
+                insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
+            }
+        }
+
+        /**
+         * Pre-N database may need an upgrade before splitting
+         */
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion == 1) {
+                // no longer need to do anything since the work is done
+                // when upgrading from version 2
+                oldVersion++;
+            }
+
+            if (oldVersion == 2) {
+                createGrantsTable(db);
+                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
+                createAccountsDeletionTrigger(db);
+                oldVersion++;
+            }
+
+            if (oldVersion == 3) {
+                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
+                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
+                oldVersion++;
+            }
+
+            if (oldVersion == 4) {
+                createSharedAccountsTable(db);
+                oldVersion++;
+            }
+
+            if (oldVersion == 5) {
+                addOldAccountNameColumn(db);
+                oldVersion++;
+            }
+
+            if (oldVersion == 6) {
+                addLastSuccessfullAuthenticatedTimeColumn(db);
+                oldVersion++;
+            }
+
+            if (oldVersion == 7) {
+                addDebugTable(db);
+                oldVersion++;
+            }
+
+            if (oldVersion == 8) {
+                populateMetaTableWithAuthTypeAndUID(
+                        db,
+                        AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
+                oldVersion++;
+            }
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
+        }
+    }
+
+    List<Account> findCeAccountsNotInDe() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        // 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();
+        }
+    }
+
+    boolean deleteCeAccount(long accountId) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+        return db.delete(
+                CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+    }
+
+    boolean isCeDatabaseAttached() {
+        return mDeDatabase.mCeAttached;
+    }
+
+    void beginTransaction() {
+        mDeDatabase.getWritableDatabase().beginTransaction();
+    }
+
+    void setTransactionSuccessful() {
+        mDeDatabase.getWritableDatabase().setTransactionSuccessful();
+    }
+
+    void endTransaction() {
+        mDeDatabase.getWritableDatabase().endTransaction();
+    }
+
+    void attachCeDatabase(File ceDbFile) {
+        CeDatabaseHelper.create(mContext, mPreNDatabaseFile, ceDbFile);
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        db.execSQL("ATTACH DATABASE '" +  ceDbFile.getPath()+ "' AS ceDb");
+        mDeDatabase.mCeAttached = true;
+    }
+
+    /*
+     * Finds the row key where the next insertion should take place. Returns number of rows
+     * if it is less {@link #MAX_DEBUG_DB_SIZE}, otherwise finds the lowest number available.
+     */
+    int calculateDebugTableInsertionPoint() {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
+        int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+        if (size < MAX_DEBUG_DB_SIZE) {
+            return size;
+        }
+
+        // This query finds the smallest timestamp value (and if 2 records have
+        // same timestamp, the choose the lower id).
+        queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
+                " FROM " + TABLE_DEBUG +
+                " ORDER BY "  + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
+                " LIMIT 1";
+        return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+    }
+
+    SQLiteStatement compileSqlStatementForLogging() {
+        // TODO b/31708085 Fix debug logging - it eagerly opens database for write without a need
+        SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+        String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
+                + " VALUES (?,?,?,?,?,?)";
+        return db.compileStatement(sql);
+    }
+
+    void dumpDebugTable(PrintWriter pw) {
+        SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+        Cursor cursor = db.query(TABLE_DEBUG, null,
+                null, null, null, null, DEBUG_TABLE_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();
+        }
+    }
+
+    public void close() {
+        mDeDatabase.close();
+    }
+
+    static void deleteDbFileWarnIfFailed(File dbFile) {
+        if (!SQLiteDatabase.deleteDatabase(dbFile)) {
+            Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
+        }
+    }
+
+    public static AccountsDb create(Context context, int userId, File preNDatabaseFile,
+            File deDatabaseFile) {
+        boolean newDbExists = deDatabaseFile.exists();
+        DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
+                deDatabaseFile.getPath());
+        // If the db just created, and there is a legacy db, migrate it
+        if (!newDbExists && preNDatabaseFile.exists()) {
+            // Migrate legacy db to the latest version -  PRE_N_DATABASE_VERSION
+            PreNDatabaseHelper
+                    preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
+                    preNDatabaseFile.getPath());
+            // Open the database to force upgrade if required
+            preNDatabaseHelper.getWritableDatabase();
+            preNDatabaseHelper.close();
+            // Move data without SPII to DE
+            deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
+        }
+        return new AccountsDb(deDatabaseHelper, context, preNDatabaseFile);
+    }
+
+}
diff --git a/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
index bb09687..2c7d921 100644
--- a/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
+++ b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
@@ -64,4 +64,10 @@
             Handler handler);
 
     void invalidateCache(int userId);
+
+    /**
+     * Request to update services info for which package has been updated, but hasn't been
+     * picked up by the cache.
+     */
+    void updateServices(int 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..c32cac8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.os.IDeviceIdentifiersPolicyService;
 import com.android.internal.telephony.TelephonyIntents;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -181,6 +182,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -286,7 +288,6 @@
 import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.provider.Settings.System.FONT_SCALE;
-import static android.security.KeyChain.ACTION_TRUST_STORE_CHANGED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -527,11 +528,6 @@
     private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
             "android.intent.action.REMOTE_BUGREPORT_FINISHED";
 
-    // Delay to disable app launch boost
-    static final int APP_BOOST_MESSAGE_DELAY = 3000;
-    // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost
-    static final int APP_BOOST_TIMEOUT = 2500;
-
     // Used to indicate that a task is removed it should also be removed from recents.
     private static final boolean REMOVE_FROM_RECENTS = true;
     // Used to indicate that an app transition should be animated.
@@ -541,11 +537,6 @@
     static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
     public static final float FULLSCREEN_SCREENSHOT_SCALE = 0.6f;
 
-    private static native int nativeMigrateToBoost();
-    private static native int nativeMigrateFromBoost();
-    private boolean mIsBoosted = false;
-    private long mBoostStartTime = 0;
-
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -565,7 +556,7 @@
     public IntentFirewall mIntentFirewall;
 
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
-    // default actuion automatically.  Important for devices without direct input
+    // default action automatically.  Important for devices without direct input
     // devices.
     private boolean mShowDialogs = true;
     private boolean mInVrMode = false;
@@ -637,7 +628,8 @@
     final AppErrors mAppErrors;
 
     public boolean canShowErrorDialogs() {
-        return mShowDialogs && !mSleeping && !mShuttingDown;
+        return mShowDialogs && !mSleeping && !mShuttingDown
+                && mLockScreenShown != LOCK_SCREEN_SHOWN;
     }
 
     private static final class PriorityState {
@@ -1130,19 +1122,21 @@
     final AppOpsService mAppOpsService;
 
     /**
-     * Current configuration information.  HistoryRecord objects are given
-     * a reference to this object to indicate which configuration they are
-     * currently running in, so this object must be kept immutable.
+     * Current global configuration information. Contains general settings for the entire system,
+     * also corresponds to the merged configuration of the default display.
      */
-    Configuration mConfiguration = new Configuration();
+    Configuration mGlobalConfiguration = new Configuration();
+
+    /** Current sequencing integer of the configuration, for skipping old configurations. */
+    private int mConfigurationSeq;
 
     /**
-     * Current sequencing integer of the configuration, for skipping old
-     * configurations.
+     * Temp object used when global configuration is updated. It is also sent to outer world
+     * instead of {@link #mGlobalConfiguration} because we don't trust anyone...
      */
-    int mConfigurationSeq = 0;
+    private Configuration mTempGlobalConfig = new Configuration();
 
-    boolean mSuppressResizeConfigChanges = false;
+    boolean mSuppressResizeConfigChanges;
 
     /**
      * Hardware-reported OpenGLES version.
@@ -1154,6 +1148,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.
@@ -1519,7 +1514,6 @@
     static final int REPORT_TIME_TRACKER_MSG = 55;
     static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
     static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
-    static final int APP_BOOST_DEACTIVATE_MSG = 58;
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
     static final int IDLE_UIDS_MSG = 60;
     static final int SYSTEM_USER_UNLOCK_MSG = 61;
@@ -1533,6 +1527,7 @@
     static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69;
     static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70;
     static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 71;
+    static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 72;
     static final int START_USER_SWITCH_FG_MSG = 712;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1726,6 +1721,7 @@
                     }
                     if (ar != null && mCompatModePackages.getPackageNotifyUnsupportedZoomLocked(
                             ar.packageName)) {
+                        // TODO(multi-display): Show dialog on appropriate display.
                         mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog(
                                 ActivityManagerService.this, mContext, ar.info.applicationInfo);
                         mUnsupportedDisplaySizeDialog.show();
@@ -2280,6 +2276,9 @@
             case REPORT_USER_SWITCH_COMPLETE_MSG: {
                 mUserController.dispatchUserSwitchComplete(msg.arg1);
             } break;
+            case REPORT_LOCKED_BOOT_COMPLETE_MSG: {
+                mUserController.dispatchLockedBootComplete(msg.arg1);
+            } break;
             case SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG: {
                 IUiAutomationConnection connection = (IUiAutomationConnection) msg.obj;
                 try {
@@ -2291,20 +2290,6 @@
                 // it is finished we make sure it is reset to its default.
                 mUserIsMonkey = false;
             } break;
-            case APP_BOOST_DEACTIVATE_MSG: {
-                synchronized(ActivityManagerService.this) {
-                    if (mIsBoosted) {
-                        if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) {
-                            nativeMigrateFromBoost();
-                            mIsBoosted = false;
-                            mBoostStartTime = 0;
-                        } else {
-                            Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
-                            mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT);
-                        }
-                    }
-                }
-            } break;
             case IDLE_UIDS_MSG: {
                 idleUids();
             } break;
@@ -2315,6 +2300,9 @@
             } break;
             case VR_MODE_CHANGE_MSG: {
                 VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+                if (vrService == null) {
+                    break;
+                }
                 final ActivityRecord r = (ActivityRecord) msg.obj;
                 boolean vrMode;
                 ComponentName requestedPackage;
@@ -2327,7 +2315,7 @@
                     callingPackage = r.info.getComponentName();
                     if (mInVrMode != vrMode) {
                         mInVrMode = vrMode;
-                        mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
+                        mShowDialogs = shouldShowDialogs(mGlobalConfiguration, mInVrMode);
                         if (r.app != null) {
                             ProcessRecord proc = r.app;
                             if (proc.vrThreadTid > 0) {
@@ -2396,22 +2384,21 @@
                 if (memInfo != null) {
                     updateCpuStatsNow();
                     long nativeTotalPss = 0;
+                    final List<ProcessCpuTracker.Stats> stats;
                     synchronized (mProcessCpuTracker) {
-                        final int N = mProcessCpuTracker.countStats();
-                        for (int j=0; j<N; j++) {
-                            ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(j);
-                            if (st.vsize <= 0 || st.uid >= Process.FIRST_APPLICATION_UID) {
-                                // This is definitely an application process; skip it.
+                        stats = mProcessCpuTracker.getStats( (st)-> {
+                            return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
+                        });
+                    }
+                    final int N = stats.size();
+                    for (int j = 0; j < N; j++) {
+                        synchronized (mPidsSelfLocked) {
+                            if (mPidsSelfLocked.indexOfKey(stats.get(j).pid) >= 0) {
+                                // This is one of our own processes; skip it.
                                 continue;
                             }
-                            synchronized (mPidsSelfLocked) {
-                                if (mPidsSelfLocked.indexOfKey(st.pid) >= 0) {
-                                    // This is one of our own processes; skip it.
-                                    continue;
-                                }
-                            }
-                            nativeTotalPss += Debug.getPss(st.pid, null, null);
                         }
+                        nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
                     }
                     memInfo.readMemInfo();
                     synchronized (ActivityManagerService.this) {
@@ -2704,10 +2691,10 @@
 
         mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
 
-        mConfiguration.setToDefaults();
-        mConfiguration.setLocales(LocaleList.getDefault());
+        mGlobalConfiguration.setToDefaults();
+        mGlobalConfiguration.setLocales(LocaleList.getDefault());
 
-        mConfigurationSeq = mConfiguration.seq = 1;
+        mConfigurationSeq = mGlobalConfiguration.seq = 1;
         mProcessCpuTracker.init();
 
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
@@ -2957,18 +2944,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;
     }
@@ -3138,8 +3131,8 @@
     }
 
     final void showUnsupportedZoomDialogIfNeededLocked(ActivityRecord r) {
-        if (mConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
-                && r.appInfo.requiresSmallestWidthDp > mConfiguration.smallestScreenWidthDp) {
+        if (mGlobalConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
+                && r.appInfo.requiresSmallestWidthDp > mGlobalConfiguration.smallestScreenWidthDp) {
             final Message msg = Message.obtain();
             msg.what = SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG;
             msg.obj = r;
@@ -3538,14 +3531,6 @@
             app = null;
         }
 
-        // app launch boost for big.little configurations
-        // use cpusets to migrate freshly launched tasks to big cores
-        nativeMigrateToBoost();
-        mIsBoosted = true;
-        mBoostStartTime = SystemClock.uptimeMillis();
-        Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
-        mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
-
         // We don't have to do anything more if:
         // (1) There is an existing application record; and
         // (2) The caller doesn't think it is dead, OR there is no thread
@@ -3806,16 +3791,19 @@
             app.killed = false;
             app.killedByAm = false;
             checkTime(startTime, "startProcess: starting to update pids map");
+            ProcessRecord oldApp;
             synchronized (mPidsSelfLocked) {
-                ProcessRecord oldApp;
-                // If there is already an app occupying that pid that hasn't been cleaned up
-                if ((oldApp = mPidsSelfLocked.get(startResult.pid)) != null && !app.isolated) {
-                    // Clean up anything relating to this pid first
-                    Slog.w(TAG, "Reusing pid " + startResult.pid
-                            + " while app is still mapped to it");
-                    cleanUpApplicationRecordLocked(oldApp, false, false, -1,
-                            true /*replacingPid*/);
-                }
+                oldApp = mPidsSelfLocked.get(startResult.pid);
+            }
+            // If there is already an app occupying that pid that hasn't been cleaned up
+            if (oldApp != null && !app.isolated) {
+                // Clean up anything relating to this pid first
+                Slog.w(TAG, "Reusing pid " + startResult.pid
+                        + " while app is still mapped to it");
+                cleanUpApplicationRecordLocked(oldApp, false, false, -1,
+                        true /*replacingPid*/);
+            }
+            synchronized (mPidsSelfLocked) {
                 this.mPidsSelfLocked.put(startResult.pid, app);
                 if (isActivityProcess) {
                     Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
@@ -4085,25 +4073,29 @@
     }
 
     @Override
-    public boolean setProcessMemoryTrimLevel(String process, int userId, int level) {
+    public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
+            throws RemoteException {
         synchronized (this) {
             final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel");
             if (app == null) {
-                return false;
+                throw new IllegalArgumentException("Unknown process: " + process);
             }
-            if (app.trimMemoryLevel < level && app.thread != null &&
-                    (level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
-                            app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND)) {
-                try {
-                    app.thread.scheduleTrimMemory(level);
-                    app.trimMemoryLevel = level;
-                    return true;
-                } catch (RemoteException e) {
-                    // Fallthrough to failure case.
-                }
+            if (app.thread == null) {
+                throw new IllegalArgumentException("Process has no app thread");
             }
+            if (app.trimMemoryLevel >= level) {
+                throw new IllegalArgumentException(
+                        "Unable to set a higher trim level than current level");
+            }
+            if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
+                    app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND)) {
+                throw new IllegalArgumentException("Unable to set a background trim level "
+                    + "on a foreground process");
+            }
+            app.thread.scheduleTrimMemory(level);
+            app.trimMemoryLevel = level;
+            return true;
         }
-        return false;
     }
 
     private void dispatchProcessesChanged() {
@@ -4751,7 +4743,7 @@
             final long origId = Binder.clearCallingIdentity();
             mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
-                    mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
+                    mGlobalConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false)) {
@@ -6135,6 +6127,8 @@
                 ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
+        didSomething |= mActivityStarter.clearPendingActivityLaunchesLocked(packageName);
+
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                 packageName, null, doit, evenPersistent, userId)) {
             if (!doit) {
@@ -6467,6 +6461,8 @@
         app.debugging = false;
         app.cached = false;
         app.killedByAm = false;
+        app.killed = false;
+
 
         // We carefully use the same state that PackageManager uses for
         // filtering, since we use this flag to decide if we need to install
@@ -6534,7 +6530,7 @@
                                  PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
-                    + processName + " with config " + mConfiguration);
+                    + processName + " with config " + mGlobalConfiguration);
             ApplicationInfo appInfo = app.instrumentationInfo != null
                     ? app.instrumentationInfo : app.info;
             app.compat = compatibilityInfoForPackageLocked(appInfo);
@@ -6543,14 +6539,27 @@
             }
             ProfilerInfo profilerInfo = profileFile == null ? null
                     : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+
+            // We deprecated Build.SERIAL and only apps that target pre NMR1
+            // SDK can see it. Since access to the serial is now behind a
+            // permission we push down the value.
+            String buildSerial = Build.UNKNOWN;
+            if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+                buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
+                        ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
+                        .getSerial();
+            }
+
             thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                     profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                     app.instrumentationUiAutomationConnection, testMode,
                     mBinderTransactionTrackingEnabled, enableTrackAllocation,
                     isRestrictedBackupMode || !normalMode, app.persistent,
-                    new Configuration(mConfiguration), app.compat,
+                    new Configuration(mGlobalConfiguration), app.compat,
                     getCommonServicesLocked(app.isolated),
-                    mCoreSettingsObserver.getCoreSettingsLocked());
+                    mCoreSettingsObserver.getCoreSettingsLocked(),
+                    buildSerial);
+
             updateLruProcessLocked(app, false, null);
             app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
         } catch (Exception e) {
@@ -9308,7 +9317,7 @@
                 r.task.stack.getDisplaySize(displaySize);
                 thumbnailInfo.taskWidth = displaySize.x;
                 thumbnailInfo.taskHeight = displaySize.y;
-                thumbnailInfo.screenOrientation = mConfiguration.orientation;
+                thumbnailInfo.screenOrientation = mGlobalConfiguration.orientation;
 
                 TaskRecord task = new TaskRecord(this,
                         mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
@@ -10766,7 +10775,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;
                         }
@@ -11466,6 +11475,7 @@
                 && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
             r.persistent = true;
+            r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
         }
         addProcessNameLocked(r);
         return r;
@@ -12050,27 +12060,29 @@
     }
 
     public void requestBugReport(int bugreportType) {
-        String service = null;
+        String extraOptions = null;
         switch (bugreportType) {
             case ActivityManager.BUGREPORT_OPTION_FULL:
-                service = "bugreport";
+                // Default options.
                 break;
             case ActivityManager.BUGREPORT_OPTION_INTERACTIVE:
-                service = "bugreportplus";
+                extraOptions = "bugreportplus";
                 break;
             case ActivityManager.BUGREPORT_OPTION_REMOTE:
-                service = "bugreportremote";
+                extraOptions = "bugreportremote";
                 break;
             case ActivityManager.BUGREPORT_OPTION_WEAR:
-                service = "bugreportwear";
+                extraOptions = "bugreportwear";
                 break;
-        }
-        if (service == null) {
-            throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
-                    + bugreportType);
+            default:
+                throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
+                        + bugreportType);
         }
         enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport");
-        SystemProperties.set("ctl.start", service);
+        if (extraOptions != null) {
+            SystemProperties.set("dumpstate.options", extraOptions);
+        }
+        SystemProperties.set("ctl.start", "bugreport");
     }
 
     public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
@@ -13140,11 +13152,11 @@
                 mSupportsFreeformWindowManagement = false;
                 mSupportsPictureInPicture = false;
             }
-            // This happens before any activities are started, so we can
-            // change mConfiguration in-place.
+            // This happens before any activities are started, so we can change global configuration
+            // in-place.
             updateConfigurationLocked(configuration, null, true);
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Initial config: " + mConfiguration);
+                    "Initial config: " + mGlobalConfiguration);
 
             // Load resources only after the current configuration has been set.
             final Resources res = mContext.getResources();
@@ -13159,10 +13171,11 @@
                     com.android.internal.R.string.config_appsNotReportingCrashes));
             mUserController.mUserSwitchUiEnabled = !res.getBoolean(
                     com.android.internal.R.bool.config_customUserSwitchUi);
-            if ((mConfiguration.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
+            if ((mGlobalConfiguration.uiMode & UI_MODE_TYPE_TELEVISION)
+                    == UI_MODE_TYPE_TELEVISION) {
                 mFullscreenThumbnailScale = (float) res
                     .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
-                    (float) mConfiguration.screenWidthDp;
+                    (float) mGlobalConfiguration.screenWidthDp;
             } else {
                 mFullscreenThumbnailScale = res.getFraction(
                     com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
@@ -13727,11 +13740,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
@@ -13803,7 +13817,7 @@
                     try {
                         java.lang.Process logcat = new ProcessBuilder(
                                 "/system/bin/timeout", "-k", "15s", "10s",
-                                "/system/bin/logcat", "-v", "time", "-b", "events", "-b", "system",
+                                "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system",
                                 "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
                                         .redirectErrorStream(true).start();
 
@@ -14013,9 +14027,10 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
         (new ActivityManagerShellCommand(this, false)).exec(
-                this, in, out, err, args, resultReceiver);
+                this, in, out, err, args, callback, resultReceiver);
     }
 
     @Override
@@ -14238,7 +14253,8 @@
                 // Dumping a single activity?
                 if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacks)) {
                     ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
-                    int res = shell.exec(this, null, fd, null, args, new ResultReceiver(null));
+                    int res = shell.exec(this, null, fd, null, args, null,
+                            new ResultReceiver(null));
                     if (res < 0) {
                         pw.println("Bad activity command, or no activities match: " + cmd);
                         pw.println("Use -h for help.");
@@ -14754,7 +14770,7 @@
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
         if (dumpPackage == null) {
-            pw.println("  mConfiguration: " + mConfiguration);
+            pw.println("  mGlobalConfiguration: " + mGlobalConfiguration);
         }
         if (dumpAll) {
             pw.println("  mConfigWillChange: " + getFocusedStack().mConfigWillChange);
@@ -16497,21 +16513,24 @@
         }
         updateCpuStatsNow();
         long[] memtrackTmp = new long[1];
+        final List<ProcessCpuTracker.Stats> stats;
+        // Get a list of Stats that have vsize > 0
         synchronized (mProcessCpuTracker) {
-            final int N = mProcessCpuTracker.countStats();
-            for (int i=0; i<N; i++) {
-                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
-                if (st.vsize > 0) {
-                    long pss = Debug.getPss(st.pid, null, memtrackTmp);
-                    if (pss > 0) {
-                        if (infoMap.indexOfKey(st.pid) < 0) {
-                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
-                                    ProcessList.NATIVE_ADJ, -1, "native", null);
-                            mi.pss = pss;
-                            mi.memtrack = memtrackTmp[0];
-                            memInfos.add(mi);
-                        }
-                    }
+            stats = mProcessCpuTracker.getStats((st) -> {
+                return st.vsize > 0;
+            });
+        }
+        final int statsCount = stats.size();
+        for (int i = 0; i < statsCount; i++) {
+            ProcessCpuTracker.Stats st = stats.get(i);
+            long pss = Debug.getPss(st.pid, null, memtrackTmp);
+            if (pss > 0) {
+                if (infoMap.indexOfKey(st.pid) < 0) {
+                    ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+                            ProcessList.NATIVE_ADJ, -1, "native", null);
+                    mi.pss = pss;
+                    mi.memtrack = memtrackTmp[0];
+                    memInfos.add(mi);
                 }
             }
         }
@@ -17764,6 +17783,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)
@@ -18733,15 +18753,15 @@
     public ConfigurationInfo getDeviceConfigurationInfo() {
         ConfigurationInfo config = new ConfigurationInfo();
         synchronized (this) {
-            config.reqTouchScreen = mConfiguration.touchscreen;
-            config.reqKeyboardType = mConfiguration.keyboard;
-            config.reqNavigation = mConfiguration.navigation;
-            if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
-                    || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
+            config.reqTouchScreen = mGlobalConfiguration.touchscreen;
+            config.reqKeyboardType = mGlobalConfiguration.keyboard;
+            config.reqNavigation = mGlobalConfiguration.navigation;
+            if (mGlobalConfiguration.navigation == Configuration.NAVIGATION_DPAD
+                    || mGlobalConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
                 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
             }
-            if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
-                    && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
+            if (mGlobalConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
+                    && mGlobalConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
                 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
             }
             config.reqGlEsVersion = GL_ES_VERSION;
@@ -18765,7 +18785,7 @@
     public Configuration getConfiguration() {
         Configuration ci;
         synchronized(this) {
-            ci = new Configuration(mConfiguration);
+            ci = new Configuration(mGlobalConfiguration);
             ci.userSetLocale = false;
         }
         return ci;
@@ -18798,8 +18818,8 @@
     @Override
     public void updatePersistentConfiguration(Configuration values) {
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
-                "updateConfiguration()");
-        enforceWriteSettingsPermission("updateConfiguration()");
+                "updatePersistentConfiguration()");
+        enforceWriteSettingsPermission("updatePersistentConfiguration()");
         if (values == null) {
             throw new NullPointerException("Configuration must not be null");
         }
@@ -18823,7 +18843,7 @@
     private void updateFontScaleIfNeeded(@UserIdInt int userId) {
         final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(),
                 FONT_SCALE, 1.0f, userId);
-        if (mConfiguration.fontScale != scaleFactor) {
+        if (mGlobalConfiguration.fontScale != scaleFactor) {
             final Configuration configuration = mWindowManager.computeNewConfiguration();
             configuration.fontScale = scaleFactor;
             synchronized (this) {
@@ -18851,6 +18871,7 @@
         throw new SecurityException(msg);
     }
 
+    @Override
     public void updateConfiguration(Configuration values) {
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "updateConfiguration()");
@@ -18875,10 +18896,12 @@
     }
 
     void updateUserConfigurationLocked() {
-        Configuration configuration = new Configuration(mConfiguration);
+        final Configuration configuration = new Configuration(mGlobalConfiguration);
+        final int currentUserId = mUserController.getCurrentUserIdLocked();
         Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
-                mUserController.getCurrentUserIdLocked(), Settings.System.canWrite(mContext));
-        updateConfigurationLocked(configuration, null, false);
+                currentUserId, Settings.System.canWrite(mContext));
+        updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
+                false /* persistent */, currentUserId, false /* deferResume */);
     }
 
     boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
@@ -18909,129 +18932,147 @@
     private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
             boolean initLocale, boolean persistent, int userId, boolean deferResume) {
         int changes = 0;
+        boolean kept = true;
 
         if (mWindowManager != null) {
             mWindowManager.deferSurfaceLayout();
         }
-        if (values != null) {
-            Configuration newConfig = new Configuration(mConfiguration);
-            changes = newConfig.updateFrom(values);
-            if (changes != 0) {
-                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
-                        "Updating configuration to: " + values);
-
-                EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
-
-                if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
-                    final LocaleList locales = values.getLocales();
-                    int bestLocaleIndex = 0;
-                    if (locales.size() > 1) {
-                        if (mSupportedSystemLocales == null) {
-                            mSupportedSystemLocales =
-                                    Resources.getSystem().getAssets().getLocales();
-                        }
-                        bestLocaleIndex = Math.max(0,
-                                locales.getFirstMatchIndex(mSupportedSystemLocales));
-                    }
-                    SystemProperties.set("persist.sys.locale",
-                            locales.get(bestLocaleIndex).toLanguageTag());
-                    LocaleList.setDefault(locales, bestLocaleIndex);
-                    mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
-                            locales.get(bestLocaleIndex)));
-                }
-
-                mConfigurationSeq++;
-                if (mConfigurationSeq <= 0) {
-                    mConfigurationSeq = 1;
-                }
-                newConfig.seq = mConfigurationSeq;
-                mConfiguration = newConfig;
-                Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
-                mUsageStatsService.reportConfigurationChange(newConfig,
-                        mUserController.getCurrentUserIdLocked());
-                //mUsageStatsService.noteStartConfig(newConfig);
-
-                final Configuration configCopy = new Configuration(mConfiguration);
-
-                // TODO: If our config changes, should we auto dismiss any currently
-                // showing dialogs?
-                mShowDialogs = shouldShowDialogs(newConfig, mInVrMode);
-
-                AttributeCache ac = AttributeCache.instance();
-                if (ac != null) {
-                    ac.updateConfiguration(configCopy);
-                }
-
-                // Make sure all resources in our process are updated
-                // right now, so that anyone who is going to retrieve
-                // resource values after we return will be sure to get
-                // the new ones.  This is especially important during
-                // boot, where the first config change needs to guarantee
-                // all resources have that config before following boot
-                // code is executed.
-                mSystemThread.applyConfigurationToResources(configCopy);
-
-                if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
-                    Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
-                    msg.obj = new Configuration(configCopy);
-                    msg.arg1 = userId;
-                    mHandler.sendMessage(msg);
-                }
-
-                final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
-                if (isDensityChange) {
-                    // Reset the unsupported display size dialog.
-                    mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
-
-                    killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
-                            ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
-                }
-
-                for (int i=mLruProcesses.size()-1; i>=0; i--) {
-                    ProcessRecord app = mLruProcesses.get(i);
-                    try {
-                        if (app.thread != null) {
-                            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
-                                    + app.processName + " new config " + mConfiguration);
-                            app.thread.scheduleConfigurationChanged(configCopy);
-                        }
-                    } catch (Exception e) {
-                    }
-                }
-                Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                        | Intent.FLAG_RECEIVER_REPLACE_PENDING
-                        | Intent.FLAG_RECEIVER_FOREGROUND);
-                broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
-                        null, AppOpsManager.OP_NONE, null, false, false,
-                        MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
-                if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
-                    intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
-                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                    if (!mProcessesReady) {
-                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                    }
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
-                }
+        try {
+            if (values != null) {
+                changes = updateGlobalConfiguration(values, initLocale, persistent, userId,
+                        deferResume);
             }
-            // Update the configuration with WM first and check if any of the stacks need to be
-            // resized due to the configuration change. If so, resize the stacks now and do any
-            // relaunches if necessary. This way we don't need to relaunch again below in
-            // ensureActivityConfigurationLocked().
+
+            kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+        } finally {
             if (mWindowManager != null) {
-                final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
-                if (resizedStacks != null) {
-                    for (int stackId : resizedStacks) {
-                        final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
-                        mStackSupervisor.resizeStackLocked(
-                                stackId, newBounds, null, null, false, false, deferResume);
-                    }
+                mWindowManager.continueSurfaceLayout();
+            }
+        }
+        return kept;
+    }
+
+    /** Update default (global) configuration and notify listeners about changes. */
+    private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
+            boolean persistent, int userId, boolean deferResume) {
+        mTempGlobalConfig.setTo(mGlobalConfiguration);
+        final int changes = mTempGlobalConfig.updateFrom(values);
+        if (changes == 0) {
+            return 0;
+        }
+
+        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+                "Updating global configuration to: " + values);
+
+        EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+
+        if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
+            final LocaleList locales = values.getLocales();
+            int bestLocaleIndex = 0;
+            if (locales.size() > 1) {
+                if (mSupportedSystemLocales == null) {
+                    mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+                }
+                bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
+            }
+            SystemProperties.set("persist.sys.locale",
+                    locales.get(bestLocaleIndex).toLanguageTag());
+            LocaleList.setDefault(locales, bestLocaleIndex);
+            mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+                    locales.get(bestLocaleIndex)));
+        }
+
+        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+        mTempGlobalConfig.seq = mConfigurationSeq;
+
+        mGlobalConfiguration.setTo(mTempGlobalConfig);
+        Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempGlobalConfig);
+        // TODO(multi-display): Update UsageEvents#Event to include displayId.
+        mUsageStatsService.reportConfigurationChange(mTempGlobalConfig,
+                mUserController.getCurrentUserIdLocked());
+
+        // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
+        mShowDialogs = shouldShowDialogs(mTempGlobalConfig, mInVrMode);
+
+        AttributeCache ac = AttributeCache.instance();
+        if (ac != null) {
+            ac.updateConfiguration(mTempGlobalConfig);
+        }
+
+        // Make sure all resources in our process are updated right now, so that anyone who is going
+        // to retrieve resource values after we return will be sure to get the new ones. This is
+        // especially important during boot, where the first config change needs to guarantee all
+        // resources have that config before following boot code is executed.
+        mSystemThread.applyConfigurationToResources(mTempGlobalConfig);
+
+        // We need another copy of global config because we're scheduling some calls instead of
+        // running them in place. We need to be sure that object we send will be handled unchanged.
+        final Configuration configCopy = new Configuration(mGlobalConfiguration);
+        if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
+            Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+            msg.obj = configCopy;
+            msg.arg1 = userId;
+            mHandler.sendMessage(msg);
+        }
+
+        // TODO(multi-display): Clear also on secondary display density change?
+        final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+        if (isDensityChange) {
+            // Reset the unsupported display size dialog.
+            mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
+
+            killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
+                    ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        }
+
+        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+            ProcessRecord app = mLruProcesses.get(i);
+            try {
+                if (app.thread != null) {
+                    if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+                            + app.processName + " new config " + configCopy);
+                    app.thread.scheduleConfigurationChanged(configCopy);
+                }
+            } catch (Exception e) {
+            }
+        }
+
+        Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
+                | Intent.FLAG_RECEIVER_FOREGROUND);
+        broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+                AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                UserHandle.USER_ALL);
+        if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+            intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            if (initLocale || !mProcessesReady) {
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            }
+            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+                    AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                    UserHandle.USER_ALL);
+        }
+
+        // Update the configuration with WM first and check if any of the stacks need to be resized
+        // due to the configuration change. If so, resize the stacks now and do any relaunches if
+        // necessary. This way we don't need to relaunch again afterwards in
+        // ensureActivityConfigurationLocked().
+        if (mWindowManager != null) {
+            final int[] resizedStacks =
+                    mWindowManager.setNewConfiguration(mTempGlobalConfig);
+            if (resizedStacks != null) {
+                for (int stackId : resizedStacks) {
+                    resizeStackWithBoundsFromWindowManager(stackId, deferResume);
                 }
             }
         }
 
+        return changes;
+    }
+
+    /** Applies latest configuration and/or visibility updates if needed. */
+    private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
         boolean kept = true;
         final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
         // mainStack is null during startup.
@@ -19051,22 +19092,28 @@
                         !PRESERVE_WINDOWS);
             }
         }
-        if (mWindowManager != null) {
-            mWindowManager.continueSurfaceLayout();
-        }
+
         return kept;
     }
 
+    /** Helper method that requests bounds from WM and applies them to stack. */
+    private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
+        final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
+        mStackSupervisor.resizeStackLocked(
+                stackId, newBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+    }
+
     /**
-     * Decide based on the configuration whether we should shouw the ANR,
-     * crash, etc dialogs.  The idea is that if there is no affordence to
+     * Decide based on the configuration whether we should show the ANR,
+     * crash, etc dialogs.  The idea is that if there is no affordance to
      * press the on-screen buttons, or the user experience would be more
      * greatly impacted than the crash itself, we shouldn't show the dialog.
      *
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
      */
-    private static final boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
+    private static boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
         final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                    && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                    && config.navigation == Configuration.NAVIGATION_NONAV);
@@ -20637,8 +20684,11 @@
             final long now = SystemClock.elapsedRealtime();
             Long lastReported = userState.mProviderLastReportedFg.get(authority);
             if (lastReported == null || lastReported < now - 60 * 1000L) {
-                mUsageStatsService.reportContentProviderUsage(
-                        authority, providerPkgName, app.userId);
+                if (mSystemReady) {
+                    // Cannot touch the user stats if not system ready
+                    mUsageStatsService.reportContentProviderUsage(
+                            authority, providerPkgName, app.userId);
+                }
                 userState.mProviderLastReportedFg.put(authority, now);
             }
         }
@@ -20668,8 +20718,10 @@
                 isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
             }
         } else {
-            isInteraction = app.curProcState
-                    <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            // If the app was being forced to the foreground, by say a Toast, then
+            // no need to treat it as an interaction
+            isInteraction = app.forcingToForeground == null
+                    && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
             app.fgInteractionTime = 0;
         }
         if (isInteraction && (!app.reportedInteraction
@@ -21599,6 +21651,10 @@
         synchronized (this) {
             currentUserId = mUserController.getCurrentUserIdLocked();
             targetUserInfo = mUserController.getUserInfo(targetUserId);
+            if (targetUserId == currentUserId) {
+                Slog.i(TAG, "user #" + targetUserId + " is already the current user");
+                return true;
+            }
             if (targetUserInfo == null) {
                 Slog.w(TAG, "No user info for user #" + targetUserId);
                 return false;
@@ -21649,6 +21705,13 @@
         return mUserController.getCurrentUser();
     }
 
+    String getStartedUserState(int userId) {
+        synchronized (this) {
+            final UserState userState = mUserController.getStartedUserStateLocked(userId);
+            return UserState.stateToString(userState.state);
+        }
+    }
+
     @Override
     public boolean isUserRunning(int userId, int flags) {
         if (!mUserController.isSameProfileGroup(userId, UserHandle.getCallingUserId())
@@ -22177,4 +22240,22 @@
             Binder.restoreCallingIdentity(callingId);
         }
     }
+
+    @Override
+    public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException {
+        final int userId = intent.getCreatorUserHandle().getIdentifier();
+        if (!mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) {
+            return false;
+        }
+        IIntentSender target = intent.getTarget();
+        if (!(target instanceof PendingIntentRecord)) {
+            return false;
+        }
+        final PendingIntentRecord record = (PendingIntentRecord) target;
+        final ResolveInfo rInfo = mStackSupervisor.resolveIntent(record.key.requestIntent,
+                record.key.requestResolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE);
+        // For direct boot aware activities, they can be shown without triggering a work challenge
+        // before the profile user is unlocked.
+        return rInfo != null && rInfo.activityInfo != null;
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index adf6d36..7142d3f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -17,26 +17,57 @@
 package com.android.server.am;
 
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AppGlobals;
 import android.app.IActivityManager;
+import android.app.ProfilerInfo;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ShellCommand;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.DebugUtils;
 
 import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
 class ActivityManagerShellCommand extends ShellCommand {
+    public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
     // IPC interface to activity manager -- don't need to do additional security checks.
     final IActivityManager mInterface;
 
     // Internal service impl -- must perform security checks before touching.
     final ActivityManagerService mInternal;
 
+    // Convenience for interacting with package manager.
+    final IPackageManager mPm;
+
+    private int mStartFlags = 0;
+    private boolean mWaitOption = false;
+    private boolean mStopOption = false;
+
+    private int mRepeat = 0;
+    private int mUserId;
+    private String mReceiverPermission;
+
+    private String mProfileFile;
+    private int mSamplingInterval;
+    private boolean mAutoStop;
+    private int mStackId;
+
     final boolean mDumping;
 
     ActivityManagerShellCommand(ActivityManagerService service, boolean dumping) {
         mInterface = service;
         mInternal = service;
+        mPm = AppGlobals.getPackageManager();
         mDumping = dumping;
     }
 
@@ -48,6 +79,15 @@
         PrintWriter pw = getOutPrintWriter();
         try {
             switch (cmd) {
+                case "start":
+                case "start-activity":
+                    return runStartActivity(pw);
+                case "startservice":
+                case "start-service":
+                    return 1; //runStartService(pw);
+                case "stopservice":
+                case "stop-service":
+                    return 1; //runStopService(pw);
                 case "force-stop":
                     return runForceStop(pw);
                 case "kill":
@@ -66,6 +106,8 @@
                     return runLenientBackgroundCheck(pw);
                 case "get-uid-state":
                     return getUidState(pw);
+                case "get-started-user-state":
+                    return getStartedUserState(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -75,6 +117,241 @@
         return -1;
     }
 
+    private Intent makeIntent(int defUser) throws URISyntaxException {
+        mStartFlags = 0;
+        mWaitOption = false;
+        mStopOption = false;
+        mRepeat = 0;
+        mProfileFile = null;
+        mSamplingInterval = 0;
+        mAutoStop = false;
+        mUserId = defUser;
+        mStackId = INVALID_STACK_ID;
+
+        return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
+            @Override
+            public boolean handleOption(String opt, ShellCommand cmd) {
+                if (opt.equals("-D")) {
+                    mStartFlags |= ActivityManager.START_FLAG_DEBUG;
+                } else if (opt.equals("-N")) {
+                    mStartFlags |= ActivityManager.START_FLAG_NATIVE_DEBUGGING;
+                } else if (opt.equals("-W")) {
+                    mWaitOption = true;
+                } else if (opt.equals("-P")) {
+                    mProfileFile = getNextArgRequired();
+                    mAutoStop = true;
+                } else if (opt.equals("--start-profiler")) {
+                    mProfileFile = getNextArgRequired();
+                    mAutoStop = false;
+                } else if (opt.equals("--sampling")) {
+                    mSamplingInterval = Integer.parseInt(getNextArgRequired());
+                } else if (opt.equals("-R")) {
+                    mRepeat = Integer.parseInt(getNextArgRequired());
+                } else if (opt.equals("-S")) {
+                    mStopOption = true;
+                } else if (opt.equals("--track-allocation")) {
+                    mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION;
+                } else if (opt.equals("--user")) {
+                    mUserId = UserHandle.parseUserArg(getNextArgRequired());
+                } else if (opt.equals("--receiver-permission")) {
+                    mReceiverPermission = getNextArgRequired();
+                } else if (opt.equals("--stack")) {
+                    mStackId = Integer.parseInt(getNextArgRequired());
+                } else {
+                    return false;
+                }
+                return true;
+            }
+        });
+    }
+
+    ParcelFileDescriptor openOutputFile(String path) {
+        try {
+            ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path,
+                    "u:r:system_server:s0");
+            if (pfd != null) {
+                return pfd;
+            }
+        } catch (RuntimeException e) {
+            getErrPrintWriter().println("Failure opening file: " + e.getMessage());
+        }
+        getErrPrintWriter().println("Error: Unable to open file: " + path);
+        getErrPrintWriter().println("Consider using a file under /data/local/tmp/");
+        return null;
+    }
+
+    int runStartActivity(PrintWriter pw) throws RemoteException {
+        Intent intent;
+        try {
+            intent = makeIntent(UserHandle.USER_CURRENT);
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+
+        if (mUserId == UserHandle.USER_ALL) {
+            getErrPrintWriter().println("Error: Can't start service with user 'all'");
+            return 1;
+        }
+
+        String mimeType = intent.getType();
+        if (mimeType == null && intent.getData() != null
+                && "content".equals(intent.getData().getScheme())) {
+            mimeType = mInterface.getProviderMimeType(intent.getData(), mUserId);
+        }
+
+        do {
+            if (mStopOption) {
+                String packageName;
+                if (intent.getComponent() != null) {
+                    packageName = intent.getComponent().getPackageName();
+                } else {
+                    List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
+                            mUserId).getList();
+                    if (activities == null || activities.size() <= 0) {
+                        getErrPrintWriter().println("Error: Intent does not match any activities: "
+                                + intent);
+                        return 1;
+                    } else if (activities.size() > 1) {
+                        getErrPrintWriter().println(
+                                "Error: Intent matches multiple activities; can't stop: "
+                                + intent);
+                        return 1;
+                    }
+                    packageName = activities.get(0).activityInfo.packageName;
+                }
+                pw.println("Stopping: " + packageName);
+                mInterface.forceStopPackage(packageName, mUserId);
+                try {
+                    Thread.sleep(250);
+                } catch (InterruptedException e) {
+                }
+            }
+
+            ProfilerInfo profilerInfo = null;
+
+            if (mProfileFile != null) {
+                ParcelFileDescriptor fd = openOutputFile(mProfileFile);
+                if (fd == null) {
+                    return 1;
+                }
+                profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop);
+            }
+
+            pw.println("Starting: " + intent);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            IActivityManager.WaitResult result = null;
+            int res;
+            final long startTime = SystemClock.uptimeMillis();
+            ActivityOptions options = null;
+            if (mStackId != INVALID_STACK_ID) {
+                options = ActivityOptions.makeBasic();
+                options.setLaunchStackId(mStackId);
+            }
+            if (mWaitOption) {
+                result = mInterface.startActivityAndWait(null, null, intent, mimeType,
+                        null, null, 0, mStartFlags, profilerInfo,
+                        options != null ? options.toBundle() : null, mUserId);
+                res = result.result;
+            } else {
+                res = mInterface.startActivityAsUser(null, null, intent, mimeType,
+                        null, null, 0, mStartFlags, profilerInfo,
+                        options != null ? options.toBundle() : null, mUserId);
+            }
+            final long endTime = SystemClock.uptimeMillis();
+            PrintWriter out = mWaitOption ? pw : getErrPrintWriter();
+            boolean launched = false;
+            switch (res) {
+                case ActivityManager.START_SUCCESS:
+                    launched = true;
+                    break;
+                case ActivityManager.START_SWITCHES_CANCELED:
+                    launched = true;
+                    out.println(
+                            "Warning: Activity not started because the "
+                                    + " current activity is being kept for the user.");
+                    break;
+                case ActivityManager.START_DELIVERED_TO_TOP:
+                    launched = true;
+                    out.println(
+                            "Warning: Activity not started, intent has "
+                                    + "been delivered to currently running "
+                                    + "top-most instance.");
+                    break;
+                case ActivityManager.START_RETURN_INTENT_TO_CALLER:
+                    launched = true;
+                    out.println(
+                            "Warning: Activity not started because intent "
+                                    + "should be handled by the caller");
+                    break;
+                case ActivityManager.START_TASK_TO_FRONT:
+                    launched = true;
+                    out.println(
+                            "Warning: Activity not started, its current "
+                                    + "task has been brought to the front");
+                    break;
+                case ActivityManager.START_INTENT_NOT_RESOLVED:
+                    out.println(
+                            "Error: Activity not started, unable to "
+                                    + "resolve " + intent.toString());
+                    break;
+                case ActivityManager.START_CLASS_NOT_FOUND:
+                    out.println(NO_CLASS_ERROR_CODE);
+                    out.println("Error: Activity class " +
+                            intent.getComponent().toShortString()
+                            + " does not exist.");
+                    break;
+                case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
+                    out.println(
+                            "Error: Activity not started, you requested to "
+                                    + "both forward and receive its result");
+                    break;
+                case ActivityManager.START_PERMISSION_DENIED:
+                    out.println(
+                            "Error: Activity not started, you do not "
+                                    + "have permission to access it.");
+                    break;
+                case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+                    out.println(
+                            "Error: Activity not started, voice control not allowed for: "
+                                    + intent);
+                    break;
+                case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:
+                    out.println(
+                            "Error: Not allowed to start background user activity"
+                                    + " that shouldn't be displayed for all users.");
+                    break;
+                default:
+                    out.println(
+                            "Error: Activity not started, unknown error code " + res);
+                    break;
+            }
+            if (mWaitOption && launched) {
+                if (result == null) {
+                    result = new IActivityManager.WaitResult();
+                    result.who = intent.getComponent();
+                }
+                pw.println("Status: " + (result.timeout ? "timeout" : "ok"));
+                if (result.who != null) {
+                    pw.println("Activity: " + result.who.flattenToShortString());
+                }
+                if (result.thisTime >= 0) {
+                    pw.println("ThisTime: " + result.thisTime);
+                }
+                if (result.totalTime >= 0) {
+                    pw.println("TotalTime: " + result.totalTime);
+                }
+                pw.println("WaitTime: " + (endTime-startTime));
+                pw.println("Complete");
+            }
+            mRepeat--;
+            if (mRepeat > 0) {
+                mInterface.unhandledBack();
+            }
+        } while (mRepeat > 0);
+        return 0;
+    }
+
     int runIsUserStopped(PrintWriter pw) {
         int userId = UserHandle.parseUserArg(getNextArgRequired());
         boolean stopped = mInternal.isUserStopped(userId);
@@ -183,6 +460,18 @@
         return 0;
     }
 
+    int getStartedUserState(PrintWriter pw) throws RemoteException {
+        mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
+                "getStartedUserState()");
+        final int userId = Integer.parseInt(getNextArgRequired());
+        try {
+            pw.println(mInternal.getStartedUserState(userId));
+        } catch (NullPointerException e) {
+            pw.println("User is not started: " + userId);
+        }
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -223,6 +512,24 @@
             pw.println("Activity manager (activity) commands:");
             pw.println("  help");
             pw.println("    Print this help text.");
+            pw.println("  start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]");
+            pw.println("          [--sampling INTERVAL] [-R COUNT] [-S]");
+            pw.println("          [--track-allocation] [--user <USER_ID> | current] <INTENT>");
+            pw.println("    Start an Activity.  Options are:");
+            pw.println("    -D: enable debugging");
+            pw.println("    -N: enable native debugging");
+            pw.println("    -W: wait for launch to complete");
+            pw.println("    --start-profiler <FILE>: start profiler and send results to <FILE>");
+            pw.println("    --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
+            pw.println("        between samples (use with --start-profiler)");
+            pw.println("    -P <FILE>: like above, but profiling stops when app goes idle");
+            pw.println("    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,");
+            pw.println("        the top activity will be finished.");
+            pw.println("    -S: force stop the target app before starting the activity");
+            pw.println("    --track-allocation: enable tracking of object allocations");
+            pw.println("    --user <USER_ID> | current: Specify which user to run as; if not");
+            pw.println("        specified then run as the current user.");
+            pw.println("    --stack <STACK_ID>: Specify into which stack should the activity be put.");
             pw.println("  force-stop [--user <USER_ID> | all | current] <PACKAGE>");
             pw.println("    Completely stop the given application package.");
             pw.println("  kill [--user <USER_ID> | all | current] <PACKAGE>");
@@ -241,6 +548,10 @@
             pw.println("    Optionally controls lenient background check mode, returns current mode.");
             pw.println("  get-uid-state <UID>");
             pw.println("    Gets the process state of an app given its <UID>.");
+            pw.println("  get-started-user-state <USER_ID>");
+            pw.println("    Gets the current state of the given started user.");
+            pw.println();
+            Intent.printIntentArgsHelp(pw, "");
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index a5c19d6..e52671f 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,9 +17,11 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 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;
@@ -744,6 +746,14 @@
                 && intent.getType() == null;
     }
 
+    static boolean isMainIntent(Intent intent) {
+        return Intent.ACTION_MAIN.equals(intent.getAction())
+                && intent.hasCategory(Intent.CATEGORY_LAUNCHER)
+                && intent.getCategories().size() == 1
+                && intent.getData() == null
+                && intent.getType() == null;
+    }
+
     private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
         if (uid == Process.myUid() || uid == 0) {
             // System process can launch home activity.
@@ -936,21 +946,25 @@
         // The activity now gets access to the data associated with this Intent.
         service.grantUriPermissionFromIntentLocked(callingUid, packageName,
                 intent, getUriPermissionsLocked(), userId);
-        // We want to immediately deliver the intent to the activity if
-        // it is currently the top resumed activity...  however, if the
-        // device is sleeping, then all activities are stopped, so in that
-        // case we will deliver it if this is the current top activity on its
-        // stack.
         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
         boolean unsent = true;
-        if ((state == ActivityState.RESUMED
-                || (service.isSleepingLocked() && task.stack != null
-                    && task.stack.topRunningActivityLocked() == this))
-                && app != null && app.thread != null) {
+        final ActivityStack stack = task.stack;
+        final boolean isTopActivityInStack =
+                stack != null && stack.topRunningActivityLocked() == this;
+        final boolean isTopActivityWhileSleeping =
+                service.isSleepingLocked() && isTopActivityInStack;
+
+        // We want to immediately deliver the intent to the activity if:
+        // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
+        //   the user to see the visual effects caused by the intent delivery now.
+        // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
+        if ((state == ActivityState.RESUMED || state == ActivityState.PAUSED
+                || isTopActivityWhileSleeping) && app != null && app.thread != null) {
             try {
                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
                 ar.add(rintent);
-                app.thread.scheduleNewIntent(ar, appToken);
+                app.thread.scheduleNewIntent(
+                        ar, appToken, state == ActivityState.PAUSED /* andPause */);
                 unsent = false;
             } catch (RemoteException e) {
                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1290,6 +1304,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.
@@ -1299,8 +1320,12 @@
                 state == ActivityState.RESUMED;
     }
 
-    public void setSleeping(boolean _sleeping) {
-        if (sleeping == _sleeping) {
+    void setSleeping(boolean _sleeping) {
+        setSleeping(_sleeping, false);
+    }
+
+    void setSleeping(boolean _sleeping, boolean force) {
+        if (!force && sleeping == _sleeping) {
             return;
         }
         if (app != null && app.thread != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fa9f518..d820627 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -29,6 +29,7 @@
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
@@ -68,6 +69,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
+import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
@@ -118,6 +120,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.Display;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -126,7 +129,6 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
-import com.android.server.wm.TaskGroup;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -162,8 +164,6 @@
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
-    private static final boolean VALIDATE_TOKENS = false;
-
     // Ticks during which we check progress while waiting for an app to launch.
     static final int LAUNCH_TICK = 500;
 
@@ -231,6 +231,13 @@
     // stack and the new stack will be on top of all stacks.
     static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
 
+    // The height/width divide used when fitting a task within a bounds with method
+    // {@link #fitWithinBounds}.
+    // We always want the task to to be visible in the bounds without affecting its size when
+    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+    // the input bounds right or bottom side minus the width or height divided by this value.
+    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
     private final RecentTasks mRecentTasks;
@@ -242,11 +249,6 @@
     private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
 
     /**
-     * Used for validating app tokens with window manager.
-     */
-    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<>();
-
-    /**
      * List of running activities, sorted by recent usage.
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
@@ -329,6 +331,12 @@
     /** The attached Display's unique identifier, or -1 if detached */
     int mDisplayId;
 
+    /** Temp variables used during override configuration update. */
+    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+    private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+    private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
+    private final Rect tempRect2 = new Rect();
+
     /** Run all ActivityStacks through this */
     final ActivityStackSupervisor mStackSupervisor;
 
@@ -544,10 +552,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 +568,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 +595,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;
                 }
             }
@@ -669,7 +673,7 @@
 
     final boolean isOnHomeDisplay() {
         return isAttached() &&
-                mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
+                mActivityContainer.mActivityDisplay.mDisplayId == DEFAULT_DISPLAY;
     }
 
     void moveToFront(String reason) {
@@ -704,9 +708,10 @@
         }
         if (task != null) {
             insertTaskAtTop(task, null);
-        } else {
-            task = topTask();
+            return;
         }
+
+        task = topTask();
         if (task != null) {
             mWindowManager.moveTaskToTop(task.taskId);
         }
@@ -854,13 +859,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 +897,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);
@@ -908,9 +908,6 @@
                 ++i;
             }
         }
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
     }
 
     void minimalResumeActivityLocked(ActivityRecord r) {
@@ -1056,22 +1053,32 @@
 
         int w = mService.mThumbnailWidth;
         int h = mService.mThumbnailHeight;
-        float scale = 1f;
-        if (w > 0) {
-            if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
 
-            // When this flag is set, we currently take the fullscreen screenshot of the activity
-            // but scaled to half the size.  This gives us a "good-enough" fullscreen thumbnail to
-            // use within SystemUI while keeping memory usage low.
-            if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
-                w = h = -1;
-                scale = mService.mFullscreenThumbnailScale;
-            }
-            return mWindowManager.screenshotApplications(who.appToken, Display.DEFAULT_DISPLAY,
-                    w, h, scale);
+        if (w <= 0) {
+            Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
+            return null;
         }
-        Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
-        return null;
+
+        if (mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
+            // When the docked stack is minimized its app windows are cropped significantly so any
+            // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
+            // in that case.
+            if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
+            return null;
+        }
+
+        float scale = 1f;
+        if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
+
+        // When this flag is set, we currently take the fullscreen screenshot of the activity but
+        // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
+        // SystemUI while keeping memory usage low.
+        if (TAKE_FULLSCREEN_SCREENSHOTS) {
+            w = h = -1;
+            scale = mService.mFullscreenThumbnailScale;
+        }
+
+        return mWindowManager.screenshotApplications(who.appToken, DEFAULT_DISPLAY, w, h, scale);
     }
 
     /**
@@ -1323,7 +1330,9 @@
             // It is possible the activity was freezing the screen before it was paused.
             // In that case go ahead and remove the freeze this activity has on the screen
             // since it is no longer visible.
-            prev.stopFreezingScreenLocked(true /*force*/);
+            if (prev != null) {
+                prev.stopFreezingScreenLocked(true /*force*/);
+            }
             mPausingActivity = null;
         }
 
@@ -1405,7 +1414,12 @@
      * this function updates the rest of our state to match that fact.
      */
     private void completeResumeLocked(ActivityRecord next) {
+        boolean wasVisible = next.visible;
         next.visible = true;
+        if (!wasVisible) {
+            // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
+            mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+        }
         next.idle = false;
         next.results = null;
         next.newIntents = null;
@@ -1607,11 +1621,6 @@
             return STACK_INVISIBLE;
         }
 
-        final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
-        if (isLockscreenShown && !StackId.isAllowedOverLockscreen(mStackId)) {
-            return STACK_INVISIBLE;
-        }
-
         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
         final int focusedStackId = focusedStack.mStackId;
 
@@ -1898,7 +1907,7 @@
             boolean stackVisibleBehind, ActivityRecord visibleBehind,
             boolean behindFullscreenActivity) {
 
-        if (!okToShowLocked(r)) {
+        if (r == null || !r.okToShowLocked()) {
             return false;
         }
 
@@ -2520,7 +2529,7 @@
             boolean notUpdated = true;
             if (mStackSupervisor.isFocusedStack(this)) {
                 Configuration config = mWindowManager.updateOrientationFromAppTokens(
-                        mService.mConfiguration,
+                        mService.mGlobalConfiguration,
                         next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
                 if (config != null) {
                     next.frozenBeforeDestroy = true;
@@ -2562,13 +2571,26 @@
                     }
                 }
 
+                boolean allowSavedSurface = true;
                 if (next.newIntents != null) {
-                    next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
+                    // Restrict saved surface to launcher start, or there is no intent at all
+                    // (eg. task being brought to front). If the intent is something else,
+                    // likely the app is going to show some specific page or view, instead of
+                    // what's left last time.
+                    for (int i = next.newIntents.size() - 1; i >= 0; i--) {
+                        final Intent intent = next.newIntents.get(i);
+                        if (intent != null && !ActivityRecord.isMainIntent(intent)) {
+                            allowSavedSurface = false;
+                            break;
+                        }
+                    }
+                    next.app.thread.scheduleNewIntent(
+                            next.newIntents, next.appToken, false /* andPause */);
                 }
 
                 // Well the app will no longer be stopped.
                 // Clear app token stopped state in window manager if needed.
-                mWindowManager.notifyAppResumed(next.appToken, next.stopped);
+                mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface);
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                         System.identityHashCode(next), next.task.taskId, next.shortComponentName);
@@ -2655,8 +2677,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 +2738,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);
@@ -2732,6 +2753,7 @@
         }
         mTaskHistory.add(taskNdx, task);
         updateTaskMovement(task, true);
+        mWindowManager.moveTaskToTop(task.taskId);
     }
 
     final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
@@ -2744,7 +2766,6 @@
             // Insert or replace.
             // Might not even be in.
             insertTaskAtTop(rTask, r);
-            mWindowManager.moveTaskToTop(taskId);
         }
         TaskRecord task = null;
         if (!newTask) {
@@ -2766,9 +2787,6 @@
                         task.addActivityToTop(r);
                         r.putInHistory();
                         addConfigOverride(r, task);
-                        if (VALIDATE_TOKENS) {
-                            validateAppTokensLocked();
-                        }
                         ActivityOptions.abort(options);
                         return;
                     }
@@ -2870,33 +2888,7 @@
             // because there is nothing for it to animate on top of.
             addConfigOverride(r, task);
             ActivityOptions.abort(options);
-            options = null;
         }
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
-    }
-
-    final void validateAppTokensLocked() {
-        mValidateAppTokens.clear();
-        mValidateAppTokens.ensureCapacity(numActivities());
-        final int numTasks = mTaskHistory.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            TaskRecord task = mTaskHistory.get(taskNdx);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            if (activities.isEmpty()) {
-                continue;
-            }
-            TaskGroup group = new TaskGroup();
-            group.taskId = task.taskId;
-            mValidateAppTokens.add(group);
-            final int numActivities = activities.size();
-            for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                group.tokens.add(r.appToken);
-            }
-        }
-        mWindowManager.validateAppTokens(mStackId, mValidateAppTokens);
     }
 
     /**
@@ -3008,10 +3000,6 @@
                 }
 
                 mWindowManager.moveTaskToBottom(targetTask.taskId);
-                if (VALIDATE_TOKENS) {
-                    validateAppTokensLocked();
-                }
-
                 replyChainEnd = -1;
             } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
                 // If the activity should just be removed -- either
@@ -3149,9 +3137,6 @@
                         setAppTask(p, task);
                     }
                     mWindowManager.moveTaskToTop(taskId);
-                    if (VALIDATE_TOKENS) {
-                        validateAppTokensLocked();
-                    }
 
                     // Now we've moved it in to place...  but what if this is
                     // a singleTop activity and we have put it on top of another
@@ -3900,9 +3885,6 @@
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
         r.app = null;
         mWindowManager.removeAppToken(r.appToken);
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
         final TaskRecord task = r.task;
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG_STACK,
@@ -4375,7 +4357,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;
@@ -4398,10 +4380,6 @@
 
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
-
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
     }
 
     /**
@@ -4516,10 +4494,6 @@
         mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
         mWindowManager.moveTaskToBottom(taskId);
 
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
-
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
         if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
             if (!mService.mBooting && !mService.mBooted) {
@@ -4582,6 +4556,86 @@
         }
     }
 
+    /** Update override configurations of all tasks in the stack. */
+    void updateOverrideConfiguration(Rect stackBounds, Rect tempTaskBounds,
+            Rect tempTaskInsetBounds) {
+
+        final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : stackBounds;
+        final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
+
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        mTmpInsetBounds.clear();
+
+        for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
+            final TaskRecord task = mTaskHistory.get(i);
+            if (task.isResizeable()) {
+                if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                    // For freeform stack we don't adjust the size of the tasks to match that
+                    // of the stack, but we do try to make sure the tasks are still contained
+                    // with the bounds of the stack.
+                    tempRect2.set(task.mBounds);
+                    fitWithinBounds(tempRect2, stackBounds);
+                    task.updateOverrideConfiguration(tempRect2);
+                } else {
+                    task.updateOverrideConfiguration(taskBounds, insetBounds);
+                }
+            }
+
+            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+            mTmpBounds.put(task.taskId, task.mBounds);
+            if (tempTaskInsetBounds != null) {
+                mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+            }
+        }
+
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        mWindowManager.prepareFreezingTaskBounds(mStackId);
+        mFullscreen = mWindowManager.resizeStack(mStackId, stackBounds, mTmpConfigs, mTmpBounds,
+                mTmpInsetBounds);
+        setBounds(stackBounds);
+    }
+
+
+    /**
+     * Adjust bounds to stay within stack bounds.
+     *
+     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
+     * that keep them unchanged, but be contained within the stack bounds.
+     *
+     * @param bounds Bounds to be adjusted.
+     * @param stackBounds Bounds within which the other bounds should remain.
+     */
+    private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
+        if (stackBounds == null || stackBounds.contains(bounds)) {
+            return;
+        }
+
+        if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) {
+            final int maxRight = stackBounds.right
+                    - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int horizontalDiff = stackBounds.left - bounds.left;
+            if ((horizontalDiff < 0 && bounds.left >= maxRight)
+                    || (bounds.left + horizontalDiff >= maxRight)) {
+                horizontalDiff = maxRight - bounds.left;
+            }
+            bounds.left += horizontalDiff;
+            bounds.right += horizontalDiff;
+        }
+
+        if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) {
+            final int maxBottom = stackBounds.bottom
+                    - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int verticalDiff = stackBounds.top - bounds.top;
+            if ((verticalDiff < 0 && bounds.top >= maxBottom)
+                    || (bounds.top + verticalDiff >= maxBottom)) {
+                verticalDiff = maxBottom - bounds.top;
+            }
+            bounds.top += verticalDiff;
+            bounds.bottom += verticalDiff;
+        }
+    }
+
     /**
      * Make sure the given activity matches the current configuration. Returns false if the activity
      * had to be destroyed.  Returns true if the configuration is the same, or the activity will
@@ -4596,21 +4650,12 @@
             return true;
         }
 
-        // TODO: We could probably make the condition below just check that the activity state is
-        // stopped, but also checking the sleep state for now to reduce change impact late in
-        // development cycle.
-        if (mService.isSleepingOrShuttingDownLocked() && r.state == ActivityState.STOPPED) {
-            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Skipping config check (stopped while sleeping): " + r);
-            return true;
-        }
-
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                 "Ensuring correct configuration: " + r);
 
         // Short circuit: if the two configurations are equal (the common case), then there is
         // nothing to do.
-        final Configuration newConfig = mService.mConfiguration;
+        final Configuration newConfig = mService.mGlobalConfiguration;
         r.task.sanitizeOverrideConfiguration(newConfig);
         final Configuration taskConfig = r.task.mOverrideConfig;
         if (r.configuration.equals(newConfig)
@@ -4740,7 +4785,7 @@
         // that has come back from the app after going idle.  In that case
         // we just want to leave the official config object now in the
         // activity and do nothing else.
-        int taskChanges = oldTaskOverride.diff(taskConfig);
+        int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
         // We don't want to use size changes if they don't cross boundaries that are important to
         // the app.
         if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
@@ -4759,48 +4804,6 @@
                 taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
             }
         }
-        return catchConfigChangesFromUnset(taskConfig, oldTaskOverride, taskChanges);
-    }
-
-    private static int catchConfigChangesFromUnset(Configuration taskConfig,
-            Configuration oldTaskOverride, int taskChanges) {
-        if (taskChanges == 0) {
-            // {@link Configuration#diff} doesn't catch changes from unset values.
-            // Check for changes we care about.
-            if (oldTaskOverride.orientation != taskConfig.orientation) {
-                taskChanges |= CONFIG_ORIENTATION;
-            }
-            // We want to explicitly track situations where the size configuration goes from
-            // undefined to defined. We don't care about crossing the threshold in that case,
-            // because there is no threshold.
-            final int oldHeight = oldTaskOverride.screenHeightDp;
-            final int newHeight = taskConfig.screenHeightDp;
-            final int undefinedHeight = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
-            if ((oldHeight == undefinedHeight && newHeight != undefinedHeight)
-                    || (oldHeight != undefinedHeight && newHeight == undefinedHeight)) {
-                taskChanges |= CONFIG_SCREEN_SIZE;
-            }
-            final int oldWidth = oldTaskOverride.screenWidthDp;
-            final int newWidth = taskConfig.screenWidthDp;
-            final int undefinedWidth = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
-            if ((oldWidth == undefinedWidth && newWidth != undefinedWidth)
-                    || (oldWidth != undefinedWidth && newWidth == undefinedWidth)) {
-                taskChanges |= CONFIG_SCREEN_SIZE;
-            }
-            final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
-            final int newSmallest = taskConfig.smallestScreenWidthDp;
-            final int undefinedSmallest = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
-            if ((oldSmallest == undefinedSmallest && newSmallest != undefinedSmallest)
-                    || (oldSmallest != undefinedSmallest && newSmallest == undefinedSmallest)) {
-                taskChanges |= CONFIG_SMALLEST_SCREEN_SIZE;
-            }
-            final int oldLayout = oldTaskOverride.screenLayout;
-            final int newLayout = taskConfig.screenLayout;
-            if ((oldLayout == SCREENLAYOUT_UNDEFINED && newLayout != SCREENLAYOUT_UNDEFINED)
-                || (oldLayout != SCREENLAYOUT_UNDEFINED && newLayout == SCREENLAYOUT_UNDEFINED)) {
-                taskChanges |= CONFIG_SCREEN_LAYOUT;
-            }
-        }
         return taskChanges;
     }
 
@@ -4840,7 +4843,7 @@
             r.forceNewConfig = false;
             mStackSupervisor.activityRelaunchingLocked(r);
             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
-                    !andResume, new Configuration(mService.mConfiguration),
+                    !andResume, new Configuration(mService.mGlobalConfiguration),
                     new Configuration(r.task.mOverrideConfig), preserveWindow);
             // Note: don't need to call pauseIfSleepingLocked() here, because
             // the caller will only pass in 'andResume' if this activity is
@@ -5031,7 +5034,7 @@
         if (top >= 0) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
             int activityTop = activities.size() - 1;
-            if (activityTop > 0) {
+            if (activityTop >= 0) {
                 finishActivityLocked(activities.get(activityTop), Activity.RESULT_CANCELED, null,
                         "unhandled-back", true);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 271483e..67604d3 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;
@@ -268,13 +267,6 @@
     /** Action restriction: launching the activity is restricted by an app op. */
     private static final int ACTIVITY_RESTRICTION_APPOP = 2;
 
-    // The height/width divide used when fitting a task within a bounds with method
-    // {@link #fitWithinBounds}.
-    // We always want the task to to be visible in the bounds without affecting its size when
-    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
-    // the input bounds right or bottom side minus the width or height divided by this value.
-    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
     /** Status Bar Service **/
     private IBinder mToken = new Binder();
     private IStatusBarService mStatusBarService;
@@ -403,13 +395,11 @@
     /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
-    // temp. rects used during resize calculation so we don't need to create a new object each time.
+    /**
+     * Temporary rect used during docked stack resize calculation so we don't need to create a new
+     * object each time.
+     */
     private final Rect tempRect = new Rect();
-    private final Rect tempRect2 = new Rect();
-
-    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
-    private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
-    private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
 
     // The default minimal size that will be used if the activity doesn't specify its minimal size.
     // It will be calculated when the default display gets added.
@@ -1192,7 +1182,7 @@
         // just restarting it anyway.
         if (checkConfig) {
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
-                    mService.mConfiguration,
+                    mService.mGlobalConfiguration,
                     r.mayFreezeScreenLocked(app) ? r.appToken : null);
             // Deferring resume here because we're going to launch new activity shortly.
             // We don't want to perform a redundant launch of the same record while ensuring
@@ -1283,7 +1273,8 @@
             }
             app.forceProcessStateUpTo(mService.mTopProcessState);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
-                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
+                    System.identityHashCode(r), r.info,
+                    new Configuration(mService.mGlobalConfiguration),
                     new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                     task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                     newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
@@ -1912,6 +1903,7 @@
         if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) {
             return null;
         }
+        // TODO(multi-display): Allow creating stacks on secondary displays.
         return createStackOnDisplay(stackId, Display.DEFAULT_DISPLAY, createOnTop);
     }
 
@@ -1923,14 +1915,6 @@
         return allStacks;
     }
 
-    IBinder getHomeActivityToken() {
-        ActivityRecord homeActivity = getHomeActivity();
-        if (homeActivity != null) {
-            return homeActivity.appToken;
-        }
-        return null;
-    }
-
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mCurrentUser);
     }
@@ -2060,39 +2044,7 @@
             return;
         }
 
-        mTmpBounds.clear();
-        mTmpConfigs.clear();
-        mTmpInsetBounds.clear();
-        final ArrayList<TaskRecord> tasks = stack.getAllTasks();
-        final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
-        final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds;
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            final TaskRecord task = tasks.get(i);
-            if (task.isResizeable()) {
-                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                    // For freeform stack we don't adjust the size of the tasks to match that
-                    // of the stack, but we do try to make sure the tasks are still contained
-                    // with the bounds of the stack.
-                    tempRect2.set(task.mBounds);
-                    fitWithinBounds(tempRect2, bounds);
-                    task.updateOverrideConfiguration(tempRect2);
-                } else {
-                    task.updateOverrideConfiguration(taskBounds, insetBounds);
-                }
-            }
-
-            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
-            mTmpBounds.put(task.taskId, task.mBounds);
-            if (tempTaskInsetBounds != null) {
-                mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
-            }
-        }
-
-        // We might trigger a configuration change. Save the current task bounds for freezing.
-        mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
-        stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs,
-                mTmpBounds, mTmpInsetBounds);
-        stack.setBounds(bounds);
+        stack.updateOverrideConfiguration(bounds, tempTaskBounds, tempTaskInsetBounds);
     }
 
     void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) {
@@ -2273,12 +2225,12 @@
 
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
 
-        final Configuration overrideConfig =  task.updateOverrideConfiguration(bounds);
+        final boolean updatedConfig = task.updateOverrideConfiguration(bounds);
         // This variable holds information whether the configuration didn't change in a significant
         // way and the activity was kept the way it was. If it's false, it means the activity had
         // to be relaunched due to configuration change.
         boolean kept = true;
-        if (overrideConfig != null) {
+        if (updatedConfig) {
             final ActivityRecord r = task.topRunningActivityLocked();
             if (r != null) {
                 final ActivityStack stack = task.stack;
@@ -2465,7 +2417,7 @@
             // entrance of the new window to be properly animated.
             // Note here we always set the replacing window first, as the flags might be needed
             // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
-            mWindowManager.setReplacingWindow(topActivity.appToken, animate);
+            mWindowManager.setWillReplaceWindow(topActivity.appToken, animate);
         }
 
         mWindowManager.deferSurfaceLayout();
@@ -2507,7 +2459,7 @@
             // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
             // window), we need to clear the replace window settings. Otherwise, we schedule a
             // timeout to remove the old window if the replacing window is not coming in time.
-            mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
+            mWindowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
         }
 
         if (!deferResume) {
@@ -3080,24 +3032,20 @@
         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;
 
         final boolean nowVisible = allResumedActivitiesVisible();
         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
             ActivityRecord s = mStoppingActivities.get(activityNdx);
+            // TODO: Remove mWaitingVisibleActivities list and just remove activity from
+            // mStoppingActivities when something else comes up.
             boolean waitingVisible = mWaitingVisibleActivities.contains(s);
             if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
             if (waitingVisible && nowVisible) {
                 mWaitingVisibleActivities.remove(s);
+                waitingVisible = false;
                 if (s.finishing) {
                     // If this activity is finishing, it is sitting on top of
                     // everyone else but we now know it is no longer needed...
@@ -3106,7 +3054,6 @@
                     // hidden by the activities in front of it.
                     if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
                     mWindowManager.setAppVisibility(s.appToken, false);
-                    waitingVisible = false;
                 }
             }
             if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
@@ -3738,6 +3685,12 @@
 
     void activityRelaunchedLocked(IBinder token) {
         mWindowManager.notifyAppRelaunchingFinished(token);
+        if (mService.isSleepingOrShuttingDownLocked()) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                r.setSleeping(true, true);
+            }
+        }
     }
 
     void activityRelaunchingLocked(ActivityRecord r) {
@@ -4372,45 +4325,6 @@
         }
     }
 
-    /**
-     * Adjust bounds to stay within stack bounds.
-     *
-     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
-     * that keep them unchanged, but be contained within the stack bounds.
-     *
-     * @param bounds Bounds to be adjusted.
-     * @param stackBounds Bounds within which the other bounds should remain.
-     */
-    private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
-        if (stackBounds == null || stackBounds.contains(bounds)) {
-            return;
-        }
-
-        if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) {
-            final int maxRight = stackBounds.right
-                    - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int horizontalDiff = stackBounds.left - bounds.left;
-            if ((horizontalDiff < 0 && bounds.left >= maxRight)
-                    || (bounds.left + horizontalDiff >= maxRight)) {
-                horizontalDiff = maxRight - bounds.left;
-            }
-            bounds.left += horizontalDiff;
-            bounds.right += horizontalDiff;
-        }
-
-        if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) {
-            final int maxBottom = stackBounds.bottom
-                    - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int verticalDiff = stackBounds.top - bounds.top;
-            if ((verticalDiff < 0 && bounds.top >= maxBottom)
-                    || (bounds.top + verticalDiff >= maxBottom)) {
-                verticalDiff = maxBottom - bounds.top;
-            }
-            bounds.top += verticalDiff;
-            bounds.bottom += verticalDiff;
-        }
-    }
-
     ActivityStack findStackBehind(ActivityStack stack) {
         // TODO(multi-display): We are only looking for stacks on the default display.
         final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
@@ -4526,6 +4440,8 @@
      * entry will be the focused activity.
      */
     public List<IBinder> getTopVisibleActivities() {
+        // TODO(multi-display): Get rid of DEFAULT_DISPLAY here. Used in
+        // VoiceInteractionManagerServiceImpl#showSessionLocked.
         final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
         if (display == null) {
             return Collections.EMPTY_LIST;
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index a8ea5f4..547161a 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -29,6 +29,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManagerInternal;
@@ -209,6 +210,11 @@
         if (!mService.mUserController.shouldConfirmCredentials(userId)) {
             return null;
         }
+        // Allow direct boot aware activity to be displayed before the user is unlocked.
+        if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId,
+                ActivityManager.FLAG_AND_LOCKED)) {
+            return null;
+        }
         final IIntentSender target = mService.getIntentSenderLocked(
                 INTENT_SENDER_ACTIVITY, callingPackage,
                 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 9f875a1..028c6ac 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -99,11 +99,9 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManagerInternal;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -416,8 +414,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(
@@ -472,7 +469,7 @@
         }
 
         ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
-                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
+                intent, resolvedType, aInfo, mService.mGlobalConfiguration, resultRecord, resultWho,
                 requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
                 options, sourceRecord);
         if (outActivity != null) {
@@ -545,9 +542,7 @@
             ephemeralIntent.setPackage(ephemeralPackage);
         } else {
             // Success intent goes back to the installer
-            // TODO; do we need any extras for the installer?
             ephemeralIntent = new Intent(launchIntent);
-            ephemeralIntent.setData(null);
         }
 
         // Intent that is eventually launched if the ephemeral package was
@@ -572,7 +567,7 @@
         intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
         intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
         // TODO: Remove when the platform has fully implemented ephemeral apps
-        intent.setData(origIntent.getData());
+        intent.setData(origIntent.getData().buildUpon().clearQuery().build());
         return intent;
     }
 
@@ -605,6 +600,9 @@
         // If we launched the activity from a no display activity that was launched from the home
         // screen, we also need to start recents to un-minimize the docked stack, since the
         // noDisplay activity will be finished shortly after.
+        // Note that some apps have trampoline activities without noDisplay being set. In that case,
+        // we have another heuristic in DockedStackDividerController.notifyAppTransitionStarting
+        // that tries to detect that case.
         // TODO: We should prevent noDisplay activities from affecting task/stack ordering and
         // visibility instead of using this flag.
         final boolean noDisplayActivityOverHome = sourceRecord != null
@@ -711,8 +709,8 @@
             String callingPackage, Intent intent, String resolvedType,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
-            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
-            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
+            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult,
+            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
             IActivityContainer iContainer, TaskRecord inTask) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
@@ -781,7 +779,8 @@
             } else {
                 stack = container.mStack;
             }
-            stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
+            stack.mConfigWillChange = globalConfig != null
+                    && mService.mGlobalConfiguration.diff(globalConfig) != 0;
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Starting activity when config will change = " + stack.mConfigWillChange);
 
@@ -870,7 +869,7 @@
                 stack.mConfigWillChange = false;
                 if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Updating to new configuration after starting activity.");
-                mService.updateConfigurationLocked(config, null, false);
+                mService.updateConfigurationLocked(globalConfig, null, false);
             }
 
             if (outResult != null) {
@@ -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;
         }
@@ -2092,4 +2091,18 @@
         return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                 (flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
     }
+
+    boolean clearPendingActivityLaunchesLocked(String packageName) {
+        boolean didSomething = false;
+
+        for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+            ActivityRecord r = pal.r;
+            if (r != null && r.packageName.equals(packageName)) {
+                mPendingActivityLaunches.remove(palNdx);
+                didSomething = true;
+            }
+        }
+        return didSomething;
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7eff773..c19a571 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -22,7 +22,6 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.server.Watchdog;
 
-import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -33,10 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -59,7 +55,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Set;
-import java.util.concurrent.Semaphore;
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
@@ -359,7 +354,7 @@
                 return;
             }
 
-            Message msg = Message.obtain();
+            final Message msg = Message.obtain();
             msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
 
             task = data.task;
@@ -575,6 +570,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 +609,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 +704,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
@@ -769,6 +768,12 @@
             } else if (app.crashing) {
                 Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
                 return;
+            } else if (app.killedByAm) {
+                Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
+                return;
+            } else if (app.killed) {
+                Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);
+                return;
             }
 
             // In case we come through here for the same app before completing
@@ -942,7 +947,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/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index a54df4b..0b282ed 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -197,8 +197,8 @@
     }
 
     public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
-        CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
-                mService.mConfiguration.smallestScreenWidthDp,
+        CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mGlobalConfiguration.screenLayout,
+                mService.mGlobalConfiguration.smallestScreenWidthDp,
                 (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0);
         //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci);
         return ci;
@@ -207,8 +207,8 @@
     public int computeCompatModeLocked(ApplicationInfo ai) {
         boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0;
         CompatibilityInfo info = new CompatibilityInfo(ai,
-                mService.mConfiguration.screenLayout,
-                mService.mConfiguration.smallestScreenWidthDp, enabled);
+                mService.mGlobalConfiguration.screenLayout,
+                mService.mGlobalConfiguration.smallestScreenWidthDp, enabled);
         if (info.alwaysSupportsScreen()) {
             return ActivityManager.COMPAT_MODE_NEVER;
         }
@@ -408,8 +408,8 @@
             out.startTag(null, "compat-packages");
 
             final IPackageManager pm = AppGlobals.getPackageManager();
-            final int screenLayout = mService.mConfiguration.screenLayout;
-            final int smallestScreenWidthDp = mService.mConfiguration.smallestScreenWidthDp;
+            final int screenLayout = mService.mGlobalConfiguration.screenLayout;
+            final int smallestScreenWidthDp = mService.mGlobalConfiguration.smallestScreenWidthDp;
             final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator();
             while (it.hasNext()) {
                 Map.Entry<String, Integer> entry = it.next();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 475b155..2b00f86 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -220,6 +220,7 @@
     void applyDisplaySize(WindowManagerService wm) {
         if (!mHaveDisplaySize) {
             Point p = new Point();
+            // TODO(multi-display): Compute based on sum of all connected displays' resolutions.
             wm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, p);
             if (p.x != 0 && p.y != 0) {
                 updateOomLevels(p.x, p.y, true);
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 48fecd5..43eb251 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -87,6 +87,8 @@
     private final RecentTasks mRecentTasks;
     private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
     private final File mTaskIdsDir;
+    // To lock file operations in TaskPersister
+    private final Object mIoLock = new Object();
 
     /**
      * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
@@ -195,52 +197,52 @@
             return mTaskIdsInFile.get(userId).clone();
         }
         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
-        BufferedReader reader = null;
-        String line;
-        try {
-            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
-            while ((line = reader.readLine()) != null) {
-                for (String taskIdString : line.split("\\s+")) {
-                    int id = Integer.parseInt(taskIdString);
-                    persistedTaskIds.put(id, true);
+        synchronized (mIoLock) {
+            BufferedReader reader = null;
+            String line;
+            try {
+                reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
+                while ((line = reader.readLine()) != null) {
+                    for (String taskIdString : line.split("\\s+")) {
+                        int id = Integer.parseInt(taskIdString);
+                        persistedTaskIds.put(id, true);
+                    }
                 }
+            } catch (FileNotFoundException e) {
+                // File doesn't exist. Ignore.
+            } catch (Exception e) {
+                Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
+            } finally {
+                IoUtils.closeQuietly(reader);
             }
-        } catch (FileNotFoundException e) {
-            // File doesn't exist. Ignore.
-        } catch (Exception e) {
-            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
-        } finally {
-            IoUtils.closeQuietly(reader);
         }
         mTaskIdsInFile.put(userId, persistedTaskIds);
         return persistedTaskIds.clone();
     }
 
+
     @VisibleForTesting
-    void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
+    void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
         if (userId < 0) {
             return;
         }
-        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
-        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
-            return;
-        }
         final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
-        BufferedWriter writer = null;
-        try {
-            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
-            for (int i = 0; i < taskIds.size(); i++) {
-                if (taskIds.valueAt(i)) {
-                    writer.write(String.valueOf(taskIds.keyAt(i)));
-                    writer.newLine();
+        synchronized (mIoLock) {
+            BufferedWriter writer = null;
+            try {
+                writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
+                for (int i = 0; i < taskIds.size(); i++) {
+                    if (taskIds.valueAt(i)) {
+                        writer.write(String.valueOf(taskIds.keyAt(i)));
+                        writer.newLine();
+                    }
                 }
+            } catch (Exception e) {
+                Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
+            } finally {
+                IoUtils.closeQuietly(writer);
             }
-        } catch (Exception e) {
-            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
-        } finally {
-            IoUtils.closeQuietly(writer);
         }
-        mTaskIdsInFile.put(userId, taskIds.clone());
     }
 
     void unloadUserDataFromMemory(int userId) {
@@ -543,16 +545,23 @@
     }
 
     private void writeTaskIdsFiles() {
-        int candidateUserIds[];
+        SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
         synchronized (mService) {
-            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
-        }
-        SparseBooleanArray taskIdsToSave;
-        for (int userId : candidateUserIds) {
-            synchronized (mService) {
-                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
+            for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
+                SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
+                SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
+                if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
+                    continue;
+                } else {
+                    SparseBooleanArray taskIdsToSaveCopy = taskIdsToSave.clone();
+                    mTaskIdsInFile.put(userId, taskIdsToSaveCopy);
+                    changedTaskIdsPerUser.put(userId, taskIdsToSaveCopy);
+                }
             }
-            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
+        }
+        for (int i = 0; i < changedTaskIdsPerUser.size(); i++) {
+            writePersistedTaskIdsForUser(changedTaskIdsPerUser.valueAt(i),
+                    changedTaskIdsPerUser.keyAt(i));
         }
     }
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c2c8e3d..6cc4d73 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -271,6 +271,7 @@
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
     int mLayerRank = -1;
 
+    /** Contains configurations settings that are different from the parent's configuration. */
     Configuration mOverrideConfig = Configuration.EMPTY;
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
@@ -575,7 +576,7 @@
      * @return whether the thumbnail was set
      */
     boolean setLastThumbnailLocked(Bitmap thumbnail) {
-        final Configuration serviceConfig = mService.mConfiguration;
+        final Configuration serviceConfig = mService.mGlobalConfiguration;
         int taskWidth = 0;
         int taskHeight = 0;
         if (mBounds != null) {
@@ -683,7 +684,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 +697,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 +706,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);
     }
@@ -1446,9 +1454,9 @@
     /**
      * Update task's override configuration based on the bounds.
      * @param bounds The bounds of the task.
-     * @return Update configuration or null if there is no change.
+     * @return True if the override configuration was updated.
      */
-    Configuration updateOverrideConfiguration(Rect bounds) {
+    boolean updateOverrideConfiguration(Rect bounds) {
         return updateOverrideConfiguration(bounds, null /* insetBounds */);
     }
 
@@ -1458,11 +1466,11 @@
      * @param insetBounds The bounds used to calculate the system insets, which is used here to
      *                    subtract the navigation bar/status bar size from the screen size reported
      *                    to the application. See {@link IActivityManager#resizeDockedStack}.
-     * @return Update configuration or null if there is no change.
+     * @return True if the override configuration was updated.
      */
-    Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
+    boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
         if (Objects.equals(mBounds, bounds)) {
-            return null;
+            return false;
         }
         final Configuration oldConfig = mOverrideConfig;
         final boolean oldFullscreen = mFullscreen;
@@ -1493,7 +1501,7 @@
             mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
         }
 
-        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
+        return !mOverrideConfig.equals(oldConfig);
     }
 
     private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds,
@@ -1531,7 +1539,7 @@
 
         // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
         // i.e. the screen area without the system bars.
-        final Configuration serviceConfig = mService.mConfiguration;
+        final Configuration serviceConfig = mService.mGlobalConfiguration;
         final Configuration config = new Configuration(Configuration.EMPTY);
         // TODO(multidisplay): Update Dp to that of display stack is on.
         final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
@@ -1572,7 +1580,6 @@
         extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
         extracted.orientation = config.orientation;
         extracted.screenLayout = config.screenLayout;
-        extracted.fontScale = config.fontScale;
         return extracted;
     }
 
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 6e371c1..0aa54d9 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.server.am.ActivityManagerService.GrantUri;
@@ -93,7 +94,16 @@
     }
 
     private void updateModeFlags() {
+        final int oldModeFlags = modeFlags;
         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
+
+        if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
+            Slog.d(TAG,
+                    "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
+                            + Integer.toHexString(oldModeFlags) + " to 0x"
+                            + Integer.toHexString(modeFlags),
+                    new Throwable());
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0407361..9697855 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -32,6 +32,7 @@
 import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL;
 import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE;
 import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.ActivityManagerService.REPORT_LOCKED_BOOT_COMPLETE_MSG;
 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
@@ -114,7 +115,7 @@
 
     // Amount of time we wait for observers to handle a user switch before
     // giving up on them and unfreezing the screen.
-    static final int USER_SWITCH_TIMEOUT = 2 * 1000;
+    static final int USER_SWITCH_TIMEOUT = 3 * 1000;
 
     private final Object mLock;
     private final Injector mInjector;
@@ -259,6 +260,8 @@
                 MetricsLogger.histogram(mInjector.getContext(), "framework_locked_boot_completed",
                     uptimeSeconds);
 
+                mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
+                        userId, 0));
                 Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -1053,6 +1056,18 @@
         mUserSwitchObservers.finishBroadcast();
     }
 
+    void dispatchLockedBootComplete(int userId) {
+        final int observerCount = mUserSwitchObservers.beginBroadcast();
+        for (int i = 0; i < observerCount; i++) {
+            try {
+                mUserSwitchObservers.getBroadcastItem(i).onLockedBootComplete(userId);
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        mUserSwitchObservers.finishBroadcast();
+    }
+
     private void stopBackgroundUsersIfEnforced(int oldUserId) {
         // Never stop system user
         if (oldUserId == UserHandle.USER_SYSTEM) {
@@ -1088,6 +1103,7 @@
                 mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks;
             }
             final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount);
+            final long dispatchStartedTime = SystemClock.elapsedRealtime();
             for (int i = 0; i < observerCount; i++) {
                 try {
                     // Prepend with unique prefix to guarantee that keys are unique
@@ -1099,6 +1115,11 @@
                         @Override
                         public void sendResult(Bundle data) throws RemoteException {
                             synchronized (mLock) {
+                                long delay = SystemClock.elapsedRealtime() - dispatchStartedTime;
+                                if (delay > USER_SWITCH_TIMEOUT) {
+                                    Slog.wtf(TAG, "User switch timeout: observer "  + name
+                                            + " sent result after " + delay + " ms");
+                                }
                                 // Early return if this session is no longer valid
                                 if (curWaitingUserSwitchCallbacks
                                         != mCurWaitingUserSwitchCallbacks) {
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index ff8014c..48238b6 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -87,7 +87,7 @@
         state = newState;
     }
 
-    private static String stateToString(int state) {
+    static String stateToString(int state) {
         switch (state) {
             case STATE_BOOTING: return "BOOTING";
             case STATE_RUNNING_LOCKED: return "RUNNING_LOCKED";
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7587847..0f351f6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3397,6 +3397,10 @@
     private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
             String caller, int flags) {
         int result = FLAG_ADJUST_VOLUME;
+        if (isPlatformTelevision()) {
+            return result;
+        }
+
         int ringerMode = getRingerModeInternal();
 
         switch (ringerMode) {
@@ -5616,6 +5620,8 @@
                 } else { // config == AudioSystem.FORCE_NONE
                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
                 }
+                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                        SENDMSG_NOOP, 0, 0, null, 0);
                 break;
             case AudioSystem.FOR_DOCK:
                 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 49be879..cc181141 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -40,9 +40,9 @@
     private static final String TAG = "MediaFocusControl";
     private static final boolean DEBUG = false;
 
-    private AudioFocusDeathHandler mDeathHandler;
-    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
-    private final IBinder mSourceRef;
+    private AudioFocusDeathHandler mDeathHandler; // may be null
+    private IAudioFocusDispatcher mFocusDispatcher; // may be null
+    private final IBinder mSourceRef; // may be null
     private final String mClientId;
     private final String mPackageName;
     private final int mCallingUid;
@@ -205,6 +205,7 @@
             if (mSourceRef != null && mDeathHandler != null) {
                 mSourceRef.unlinkToDeath(mDeathHandler, 0);
                 mDeathHandler = null;
+                mFocusDispatcher = null;
             }
         } catch (java.util.NoSuchElementException e) {
             Log.e(TAG, "FocusRequester.release() hit ", e);
@@ -275,12 +276,13 @@
             mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
             mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
-            if (mFocusDispatcher != null) {
+            final IAudioFocusDispatcher fd = mFocusDispatcher;
+            if (fd != null) {
                 if (DEBUG) {
                     Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
                         + mClientId);
                 }
-                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
+                fd.dispatchAudioFocusChange(focusGain, mClientId);
             }
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
@@ -311,14 +313,15 @@
                             toAudioFocusInfo(), false /* wasDispatched */);
                     return;
                 }
-                if (mFocusDispatcher != null) {
+                final IAudioFocusDispatcher fd = mFocusDispatcher;
+                if (fd != null) {
                     if (DEBUG) {
                         Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
                             + mClientId);
                     }
                     mFocusController.notifyExtPolicyFocusLoss_syncAf(
                             toAudioFocusInfo(), true /* wasDispatched */);
-                    mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
+                    fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
                 }
             }
         } catch (android.os.RemoteException e) {
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 278d70b..206834e 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -160,6 +160,7 @@
                     Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
                             + clientToRemove);
                     stackIterator.remove();
+                    // stack entry not used anymore, clear references
                     fr.release();
                 }
             }
@@ -171,7 +172,7 @@
      * Called synchronized on mAudioFocusLock
      * Remove focus listeners from the focus stack for a particular client when it has died.
      */
-    private void removeFocusStackEntryForClient(IBinder cb) {
+    private void removeFocusStackEntryOnDeath(IBinder cb) {
         // is the owner of the audio focus part of the client to remove?
         boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
                 mFocusStack.peek().hasSameBinder(cb);
@@ -181,9 +182,10 @@
         while(stackIterator.hasNext()) {
             FocusRequester fr = stackIterator.next();
             if(fr.hasSameBinder(cb)) {
-                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
+                Log.i(TAG, "AudioFocus  removeFocusStackEntryOnDeath(): removing entry for " + cb);
                 stackIterator.remove();
-                // the client just died, no need to unlink to its death
+                // stack entry not used anymore, clear references
+                fr.release();
             }
         }
         if (isTopOfStackForClientToRemove) {
@@ -257,14 +259,9 @@
 
         public void binderDied() {
             synchronized(mAudioFocusLock) {
-                Log.w(TAG, "  AudioFocus   audio focus client died");
-                removeFocusStackEntryForClient(mCb);
+                removeFocusStackEntryOnDeath(mCb);
             }
         }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
     }
 
     /**
@@ -420,6 +417,7 @@
             // (premature death == death before abandoning focus)
             // Register for client death notification
             AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+
             try {
                 cb.linkToDeath(afdh, 0);
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 66aa403..5772a57 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -20,7 +20,6 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ContentProvider;
@@ -28,7 +27,6 @@
 import android.content.IOnPrimaryClipChangedListener;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -47,23 +45,57 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.server.SystemService;
+
 import java.util.HashSet;
 import java.util.List;
 
 /**
  * Implementation of the clipboard for copy and paste.
  */
-public class ClipboardService extends IClipboard.Stub {
+public class ClipboardService extends SystemService {
 
     private static final String TAG = "ClipboardService";
 
-    private final Context mContext;
     private final IActivityManager mAm;
     private final IUserManager mUm;
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
     private final IBinder mPermissionOwner;
 
+    private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
+
+    /**
+     * Instantiates the clipboard.
+     */
+    public ClipboardService(Context context) {
+        super(context);
+
+        mAm = ActivityManagerNative.getDefault();
+        mPm = getContext().getPackageManager();
+        mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
+        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+        IBinder permOwner = null;
+        try {
+            permOwner = mAm.newUriPermissionOwner("clipboard");
+        } catch (RemoteException e) {
+            Slog.w("clipboard", "AM dead", e);
+        }
+        mPermissionOwner = permOwner;
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
+    }
+
+    @Override
+    public void onCleanupUser(int userId) {
+        synchronized (mClipboards) {
+            mClipboards.remove(userId);
+        }
+    }
+
     private class ListenerInfo {
         final int mUid;
         final String mPackageName;
@@ -89,52 +121,141 @@
         }
     }
 
-    private SparseArray<PerUserClipboard> mClipboards = new SparseArray<PerUserClipboard>();
+    private class ClipboardImpl extends IClipboard.Stub {
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            try {
+                return super.onTransact(code, data, reply, flags);
+            } catch (RuntimeException e) {
+                if (!(e instanceof SecurityException)) {
+                    Slog.wtf("clipboard", "Exception: ", e);
+                }
+                throw e;
+            }
 
-    /**
-     * Instantiates the clipboard.
-     */
-    public ClipboardService(Context context) {
-        mContext = context;
-        mAm = ActivityManagerNative.getDefault();
-        mPm = context.getPackageManager();
-        mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
-        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-        IBinder permOwner = null;
-        try {
-            permOwner = mAm.newUriPermissionOwner("clipboard");
-        } catch (RemoteException e) {
-            Slog.w("clipboard", "AM dead", e);
         }
-        mPermissionOwner = permOwner;
 
-        // Remove the clipboard if a user is removed
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+        @Override
+        public void setPrimaryClip(ClipData clip, String callingPackage) {
+            synchronized (this) {
+                if (clip != null && clip.getItemCount() <= 0) {
+                    throw new IllegalArgumentException("No items");
+                }
+                final int callingUid = Binder.getCallingUid();
+                if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
+                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                    return;
+                }
+                checkDataOwnerLocked(clip, callingUid);
+                final int userId = UserHandle.getUserId(callingUid);
+                PerUserClipboard clipboard = getClipboard(userId);
+                revokeUris(clipboard);
+                setPrimaryClipInternal(clipboard, clip);
+                List<UserInfo> related = getRelatedProfiles(userId);
+                if (related != null) {
+                    int size = related.size();
+                    if (size > 1) { // Related profiles list include the current profile.
+                        boolean canCopy = false;
+                        try {
+                            canCopy = !mUm.getUserRestrictions(userId).getBoolean(
+                                    UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Remote Exception calling UserManager: " + e);
+                        }
+                        // Copy clip data to related users if allowed. If disallowed, then remove
+                        // primary clip in related users to prevent pasting stale content.
+                        if (!canCopy) {
+                            clip = null;
+                        } else {
+                            // We want to fix the uris of the related user's clip without changing the
+                            // uris of the current user's clip.
+                            // So, copy the ClipData, and then copy all the items, so that nothing
+                            // is shared in memmory.
+                            clip = new ClipData(clip);
+                            for (int i = clip.getItemCount() - 1; i >= 0; i--) {
+                                clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
+                            }
+                            clip.fixUrisLight(userId);
+                        }
+                        for (int i = 0; i < size; i++) {
+                            int id = related.get(i).id;
+                            if (id != userId) {
+                                setPrimaryClipInternal(getClipboard(id), clip);
+                            }
+                        }
+                    }
                 }
             }
-        }, userFilter);
-    }
-
-    @Override
-    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-            throws RemoteException {
-        try {
-            return super.onTransact(code, data, reply, flags);
-        } catch (RuntimeException e) {
-            if (!(e instanceof SecurityException)) {
-                Slog.wtf("clipboard", "Exception: ", e);
-            }
-            throw e;
         }
-        
-    }
+
+        @Override
+        public ClipData getPrimaryClip(String pkg) {
+            synchronized (this) {
+                if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+                        pkg) != AppOpsManager.MODE_ALLOWED) {
+                    return null;
+                }
+                addActiveOwnerLocked(Binder.getCallingUid(), pkg);
+                return getClipboard().primaryClip;
+            }
+        }
+
+        @Override
+        public ClipDescription getPrimaryClipDescription(String callingPackage) {
+            synchronized (this) {
+                if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                    return null;
+                }
+                PerUserClipboard clipboard = getClipboard();
+                return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
+            }
+        }
+
+        @Override
+        public boolean hasPrimaryClip(String callingPackage) {
+            synchronized (this) {
+                if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                    return false;
+                }
+                return getClipboard().primaryClip != null;
+            }
+        }
+
+        @Override
+        public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+                String callingPackage) {
+            synchronized (this) {
+                getClipboard().primaryClipListeners.register(listener,
+                        new ListenerInfo(Binder.getCallingUid(), callingPackage));
+            }
+        }
+
+        @Override
+        public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
+            synchronized (this) {
+                getClipboard().primaryClipListeners.unregister(listener);
+            }
+        }
+
+        @Override
+        public boolean hasClipboardText(String callingPackage) {
+            synchronized (this) {
+                if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+                        callingPackage) != AppOpsManager.MODE_ALLOWED) {
+                    return false;
+                }
+                PerUserClipboard clipboard = getClipboard();
+                if (clipboard.primaryClip != null) {
+                    CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
+                    return text != null && text.length() > 0;
+                }
+                return false;
+            }
+        }
+    };
 
     private PerUserClipboard getClipboard() {
         return getClipboard(UserHandle.getCallingUserId());
@@ -151,64 +272,6 @@
         }
     }
 
-    private void removeClipboard(int userId) {
-        synchronized (mClipboards) {
-            mClipboards.remove(userId);
-        }
-    }
-
-    public void setPrimaryClip(ClipData clip, String callingPackage) {
-        synchronized (this) {
-            if (clip != null && clip.getItemCount() <= 0) {
-                throw new IllegalArgumentException("No items");
-            }
-            final int callingUid = Binder.getCallingUid();
-            if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
-                return;
-            }
-            checkDataOwnerLocked(clip, callingUid);
-            final int userId = UserHandle.getUserId(callingUid);
-            PerUserClipboard clipboard = getClipboard(userId);
-            revokeUris(clipboard);
-            setPrimaryClipInternal(clipboard, clip);
-            List<UserInfo> related = getRelatedProfiles(userId);
-            if (related != null) {
-                int size = related.size();
-                if (size > 1) { // Related profiles list include the current profile.
-                    boolean canCopy = false;
-                    try {
-                        canCopy = !mUm.getUserRestrictions(userId).getBoolean(
-                                UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Remote Exception calling UserManager: " + e);
-                    }
-                    // Copy clip data to related users if allowed. If disallowed, then remove
-                    // primary clip in related users to prevent pasting stale content.
-                    if (!canCopy) {
-                        clip = null;
-                    } else {
-                        // We want to fix the uris of the related user's clip without changing the
-                        // uris of the current user's clip.
-                        // So, copy the ClipData, and then copy all the items, so that nothing
-                        // is shared in memmory.
-                        clip = new ClipData(clip);
-                        for (int i = clip.getItemCount() - 1; i >= 0; i--) {
-                            clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
-                        }
-                        clip.fixUrisLight(userId);
-                    }
-                    for (int i = 0; i < size; i++) {
-                        int id = related.get(i).id;
-                        if (id != userId) {
-                            setPrimaryClipInternal(getClipboard(id), clip);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     List<UserInfo> getRelatedProfiles(int userId) {
         final List<UserInfo> related;
         final long origId = Binder.clearCallingIdentity();
@@ -251,67 +314,6 @@
             Binder.restoreCallingIdentity(ident);
         }
     }
-    
-    public ClipData getPrimaryClip(String pkg) {
-        synchronized (this) {
-            if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
-                    pkg) != AppOpsManager.MODE_ALLOWED) {
-                return null;
-            }
-            addActiveOwnerLocked(Binder.getCallingUid(), pkg);
-            return getClipboard().primaryClip;
-        }
-    }
-
-    public ClipDescription getPrimaryClipDescription(String callingPackage) {
-        synchronized (this) {
-            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
-                return null;
-            }
-            PerUserClipboard clipboard = getClipboard();
-            return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
-        }
-    }
-
-    public boolean hasPrimaryClip(String callingPackage) {
-        synchronized (this) {
-            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
-                return false;
-            }
-            return getClipboard().primaryClip != null;
-        }
-    }
-
-    public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
-            String callingPackage) {
-        synchronized (this) {
-            getClipboard().primaryClipListeners.register(listener,
-                    new ListenerInfo(Binder.getCallingUid(), callingPackage));
-        }
-    }
-
-    public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
-        synchronized (this) {
-            getClipboard().primaryClipListeners.unregister(listener);
-        }
-    }
-
-    public boolean hasClipboardText(String callingPackage) {
-        synchronized (this) {
-            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
-                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
-                return false;
-            }
-            PerUserClipboard clipboard = getClipboard();
-            if (clipboard.primaryClip != null) {
-                CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
-                return text != null && text.length() > 0;
-            }
-            return false;
-        }
-    }
 
     private final void checkUriOwnerLocked(Uri uri, int uid) {
         if (!"content".equals(uri.getScheme())) {
diff --git a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
deleted file mode 100644
index 8d206ef..0000000
--- a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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.content.Context;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.net.NetworkRequest;
-import android.net.metrics.DnsEvent;
-import android.net.metrics.IDnsEventListener;
-import android.net.metrics.IpConnectivityLog;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-
-/**
- * Implementation of the IDnsEventListener interface.
- */
-public class DnsEventListenerService extends IDnsEventListener.Stub {
-
-    public static final String SERVICE_NAME = "dns_listener";
-
-    private static final String TAG = DnsEventListenerService.class.getSimpleName();
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
-    // TODO: read this constant from system property
-    private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100;
-
-    // Stores the results of a number of consecutive DNS lookups on the same network.
-    // This class is not thread-safe and it is the responsibility of the service to call its methods
-    // on one thread at a time.
-    private class DnsEventBatch {
-        private final int mNetId;
-
-        private final byte[] mEventTypes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
-        private final byte[] mReturnCodes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
-        private final int[] mLatenciesMs = new int[MAX_LOOKUPS_PER_DNS_EVENT];
-        private int mEventCount;
-
-        public DnsEventBatch(int netId) {
-            mNetId = netId;
-        }
-
-        public void addResult(byte eventType, byte returnCode, int latencyMs) {
-            mEventTypes[mEventCount] = eventType;
-            mReturnCodes[mEventCount] = returnCode;
-            mLatenciesMs[mEventCount] = latencyMs;
-            mEventCount++;
-            if (mEventCount == MAX_LOOKUPS_PER_DNS_EVENT) {
-                logAndClear();
-            }
-        }
-
-        public void logAndClear() {
-            // Did we lose a race with addResult?
-            if (mEventCount == 0) {
-                return;
-            }
-
-            // Only log as many events as we actually have.
-            byte[] eventTypes = Arrays.copyOf(mEventTypes, mEventCount);
-            byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
-            int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
-            mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs));
-            maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
-            mEventCount = 0;
-        }
-
-        // For debugging and unit tests only.
-        public String toString() {
-            return String.format("%s %d %d", getClass().getSimpleName(), mNetId, mEventCount);
-        }
-    }
-
-    // Only sorted for ease of debugging. Because we only typically have a handful of networks up
-    // at any given time, performance is not a concern.
-    @GuardedBy("this")
-    private final SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>();
-
-    // We register a NetworkCallback to ensure that when a network disconnects, we flush the DNS
-    // queries we've logged on that network. Because we do not do this periodically, we might lose
-    // up to MAX_LOOKUPS_PER_DNS_EVENT lookup stats on each network when the system is shutting
-    // down. We believe this to be sufficient for now.
-    private final ConnectivityManager mCm;
-    private final IpConnectivityLog mMetricsLog;
-    private final NetworkCallback mNetworkCallback = new NetworkCallback() {
-        @Override
-        public void onLost(Network network) {
-            synchronized (DnsEventListenerService.this) {
-                DnsEventBatch batch = mEventBatches.remove(network.netId);
-                if (batch != null) {
-                    batch.logAndClear();
-                }
-            }
-        }
-    };
-
-    public DnsEventListenerService(Context context) {
-        this(context.getSystemService(ConnectivityManager.class), new IpConnectivityLog());
-    }
-
-    @VisibleForTesting
-    public DnsEventListenerService(ConnectivityManager cm, IpConnectivityLog log) {
-        // We are started when boot is complete, so ConnectivityService should already be running.
-        mCm = cm;
-        mMetricsLog = log;
-        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
-        mCm.registerNetworkCallback(request, mNetworkCallback);
-    }
-
-    @Override
-    // Called concurrently by multiple binder threads.
-    public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs) {
-        maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
-                netId, eventType, returnCode, latencyMs));
-
-        DnsEventBatch batch = mEventBatches.get(netId);
-        if (batch == null) {
-            batch = new DnsEventBatch(netId);
-            mEventBatches.put(netId, batch);
-        }
-        batch.addResult((byte) eventType, (byte) returnCode, latencyMs);
-    }
-
-    public synchronized void dump(PrintWriter writer) {
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(TAG + ":");
-        pw.increaseIndent();
-        for (DnsEventBatch batch : mEventBatches.values()) {
-            pw.println(batch.toString());
-        }
-        pw.decreaseIndent();
-    }
-
-    private static void maybeLog(String s) {
-        if (DBG) Log.d(TAG, s);
-    }
-
-    private static void maybeVerboseLog(String s) {
-        if (VDBG) Log.d(TAG, s);
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
new file mode 100644
index 0000000..f1ef947
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -0,0 +1,257 @@
+/*
+ * 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.net.ConnectivityMetricsEvent;
+import android.net.metrics.ApfProgramEvent;
+import android.net.metrics.ApfStats;
+import android.net.metrics.DefaultNetworkEvent;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.DhcpErrorEvent;
+import android.net.metrics.DnsEvent;
+import android.net.metrics.IpManagerEvent;
+import android.net.metrics.IpReachabilityEvent;
+import android.net.metrics.NetworkEvent;
+import android.net.metrics.RaEvent;
+import android.net.metrics.ValidationProbeEvent;
+import android.os.Parcelable;
+import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.NetworkId;
+
+/** {@hide} */
+final public class IpConnectivityEventBuilder {
+    private IpConnectivityEventBuilder() {
+    }
+
+    public static byte[] serialize(int dropped, List<ConnectivityMetricsEvent> events)
+            throws IOException {
+        final IpConnectivityLog log = new IpConnectivityLog();
+        log.events = toProto(events);
+        log.droppedEvents = dropped;
+        return IpConnectivityLog.toByteArray(log);
+    }
+
+    public static IpConnectivityEvent[] toProto(List<ConnectivityMetricsEvent> eventsIn) {
+        final ArrayList<IpConnectivityEvent> eventsOut = new ArrayList<>(eventsIn.size());
+        for (ConnectivityMetricsEvent in : eventsIn) {
+            final IpConnectivityEvent out = toProto(in);
+            if (out == null) {
+                continue;
+            }
+            eventsOut.add(out);
+        }
+        return eventsOut.toArray(new IpConnectivityEvent[eventsOut.size()]);
+    }
+
+    public static IpConnectivityEvent toProto(ConnectivityMetricsEvent ev) {
+        final IpConnectivityEvent out = new IpConnectivityEvent();
+        if (!setEvent(out, ev.data)) {
+            return null;
+        }
+        out.timeMs = ev.timestamp;
+        return out;
+    }
+
+    private static boolean setEvent(IpConnectivityEvent out, Parcelable in) {
+        if (in instanceof DhcpErrorEvent) {
+            setDhcpErrorEvent(out, (DhcpErrorEvent) in);
+            return true;
+        }
+
+        if (in instanceof DhcpClientEvent) {
+            setDhcpClientEvent(out, (DhcpClientEvent) in);
+            return true;
+        }
+
+        if (in instanceof DnsEvent) {
+            setDnsEvent(out, (DnsEvent) in);
+            return true;
+        }
+
+        if (in instanceof IpManagerEvent) {
+            setIpManagerEvent(out, (IpManagerEvent) in);
+            return true;
+        }
+
+        if (in instanceof IpReachabilityEvent) {
+            setIpReachabilityEvent(out, (IpReachabilityEvent) in);
+            return true;
+        }
+
+        if (in instanceof DefaultNetworkEvent) {
+            setDefaultNetworkEvent(out, (DefaultNetworkEvent) in);
+            return true;
+        }
+
+        if (in instanceof NetworkEvent) {
+            setNetworkEvent(out, (NetworkEvent) in);
+            return true;
+        }
+
+        if (in instanceof ValidationProbeEvent) {
+            setValidationProbeEvent(out, (ValidationProbeEvent) in);
+            return true;
+        }
+
+        if (in instanceof ApfProgramEvent) {
+            setApfProgramEvent(out, (ApfProgramEvent) in);
+            return true;
+        }
+
+        if (in instanceof ApfStats) {
+            setApfStats(out, (ApfStats) in);
+            return true;
+        }
+
+        if (in instanceof RaEvent) {
+            setRaEvent(out, (RaEvent) in);
+            return true;
+        }
+
+        return false;
+    }
+
+    private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
+        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+        out.dhcpEvent.ifName = in.ifName;
+        out.dhcpEvent.errorCode = in.errorCode;
+    }
+
+    private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
+        out.dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
+        out.dhcpEvent.ifName = in.ifName;
+        out.dhcpEvent.stateTransition = in.msg;
+        out.dhcpEvent.durationMs = in.durationMs;
+    }
+
+    private static void setDnsEvent(IpConnectivityEvent out, DnsEvent in) {
+        out.dnsLookupBatch = new IpConnectivityLogClass.DNSLookupBatch();
+        out.dnsLookupBatch.networkId = netIdOf(in.netId);
+        out.dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
+        out.dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
+        out.dnsLookupBatch.latenciesMs = in.latenciesMs;
+    }
+
+    private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
+        out.ipProvisioningEvent = new IpConnectivityLogClass.IpProvisioningEvent();
+        out.ipProvisioningEvent.ifName = in.ifName;
+        out.ipProvisioningEvent.eventType = in.eventType;
+        out.ipProvisioningEvent.latencyMs = (int) in.durationMs;
+    }
+
+    private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
+        out.ipReachabilityEvent = new IpConnectivityLogClass.IpReachabilityEvent();
+        out.ipReachabilityEvent.ifName = in.ifName;
+        out.ipReachabilityEvent.eventType = in.eventType;
+    }
+
+    private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) {
+        out.defaultNetworkEvent = new IpConnectivityLogClass.DefaultNetworkEvent();
+        out.defaultNetworkEvent.networkId = netIdOf(in.netId);
+        out.defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId);
+        out.defaultNetworkEvent.transportTypes = in.transportTypes;
+        out.defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in);
+    }
+
+    private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
+        out.networkEvent = new IpConnectivityLogClass.NetworkEvent();
+        out.networkEvent.networkId = netIdOf(in.netId);
+        out.networkEvent.eventType = in.eventType;
+        out.networkEvent.latencyMs = (int) in.durationMs;
+    }
+
+    private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
+        out.validationProbeEvent = new IpConnectivityLogClass.ValidationProbeEvent();
+        out.validationProbeEvent.networkId = netIdOf(in.netId);
+        out.validationProbeEvent.latencyMs = (int) in.durationMs;
+        out.validationProbeEvent.probeType = in.probeType;
+        out.validationProbeEvent.probeResult = in.returnCode;
+    }
+
+    private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
+        out.apfProgramEvent = new IpConnectivityLogClass.ApfProgramEvent();
+        out.apfProgramEvent.lifetime = in.lifetime;
+        out.apfProgramEvent.filteredRas = in.filteredRas;
+        out.apfProgramEvent.currentRas = in.currentRas;
+        out.apfProgramEvent.programLength = in.programLength;
+        if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
+            out.apfProgramEvent.dropMulticast = true;
+        }
+        if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
+            out.apfProgramEvent.hasIpv4Addr = true;
+        }
+    }
+
+    private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
+        out.apfStatistics = new IpConnectivityLogClass.ApfStatistics();
+        out.apfStatistics.durationMs = in.durationMs;
+        out.apfStatistics.receivedRas = in.receivedRas;
+        out.apfStatistics.matchingRas = in.matchingRas;
+        out.apfStatistics.droppedRas = in.droppedRas;
+        out.apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
+        out.apfStatistics.parseErrors = in.parseErrors;
+        out.apfStatistics.programUpdates = in.programUpdates;
+        out.apfStatistics.maxProgramSize = in.maxProgramSize;
+    }
+
+    private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
+        out.raEvent = new IpConnectivityLogClass.RaEvent();
+        out.raEvent.routerLifetime = in.routerLifetime;
+        out.raEvent.prefixValidLifetime = in.prefixValidLifetime;
+        out.raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
+        out.raEvent.routeInfoLifetime = in.routeInfoLifetime;
+        out.raEvent.rdnssLifetime = in.rdnssLifetime;
+        out.raEvent.dnsslLifetime = in.dnsslLifetime;
+    }
+
+    private static int[] bytesToInts(byte[] in) {
+        final int[] out = new int[in.length];
+        for (int i = 0; i < in.length; i++) {
+            out[i] = in[i] & 0xFF;
+        }
+        return out;
+    }
+
+    private static NetworkId netIdOf(int netid) {
+        final NetworkId ni = new NetworkId();
+        ni.networkId = netid;
+        return ni;
+    }
+
+    private static int ipSupportOf(DefaultNetworkEvent in) {
+        if (in.prevIPv4 && in.prevIPv6) {
+            return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
+        }
+        if (in.prevIPv6) {
+            return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
+        }
+        if (in.prevIPv4) {
+            return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
+        }
+        return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
+    }
+
+    private static boolean isBitSet(int flags, int bit) {
+        return (flags & (1 << bit)) != 0;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
new file mode 100644
index 0000000..28e724c
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -0,0 +1,229 @@
+/*
+ * 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.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.metrics.IpConnectivityLog;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
+
+/** {@hide} */
+final public class IpConnectivityMetrics extends SystemService {
+    private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;
+
+    // Default size of the event buffer. Once the buffer is full, incoming events are dropped.
+    private static final int DEFAULT_BUFFER_SIZE = 2000;
+
+    // Lock ensuring that concurrent manipulations of the event buffer are correct.
+    // There are three concurrent operations to synchronize:
+    //  - appending events to the buffer.
+    //  - iterating throught the buffer.
+    //  - flushing the buffer content and replacing it by a new buffer.
+    private final Object mLock = new Object();
+
+    @VisibleForTesting
+    public final Impl impl = new Impl();
+    private NetdEventListenerService mNetdListener;
+
+    @GuardedBy("mLock")
+    private ArrayList<ConnectivityMetricsEvent> mBuffer;
+    @GuardedBy("mLock")
+    private int mDropped;
+    @GuardedBy("mLock")
+    private int mCapacity;
+
+    public IpConnectivityMetrics(Context ctx) {
+        super(ctx);
+        initBuffer();
+    }
+
+    @Override
+    public void onStart() {
+        if (DBG) Log.d(TAG, "onStart");
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            if (DBG) Log.d(TAG, "onBootPhase");
+            mNetdListener = new NetdEventListenerService(getContext());
+
+            publishBinderService(SERVICE_NAME, impl);
+            publishBinderService(mNetdListener.SERVICE_NAME, mNetdListener);
+        }
+    }
+
+    @VisibleForTesting
+    public int bufferCapacity() {
+        return DEFAULT_BUFFER_SIZE; // TODO: read from config
+    }
+
+    private void initBuffer() {
+        synchronized (mLock) {
+            mDropped = 0;
+            mCapacity = bufferCapacity();
+            mBuffer = new ArrayList<>(mCapacity);
+        }
+    }
+
+    private int append(ConnectivityMetricsEvent event) {
+        if (DBG) Log.d(TAG, "logEvent: " + event);
+        synchronized (mLock) {
+            final int left = mCapacity - mBuffer.size();
+            if (event == null) {
+                return left;
+            }
+            if (left == 0) {
+                mDropped++;
+                return 0;
+            }
+            mBuffer.add(event);
+            return left - 1;
+        }
+    }
+
+    private String flushEncodedOutput() {
+        final ArrayList<ConnectivityMetricsEvent> events;
+        final int dropped;
+        synchronized (mLock) {
+            events = mBuffer;
+            dropped = mDropped;
+            initBuffer();
+        }
+
+        final byte[] data;
+        try {
+            data = IpConnectivityEventBuilder.serialize(dropped, events);
+        } catch (IOException e) {
+            Log.e(TAG, "could not serialize events", e);
+            return "";
+        }
+
+        return Base64.encodeToString(data, Base64.DEFAULT);
+    }
+
+    /**
+     * Clears the event buffer and prints its content as a protobuf serialized byte array
+     * inside a base64 encoded string.
+     */
+    private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.print(flushEncodedOutput());
+    }
+
+    /**
+     * Prints the content of the event buffer, either using the events ASCII representation
+     * or using protobuf text format.
+     */
+    private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final ArrayList<ConnectivityMetricsEvent> events;
+        synchronized (mLock) {
+            events = new ArrayList(mBuffer);
+        }
+
+        if (args.length > 1 && args[1].equals("proto")) {
+            for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
+                pw.print(ev.toString());
+            }
+            return;
+        }
+
+        for (ConnectivityMetricsEvent ev : events) {
+            pw.println(ev.toString());
+        }
+    }
+
+    private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mLock) {
+            pw.println("Buffered events: " + mBuffer.size());
+            pw.println("Buffer capacity: " + mCapacity);
+            pw.println("Dropped events: " + mDropped);
+        }
+        if (mNetdListener != null) {
+            mNetdListener.dump(pw);
+        }
+    }
+
+    private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (args.length == 0) {
+            pw.println("No command");
+            return;
+        }
+        pw.println("Unknown command " + TextUtils.join(" ", args));
+    }
+
+    public final class Impl extends IIpConnectivityMetrics.Stub {
+        static final String CMD_FLUSH   = "flush";
+        static final String CMD_LIST    = "list";
+        static final String CMD_STATS   = "stats";
+        static final String CMD_DEFAULT = CMD_STATS;
+
+        @Override
+        public int logEvent(ConnectivityMetricsEvent event) {
+            enforceConnectivityInternalPermission();
+            return append(event);
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            enforceDumpPermission();
+            if (DBG) Log.d(TAG, "dumpsys " + TextUtils.join(" ", args));
+            final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
+            switch (cmd) {
+                case CMD_FLUSH:
+                    cmdFlush(fd, pw, args);
+                    return;
+                case CMD_LIST:
+                    cmdList(fd, pw, args);
+                    return;
+                case CMD_STATS:
+                    cmdStats(fd, pw, args);
+                    return;
+                default:
+                    cmdDefault(fd, pw, args);
+            }
+        }
+
+        private void enforceConnectivityInternalPermission() {
+            enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
+        }
+
+        private void enforceDumpPermission() {
+            enforcePermission(android.Manifest.permission.DUMP);
+        }
+
+        private void enforcePermission(String what) {
+            getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
new file mode 100644
index 0000000..635db19
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -0,0 +1,304 @@
+/*
+ * 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.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkCapabilities;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.SparseBooleanArray;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.MessageUtils;
+import com.android.server.connectivity.NetworkNotificationManager;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+
+import static android.net.ConnectivityManager.NETID_UNSET;
+
+/**
+ * Class that monitors default network linger events and possibly notifies the user of network
+ * switches.
+ *
+ * This class is not thread-safe and all its methods must be called on the ConnectivityService
+ * handler thread.
+ */
+public class LingerMonitor {
+
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+    private static final String TAG = LingerMonitor.class.getSimpleName();
+
+    public static final int DEFAULT_NOTIFICATION_DAILY_LIMIT = 3;
+    public static final long DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS = DateUtils.MINUTE_IN_MILLIS;
+
+    private static final HashMap<String, Integer> TRANSPORT_NAMES = makeTransportToNameMap();
+    @VisibleForTesting
+    public static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+            "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+
+    @VisibleForTesting
+    public static final int NOTIFY_TYPE_NONE         = 0;
+    public static final int NOTIFY_TYPE_NOTIFICATION = 1;
+    public static final int NOTIFY_TYPE_TOAST        = 2;
+
+    private static SparseArray<String> sNotifyTypeNames = MessageUtils.findMessageNames(
+            new Class[] { LingerMonitor.class }, new String[]{ "NOTIFY_TYPE_" });
+
+    private final Context mContext;
+    private final NetworkNotificationManager mNotifier;
+    private final int mDailyLimit;
+    private final long mRateLimitMillis;
+
+    private long mFirstNotificationMillis;
+    private long mLastNotificationMillis;
+    private int mNotificationCounter;
+
+    /** Current notifications. Maps the netId we switched away from to the netId we switched to. */
+    private final SparseIntArray mNotifications = new SparseIntArray();
+
+    /** Whether we ever notified that we switched away from a particular network. */
+    private final SparseBooleanArray mEverNotified = new SparseBooleanArray();
+
+    public LingerMonitor(Context context, NetworkNotificationManager notifier,
+            int dailyLimit, long rateLimitMillis) {
+        mContext = context;
+        mNotifier = notifier;
+        mDailyLimit = dailyLimit;
+        mRateLimitMillis = rateLimitMillis;
+    }
+
+    private static HashMap<String, Integer> makeTransportToNameMap() {
+        SparseArray<String> numberToName = MessageUtils.findMessageNames(
+            new Class[] { NetworkCapabilities.class }, new String[]{ "TRANSPORT_" });
+        HashMap<String, Integer> nameToNumber = new HashMap<>();
+        for (int i = 0; i < numberToName.size(); i++) {
+            // MessageUtils will fail to initialize if there are duplicate constant values, so there
+            // are no duplicates here.
+            nameToNumber.put(numberToName.valueAt(i), numberToName.keyAt(i));
+        }
+        return nameToNumber;
+    }
+
+    private static boolean hasTransport(NetworkAgentInfo nai, int transport) {
+        return nai.networkCapabilities.hasTransport(transport);
+    }
+
+    private int getNotificationSource(NetworkAgentInfo toNai) {
+        for (int i = 0; i < mNotifications.size(); i++) {
+            if (mNotifications.valueAt(i) == toNai.network.netId) {
+                return mNotifications.keyAt(i);
+            }
+        }
+        return NETID_UNSET;
+    }
+
+    private boolean everNotified(NetworkAgentInfo nai) {
+        return mEverNotified.get(nai.network.netId, false);
+    }
+
+    @VisibleForTesting
+    public boolean isNotificationEnabled(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+        // TODO: Evaluate moving to CarrierConfigManager.
+        String[] notifySwitches =
+                mContext.getResources().getStringArray(R.array.config_networkNotifySwitches);
+
+        if (VDBG) {
+            Log.d(TAG, "Notify on network switches: " + Arrays.toString(notifySwitches));
+        }
+
+        for (String notifySwitch : notifySwitches) {
+            if (TextUtils.isEmpty(notifySwitch)) continue;
+            String[] transports = notifySwitch.split("-", 2);
+            if (transports.length != 2) {
+                Log.e(TAG, "Invalid network switch notification configuration: " + notifySwitch);
+                continue;
+            }
+            int fromTransport = TRANSPORT_NAMES.get("TRANSPORT_" + transports[0]);
+            int toTransport = TRANSPORT_NAMES.get("TRANSPORT_" + transports[1]);
+            if (hasTransport(fromNai, fromTransport) && hasTransport(toNai, toTransport)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private void showNotification(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+        mNotifier.showNotification(fromNai.network.netId, NotificationType.NETWORK_SWITCH,
+                fromNai, toNai, createNotificationIntent(), true);
+    }
+
+    @VisibleForTesting
+    protected PendingIntent createNotificationIntent() {
+        return PendingIntent.getActivityAsUser(mContext, 0, CELLULAR_SETTINGS,
+                PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+    }
+
+    // Removes any notification that was put up as a result of switching to nai.
+    private void maybeStopNotifying(NetworkAgentInfo nai) {
+        int fromNetId = getNotificationSource(nai);
+        if (fromNetId != NETID_UNSET) {
+            mNotifications.delete(fromNetId);
+            mNotifier.clearNotification(fromNetId);
+            // Toasts can't be deleted.
+        }
+    }
+
+    // Notify the user of a network switch using a notification or a toast.
+    private void notify(NetworkAgentInfo fromNai, NetworkAgentInfo toNai, boolean forceToast) {
+        int notifyType =
+                mContext.getResources().getInteger(R.integer.config_networkNotifySwitchType);
+        if (notifyType == NOTIFY_TYPE_NOTIFICATION && forceToast) {
+            notifyType = NOTIFY_TYPE_TOAST;
+        }
+
+        if (VDBG) {
+            Log.d(TAG, "Notify type: " + sNotifyTypeNames.get(notifyType, "" + notifyType));
+        }
+
+        switch (notifyType) {
+            case NOTIFY_TYPE_NONE:
+                return;
+            case NOTIFY_TYPE_NOTIFICATION:
+                showNotification(fromNai, toNai);
+                break;
+            case NOTIFY_TYPE_TOAST:
+                mNotifier.showToast(fromNai, toNai);
+                break;
+            default:
+                Log.e(TAG, "Unknown notify type " + notifyType);
+                return;
+        }
+
+        if (DBG) {
+            Log.d(TAG, "Notifying switch from=" + fromNai.name() + " to=" + toNai.name() +
+                    " type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
+        }
+
+        mNotifications.put(fromNai.network.netId, toNai.network.netId);
+        mEverNotified.put(fromNai.network.netId, true);
+    }
+
+    // The default network changed from fromNai to toNai due to a change in score.
+    public void noteLingerDefaultNetwork(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+        if (VDBG) {
+            Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.name() +
+                    " everValidated=" + fromNai.everValidated +
+                    " lastValidated=" + fromNai.lastValidated +
+                    " to=" + toNai.name());
+        }
+
+        // If we are currently notifying the user because the device switched to fromNai, now that
+        // we are switching away from it we should remove the notification. This includes the case
+        // where we switch back to toNai because its score improved again (e.g., because it regained
+        // Internet access).
+        maybeStopNotifying(fromNai);
+
+        // If this network never validated, don't notify. Otherwise, we could do things like:
+        //
+        // 1. Unvalidated wifi connects.
+        // 2. Unvalidated mobile data connects.
+        // 3. Cell validates, and we show a notification.
+        // or:
+        // 1. User connects to wireless printer.
+        // 2. User turns on cellular data.
+        // 3. We show a notification.
+        if (!fromNai.everValidated) return;
+
+        // If this network is a captive portal, don't notify. This cannot happen on initial connect
+        // to a captive portal, because the everValidated check above will fail. However, it can
+        // happen if the captive portal reasserts itself (e.g., because its timeout fires). In that
+        // case, as soon as the captive portal reasserts itself, we'll show a sign-in notification.
+        // We don't want to overwrite that notification with this one; the user has already been
+        // notified, and of the two, the captive portal notification is the more useful one because
+        // it allows the user to sign in to the captive portal. In this case, display a toast
+        // in addition to the captive portal notification.
+        //
+        // Note that if the network we switch to is already up when the captive portal reappears,
+        // this won't work because NetworkMonitor tells ConnectivityService that the network is
+        // unvalidated (causing a switch) before asking it to show the sign in notification. In this
+        // case, the toast won't show and we'll only display the sign in notification. This is the
+        // best we can do at this time.
+        boolean forceToast = fromNai.networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+
+        // Only show the notification once, in order to avoid irritating the user every time.
+        // TODO: should we do this?
+        if (everNotified(fromNai)) {
+            if (VDBG) {
+                Log.d(TAG, "Not notifying handover from " + fromNai.name() + ", already notified");
+            }
+            return;
+        }
+
+        // Only show the notification if we switched away because a network became unvalidated, not
+        // because its score changed.
+        // TODO: instead of just skipping notification, keep a note of it, and show it if it becomes
+        // unvalidated.
+        if (fromNai.lastValidated) return;
+
+        if (!isNotificationEnabled(fromNai, toNai)) return;
+
+        final long now = SystemClock.elapsedRealtime();
+        if (isRateLimited(now) || isAboveDailyLimit(now)) return;
+
+        notify(fromNai, toNai, forceToast);
+    }
+
+    public void noteDisconnect(NetworkAgentInfo nai) {
+        mNotifications.delete(nai.network.netId);
+        mEverNotified.delete(nai.network.netId);
+        maybeStopNotifying(nai);
+        // No need to cancel notifications on nai: NetworkMonitor does that on disconnect.
+    }
+
+    private boolean isRateLimited(long now) {
+        final long millisSinceLast = now - mLastNotificationMillis;
+        if (millisSinceLast < mRateLimitMillis) {
+            return true;
+        }
+        mLastNotificationMillis = now;
+        return false;
+    }
+
+    private boolean isAboveDailyLimit(long now) {
+        if (mFirstNotificationMillis == 0) {
+            mFirstNotificationMillis = now;
+        }
+        final long millisSinceFirst = now - mFirstNotificationMillis;
+        if (millisSinceFirst > DateUtils.DAY_IN_MILLIS) {
+            mNotificationCounter = 0;
+            mFirstNotificationMillis = 0;
+        }
+        if (mNotificationCounter >= mDailyLimit) {
+            return true;
+        }
+        mNotificationCounter++;
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 05f1a6e..1c9feb2 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -56,8 +56,6 @@
             if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
             publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
                     mBinder);
-            mDnsListener = new DnsEventListenerService(getContext());
-            publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
         }
     }
 
@@ -86,8 +84,6 @@
 
     private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
 
-    private DnsEventListenerService mDnsListener;
-
     private void enforceConnectivityInternalPermission() {
         getContext().enforceCallingOrSelfPermission(
                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
@@ -219,11 +215,6 @@
                     }
                 }
             }
-
-            pw.println();
-            if (mDnsListener != null) {
-                mDnsListener.dump(pw);
-            }
         }
 
         public long logEvent(ConnectivityMetricsEvent event) {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
new file mode 100644
index 0000000..e7198d3
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -0,0 +1,166 @@
+/*
+ * 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.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.metrics.DnsEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.INetdEventListener;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+
+/**
+ * Implementation of the INetdEventListener interface.
+ */
+public class NetdEventListenerService extends INetdEventListener.Stub {
+
+    public static final String SERVICE_NAME = "netd_listener";
+
+    private static final String TAG = NetdEventListenerService.class.getSimpleName();
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    // TODO: read this constant from system property
+    private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100;
+
+    // Stores the results of a number of consecutive DNS lookups on the same network.
+    // This class is not thread-safe and it is the responsibility of the service to call its methods
+    // on one thread at a time.
+    private class DnsEventBatch {
+        private final int mNetId;
+
+        private final byte[] mEventTypes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
+        private final byte[] mReturnCodes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
+        private final int[] mLatenciesMs = new int[MAX_LOOKUPS_PER_DNS_EVENT];
+        private int mEventCount;
+
+        public DnsEventBatch(int netId) {
+            mNetId = netId;
+        }
+
+        public void addResult(byte eventType, byte returnCode, int latencyMs) {
+            mEventTypes[mEventCount] = eventType;
+            mReturnCodes[mEventCount] = returnCode;
+            mLatenciesMs[mEventCount] = latencyMs;
+            mEventCount++;
+            if (mEventCount == MAX_LOOKUPS_PER_DNS_EVENT) {
+                logAndClear();
+            }
+        }
+
+        public void logAndClear() {
+            // Did we lose a race with addResult?
+            if (mEventCount == 0) {
+                return;
+            }
+
+            // Only log as many events as we actually have.
+            byte[] eventTypes = Arrays.copyOf(mEventTypes, mEventCount);
+            byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
+            int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
+            mMetricsLog.log(new DnsEvent(mNetId, eventTypes, returnCodes, latenciesMs));
+            maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
+            mEventCount = 0;
+        }
+
+        // For debugging and unit tests only.
+        public String toString() {
+            return String.format("%s %d %d", getClass().getSimpleName(), mNetId, mEventCount);
+        }
+    }
+
+    // Only sorted for ease of debugging. Because we only typically have a handful of networks up
+    // at any given time, performance is not a concern.
+    @GuardedBy("this")
+    private final SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>();
+
+    // We register a NetworkCallback to ensure that when a network disconnects, we flush the DNS
+    // queries we've logged on that network. Because we do not do this periodically, we might lose
+    // up to MAX_LOOKUPS_PER_DNS_EVENT lookup stats on each network when the system is shutting
+    // down. We believe this to be sufficient for now.
+    private final ConnectivityManager mCm;
+    private final IpConnectivityLog mMetricsLog;
+    private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+        @Override
+        public void onLost(Network network) {
+            synchronized (NetdEventListenerService.this) {
+                DnsEventBatch batch = mEventBatches.remove(network.netId);
+                if (batch != null) {
+                    batch.logAndClear();
+                }
+            }
+        }
+    };
+
+    public NetdEventListenerService(Context context) {
+        this(context.getSystemService(ConnectivityManager.class), new IpConnectivityLog());
+    }
+
+    @VisibleForTesting
+    public NetdEventListenerService(ConnectivityManager cm, IpConnectivityLog log) {
+        // We are started when boot is complete, so ConnectivityService should already be running.
+        mCm = cm;
+        mMetricsLog = log;
+        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        mCm.registerNetworkCallback(request, mNetworkCallback);
+    }
+
+    @Override
+    // Called concurrently by multiple binder threads.
+    public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs) {
+        maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
+                netId, eventType, returnCode, latencyMs));
+
+        DnsEventBatch batch = mEventBatches.get(netId);
+        if (batch == null) {
+            batch = new DnsEventBatch(netId);
+            mEventBatches.put(netId, batch);
+        }
+        batch.addResult((byte) eventType, (byte) returnCode, latencyMs);
+    }
+
+    public synchronized void dump(PrintWriter writer) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println(TAG + ":");
+        pw.increaseIndent();
+        for (DnsEventBatch batch : mEventBatches.values()) {
+            pw.println(batch.toString());
+        }
+        pw.decreaseIndent();
+    }
+
+    private static void maybeLog(String s) {
+        if (DBG) Log.d(TAG, s);
+    }
+
+    private static void maybeVerboseLog(String s) {
+        if (VDBG) Log.d(TAG, s);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 7a25df6..2a618bc 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -104,15 +104,18 @@
 // -----------------------------------------------
 // If a network has no chance of satisfying any requests (even if it were to become validated
 // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
-// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
-// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
-// highest scoring network for any NetworkRequest, then there will be a 30s pause before
-// ConnectivityService disconnects the NetworkAgent's AsyncChannel.  During this pause the
-// network is considered "lingering".  This pause exists to allow network communication to be
-// wrapped up rather than abruptly terminated.  During this pause if the network begins satisfying
-// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
-// AsyncChannel, and the network is no longer considered "lingering".
+//
+// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
+// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
+// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
+// wrapped up rather than abruptly terminated. During this pause the network is said to be
+// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
+// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
+// the network is no longer considered "lingering". After the linger timer expires, if the network
+// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
+// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
 public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
+
     public NetworkInfo networkInfo;
     // This Network object should always be used if possible, so as to encourage reuse of the
     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
@@ -137,12 +140,14 @@
     public boolean everValidated;
 
     // The result of the last validation attempt on this network (true if validated, false if not).
-    // This bit exists only because we never unvalidate a network once it's been validated, and that
-    // is because the network scoring and revalidation code does not (may not?) deal properly with
-    // networks becoming unvalidated.
-    // TODO: Fix the network scoring code, remove this, and rename everValidated to validated.
     public boolean lastValidated;
 
+    // If true, becoming unvalidated will lower the network's score. This is only meaningful if the
+    // system is configured not to do this for certain networks, e.g., if the
+    // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via
+    // Settings.Global.NETWORK_AVOID_BAD_WIFI.
+    public boolean avoidUnvalidated;
+
     // Whether a captive portal was ever detected on this network.
     // This is a sticky bit; once set it is never cleared.
     public boolean everCaptivePortalDetected;
@@ -227,11 +232,13 @@
 
     // The list of NetworkRequests being satisfied by this Network.
     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
-    // The list of NetworkRequests that this Network previously satisfied with the highest
-    // score.  A non-empty list indicates that if this Network was validated it is lingered.
+
     // How many of the satisfied requests are actual requests and not listens.
     private int mNumRequestNetworkRequests = 0;
 
+    // How many of the satisfied requests are of type BACKGROUND_REQUEST.
+    private int mNumBackgroundNetworkRequests = 0;
+
     public final Messenger messenger;
     public final AsyncChannel asyncChannel;
 
@@ -265,6 +272,32 @@
     //
     // These functions must only called on ConnectivityService's main thread.
 
+    private static final boolean ADD = true;
+    private static final boolean REMOVE = false;
+
+    private void updateRequestCounts(boolean add, NetworkRequest request) {
+        int delta = add ? +1 : -1;
+        switch (request.type) {
+            case REQUEST:
+            case TRACK_DEFAULT:
+                mNumRequestNetworkRequests += delta;
+                break;
+
+            case BACKGROUND_REQUEST:
+                mNumRequestNetworkRequests += delta;
+                mNumBackgroundNetworkRequests += delta;
+                break;
+
+            case LISTEN:
+                break;
+
+            case NONE:
+            default:
+                Log.wtf(TAG, "Unhandled request type " + request.type);
+                break;
+        }
+    }
+
     /**
      * Add {@code networkRequest} to this network as it's satisfied by this network.
      * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
@@ -273,9 +306,15 @@
     public boolean addRequest(NetworkRequest networkRequest) {
         NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
         if (existing == networkRequest) return false;
-        if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--;
+        if (existing != null) {
+            // Should only happen if the requestId wraps. If that happens lots of other things will
+            // be broken as well.
+            Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
+                    networkRequest, existing, name()));
+            updateRequestCounts(REMOVE, existing);
+        }
         mNetworkRequests.put(networkRequest.requestId, networkRequest);
-        if (networkRequest.isRequest()) mNumRequestNetworkRequests++;
+        updateRequestCounts(ADD, networkRequest);
         return true;
     }
 
@@ -285,9 +324,9 @@
     public void removeRequest(int requestId) {
         NetworkRequest existing = mNetworkRequests.get(requestId);
         if (existing == null) return;
+        updateRequestCounts(REMOVE, existing);
         mNetworkRequests.remove(requestId);
         if (existing.isRequest()) {
-            mNumRequestNetworkRequests--;
             unlingerRequest(existing);
         }
     }
@@ -316,12 +355,37 @@
     }
 
     /**
+     * Returns the number of requests currently satisfied by this network of type
+     * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}.
+     */
+    public int numBackgroundNetworkRequests() {
+        return mNumBackgroundNetworkRequests;
+    }
+
+    /**
+     * Returns the number of foreground requests currently satisfied by this network.
+     */
+    public int numForegroundNetworkRequests() {
+        return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests;
+    }
+
+    /**
      * Returns the number of requests of any type currently satisfied by this network.
      */
     public int numNetworkRequests() {
         return mNetworkRequests.size();
     }
 
+    /**
+     * Returns whether the network is a background network. A network is a background network if it
+     * is satisfying no foreground requests and at least one background request. (If it did not have
+     * a background request, it would be a speculative network that is only being kept up because
+     * it might satisfy a request if it validated).
+     */
+    public boolean isBackgroundNetwork() {
+        return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
+    }
+
     // Does this network satisfy request?
     public boolean satisfies(NetworkRequest request) {
         return created &&
@@ -354,16 +418,22 @@
         }
 
         int score = currentScore;
-        // Use NET_CAPABILITY_VALIDATED here instead of lastValidated, this allows
-        // ConnectivityService.updateCapabilities() to compute the old score prior to updating
-        // networkCapabilities (with a potentially different validated state).
-        if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) && !pretendValidated) {
+        if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
             score -= UNVALIDATED_SCORE_PENALTY;
         }
         if (score < 0) score = 0;
         return score;
     }
 
+    // Return true on devices configured to ignore score penalty for wifi networks
+    // that become unvalidated (b/31075769).
+    private boolean ignoreWifiUnvalidationPenalty() {
+        boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
+                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
+        return isWifi && !avoidBadWifi && everValidated;
+    }
+
     // Get the current score for this Network.  This may be modified from what the
     // NetworkAgent sent, as it has modifiers applied to it.
     public int getCurrentScore() {
@@ -411,14 +481,17 @@
 
     /**
      * Cancel lingering. Called by ConnectivityService when a request is added to this network.
+     * Returns true if the given request was lingering on this network, false otherwise.
      */
-    public void unlingerRequest(NetworkRequest request) {
+    public boolean unlingerRequest(NetworkRequest request) {
         LingerTimer timer = mLingerTimerForRequest.get(request.requestId);
         if (timer != null) {
             if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + this.name());
             mLingerTimers.remove(timer);
             mLingerTimerForRequest.remove(request.requestId);
+            return true;
         }
+        return false;
     }
 
     public long getLingerExpiry() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 42d80fc..6eb89fa 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -23,7 +23,6 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -37,14 +36,12 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.metrics.ValidationProbeEvent;
+import android.net.util.Stopwatch;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.util.Stopwatch;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Process;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.CellIdentityCdma;
@@ -66,27 +63,39 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.internal.util.WakeupMessage;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
-import java.net.UnknownHostException;
 import java.net.URL;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
+import java.net.UnknownHostException;
 import java.util.List;
 import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * {@hide}
  */
 public class NetworkMonitor extends StateMachine {
-    private static final boolean DBG = false;
     private static final String TAG = NetworkMonitor.class.getSimpleName();
-    private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
+    private static final boolean DBG = false;
+
+    // Default configuration values for captive portal detection probes.
+    // TODO: append a random length parameter to the default HTTPS url.
+    // TODO: randomize browser version ids in the default User-Agent String.
+    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
+    private static final String DEFAULT_HTTP_URL      =
+            "http://connectivitycheck.gstatic.com/generate_204";
+    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
+    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
+                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
+                                                      + "Chrome/52.0.2743.82 Safari/537.36";
+
     private static final int SOCKET_TIMEOUT_MS = 10000;
+    private static final int PROBE_TIMEOUT_MS  = 3000;
+
     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
             "android.net.conn.NETWORK_CONDITIONS_MEASURED";
     public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
@@ -224,6 +233,9 @@
 
     private final Stopwatch mEvaluationTimer = new Stopwatch();
 
+    // This variable is set before transitioning to the mCaptivePortalState.
+    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
+
     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
             NetworkRequest defaultRequest) {
         this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog());
@@ -389,6 +401,8 @@
                                     sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
                                 }
                             }));
+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
+                            mLastPortalProbeResult.detectUrl);
                     intent.setFlags(
                             Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -412,14 +426,22 @@
      */
     @VisibleForTesting
     public static final class CaptivePortalProbeResult {
-        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599, null);
+        static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599);
 
-        final int mHttpResponseCode; // HTTP response code returned from Internet probe.
-        final String mRedirectUrl;   // Redirect destination returned from Internet probe.
+        private final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
+        final String redirectUrl;             // Redirect destination returned from Internet probe.
+        final String detectUrl;               // URL where a 204 response code indicates
+                                              // captive portal has been appeased.
 
-        public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) {
+        public CaptivePortalProbeResult(
+                int httpResponseCode, String redirectUrl, String detectUrl) {
             mHttpResponseCode = httpResponseCode;
-            mRedirectUrl = redirectUrl;
+            this.redirectUrl = redirectUrl;
+            this.detectUrl = detectUrl;
+        }
+
+        public CaptivePortalProbeResult(int httpResponseCode) {
+            this(httpResponseCode, null, null);
         }
 
         boolean isSuccessful() { return mHttpResponseCode == 204; }
@@ -492,7 +514,8 @@
                         transitionTo(mValidatedState);
                     } else if (probeResult.isPortal()) {
                         mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
+                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
+                        mLastPortalProbeResult = probeResult;
                         transitionTo(mCaptivePortalState);
                     } else {
                         final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
@@ -500,7 +523,7 @@
                         logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
                         mConnectivityServiceHandler.sendMessage(obtainMessage(
                                 EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
-                                probeResult.mRedirectUrl));
+                                probeResult.redirectUrl));
                         if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
                             // Don't continue to blame UID forever.
                             TrafficStats.clearThreadStatsUid();
@@ -585,22 +608,33 @@
         }
     }
 
-    private static String getCaptivePortalServerUrl(Context context, boolean isHttps) {
-        String server = Settings.Global.getString(context.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_SERVER);
-        if (server == null) server = DEFAULT_SERVER;
-        return (isHttps ? "https" : "http") + "://" + server + "/generate_204";
+    private static String getCaptivePortalServerHttpsUrl(Context context) {
+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
     }
 
-    public static String getCaptivePortalServerUrl(Context context) {
-        return getCaptivePortalServerUrl(context, false);
+    public static String getCaptivePortalServerHttpUrl(Context context) {
+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
+    }
+
+    private static String getCaptivePortalFallbackUrl(Context context) {
+        return getSetting(context,
+                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
+    }
+
+    private static String getCaptivePortalUserAgent(Context context) {
+        return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+    }
+
+    private static String getSetting(Context context, String symbol, String defaultValue) {
+        final String value = Settings.Global.getString(context.getContentResolver(), symbol);
+        return value != null ? value : defaultValue;
     }
 
     @VisibleForTesting
     protected CaptivePortalProbeResult isCaptivePortal() {
-        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null);
+        if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
 
-        URL pacUrl = null, httpUrl = null, httpsUrl = null;
+        URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
 
         // On networks with a PAC instead of fetching a URL that should result in a 204
         // response, we instead simply fetch the PAC script.  This is done for a few reasons:
@@ -621,20 +655,17 @@
         //    results for network validation.
         final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
         if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
-            try {
-                pacUrl = new URL(proxyInfo.getPacFileUrl().toString());
-            } catch (MalformedURLException e) {
-                validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString());
+            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
+            if (pacUrl == null) {
                 return CaptivePortalProbeResult.FAILED;
             }
         }
 
         if (pacUrl == null) {
-            try {
-                httpUrl = new URL(getCaptivePortalServerUrl(mContext, false));
-                httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true));
-            } catch (MalformedURLException e) {
-                validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false));
+            httpsUrl = makeURL(getCaptivePortalServerHttpsUrl(mContext));
+            httpUrl = makeURL(getCaptivePortalServerHttpUrl(mContext));
+            fallbackUrl = makeURL(getCaptivePortalFallbackUrl(mContext));
+            if (httpUrl == null || httpsUrl == null) {
                 return CaptivePortalProbeResult.FAILED;
             }
         }
@@ -680,7 +711,7 @@
         if (pacUrl != null) {
             result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
         } else if (mUseHttps) {
-            result = sendParallelHttpProbes(httpsUrl, httpUrl);
+            result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
         } else {
             result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
         }
@@ -710,6 +741,10 @@
             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setUseCaches(false);
+            final String userAgent = getCaptivePortalUserAgent(mContext);
+            if (userAgent != null) {
+               urlConnection.setRequestProperty("User-Agent", userAgent);
+            }
 
             // Time how long it takes to get a response to our request
             long requestTimestamp = SystemClock.elapsedRealtime();
@@ -755,28 +790,24 @@
             }
         }
         logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
-        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
+        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
     }
 
-    private CaptivePortalProbeResult sendParallelHttpProbes(URL httpsUrl, URL httpUrl) {
-        // Number of probes to wait for. We might wait for all of them, but we might also return if
-        // only one of them has replied. For example, we immediately return if the HTTP probe finds
-        // a captive portal, even if the HTTPS probe is timing out.
+    private CaptivePortalProbeResult sendParallelHttpProbes(
+            URL httpsUrl, URL httpUrl, URL fallbackUrl) {
+        // Number of probes to wait for. If a probe completes with a conclusive answer
+        // it shortcuts the latch immediately by forcing the count to 0.
         final CountDownLatch latch = new CountDownLatch(2);
 
-        // Which probe result we're going to use. This doesn't need to be atomic, but it does need
-        // to be final because otherwise we can't set it from the ProbeThreads.
-        final AtomicReference<CaptivePortalProbeResult> finalResult = new AtomicReference<>();
-
         final class ProbeThread extends Thread {
             private final boolean mIsHttps;
-            private volatile CaptivePortalProbeResult mResult;
+            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
 
             public ProbeThread(boolean isHttps) {
                 mIsHttps = isHttps;
             }
 
-            public CaptivePortalProbeResult getResult() {
+            public CaptivePortalProbeResult result() {
                 return mResult;
             }
 
@@ -788,32 +819,66 @@
                     mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
                 }
                 if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
-                    // HTTPS succeeded, or HTTP found a portal. Don't wait for the other probe.
-                    finalResult.compareAndSet(null, mResult);
-                    latch.countDown();
+                    // Stop waiting immediately if https succeeds or if http finds a portal.
+                    while (latch.getCount() > 0) {
+                        latch.countDown();
+                    }
                 }
-                // Signal that one probe has completed. If we've already made a decision, or if this
-                // is the second probe, the latch will be at zero and we'll return a result.
+                // Signal this probe has completed.
                 latch.countDown();
             }
         }
 
-        ProbeThread httpsProbe = new ProbeThread(true);
-        ProbeThread httpProbe = new ProbeThread(false);
-        httpsProbe.start();
-        httpProbe.start();
+        final ProbeThread httpsProbe = new ProbeThread(true);
+        final ProbeThread httpProbe = new ProbeThread(false);
 
         try {
-            latch.await();
+            httpsProbe.start();
+            httpProbe.start();
+            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
-            validationLog("Error: probe wait interrupted!");
+            validationLog("Error: probes wait interrupted!");
             return CaptivePortalProbeResult.FAILED;
         }
 
-        // If there was no deciding probe, that means that both probes completed. Return HTTPS.
-        finalResult.compareAndSet(null, httpsProbe.getResult());
+        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
+        final CaptivePortalProbeResult httpResult = httpProbe.result();
 
-        return finalResult.get();
+        // Look for a conclusive probe result first.
+        if (httpResult.isPortal()) {
+            return httpResult;
+        }
+        // httpsResult.isPortal() is not expected, but check it nonetheless.
+        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
+            return httpsResult;
+        }
+        // If a fallback url is specified, use a fallback probe to try again portal detection.
+        if (fallbackUrl != null) {
+            CaptivePortalProbeResult result =
+                    sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK);
+            if (result.isPortal()) {
+                return result;
+            }
+        }
+        // Otherwise wait until https probe completes and use its result.
+        try {
+            httpsProbe.join();
+        } catch (InterruptedException e) {
+            validationLog("Error: https probe wait interrupted!");
+            return CaptivePortalProbeResult.FAILED;
+        }
+        return httpsProbe.result();
+    }
+
+    private URL makeURL(String url) {
+        if (url != null) {
+            try {
+                return new URL(url);
+            } catch (MalformedURLException e) {
+                validationLog("Bad URL: " + url);
+            }
+        }
+        return null;
     }
 
     /**
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..f7b01be
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -0,0 +1,225 @@
+/*
+ * 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.widget.Toast;
+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, LOST_INTERNET, NETWORK_SWITCH };
+
+    private static final String NOTIFICATION_ID = "Connectivity.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.
+     * @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
+     *         or LOST_INTERNET notification, this is the network we're connecting to. For a
+     *         NETWORK_SWITCH notification it's the network that we switched from. When this network
+     *         disconnects the notification is removed.
+     * @param switchToNai for a NETWORK_SWITCH notification, the network we are switching to. Null
+     *         in all other cases. Only used to determine the text of the notification.
+     */
+    public void showNotification(int id, NotificationType notifyType, NetworkAgentInfo nai,
+            NetworkAgentInfo switchToNai, 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.LOST_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 if (notifyType == NotificationType.NETWORK_SWITCH) {
+            String fromTransport = getTransportName(transportType);
+            String toTransport = getTransportName(getFirstTransportType(switchToNai));
+            title = r.getString(R.string.network_switch_metered, toTransport);
+            details = r.getString(R.string.network_switch_metered_detail, toTransport,
+                    fromTransport);
+        } else {
+            Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network transport "
+                    + getTransportName(transportType));
+            return;
+        }
+
+        Notification.Builder builder = new Notification.Builder(mContext)
+                .setWhen(System.currentTimeMillis())
+                .setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
+                .setSmallIcon(icon)
+                .setAutoCancel(true)
+                .setTicker(title)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentIntent(intent)
+                .setLocalOnly(true)
+                .setPriority(highPriority ?
+                        Notification.PRIORITY_HIGH :
+                        Notification.PRIORITY_DEFAULT)
+                .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
+                .setOnlyAlertOnce(true);
+
+        if (notifyType == NotificationType.NETWORK_SWITCH) {
+            builder.setStyle(new Notification.BigTextStyle().bigText(details));
+        } else {
+            builder.setContentText(details);
+        }
+
+        Notification notification = builder.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, null, pendingIntent, false);
+        } else {
+            clearNotification(id);
+        }
+    }
+
+    public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+        String fromTransport = getTransportName(getFirstTransportType(fromNai));
+        String toTransport = getTransportName(getFirstTransportType(toNai));
+        String text = mContext.getResources().getString(
+                R.string.network_switch_metered_toast, fromTransport, toTransport);
+        Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 7d1da01..58c76ec 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -27,6 +27,7 @@
 import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -39,10 +40,10 @@
 import com.android.net.IProxyCallback;
 import com.android.net.IProxyPortListener;
 import com.android.net.IProxyService;
-import com.android.server.IoThread;
 
 import libcore.io.Streams;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -66,6 +67,7 @@
     private static final int DELAY_1 = 0;
     private static final int DELAY_4 = 3;
     private static final int DELAY_LONG = 4;
+    private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
     /** Keep these values up-to-date with ProxyService.java */
     public static final String KEY_PROXY = "keyProxy";
@@ -123,15 +125,21 @@
         }
     };
 
+    private final HandlerThread mNetThread = new HandlerThread("android.pacmanager",
+            android.os.Process.THREAD_PRIORITY_DEFAULT);
+    private final Handler mNetThreadHandler;
+
     class PacRefreshIntentReceiver extends BroadcastReceiver {
         public void onReceive(Context context, Intent intent) {
-            IoThread.getHandler().post(mPacDownloader);
+            mNetThreadHandler.post(mPacDownloader);
         }
     }
 
     public PacManager(Context context, Handler handler, int proxyMessage) {
         mContext = context;
         mLastPort = -1;
+        mNetThread.start();
+        mNetThreadHandler = new Handler(mNetThread.getLooper());
 
         mPacRefreshIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_PAC_REFRESH), 0);
@@ -199,7 +207,25 @@
     private static String get(Uri pacUri) throws IOException {
         URL url = new URL(pacUri.toString());
         URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
-        return new String(Streams.readFully(urlConnection.getInputStream()));
+        long contentLength = -1;
+        try {
+            contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));
+        } catch (NumberFormatException e) {
+            // Ignore
+        }
+        if (contentLength > MAX_PAC_SIZE) {
+            throw new IOException("PAC too big: " + contentLength + " bytes");
+        }
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = urlConnection.getInputStream().read(buffer)) != -1) {
+            bytes.write(buffer, 0, count);
+            if (bytes.size() > MAX_PAC_SIZE) {
+                throw new IOException("PAC too big");
+            }
+        }
+        return bytes.toString();
     }
 
     private int getNextDelay(int currentDelay) {
@@ -267,7 +293,7 @@
         intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
         if ((mProxyConnection != null) && (mConnection != null)) {
             // Already bound no need to bind again, just download the new file.
-            IoThread.getHandler().post(mPacDownloader);
+            mNetThreadHandler.post(mPacDownloader);
             return;
         }
         mConnection = new ServiceConnection() {
@@ -297,7 +323,7 @@
                         } catch (RemoteException e) {
                             Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e);
                         }
-                        IoThread.getHandler().post(mPacDownloader);
+                        mNetThreadHandler.post(mPacDownloader);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index e0d8373..50faf3b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -33,6 +33,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
 import android.net.Network;
@@ -49,6 +50,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -123,6 +125,7 @@
 
     private final INetworkManagementService mNMService;
     private final INetworkStatsService mStatsService;
+    private final INetworkPolicyManager mPolicyManager;
     private final Looper mLooper;
 
     private static class TetherState {
@@ -177,10 +180,11 @@
     private boolean mWifiTetherRequested;
 
     public Tethering(Context context, INetworkManagementService nmService,
-            INetworkStatsService statsService) {
+            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         mContext = context;
         mNMService = nmService;
         mStatsService = statsService;
+        mPolicyManager = policyManager;
 
         mPublicSync = new Object();
 
@@ -622,12 +626,9 @@
     }
 
     public void untetherAll() {
-        synchronized (mPublicSync) {
-            if (DBG) Log.d(TAG, "Untethering " + mTetherStates.keySet());
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                untether(mTetherStates.keyAt(i));
-            }
-        }
+        stopTethering(ConnectivityManager.TETHERING_WIFI);
+        stopTethering(ConnectivityManager.TETHERING_USB);
+        stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
     }
 
     public int getLastTetherError(String iface) {
@@ -1616,6 +1617,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 +1625,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 +1664,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 +1694,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;
@@ -1902,6 +1909,15 @@
                     " with error " + error);
         }
 
+        try {
+            // Notify that we're tethering (or not) this interface.
+            // This is how data saver for instance knows if the user explicitly
+            // turned on tethering (thus keeping us from being in data saver mode).
+            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
+        } catch (RemoteException e) {
+            // Not really very much we can do here.
+        }
+
         switch (state) {
             case IControlsTethering.STATE_UNAVAILABLE:
             case IControlsTethering.STATE_AVAILABLE:
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..c2c1a8c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -25,7 +25,9 @@
 import android.net.RouteInfo;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.net.util.NetdService;
 import android.os.INetworkManagementService;
+import android.os.ServiceSpecificException;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Slog;
@@ -192,7 +194,7 @@
 
     private void configureLocalDns(
             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
-        INetd netd = getNetdServiceOrNull();
+        final INetd netd = NetdService.getInstance();
         if (netd == null) {
             if (newDnses != null) newDnses.clear();
             Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
@@ -205,7 +207,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 +224,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 +233,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();
         }
@@ -264,18 +266,6 @@
         return localRoutes;
     }
 
-    private INetd getNetdServiceOrNull() {
-        if (mNMService != null) {
-            try {
-                return mNMService.getNetdService();
-            } catch (RemoteException ignored) {
-                // This blocks until netd can be reached, but it can return
-                // null during a netd crash.
-            }
-        }
-        return null;
-    }
-
     // Given a prefix like 2001:db8::/64 return 2001:db8::1.
     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
         final byte[] dnsBytes = localPrefix.getRawAddress();
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 9e7cb93..6ca4e27 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -141,10 +141,17 @@
             if (ifcg != null) {
                 InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
                 ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
-                if (enabled) {
-                    ifcg.setInterfaceUp();
+                if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
+                    // The WiFi stack has ownership of the interface up/down state.
+                    // It is unclear whether the bluetooth or USB stacks will manage their own
+                    // state.
+                    ifcg.ignoreInterfaceUpDownStatus();
                 } else {
-                    ifcg.setInterfaceDown();
+                    if (enabled) {
+                        ifcg.setInterfaceUp();
+                    } else {
+                        ifcg.setInterfaceDown();
+                    }
                 }
                 ifcg.clearFlag("running");
                 mNMService.setInterfaceConfig(mIfaceName, ifcg);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 01b2393..4e236d1 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -482,8 +482,7 @@
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
                 syncManager.scheduleSync(account, userId, uId, authority, extras,
-                        0 /* no delay */, 0 /* no delay */,
-                        false /* onlyThoseWithUnkownSyncableState */);
+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -547,12 +546,9 @@
                 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 */);
+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -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..2d6bef4 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;
@@ -47,6 +48,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ProviderInfo;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
@@ -64,6 +66,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 +82,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 +137,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 +200,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 +321,12 @@
 
     private final UserManager mUserManager;
 
+    private final AccountManager mAccountManager;
+
+    private final AccountManagerInternal mAccountManagerInternal;
+
+    private final PackageManagerInternal mPackageManagerInternal;
+
     private List<UserInfo> getAllUsers() {
         return mUserManager.getUsers();
     }
@@ -490,9 +507,7 @@
             @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);
+                        AuthorityInfo.UNDEFINED);
             }
         });
 
@@ -522,8 +537,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, AuthorityInfo.UNDEFINED);
                 }
             }
         }, mSyncHandler);
@@ -562,6 +576,19 @@
         }
         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);
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+        mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
+            // If the UID gained access to the account kick-off syncs lacking account access
+            if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
+                scheduleSync(account, UserHandle.getUserId(uid),
+                        SyncOperation.REASON_ACCOUNTS_UPDATED,
+                        null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS);
+            }
+        });
+
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                 BatteryStats.SERVICE_NAME));
 
@@ -631,6 +658,37 @@
                 mContext.startService(startServiceIntent);
             }
         });
+
+        // Sync adapters were able to access the synced account without the accounts
+        // permission which circumvents our permission model. Therefore, we require
+        // sync adapters that don't have access to the account to get user consent.
+        // This can be noisy, therefore we will white-list sync adapters installed
+        // before we started checking for account access because they already know
+        // the account (they run before) which is the genie is out of the bottle.
+        whiteListExistingSyncAdaptersIfNeeded();
+    }
+
+    private void whiteListExistingSyncAdaptersIfNeeded() {
+        if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
+            return;
+        }
+        List<UserInfo> users = mUserManager.getUsers(true);
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            UserHandle userHandle = users.get(i).getUserHandle();
+            final int userId = userHandle.getIdentifier();
+            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
+                    : mSyncAdapters.getAllServices(userId)) {
+                String packageName = service.componentName.getPackageName();
+                for (Account account : mAccountManager.getAccountsByTypeAsUser(
+                        service.type.accountType, userHandle)) {
+                    if (!canAccessAccount(account, packageName, userId)) {
+                        mAccountManager.updateAppPermission(account,
+                                AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
+                    }
+                }
+            }
+        }
     }
 
     private boolean isDeviceProvisioned() {
@@ -655,7 +713,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 +724,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 +791,11 @@
      * @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.
+     * @param targetSyncState Only sync authorities that have the specified sync state.
+     *           Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
-            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, int targetSyncState) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -749,17 +805,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 +874,45 @@
             }
 
             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");
+
+                if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
+                    if (isLoggable) {
+                        Slog.v(TAG, "    Not scheduling sync operation: "
+                                + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
+                    }
+                    Bundle finalExtras = new Bundle(extras);
+                    String packageName = syncAdapterInfo.componentName.getPackageName();
+                    // If the app did not run and has no account access, done
+                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
                         continue;
                     }
-                } catch (RemoteException e) {
+                    mAccountManagerInternal.requestAccountAccess(account.account,
+                            packageName, userId,
+                            new RemoteCallback((Bundle result) -> {
+                                if (result != null
+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+                                    scheduleSync(account.account, userId, reason, authority,
+                                            finalExtras, targetSyncState);
+                                }
+                            }
+                        ));
+                    continue;
                 }
+
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
                 if (isSyncable < 0 && isAlwaysSyncable) {
@@ -838,9 +920,11 @@
                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
                     isSyncable = AuthorityInfo.SYNCABLE;
                 }
-                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+
+                if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
                     continue;
                 }
+
                 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
                     continue;
                 }
@@ -863,7 +947,10 @@
                                 account.account, authority, account.userId);
                 long delayUntil =
                         mSyncStorageEngine.getDelayUntilTime(info);
-                if (isSyncable < 0) {
+
+                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
+
+                if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
                     // Initialisation sync.
                     Bundle newExtras = new Bundle();
                     newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
@@ -882,13 +969,11 @@
                                     owningUid, owningPackage, reason, source,
                                     authority, newExtras, allowParallelSyncs)
                     );
-                }
-                if (!onlyThoseWithUnkownSyncableState) {
+                } else if (targetSyncState == AuthorityInfo.UNDEFINED
+                        || targetSyncState == isSyncable) {
                     if (isLoggable) {
                         Slog.v(TAG, "scheduleSync:"
                                 + " delay until " + delayUntil
-                                + " run by " + runtimeMillis
-                                + " flexMillis " + beforeRuntimeMillis
                                 + ", source " + source
                                 + ", account " + account
                                 + ", authority " + authority
@@ -904,6 +989,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,9 +1095,7 @@
         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 */);
+                AuthorityInfo.UNDEFINED);
     }
 
     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1421,8 +1554,7 @@
                 mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    0 /* no delay */, 0 /* No flexMillis */,
-                    true /* onlyThoseWithUnknownSyncableState */);
+                    AuthorityInfo.NOT_INITIALIZED);
         }
     }
 
@@ -2530,13 +2662,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 +2733,8 @@
 
             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, AuthorityInfo.NOT_INITIALIZED);
             }
         }
 
@@ -2665,6 +2802,31 @@
                     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: {
+                    String packageName = op.owningPackage;
+                    final int userId = UserHandle.getUserId(op.owningUid);
+                    // If the app did not run and has no account access, done
+                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+                        return;
+                    }
+                    mAccountManagerInternal.requestAccountAccess(op.target.account,
+                            packageName, userId, 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 +2887,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.NOT_SYNCABLE) {
+                if (isLoggable) {
+                    Slog.v(TAG, "    Dropping sync operation: isSyncable == NOT_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 +2931,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..069ae73 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -137,7 +137,7 @@
     private static final boolean SYNC_ENABLED_DEFAULT = false;
 
     // the version of the accounts xml file format
-    private static final int ACCOUNTS_VERSION = 2;
+    private static final int ACCOUNTS_VERSION = 3;
 
     private static HashMap<String, String> sAuthorityRenames;
     private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
@@ -211,6 +211,12 @@
 
     public static class AuthorityInfo {
         // Legal values of getIsSyncable
+
+        /**
+         * The syncable state is undefined.
+         */
+        public static final int UNDEFINED = -2;
+
         /**
          * Default state for a newly installed adapter. An uninitialized adapter will receive an
          * initialization sync which are governed by a different set of rules to that of regular
@@ -234,6 +240,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;
@@ -402,6 +414,8 @@
     private OnSyncRequestListener mSyncRequestListener;
     private OnAuthorityRemovedListener mAuthorityRemovedListener;
 
+    private boolean mGrantSyncAdaptersAccountAccess;
+
     private SyncStorageEngine(Context context, File dataDir) {
         mContext = context;
         sSyncStorageEngine = this;
@@ -1404,6 +1418,10 @@
         }
     }
 
+    public boolean shouldGrantSyncAdaptersAccountAccess() {
+        return mGrantSyncAdaptersAccountAccess;
+    }
+
     /**
      * public for testing
      */
@@ -1458,6 +1476,11 @@
                 } catch (NumberFormatException e) {
                     version = 0;
                 }
+
+                if (version < 3) {
+                    mGrantSyncAdaptersAccountAccess = true;
+                }
+
                 String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
                 try {
                     int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
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/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index a16fcd2..2541050 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -547,6 +547,11 @@
                 logEglError("eglChooseConfig");
                 return false;
             }
+            if (numEglConfigs[0] <= 0) {
+                Slog.e(TAG, "no valid config found");
+                return false;
+            }
+
             mEglConfig = eglConfigs[0];
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0abd2e7..971989b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1402,6 +1402,9 @@
                 throw new IllegalArgumentException("width, height, and densityDpi must be "
                         + "greater than 0");
             }
+            if (surface != null && surface.isSingleBuffered()) {
+                throw new IllegalArgumentException("Surface can't be single-buffered");
+            }
 
             if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
                 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
@@ -1460,6 +1463,9 @@
 
         @Override // Binder call
         public void setVirtualDisplaySurface(IVirtualDisplayCallback callback, Surface surface) {
+            if (surface != null && surface.isSingleBuffered()) {
+                throw new IllegalArgumentException("Surface can't be single-buffered");
+            }
             final long token = Binder.clearCallingIdentity();
             try {
                 setVirtualDisplaySurfaceInternal(callback.asBinder(), surface);
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..0ec48b9 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -33,8 +33,11 @@
 import android.opengl.Matrix;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
 import android.util.MathUtils;
 import android.util.Slog;
 import android.view.animation.AnimationUtils;
@@ -44,7 +47,9 @@
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
+import com.android.server.vr.VrManagerService;
 
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.Calendar;
 import java.util.TimeZone;
 
@@ -83,6 +88,31 @@
     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
 
     private final Handler mHandler;
+    private final AtomicBoolean mIgnoreAllColorMatrixChanges = new AtomicBoolean();
+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+        @Override
+        public void onVrStateChanged(final boolean enabled) {
+            // Turn off all night mode display stuff while device is in VR mode.
+            mIgnoreAllColorMatrixChanges.set(enabled);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    // Cancel in-progress animations
+                    if (mColorMatrixAnimator != null) {
+                        mColorMatrixAnimator.cancel();
+                    }
+
+                    final DisplayTransformManager dtm =
+                            getLocalService(DisplayTransformManager.class);
+                    if (enabled) {
+                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_IDENTITY);
+                    } else if (mController.isActivated()) {
+                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, MATRIX_NIGHT);
+                    }
+                }
+            });
+        }
+    };
 
     private int mCurrentUser = UserHandle.USER_NULL;
     private ContentObserver mUserSetupObserver;
@@ -105,7 +135,17 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_BOOT_COMPLETED) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            IVrManager vrManager =
+                    (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
+            if (vrManager != null) {
+                try {
+                    vrManager.registerListener(mVrStateCallbacks);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+                }
+            }
+        } else if (phase == PHASE_BOOT_COMPLETED) {
             mBootCompleted = true;
 
             // Register listeners now that boot is complete.
@@ -182,6 +222,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 +238,8 @@
     }
 
     private void tearDown() {
+        Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
+
         if (mController != null) {
             mController.setListener(null);
             mController = null;
@@ -230,6 +274,11 @@
                 mColorMatrixAnimator.cancel();
             }
 
+            // Don't do any color matrix change animations if we are ignoring them anyway.
+            if (mIgnoreAllColorMatrixChanges.get()) {
+                return;
+            }
+
             final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
             final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
             final float[] to = mIsActivated ? MATRIX_NIGHT : null;
@@ -273,6 +322,8 @@
 
     @Override
     public void onAutoModeChanged(int autoMode) {
+        Slog.d(TAG, "onAutoModeChanged: autoMode=" + autoMode);
+
         if (mAutoMode != null) {
             mAutoMode.onStop();
             mAutoMode = null;
@@ -291,6 +342,8 @@
 
     @Override
     public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomStartTimeChanged(startTime);
         }
@@ -298,6 +351,8 @@
 
     @Override
     public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomEndTimeChanged(endTime);
         }
@@ -419,7 +474,7 @@
 
         @Override
         public void onAlarm() {
-            if (DEBUG) Slog.d(TAG, "onAlarm");
+            Slog.d(TAG, "onAlarm");
             updateActivated();
         }
     }
@@ -477,7 +532,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/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index a633996..3072f43 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -24,8 +24,11 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.IBinder.DeathRecipient;
 import android.os.SystemClock;
@@ -116,19 +119,19 @@
     }
 
     public void startDream(Binder token, ComponentName name,
-            boolean isTest, boolean canDoze, int userId) {
+            boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
         stopDream(true /*immediate*/);
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
         try {
-            // Close the notification shade. Don't need to send to all, but better to be explicit.
+            // Close the notification shade. No need to send to all, but better to be explicit.
             mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
 
             Slog.i(TAG, "Starting dream: name=" + name
                     + ", isTest=" + isTest + ", canDoze=" + canDoze
                     + ", userId=" + userId);
 
-            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
+            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
 
             mDreamStartTime = SystemClock.elapsedRealtime();
             MetricsLogger.visible(mContext,
@@ -230,6 +233,7 @@
             if (oldDream.mBound) {
                 mContext.unbindService(oldDream);
             }
+            oldDream.releaseWakeLockIfNeeded();
 
             try {
                 mIWindowManager.removeWindowToken(oldDream.mToken);
@@ -251,7 +255,8 @@
     private void attach(IDreamService service) {
         try {
             service.asBinder().linkToDeath(mCurrentDream, 0);
-            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
+            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
+                    mCurrentDream.mDreamingStartedCallback);
         } catch (RemoteException ex) {
             Slog.e(TAG, "The dream service died unexpectedly.", ex);
             stopDream(true /*immediate*/);
@@ -280,6 +285,7 @@
         public final boolean mCanDoze;
         public final int mUserId;
 
+        public PowerManager.WakeLock mWakeLock;
         public boolean mBound;
         public boolean mConnected;
         public IDreamService mService;
@@ -288,12 +294,17 @@
         public boolean mWakingGently;
 
         public DreamRecord(Binder token, ComponentName name,
-                boolean isTest, boolean canDoze, int userId) {
+                boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
             mToken = token;
             mName = name;
             mIsTest = isTest;
             mCanDoze = canDoze;
             mUserId  = userId;
+            mWakeLock = wakeLock;
+            // Hold the lock while we're waiting for the service to connect and start dreaming.
+            // Released after the service has started dreaming, we stop dreaming, or it timed out.
+            mWakeLock.acquire();
+            mHandler.postDelayed(mReleaseWakeLockIfNeeded, 10000);
         }
 
         // May be called on any thread.
@@ -319,6 +330,9 @@
                     mConnected = true;
                     if (mCurrentDream == DreamRecord.this && mService == null) {
                         attach(IDreamService.Stub.asInterface(service));
+                        // Wake lock will be released once dreaming starts.
+                    } else {
+                        releaseWakeLockIfNeeded();
                     }
                 }
             });
@@ -337,5 +351,23 @@
                 }
             });
         }
+
+        void releaseWakeLockIfNeeded() {
+            if (mWakeLock != null) {
+                mWakeLock.release();
+                mWakeLock = null;
+                mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
+            }
+        }
+
+        final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;
+
+        final IRemoteCallback mDreamingStartedCallback = new IRemoteCallback.Stub() {
+            // May be called on any thread.
+            @Override
+            public void sendResult(Bundle data) throws RemoteException {
+                mHandler.post(mReleaseWakeLockIfNeeded);
+            }
+        };
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index a783fa2..20bccf1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -370,12 +370,10 @@
         mCurrentDreamCanDoze = canDoze;
         mCurrentDreamUserId = userId;
 
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mController.startDream(newToken, name, isTest, canDoze, userId);
-            }
-        });
+        PowerManager.WakeLock wakeLock = mPowerManager
+                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
+        mHandler.post(wakeLock.wrap(
+                () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
     }
 
     private void stopDreamLocked(final boolean immediate) {
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
new file mode 100644
index 0000000..cca9f10
--- /dev/null
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -0,0 +1,312 @@
+/*
+ * 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.emergency;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A service that listens to connectivity and SIM card changes and determines if the emergency mode
+ * should be enabled
+ */
+public class EmergencyAffordanceService extends SystemService {
+
+    private static final String TAG = "EmergencyAffordanceService";
+
+    private static final int NUM_SCANS_UNTIL_ABORT = 4;
+
+    private static final int INITIALIZE_STATE = 1;
+    private static final int CELL_INFO_STATE_CHANGED = 2;
+    private static final int SUBSCRIPTION_CHANGED = 3;
+
+    /**
+     * Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
+     * requires the emergency affordance. The value is a boolean (1 or 0).
+     * @hide
+     */
+    private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
+
+    private final Context mContext;
+    private final ArrayList<Integer> mEmergencyCallMccNumbers;
+
+    private final Object mLock = new Object();
+
+    private TelephonyManager mTelephonyManager;
+    private SubscriptionManager mSubscriptionManager;
+    private boolean mEmergencyAffordanceNeeded;
+    private MyHandler mHandler;
+    private int mScansCompleted;
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onCellInfoChanged(List<CellInfo> cellInfo) {
+            if (!isEmergencyAffordanceNeeded()) {
+                requestCellScan();
+            }
+        }
+
+        @Override
+        public void onCellLocationChanged(CellLocation location) {
+            if (!isEmergencyAffordanceNeeded()) {
+                requestCellScan();
+            }
+        }
+    };
+    private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Settings.Global.getInt(context.getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
+                startScanning();
+                requestCellScan();
+            }
+        }
+    };
+    private boolean mSimNeedsEmergencyAffordance;
+    private boolean mNetworkNeedsEmergencyAffordance;
+
+    private void requestCellScan() {
+        mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
+    }
+
+    private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
+            = new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
+        }
+    };
+
+    public EmergencyAffordanceService(Context context) {
+        super(context);
+        mContext = context;
+        int[] numbers = context.getResources().getIntArray(
+                com.android.internal.R.array.config_emergency_mcc_codes);
+        mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
+        for (int i = 0; i < numbers.length; i++) {
+            mEmergencyCallMccNumbers.add(numbers[i]);
+        }
+    }
+
+    private void updateEmergencyAffordanceNeeded() {
+        synchronized (mLock) {
+            mEmergencyAffordanceNeeded = mSimNeedsEmergencyAffordance ||
+                    mNetworkNeedsEmergencyAffordance;
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+                    mEmergencyAffordanceNeeded ? 1 : 0);
+            if (mEmergencyAffordanceNeeded) {
+                stopScanning();
+            }
+        }
+    }
+
+    private void stopScanning() {
+        synchronized (mLock) {
+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+            mScansCompleted = 0;
+        }
+    }
+
+    private boolean isEmergencyAffordanceNeeded() {
+        synchronized (mLock) {
+            return mEmergencyAffordanceNeeded;
+        }
+    }
+
+    @Override
+    public void onStart() {
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+            mSubscriptionManager = SubscriptionManager.from(mContext);
+            HandlerThread thread = new HandlerThread(TAG);
+            thread.start();
+            mHandler = new MyHandler(thread.getLooper());
+            mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
+            startScanning();
+            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            mContext.registerReceiver(mAirplaneModeReceiver, filter);
+            mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+        }
+    }
+
+    private void startScanning() {
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
+                | PhoneStateListener.LISTEN_CELL_LOCATION);
+    }
+
+    /** Handler to do the heavier work on */
+    private class MyHandler extends Handler {
+
+        public MyHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case INITIALIZE_STATE:
+                    handleInitializeState();
+                    break;
+                case CELL_INFO_STATE_CHANGED:
+                    handleUpdateCellInfo();
+                    break;
+                case SUBSCRIPTION_CHANGED:
+                    handleUpdateSimSubscriptionInfo();
+                    break;
+            }
+        }
+    }
+
+    private void handleInitializeState() {
+        if (handleUpdateSimSubscriptionInfo()) {
+            return;
+        }
+        if (handleUpdateCellInfo()) {
+            return;
+        }
+        updateEmergencyAffordanceNeeded();
+    }
+
+    private boolean handleUpdateSimSubscriptionInfo() {
+        boolean neededBefore = simNeededAffordanceBefore();
+        boolean neededNow = neededBefore;
+        List<SubscriptionInfo> activeSubscriptionInfoList =
+                mSubscriptionManager.getActiveSubscriptionInfoList();
+        if (activeSubscriptionInfoList == null) {
+            return neededNow;
+        }
+        for (SubscriptionInfo info : activeSubscriptionInfoList) {
+            int mcc = info.getMcc();
+            if (mccRequiresEmergencyAffordance(mcc)) {
+                neededNow = true;
+                break;
+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE){
+                // a Sim with a different mcc code was found
+                neededNow = false;
+            }
+            String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
+            mcc = 0;
+            if (simOperator != null && simOperator.length() >= 3) {
+                mcc = Integer.parseInt(simOperator.substring(0, 3));
+            }
+            if (mcc != 0) {
+                if (mccRequiresEmergencyAffordance(mcc)) {
+                    neededNow = true;
+                    break;
+                } else {
+                    // a Sim with a different mcc code was found
+                    neededNow = false;
+                }
+            }
+        }
+        if (neededNow != neededBefore) {
+            setSimNeedsEmergencyAffordance(neededNow);
+        }
+        return neededNow;
+    }
+
+    private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
+        mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
+        Settings.Global.putInt(mContext.getContentResolver(),
+                EMERGENCY_SIM_INSERTED_SETTING,
+                simNeedsEmergencyAffordance ? 1 : 0);
+        updateEmergencyAffordanceNeeded();
+    }
+
+    private boolean simNeededAffordanceBefore() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                "emergency_sim_inserted_before", 0) != 0;
+    }
+
+    private boolean handleUpdateCellInfo() {
+        List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
+        if (cellInfos == null) {
+            return false;
+        }
+        boolean stopScanningAfterScan = false;
+        for (CellInfo cellInfo : cellInfos) {
+            int mcc = 0;
+            if (cellInfo instanceof CellInfoGsm) {
+                mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
+            } else if (cellInfo instanceof CellInfoLte) {
+                mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
+            } else if (cellInfo instanceof CellInfoWcdma) {
+                mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
+            }
+            if (mccRequiresEmergencyAffordance(mcc)) {
+                setNetworkNeedsEmergencyAffordance(true);
+                return true;
+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
+                // we found an mcc that isn't in the list, abort
+                stopScanningAfterScan = true;
+            }
+        }
+        if (stopScanningAfterScan) {
+            stopScanning();
+        } else {
+            onCellScanFinishedUnsuccessful();
+        }
+        setNetworkNeedsEmergencyAffordance(false);
+        return false;
+    }
+
+    private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
+        synchronized (mLock) {
+            mNetworkNeedsEmergencyAffordance = needsAffordance;
+            updateEmergencyAffordanceNeeded();
+        }
+    }
+
+    private void onCellScanFinishedUnsuccessful() {
+        synchronized (mLock) {
+            mScansCompleted++;
+            if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
+                stopScanning();
+            }
+        }
+    }
+
+    private boolean mccRequiresEmergencyAffordance(int mcc) {
+        return mEmergencyCallMccNumbers.contains(mcc);
+    }
+}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 73c8469..9523a1c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -195,6 +195,7 @@
     public void binderDied() {
         Slog.v(TAG, "fingerprintd died");
         mDaemon = null;
+        mCurrentUserId = UserHandle.USER_CURRENT;
         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
     }
 
@@ -1068,14 +1069,6 @@
                         mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
                                 .sendToTarget();
                     }
-                    @Override
-                    public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                        // Ignore.
-                    }
-                    @Override
-                    public void onForegroundProfileSwitch(int newProfileId) {
-                        // Ignore.
-                    }
                 }, TAG);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to listen for user switching event" ,e);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 74095ac..87f4030 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Build;
 import android.os.LocaleList;
+import android.os.ShellCallback;
 import android.util.Log;
 import android.view.Display;
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
@@ -91,10 +91,8 @@
 import android.view.Surface;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicy;
-import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
-import android.widget.Toast;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -103,11 +101,8 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -1739,8 +1734,9 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
-        (new Shell()).exec(this, in, out, err, args, resultReceiver);
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     public int onShellCommand(Shell shell, String cmd) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 9d93146..fe3a02d 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -44,9 +44,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -62,6 +60,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -1718,9 +1717,9 @@
 
         @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-                String[] args, ResultReceiver resultReceiver) throws RemoteException {
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
                 (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
-                        this, in, out, err, args, resultReceiver);
+                        this, in, out, err, args, callback, resultReceiver);
         }
     };
 
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 8303d5c..27f397d 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -307,10 +307,24 @@
         this.service = IJobService.Stub.asInterface(service);
         final PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
-        mWakeLock.setWorkSource(new WorkSource(runningJob.getSourceUid()));
-        mWakeLock.setReferenceCounted(false);
-        mWakeLock.acquire();
+        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                runningJob.getTag());
+        wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
+        wl.setReferenceCounted(false);
+        wl.acquire();
+        synchronized (mLock) {
+            // We use a new wakelock instance per job.  In rare cases there is a race between
+            // teardown following job completion/cancellation and new job service spin-up
+            // such that if we simply assign mWakeLock to be the new instance, we orphan
+            // the currently-live lock instead of cleanly replacing it.  Watch for this and
+            // explicitly fast-forward the release if we're in that situation.
+            if (mWakeLock != null) {
+                Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock
+                        + " tag=" + mWakeLock.getTag());
+                mWakeLock.release();
+            }
+            mWakeLock = wl;
+        }
         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
     }
 
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 7120191..b65330a 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -176,12 +176,7 @@
         }
 
         @Override
-        public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
-            updateTrackedJobs(uid);
-        }
-
-        @Override
-        public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
+        public void onUidPoliciesChanged(int uid, int uidPolicies) {
             updateTrackedJobs(uid);
         }
     };
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 07048a4..ca64817 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -172,10 +172,12 @@
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             IVrManager vrManager =
                     (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
-            try {
-                vrManager.registerListener(mVrStateCallbacks);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            if (vrManager != null) {
+                try {
+                    vrManager.registerListener(mVrStateCallbacks);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index c464371..bf779859 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -22,6 +22,10 @@
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.URL;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
 import java.util.Properties;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
@@ -37,6 +41,7 @@
 
     private static final String TAG = "GpsXtraDownloader";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000;  // 1MB.
     private static final String DEFAULT_USER_AGENT = "Android";
     private static final int CONNECTION_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
 
@@ -124,7 +129,19 @@
                 return null;
             }
 
-            return Streams.readFully(connection.getInputStream());
+            try (InputStream in = connection.getInputStream()) {
+                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+                byte[] buffer = new byte[1024];
+                int count;
+                while ((count = in.read(buffer)) != -1) {
+                    bytes.write(buffer, 0, count);
+                    if (bytes.size() > MAXIMUM_CONTENT_LENGTH_BYTES) {
+                        if (DEBUG) Log.d(TAG, "XTRA file too large");
+                        return null;
+                    }
+                }
+                return bytes.toByteArray();
+            }
         } catch (IOException ioe) {
             if (DEBUG) Log.d(TAG, "Error downloading gps XTRA: ", ioe);
         } finally {
@@ -136,3 +153,4 @@
     }
 
 }
+
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 2d71ce9..ede6e30 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -108,7 +108,7 @@
     private CharSequence mQueueTitle;
     private int mRatingType;
     private int mRepeatMode;
-    private boolean mShuffleMode;
+    private boolean mShuffleModeEnabled;
     private long mLastActiveTime;
     // End TransportPerformer fields
 
@@ -649,7 +649,7 @@
             for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
                 ISessionControllerCallback cb = mControllerCallbacks.get(i);
                 try {
-                    cb.onShuffleModeChanged(mShuffleMode);
+                    cb.onShuffleModeChanged(mShuffleModeEnabled);
                 } catch (DeadObjectException e) {
                     mControllerCallbacks.remove(i);
                     Log.w(TAG, "Removed dead callback in pushShuffleModeUpdate.", e);
@@ -880,11 +880,11 @@
         }
 
         @Override
-        public void setShuffleMode(boolean shuffleMode) {
+        public void setShuffleModeEnabled(boolean enabled) {
             boolean changed;
             synchronized (mLock) {
-                changed = mShuffleMode != shuffleMode;
-                mShuffleMode = shuffleMode;
+                changed = mShuffleModeEnabled != enabled;
+                mShuffleModeEnabled = enabled;
             }
             if (changed) {
                 mHandler.post(MessageHandler.MSG_UPDATE_SHUFFLE_MODE);
@@ -1115,9 +1115,9 @@
             }
         }
 
-        public void shuffleMode(boolean shuffleMode) {
+        public void shuffleMode(boolean enabled) {
             try {
-                mCb.onShuffleMode(shuffleMode);
+                mCb.onShuffleMode(enabled);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in shuffleMode.", e);
             }
@@ -1364,9 +1364,9 @@
         }
 
         @Override
-        public void shuffleMode(boolean shuffleMode) throws RemoteException {
+        public void shuffleMode(boolean enabled) throws RemoteException {
             updateCallingPackage();
-            mSessionCb.shuffleMode(shuffleMode);
+            mSessionCb.shuffleMode(enabled);
         }
 
 
@@ -1419,8 +1419,8 @@
         }
 
         @Override
-        public boolean getShuffleMode() {
-            return mShuffleMode;
+        public boolean isShuffleModeEnabled() {
+            return mShuffleModeEnabled;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 2f77f93..4c58ffd 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -78,6 +78,8 @@
 public class MediaSessionService extends SystemService implements Monitor {
     private static final String TAG = "MediaSessionService";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // Leave log for media key event always.
+    private static final boolean DEBUG_MEDIA_KEY_EVENT = DEBUG || true;
 
     private static final int WAKELOCK_TIMEOUT = 5000;
 
@@ -302,7 +304,7 @@
      */
     private void destroySessionLocked(MediaSessionRecord session) {
         if (DEBUG) {
-            Log.d(TAG, "Destroying session : " + session.toString());
+            Log.d(TAG, "Destroying " + session);
         }
         int userId = session.getUserId();
         UserRecord user = mUserRecords.get(userId);
@@ -408,7 +410,7 @@
                     if (component != null) {
                         if (compName.equals(component)) {
                             if (DEBUG) {
-                                Log.d(TAG, "ok to get sessions: " + component +
+                                Log.d(TAG, "ok to get sessions. " + component +
                                         " is authorized notification listener");
                             }
                             return true;
@@ -417,7 +419,7 @@
                 }
             }
             if (DEBUG) {
-                Log.d(TAG, "not ok to get sessions, " + compName +
+                Log.d(TAG, "not ok to get sessions. " + compName +
                         " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
             }
         }
@@ -462,7 +464,7 @@
         mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
 
         if (DEBUG) {
-            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
+            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
         }
         return session;
     }
@@ -765,6 +767,13 @@
                             + "setup is in progress.");
                     return;
                 }
+                if (isGlobalPriorityActive() && uid != Process.SYSTEM_UID) {
+                    // Prevent dispatching key event through reflection while the global priority
+                    // session is active.
+                    Slog.i(TAG, "Only the system can dispatch media key event "
+                            + "to the global priority session.");
+                    return;
+                }
 
                 synchronized (mLock) {
                     // If we don't have a media button receiver to fall back on
@@ -881,17 +890,16 @@
 
         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
                 MediaSessionRecord session) {
-            if (DEBUG) {
-                String description = session == null ? null : session.toString();
-                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
-                        + flags + ", suggestedStream=" + suggestedStream);
-
-            }
             boolean preferSuggestedStream = false;
             if (isValidLocalStreamType(suggestedStream)
                     && AudioSystem.isStreamActive(suggestedStream, 0)) {
                 preferSuggestedStream = true;
             }
+            if (DEBUG) {
+                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream
+                        + ", preferSuggestedStream=" + preferSuggestedStream);
+            }
             if (session == null || preferSuggestedStream) {
                 if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
                         && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
@@ -957,8 +965,8 @@
         private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
                 MediaSessionRecord session) {
             if (session != null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Sending media key to " + session.toString());
+                if (DEBUG_MEDIA_KEY_EVENT) {
+                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
                 }
                 if (needWakeLock) {
                     mKeyEventReceiver.aquireWakeLockLocked();
@@ -977,11 +985,6 @@
                             && user.mRestoredMediaButtonReceiver == null) {
                         continue;
                     }
-                    if (DEBUG) {
-                        Log.d(TAG, "Sending media key to last known PendingIntent "
-                                + user.mLastMediaButtonReceiver + " or restored Intent "
-                                + user.mRestoredMediaButtonReceiver);
-                    }
                     if (needWakeLock) {
                         mKeyEventReceiver.aquireWakeLockLocked();
                     }
@@ -990,10 +993,19 @@
                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
                     try {
                         if (user.mLastMediaButtonReceiver != null) {
+                            if (DEBUG_MEDIA_KEY_EVENT) {
+                                Log.d(TAG, "Sending " + keyEvent
+                                        + " to the last known pendingIntent "
+                                        + user.mLastMediaButtonReceiver);
+                            }
                             user.mLastMediaButtonReceiver.send(getContext(),
                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                                     mediaButtonIntent, mKeyEventReceiver, mHandler);
                         } else {
+                            if (DEBUG_MEDIA_KEY_EVENT) {
+                                Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+                                        + user.mRestoredMediaButtonReceiver);
+                            }
                             mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
                             getContext().sendBroadcastAsUser(mediaButtonIntent,
                                     UserHandle.of(userId));
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9ca609f..2bccfee 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;
@@ -90,6 +92,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -120,7 +123,6 @@
 import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
 import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkTemplate;
@@ -141,6 +143,8 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -152,7 +156,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;
@@ -165,7 +168,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -286,10 +288,11 @@
     private static final int MSG_LIMIT_REACHED = 5;
     private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
     private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
-    private static final int MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED = 9;
     private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
     private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
-    private static final int MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED = 12;
+    private static final int MSG_POLICIES_CHANGED = 13;
+    private static final int MSG_SET_FIREWALL_RULES = 14;
+    private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -357,12 +360,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")
@@ -405,7 +402,6 @@
 
     private final AppOpsManager mAppOps;
 
-    private final MyPackageMonitor mPackageMonitor;
     private final IPackageManager mIPm;
 
 
@@ -417,7 +413,8 @@
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement) {
         this(context, activityManager, networkStats, networkManagement,
-                NtpTrustedTime.getInstance(context), getSystemDir(), false);
+                AppGlobals.getPackageManager(), NtpTrustedTime.getInstance(context), getSystemDir(),
+                false);
     }
 
     private static File getSystemDir() {
@@ -426,7 +423,7 @@
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement,
-            TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
+            IPackageManager pm, TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
@@ -435,7 +432,7 @@
                 Context.DEVICE_IDLE_CONTROLLER));
         mTime = checkNotNull(time, "missing TrustedTime");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mIPm = AppGlobals.getPackageManager();
+        mIPm = pm;
 
         HandlerThread thread = new HandlerThread(TAG);
         thread.start();
@@ -447,8 +444,6 @@
 
         mAppOps = context.getSystemService(AppOpsManager.class);
 
-        mPackageMonitor = new MyPackageMonitor();
-
         // Expose private service for system components to use.
         LocalServices.addService(NetworkPolicyManagerInternal.class,
                 new NetworkPolicyManagerInternalImpl());
@@ -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();
@@ -514,12 +509,13 @@
             try {
                 app = pm.getApplicationInfoAsUser(pkg, PackageManager.MATCH_SYSTEM_ONLY, userId);
             } catch (PackageManager.NameNotFoundException e) {
-                // Should not happen
-                Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
+                if (LOGD) Slog.d(TAG, "No ApplicationInfo for package " + pkg);
+                // Ignore it - some apps on allow-in-data-usage-save are optional.
                 continue;
             }
             if (!app.isPrivilegedApp()) {
-                Slog.wtf(TAG, "pm.getApplicationInfoAsUser() returned non-privileged app: " + pkg);
+                Slog.e(TAG, "addDefaultRestrictBackgroundWhitelistUidsUL(): "
+                        + "skipping non-privileged app  " + pkg);
                 continue;
             }
             final int uid = UserHandle.getUid(userId, app.uid);
@@ -529,9 +525,10 @@
                         + "background whitelist. Revoked status: "
                         + mRestrictBackgroundWhitelistRevokedUids.get(uid));
             if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
-                Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
-                        + userId + ") to restrict background whitelist");
-                mRestrictBackgroundWhitelistUids.append(uid, true);
+                if (LOGD)
+                    Slog.d(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
+                            + userId + ") to restrict background whitelist");
+                setUidPolicyUncheckedUL(uid, POLICY_ALLOW_METERED_BACKGROUND, false);
                 changed = true;
             }
         }
@@ -569,117 +566,125 @@
     }
 
     public void systemReady() {
-        if (!isBandwidthControlEnabled()) {
-            Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
-            return;
-        }
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "systemReady");
+        try {
+            if (!isBandwidthControlEnabled()) {
+                Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
+                return;
+            }
 
-        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+            mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
 
-        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
-
-        synchronized (mUidRulesFirstLock) {
-            synchronized (mNetworkPoliciesSecondLock) {
-                updatePowerSaveWhitelistUL();
-                mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
-                mPowerManagerInternal.registerLowPowerModeObserver(
-                        new PowerManagerInternal.LowPowerModeListener() {
-                    @Override
-                    public void onLowPowerModeChanged(boolean enabled) {
-                        if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
-                        synchronized (mUidRulesFirstLock) {
-                            if (mRestrictPower != enabled) {
-                                mRestrictPower = enabled;
-                                updateRulesForRestrictPowerUL();
+            synchronized (mUidRulesFirstLock) {
+                synchronized (mNetworkPoliciesSecondLock) {
+                    updatePowerSaveWhitelistUL();
+                    mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+                    mPowerManagerInternal.registerLowPowerModeObserver(
+                            new PowerManagerInternal.LowPowerModeListener() {
+                        @Override
+                        public void onLowPowerModeChanged(boolean enabled) {
+                            if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
+                            synchronized (mUidRulesFirstLock) {
+                                if (mRestrictPower != enabled) {
+                                    mRestrictPower = enabled;
+                                    updateRulesForRestrictPowerUL();
+                                }
                             }
                         }
+                    });
+                    mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+
+                    mSystemReady = true;
+
+                    // read policy from disk
+                    readPolicyAL();
+
+                    if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
+                        writePolicyAL();
                     }
-                });
-                mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
 
-                mSystemReady = true;
-
-                // read policy from disk
-                readPolicyAL();
-
-                if (addDefaultRestrictBackgroundWhitelistUidsUL()) {
-                    writePolicyAL();
+                    setRestrictBackgroundUL(mRestrictBackground);
+                    updateRulesForGlobalChangeAL(false);
+                    updateNotificationsNL();
                 }
-
-                setRestrictBackgroundUL(mRestrictBackground);
-                updateRulesForGlobalChangeAL(false);
-                updateNotificationsNL();
             }
+
+            try {
+                mActivityManager.registerUidObserver(mUidObserver,
+                        ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
+                mNetworkManager.registerObserver(mAlertObserver);
+            } catch (RemoteException e) {
+                // ignored; both services live in system_server
+            }
+
+            // listen for changes to power save whitelist
+            final IntentFilter whitelistFilter = new IntentFilter(
+                    PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+            mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
+
+            DeviceIdleController.LocalService deviceIdleService
+                    = LocalServices.getService(DeviceIdleController.LocalService.class);
+            deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
+
+            // watch for network interfaces to be claimed
+            final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
+            mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
+
+            // listen for package changes to update policy
+            final IntentFilter packageFilter = new IntentFilter();
+            packageFilter.addAction(ACTION_PACKAGE_ADDED);
+            packageFilter.addDataScheme("package");
+            mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
+
+            // listen for UID changes to update policy
+            mContext.registerReceiver(
+                    mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
+
+            // listen for user changes to update policy
+            final IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(ACTION_USER_ADDED);
+            userFilter.addAction(ACTION_USER_REMOVED);
+            mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
+
+            // listen for stats update events
+            final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
+            mContext.registerReceiver(
+                    mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
+
+            // listen for restrict background changes from notifications
+            final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
+            mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
+
+            // listen for snooze warning from notifications
+            final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
+            mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
+                    MANAGE_NETWORK_POLICY, mHandler);
+
+            // listen for configured wifi networks to be removed
+            final IntentFilter wifiConfigFilter =
+                    new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
+            mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
+
+            // listen for wifi state changes to catch metered hint
+            final IntentFilter wifiStateFilter = new IntentFilter(
+                    WifiManager.NETWORK_STATE_CHANGED_ACTION);
+            mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
+
+            mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
-
-        try {
-            mActivityManager.registerUidObserver(mUidObserver,
-                    ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
-            mNetworkManager.registerObserver(mAlertObserver);
-        } catch (RemoteException e) {
-            // ignored; both services live in system_server
-        }
-
-        // listen for changes to power save whitelist
-        final IntentFilter whitelistFilter = new IntentFilter(
-                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
-        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
-
-        DeviceIdleController.LocalService deviceIdleService
-                = LocalServices.getService(DeviceIdleController.LocalService.class);
-        deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
-
-        // watch for network interfaces to be claimed
-        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
-        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
-
-        // listen for package changes to update policy
-        final IntentFilter packageFilter = new IntentFilter();
-        packageFilter.addAction(ACTION_PACKAGE_ADDED);
-        packageFilter.addDataScheme("package");
-        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
-
-        // listen for UID changes to update policy
-        mContext.registerReceiver(
-                mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
-
-        // listen for user changes to update policy
-        final IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(ACTION_USER_ADDED);
-        userFilter.addAction(ACTION_USER_REMOVED);
-        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
-
-        // listen for stats update events
-        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
-        mContext.registerReceiver(
-                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
-
-        // listen for restrict background changes from notifications
-        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
-        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
-
-        // listen for snooze warning from notifications
-        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
-        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
-                MANAGE_NETWORK_POLICY, mHandler);
-
-        // listen for configured wifi networks to be removed
-        final IntentFilter wifiConfigFilter = new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
-        mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
-
-        // listen for wifi state changes to catch metered hint
-        final IntentFilter wifiStateFilter = new IntentFilter(
-                WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
-
-        mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
-
     }
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
-            synchronized (mUidRulesFirstLock) {
-                updateUidStateUL(uid, procState);
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
+            try {
+                synchronized (mUidRulesFirstLock) {
+                    updateUidStateUL(uid, procState);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
         }
 
@@ -703,6 +708,7 @@
             synchronized (mUidRulesFirstLock) {
                 updatePowerSaveWhitelistUL();
                 updateRulesForRestrictPowerUL();
+                updateRulesForAppIdleUL();
             }
         }
     };
@@ -749,8 +755,7 @@
             // remove any policy and update rules to clean up
             if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
             synchronized (mUidRulesFirstLock) {
-                mUidPolicy.delete(uid);
-                updateRestrictionRulesForUidUL(uid);
+                onUidDeletedUL(uid);
                 synchronized (mNetworkPoliciesSecondLock) {
                     writePolicyAL();
                 }
@@ -1432,8 +1437,14 @@
                 + "; generating default policy");
 
         // Build default mobile policy, and assume usage cycle starts today
-        final long warningBytes = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
+        final int dataWarningConfig = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_networkPolicyDefaultWarning);
+        final long warningBytes;
+        if (dataWarningConfig == WARNING_DISABLED) {
+            warningBytes = WARNING_DISABLED;
+        } else {
+            warningBytes = dataWarningConfig * MB_IN_BYTES;
+        }
 
         final Time time = new Time();
         time.setToNow();
@@ -1460,6 +1471,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 +1583,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 +1596,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 +1704,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);
@@ -1757,21 +1782,35 @@
     private void setUidPolicyUncheckedUL(int uid, int oldPolicy, int policy, boolean persist) {
         setUidPolicyUncheckedUL(uid, policy, persist);
 
-        final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND;
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED, uid,
-                isBlacklisted ? 1 : 0).sendToTarget();
-
-        final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND;
-        // Checks if app was added or removed to the blacklist.
-        if ((oldPolicy == POLICY_NONE && isBlacklisted)
-                || (wasBlacklisted && policy == POLICY_NONE)) {
-            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 1, null)
-                    .sendToTarget();
+        final boolean notifyApp;
+        if (!isUidValidForWhitelistRules(uid)) {
+            notifyApp = false;
+        } else {
+            final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND;
+            final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND;
+            final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND;
+            final boolean isWhitelisted = policy == POLICY_ALLOW_METERED_BACKGROUND;
+            final boolean wasBlocked = wasBlacklisted || (mRestrictBackground && !wasWhitelisted);
+            final boolean isBlocked = isBlacklisted || (mRestrictBackground && !isWhitelisted);
+            if ((wasWhitelisted && (!isWhitelisted || isBlacklisted))
+                    && mDefaultRestrictBackgroundWhitelistUids.get(uid)
+                    && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
+                if (LOGD)
+                    Slog.d(TAG, "Adding uid " + uid + " to revoked restrict background whitelist");
+                mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
+            }
+            notifyApp = wasBlocked != isBlocked;
         }
+        mHandler.obtainMessage(MSG_POLICIES_CHANGED, uid, policy, Boolean.valueOf(notifyApp))
+                .sendToTarget();
     }
 
     private void setUidPolicyUncheckedUL(int uid, int policy, boolean persist) {
-        mUidPolicy.put(uid, policy);
+        if (policy == POLICY_NONE) {
+            mUidPolicy.delete(uid);
+        } else {
+            mUidPolicy.put(uid, policy);
+        }
 
         // uid policy changed, recompute rules and persist policy.
         updateRulesForDataUsageRestrictionsUL(uid);
@@ -1800,7 +1839,8 @@
             for (int i = 0; i < mUidPolicy.size(); i++) {
                 final int uid = mUidPolicy.keyAt(i);
                 final int uidPolicy = mUidPolicy.valueAt(i);
-                if (uidPolicy == policy) {
+                if ((policy == POLICY_NONE && uidPolicy == POLICY_NONE) ||
+                        (uidPolicy & policy) != 0) {
                     uids = appendInt(uids, uid);
                 }
             }
@@ -1817,22 +1857,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);
@@ -2022,25 +2046,30 @@
 
     @Override
     public void setRestrictBackground(boolean restrictBackground) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        final long token = Binder.clearCallingIdentity();
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground");
         try {
-            maybeRefreshTrustedTime();
-            synchronized (mUidRulesFirstLock) {
-                if (restrictBackground == mRestrictBackground) {
-                    // Ideally, UI should never allow this scenario...
-                    Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
-                    return;
+            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                maybeRefreshTrustedTime();
+                synchronized (mUidRulesFirstLock) {
+                    if (restrictBackground == mRestrictBackground) {
+                        // Ideally, UI should never allow this scenario...
+                        Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+                        return;
+                    }
+                    setRestrictBackgroundUL(restrictBackground);
                 }
-                setRestrictBackgroundUL(restrictBackground);
+
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
 
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
+                    .sendToTarget();
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
-
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
-                .sendToTarget();
     }
 
     private void setRestrictBackgroundUL(boolean restrictBackground) {
@@ -2050,7 +2079,7 @@
         // Must whitelist foreground apps before turning data saver mode on.
         // TODO: there is no need to iterate through all apps here, just those in the foreground,
         // so it could call AM to get the UIDs of such apps, and iterate through them instead.
-        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
+        updateRulesForRestrictBackgroundUL();
         try {
             if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
                 Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
@@ -2069,106 +2098,6 @@
     }
 
     @Override
-    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);
-            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);
-            if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
-                    && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
-                if (LOGD) Slog.d(TAG, "Removing uid " + uid
-                        + " from revoked restrict background whitelist");
-                mRestrictBackgroundWhitelistRevokedUids.delete(uid);
-            }
-            if (needFirewallRules) {
-                // Only update firewall rules if necessary...
-                updateRulesForDataUsageRestrictionsUL(uid);
-            }
-            // ...but always persists the whitelist request.
-            synchronized (mNetworkPoliciesSecondLock) {
-                writePolicyAL();
-            }
-            changed = (mRestrictBackground && !oldStatus && needFirewallRules) ? 1 : 0;
-        }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed,
-                Boolean.TRUE).sendToTarget();
-    }
-
-    @Override
-    public void removeRestrictBackgroundWhitelistedUid(int uid) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        final boolean changed;
-        synchronized (mUidRulesFirstLock) {
-            changed = removeRestrictBackgroundWhitelistedUidUL(uid, false, true);
-        }
-        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, changed ? 1 : 0,
-                Boolean.FALSE).sendToTarget();
-    }
-
-    /**
-     * Removes a uid from the restricted background whitelist, returning whether its current
-     * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
-     */
-    private boolean removeRestrictBackgroundWhitelistedUidUL(int uid, boolean uidDeleted,
-            boolean updateNow) {
-        final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
-        if (!oldStatus && !uidDeleted) {
-            if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
-            return false;
-        }
-        final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
-        if (oldStatus) {
-            Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
-            mRestrictBackgroundWhitelistUids.delete(uid);
-        }
-        if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
-                && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
-            if (LOGD) Slog.d(TAG, "Adding uid " + uid
-                    + " to revoked restrict background whitelist");
-            mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
-        }
-        if (needFirewallRules) {
-            // Only update firewall rules if necessary...
-            updateRulesForDataUsageRestrictionsUL(uid, uidDeleted);
-        }
-        if (updateNow) {
-            // ...but always persists the whitelist request.
-            synchronized (mNetworkPoliciesSecondLock) {
-                writePolicyAL();
-            }
-        }
-        // Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
-        // app was whitelisted before).
-        return mRestrictBackground && needFirewallRules;
-    }
-
-    @Override
-    public int[] getRestrictBackgroundWhitelistedUids() {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        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);
-            }
-            if (LOGV) {
-                Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
-                        + mRestrictBackgroundWhitelistUids);
-            }
-            return whitelist;
-        }
-    }
-
-    @Override
     public int getRestrictBackgroundByCaller() {
         mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
         final int uid = Binder.getCallingUid();
@@ -2189,7 +2118,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;
         }
@@ -2207,21 +2136,26 @@
     @Override
     public void setDeviceIdleMode(boolean enabled) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
-        synchronized (mUidRulesFirstLock) {
-            if (mDeviceIdleMode != enabled) {
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDeviceIdleMode");
+        try {
+            synchronized (mUidRulesFirstLock) {
+                if (mDeviceIdleMode == enabled) {
+                    return;
+                }
                 mDeviceIdleMode = enabled;
                 if (mSystemReady) {
                     // Device idle change means we need to rebuild rules for all
                     // known apps, so do a global refresh.
                     updateRulesForRestrictPowerUL();
                 }
-                if (enabled) {
-                    EventLogTags.writeDeviceIdleOnPhase("net");
-                } else {
-                    EventLogTags.writeDeviceIdleOffPhase("net");
-                }
             }
+            if (enabled) {
+                EventLogTags.writeDeviceIdleOnPhase("net");
+            } else {
+                EventLogTags.writeDeviceIdleOffPhase("net");
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
     }
 
@@ -2352,7 +2286,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,18 +2319,6 @@
                     fout.decreaseIndent();
                 }
 
-                size = mRestrictBackgroundWhitelistUids.size();
-                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.println();
-                    }
-                    fout.decreaseIndent();
-                }
-
                 size = mDefaultRestrictBackgroundWhitelistUids.size();
                 if (size > 0) {
                     fout.println("Default restrict background whitelist uids:");
@@ -2469,9 +2391,9 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
         (new NetworkPolicyManagerShellCommand(mContext, this)).exec(
-                this, in, out, err, args, resultReceiver);
+                this, in, out, err, args, callback, resultReceiver);
     }
 
     @Override
@@ -2509,25 +2431,30 @@
      * {@link #updateRulesForPowerRestrictionsUL(int)}
      */
     private void updateUidStateUL(int uid, int uidState) {
-        final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
-        if (oldUidState != uidState) {
-            // state changed, push updated rules
-            mUidState.put(uid, uidState);
-            updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
-            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
-                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
-                if (isUidIdle(uid)) {
-                    updateRuleForAppIdleUL(uid);
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
+        try {
+            final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+            if (oldUidState != uidState) {
+                // state changed, push updated rules
+                mUidState.put(uid, uidState);
+                updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
+                if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
+                        != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
+                    if (isUidIdle(uid)) {
+                        updateRuleForAppIdleUL(uid);
+                    }
+                    if (mDeviceIdleMode) {
+                        updateRuleForDeviceIdleUL(uid);
+                    }
+                    if (mRestrictPower) {
+                        updateRuleForRestrictPowerUL(uid);
+                    }
+                    updateRulesForPowerRestrictionsUL(uid);
                 }
-                if (mDeviceIdleMode) {
-                    updateRuleForDeviceIdleUL(uid);
-                }
-                if (mRestrictPower) {
-                    updateRuleForRestrictPowerUL(uid);
-                }
-                updateRulesForPowerRestrictionsUL(uid);
+                updateNetworkStats(uid, isUidStateForegroundUL(uidState));
             }
-            updateNetworkStats(uid, isUidStateForegroundUL(uidState));
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
     }
 
@@ -2580,8 +2507,13 @@
     }
 
     void updateRulesForPowerSaveUL() {
-        updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
-                mUidFirewallPowerSaveRules);
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
+        try {
+            updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+                    mUidFirewallPowerSaveRules);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+        }
     }
 
     void updateRuleForRestrictPowerUL(int uid) {
@@ -2589,8 +2521,13 @@
     }
 
     void updateRulesForDeviceIdleUL() {
-        updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
-                mUidFirewallDozableRules);
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
+        try {
+            updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+                    mUidFirewallDozableRules);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+        }
     }
 
     void updateRuleForDeviceIdleUL(int uid) {
@@ -2627,10 +2564,10 @@
                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
                 }
             }
-            setUidFirewallRules(chain, uidRules);
+            setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
+        } else {
+            setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
         }
-
-        enableFirewallChainUL(chain, enabled);
     }
 
     private boolean isWhitelistedBatterySaverUL(int uid) {
@@ -2652,27 +2589,32 @@
     }
 
     void updateRulesForAppIdleUL() {
-        final SparseIntArray uidRules = mUidFirewallStandbyRules;
-        uidRules.clear();
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForAppIdleUL");
+        try {
+            final SparseIntArray uidRules = mUidFirewallStandbyRules;
+            uidRules.clear();
 
-        // Fully update the app idle firewall chain.
-        final List<UserInfo> users = mUserManager.getUsers();
-        for (int ui = users.size() - 1; ui >= 0; ui--) {
-            UserInfo user = users.get(ui);
-            int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
-            for (int uid : idleUids) {
-                if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
-                    // quick check: if this uid doesn't have INTERNET permission, it
-                    // doesn't have network access anyway, so it is a waste to mess
-                    // with it here.
-                    if (hasInternetPermissions(uid)) {
-                        uidRules.put(uid, FIREWALL_RULE_DENY);
+            // Fully update the app idle firewall chain.
+            final List<UserInfo> users = mUserManager.getUsers();
+            for (int ui = users.size() - 1; ui >= 0; ui--) {
+                UserInfo user = users.get(ui);
+                int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
+                for (int uid : idleUids) {
+                    if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
+                        // quick check: if this uid doesn't have INTERNET permission, it
+                        // doesn't have network access anyway, so it is a waste to mess
+                        // with it here.
+                        if (hasInternetPermissions(uid)) {
+                            uidRules.put(uid, FIREWALL_RULE_DENY);
+                        }
                     }
                 }
             }
-        }
 
-        setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
+            setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+        }
     }
 
     void updateRuleForAppIdleUL(int uid) {
@@ -2687,9 +2629,31 @@
         }
     }
 
+    /**
+     * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
+     * changed.
+     */
     void updateRulesForAppIdleParoleUL() {
-        boolean enableChain = !mUsageStats.isAppIdleParoleOn();
+        boolean paroled = mUsageStats.isAppIdleParoleOn();
+        boolean enableChain = !paroled;
         enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
+
+        int ruleCount = mUidFirewallStandbyRules.size();
+        for (int i = 0; i < ruleCount; i++) {
+            int uid = mUidFirewallStandbyRules.keyAt(i);
+            int oldRules = mUidRules.get(uid);
+            if (enableChain) {
+                // Chain wasn't enabled before and the other power-related
+                // chains are whitelists, so we can clear the
+                // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
+                // the effective rules result in blocking network access.
+                oldRules &= MASK_METERED_NETWORKS;
+            } else {
+                // Skip if it had no restrictions to begin with
+                if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+            }
+            updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+        }
     }
 
     /**
@@ -2697,33 +2661,41 @@
      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
      */
     private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
-        long start;
-        if (LOGD) start = System.currentTimeMillis();
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForGlobalChangeAL");
+        try {
+            updateRulesForAppIdleUL();
+            updateRulesForRestrictPowerUL();
+            updateRulesForRestrictBackgroundUL();
 
-        updateRulesForRestrictPowerUL();
-        updateRulesForRestrictBackgroundUL();
-
-        // If the set of restricted networks may have changed, re-evaluate those.
-        if (restrictedNetworksChanged) {
-            normalizePoliciesNL();
-            updateNetworkRulesNL();
-        }
-        if (LOGD) {
-            final long delta = System.currentTimeMillis() - start;
-            Slog.d(TAG, "updateRulesForGlobalChangeAL(" + restrictedNetworksChanged + ") took "
-                    + delta + "ms");
+            // If the set of restricted networks may have changed, re-evaluate those.
+            if (restrictedNetworksChanged) {
+                normalizePoliciesNL();
+                updateNetworkRulesNL();
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
     }
 
+    // TODO: rename / document to make it clear these are global (not app-specific) rules
     private void updateRulesForRestrictPowerUL() {
-        updateRulesForDeviceIdleUL();
-        updateRulesForAppIdleUL();
-        updateRulesForPowerSaveUL();
-        updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
+        try {
+            updateRulesForDeviceIdleUL();
+            updateRulesForPowerSaveUL();
+            updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+        }
     }
 
     private void updateRulesForRestrictBackgroundUL() {
-        updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
+        Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictBackgroundUL");
+        try {
+            updateRulesForAllAppsUL(TYPE_RESTRICT_BACKGROUND);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+        }
     }
 
     private static final int TYPE_RESTRICT_BACKGROUND = 1;
@@ -2738,33 +2710,42 @@
 
     // TODO: refactor / consolidate all those updateXyz methods, there are way too many of them...
     private void updateRulesForAllAppsUL(@RestrictType int type) {
-        final PackageManager pm = mContext.getPackageManager();
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL-" + type);
+        }
+        try {
+            final PackageManager pm = mContext.getPackageManager();
 
-        // update rules for all installed applications
-        final List<UserInfo> users = mUserManager.getUsers();
-        final List<ApplicationInfo> apps = pm.getInstalledApplications(
-                PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
-                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+            // update rules for all installed applications
+            final List<UserInfo> users = mUserManager.getUsers();
+            final List<ApplicationInfo> apps = pm.getInstalledApplications(
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
 
-        final int usersSize = users.size();
-        final int appsSize = apps.size();
-        for (int i = 0; i < usersSize; i++) {
-            final UserInfo user = users.get(i);
-            for (int j = 0; j < appsSize; j++) {
-                final ApplicationInfo app = apps.get(j);
-                final int uid = UserHandle.getUid(user.id, app.uid);
-                switch (type) {
-                    case TYPE_RESTRICT_BACKGROUND:
-                        updateRulesForDataUsageRestrictionsUL(uid);
-                        break;
-                    case TYPE_RESTRICT_POWER:
-                        updateRulesForPowerRestrictionsUL(uid);
-                        break;
-                    default:
-                        Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
+            final int usersSize = users.size();
+            final int appsSize = apps.size();
+            for (int i = 0; i < usersSize; i++) {
+                final UserInfo user = users.get(i);
+                for (int j = 0; j < appsSize; j++) {
+                    final ApplicationInfo app = apps.get(j);
+                    final int uid = UserHandle.getUid(user.id, app.uid);
+                    switch (type) {
+                        case TYPE_RESTRICT_BACKGROUND:
+                            updateRulesForDataUsageRestrictionsUL(uid);
+                            break;
+                        case TYPE_RESTRICT_POWER:
+                            updateRulesForPowerRestrictionsUL(uid);
+                            break;
+                        default:
+                            Slog.w(TAG, "Invalid type for updateRulesForAllApps: " + type);
+                    }
                 }
             }
+        } finally {
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
+                Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+            }
         }
     }
 
@@ -2832,6 +2813,24 @@
     }
 
     /**
+     * Clears all state - internal and external - associated with an UID.
+     */
+    private void onUidDeletedUL(int uid) {
+        // First cleanup in-memory state synchronously...
+        mUidRules.delete(uid);
+        mUidPolicy.delete(uid);
+        mUidFirewallStandbyRules.delete(uid);
+        mUidFirewallDozableRules.delete(uid);
+        mUidFirewallPowerSaveRules.delete(uid);
+        mPowerSaveWhitelistExceptIdleAppIds.delete(uid);
+        mPowerSaveWhitelistAppIds.delete(uid);
+        mPowerSaveTempWhitelistAppIds.delete(uid);
+
+        // ...then update iptables asynchronously.
+        mHandler.obtainMessage(MSG_RESET_FIREWALL_RULES_BY_UID, uid, 0).sendToTarget();
+    }
+
+    /**
      * Applies network rules to bandwidth and firewall controllers based on uid policy.
      *
      * <p>There are currently 4 types of restriction rules:
@@ -2897,15 +2896,7 @@
      *
      */
     private void updateRulesForDataUsageRestrictionsUL(int uid) {
-        updateRulesForDataUsageRestrictionsUL(uid, false);
-    }
-
-    /**
-     * Overloaded version of {@link #updateRulesForDataUsageRestrictionsUL(int)} called when an
-     * app is removed - it ignores the UID validity check.
-     */
-    private void updateRulesForDataUsageRestrictionsUL(int uid, boolean uidDeleted) {
-        if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
+        if (!isUidValidForWhitelistRules(uid)) {
             if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
             return;
         }
@@ -2915,7 +2906,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;
 
@@ -3026,14 +3017,34 @@
      * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
      */
     private void updateRulesForPowerRestrictionsUL(int uid) {
+        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
+
+        final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
+
+        if (newUidRules == RULE_NONE) {
+            mUidRules.delete(uid);
+        } else {
+            mUidRules.put(uid, newUidRules);
+        }
+    }
+
+    /**
+     * Similar to above but ignores idle state if app standby is currently disabled by parole.
+     *
+     * @param uid the uid of the app to update rules for
+     * @param oldUidRules the current rules for the uid, in order to determine if there's a change
+     * @param paroled whether to ignore idle state of apps and only look at other restrictions.
+     *
+     * @return the new computed rules for the uid
+     */
+    private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
         if (!isUidValidForBlacklistRules(uid)) {
             if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
-            return;
+            return RULE_NONE;
         }
 
-        final boolean isIdle = isUidIdle(uid);
+        final boolean isIdle = !paroled && isUidIdle(uid);
         final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
-        final int oldUidRules = mUidRules.get(uid, RULE_NONE);
         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
 
         final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid);
@@ -3067,12 +3078,6 @@
                     + ", oldUidRules=" + uidRulesToString(oldUidRules));
         }
 
-        if (newUidRules == RULE_NONE) {
-            mUidRules.delete(uid);
-        } else {
-            mUidRules.put(uid, newUidRules);
-        }
-
         // Second step: notify listeners if state changed.
         if (newRule != oldRule) {
             if (newRule == RULE_NONE || (newRule & RULE_ALLOW_ALL) != 0) {
@@ -3089,6 +3094,8 @@
             }
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
         }
+
+        return newUidRules;
     }
 
     private class AppIdleStateChangeListener
@@ -3145,21 +3152,11 @@
         }
     }
 
-    private void dispatchRestrictBackgroundWhitelistChanged(INetworkPolicyListener listener,
-            int uid, boolean whitelisted) {
+    private void dispatchUidPoliciesChanged(INetworkPolicyListener listener, int uid,
+            int uidPolicies) {
         if (listener != null) {
             try {
-                listener.onRestrictBackgroundWhitelistChanged(uid, whitelisted);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    private void dispatchRestrictBackgroundBlacklistChanged(INetworkPolicyListener listener,
-            int uid, boolean blacklisted) {
-        if (listener != null) {
-            try {
-                listener.onRestrictBackgroundBlacklistChanged(uid, blacklisted);
+                listener.onUidPoliciesChanged(uid, uidPolicies);
             } catch (RemoteException ignored) {
             }
         }
@@ -3227,62 +3224,22 @@
                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
                     return true;
                 }
-                case MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED: {
-                    // MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED can be called in 2 occasions:
-                    // - when an app is whitelisted
-                    // - when an app is blacklisted
-                    //
-                    // Whether the internal listeners (INetworkPolicyListener implementations) or
-                    // app broadcast receivers are notified depend on the following rules:
-                    //
-                    // - App receivers are only notified when the app status changed (msg.arg2 = 1)
-                    // - Listeners are only notified when app was whitelisted (msg.obj is not null),
-                    //   since blacklist notifications are handled through MSG_RULES_CHANGED).
+                case MSG_POLICIES_CHANGED: {
                     final int uid = msg.arg1;
-                    final boolean changed = msg.arg2 == 1;
-                    final Boolean whitelisted = (Boolean) msg.obj;
-
+                    final int policy = msg.arg2;
+                    final Boolean notifyApp = (Boolean) msg.obj;
                     // First notify internal listeners...
-                    if (whitelisted != null) {
-                        final boolean whitelistedBool = whitelisted.booleanValue();
-                        dispatchRestrictBackgroundWhitelistChanged(mConnectivityListener, uid,
-                                whitelistedBool);
-                        final int length = mListeners.beginBroadcast();
-                        for (int i = 0; i < length; i++) {
-                            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
-                            dispatchRestrictBackgroundWhitelistChanged(listener, uid,
-                                    whitelistedBool);
-                        }
-                        mListeners.finishBroadcast();
-                    }
-                    final PackageManager pm = mContext.getPackageManager();
-                    final String[] packages = pm.getPackagesForUid(uid);
-                    if (changed && packages != null) {
-                        // ...then notify apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
-                        final int userId = UserHandle.getUserId(uid);
-                        for (String packageName : packages) {
-                            final Intent intent = new Intent(
-                                    ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
-                            intent.setPackage(packageName);
-                            intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                            mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-                        }
-                    }
-                    return true;
-                }
-                case MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED: {
-                    final int uid = msg.arg1;
-                    final boolean blacklisted = msg.arg2 == 1;
-
-                    dispatchRestrictBackgroundBlacklistChanged(mConnectivityListener, uid,
-                            blacklisted);
+                    dispatchUidPoliciesChanged(mConnectivityListener, uid, policy);
                     final int length = mListeners.beginBroadcast();
                     for (int i = 0; i < length; i++) {
                         final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
-                        dispatchRestrictBackgroundBlacklistChanged(listener, uid,
-                                blacklisted);
+                        dispatchUidPoliciesChanged(listener, uid, policy);
                     }
                     mListeners.finishBroadcast();
+                    // ...then apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
+                    if (notifyApp.booleanValue()) {
+                        broadcastRestrictBackgroundChanged(uid, notifyApp);
+                    }
                     return true;
                 }
                 case MSG_ADVISE_PERSIST_THRESHOLD: {
@@ -3308,13 +3265,45 @@
                     removeInterfaceQuota((String) msg.obj);
                     return true;
                 }
+                case MSG_SET_FIREWALL_RULES: {
+                    final int chain = msg.arg1;
+                    final int toggle = msg.arg2;
+                    final SparseIntArray uidRules = (SparseIntArray) msg.obj;
+                    if (uidRules != null) {
+                        setUidFirewallRules(chain, uidRules);
+                    }
+                    if (toggle != CHAIN_TOGGLE_NONE) {
+                        enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
+                    }
+                    return true;
+                }
+                case MSG_RESET_FIREWALL_RULES_BY_UID: {
+                    resetUidFirewallRules(msg.arg1);
+                    return true;
+                }
                 default: {
                     return false;
                 }
             }
         }
+
     };
 
+    private void broadcastRestrictBackgroundChanged(int uid, Boolean changed) {
+        final PackageManager pm = mContext.getPackageManager();
+        final String[] packages = pm.getPackagesForUid(uid);
+        if (packages != null) {
+            final int userId = UserHandle.getUserId(uid);
+            for (String packageName : packages) {
+                final Intent intent =
+                        new Intent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
+                intent.setPackage(packageName);
+                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+            }
+        }
+    }
+
     private void setInterfaceQuota(String iface, long quotaBytes) {
         try {
             mNetworkManager.setInterfaceQuota(iface, quotaBytes);
@@ -3357,6 +3346,31 @@
         }
     }
 
+    private static final int CHAIN_TOGGLE_NONE = 0;
+    private static final int CHAIN_TOGGLE_ENABLE = 1;
+    private static final int CHAIN_TOGGLE_DISABLE = 2;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            CHAIN_TOGGLE_NONE,
+            CHAIN_TOGGLE_ENABLE,
+            CHAIN_TOGGLE_DISABLE
+    })
+    public @interface ChainToggleType {
+    }
+
+    /**
+     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
+     * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
+     *
+     * @param chain firewall chain.
+     * @param uidRules new UID rules; if {@code null}, only toggles chain state.
+     * @param toggle whether the chain should be enabled, disabled, or not changed.
+     */
+    private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
+            @ChainToggleType int toggle) {
+        mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
+    }
+
     /**
      * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
      * here to netd.  It will clean up dead rules and make sure the target chain only contains rules
@@ -3419,6 +3433,24 @@
         }
     }
 
+    /**
+     * Resets all firewall rules associated with an UID.
+     */
+    private void resetUidFirewallRules(int uid) {
+        try {
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
+            mNetworkManager
+                    .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setUidMeteredNetworkWhitelist(uid, false);
+            mNetworkManager.setUidMeteredNetworkBlacklist(uid, false);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
             return mNetworkStats.getNetworkTotalBytes(template, start, end);
@@ -3527,18 +3559,6 @@
         }
     }
 
-    private class MyPackageMonitor extends PackageMonitor {
-
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
-            synchronized (mUidRulesFirstLock) {
-                removeRestrictBackgroundWhitelistedUidUL(uid, true, true);
-                updateRestrictionRulesForUidUL(uid);
-            }
-        }
-    }
-
     private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
 
         @Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 5e68f8e..8ced1c2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -16,9 +16,11 @@
 
 package com.android.server.net;
 
+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.wifi.WifiInfo.removeDoubleQuotes;
+
 import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
 import static com.android.server.net.NetworkPolicyManagerService.TAG;
 
@@ -191,10 +193,10 @@
         return -1;
     }
 
-    private int listRestrictBackgroundWhitelist() throws RemoteException {
+    private int listUidPolicies(String msg, int policy) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
-        pw.print("Restrict background whitelisted UIDs: ");
+        final int[] uids = mInterface.getUidsWithPolicy(policy);
+        pw.print(msg); pw.print(": ");
         if (uids.length == 0) {
             pw.println("none");
         } else {
@@ -208,22 +210,14 @@
         return 0;
     }
 
-    private int listRestrictBackgroundBlacklist() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
+    private int listRestrictBackgroundWhitelist() throws RemoteException {
+        return listUidPolicies("Restrict background whitelisted UIDs",
+                POLICY_ALLOW_METERED_BACKGROUND);
+    }
 
-        final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
-        pw.print("Restrict background blacklisted UIDs: ");
-        if (uids.length == 0) {
-            pw.println("none");
-        } else {
-            for (int i = 0; i < uids.length; i++) {
-                int uid = uids[i];
-                pw.print(uid);
-                pw.print(' ');
-            }
-        }
-        pw.println();
-        return 0;
+    private int listRestrictBackgroundBlacklist() throws RemoteException {
+        return listUidPolicies("Restrict background blacklisted UIDs",
+                POLICY_REJECT_METERED_BACKGROUND);
     }
 
     private int getRestrictBackground() throws RemoteException {
@@ -242,42 +236,46 @@
         return 0;
     }
 
-    private int addRestrictBackgroundWhitelist() throws RemoteException {
-      final int uid = getUidFromNextArg();
-      if (uid < 0) {
-          return uid;
-      }
-      mInterface.addRestrictBackgroundWhitelistedUid(uid);
-      return 0;
-    }
-
-    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+    private int setUidPolicy(int policy) throws RemoteException {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
             return uid;
         }
-        mInterface.removeRestrictBackgroundWhitelistedUid(uid);
+        mInterface.setUidPolicy(uid, policy);
         return 0;
     }
 
-    private int addRestrictBackgroundBlacklist() throws RemoteException {
+    private int resetUidPolicy(String errorMessage, int expectedPolicy) throws RemoteException {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
             return uid;
         }
-        mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
-        return 0;
-    }
-
-    private int removeRestrictBackgroundBlacklist() throws RemoteException {
-        final int uid = getUidFromNextArg();
-        if (uid < 0) {
-            return uid;
+        int actualPolicy = mInterface.getUidPolicy(uid);
+        if (actualPolicy != expectedPolicy) {
+            final PrintWriter pw = getOutPrintWriter();
+            pw.print("Error: UID "); pw.print(uid); pw.print(' '); pw.println(errorMessage);
+            return -1;
         }
         mInterface.setUidPolicy(uid, POLICY_NONE);
         return 0;
     }
 
+    private int addRestrictBackgroundWhitelist() throws RemoteException {
+        return setUidPolicy(POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
+    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+        return resetUidPolicy("not whitelisted", POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
+    private int addRestrictBackgroundBlacklist() throws RemoteException {
+        return setUidPolicy(POLICY_REJECT_METERED_BACKGROUND);
+    }
+
+    private int removeRestrictBackgroundBlacklist() throws RemoteException {
+        return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
+    }
+
     private int listWifiNetworks() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String arg = getNextArg();
@@ -335,9 +333,11 @@
                 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
                 newPolicies[newPolicies.length - 1] = policy;
                 mInterface.setNetworkPolicies(newPolicies);
+                return 0;
             }
         }
-        return 0;
+        pw.print("Error: didn't find network with SSID "); pw.println(id);
+        return -1;
     }
 
     private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
diff --git a/services/core/java/com/android/server/notification/ImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
index 885b9b7..3bdc22c 100644
--- a/services/core/java/com/android/server/notification/ImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -15,6 +15,7 @@
 */
 package com.android.server.notification;
 
+import android.app.NotificationManager;
 import android.content.Context;
 import android.util.Slog;
 
@@ -41,10 +42,17 @@
             if (DBG) Slog.d(TAG, "missing config");
             return null;
         }
-
-        record.setUserImportance(
-                mConfig.getImportance(record.sbn.getPackageName(), record.sbn.getUid()));
-
+        int importance = NotificationManager.IMPORTANCE_UNSPECIFIED;
+        int appImportance = mConfig.getImportance(
+                record.sbn.getPackageName(), record.sbn.getUid());
+        int channelImportance = record.getChannel().getImportance();
+        if (appImportance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
+            record.setUserImportance(channelImportance);
+        } else if (channelImportance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
+            record.setUserImportance(appImportance);
+        } else {
+            record.setUserImportance(Math.min(appImportance, channelImportance));
+        }
         return null;
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cee5a46..0c7c8aa 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationRankerService.REASON_CHANNEL_BANNED;
 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
@@ -55,10 +56,10 @@
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
-import android.app.RemoteInput;
 import android.app.StatusBarManager;
 import android.app.backup.BackupManager;
 import android.app.usage.UsageEvents;
@@ -93,7 +94,6 @@
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -122,6 +122,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+import android.view.WindowManager;
+import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
@@ -138,8 +140,8 @@
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
+import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.VrManagerInternal;
 import com.android.server.notification.ManagedServices.UserProfiles;
 
 import libcore.io.IoUtils;
@@ -193,7 +195,7 @@
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
     private static final int MESSAGE_RANKING_SORT = 1001;
 
-    static final int LONG_DELAY = 3500; // 3.5 seconds
+    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
     static final int SHORT_DELAY = 2000; // 2 seconds
 
     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
@@ -231,7 +233,7 @@
     AudioManagerInternal mAudioManagerInternal;
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
-    private VrManagerInternal mVrManagerInternal;
+    private WindowManagerInternal mWindowManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
     private Handler mHandler;
@@ -452,13 +454,15 @@
         final String pkg;
         final ITransientNotification callback;
         int duration;
+        Binder token;
 
-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
-        {
+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
+                    Binder token) {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
+            this.token = token;
         }
 
         void update(int duration) {
@@ -742,8 +746,8 @@
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
-                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
-                                    changeUserId, reason, null);
+                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
+                                    !queryRestart, changeUserId, reason, null);
                         }
                     }
                 }
@@ -775,13 +779,13 @@
             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
-                    cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
+                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
                             REASON_USER_STOPPED, null);
                 }
             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
-                    cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
+                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
                             REASON_PROFILE_TURNED_OFF, null);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
@@ -903,6 +907,28 @@
     }
 
     @VisibleForTesting
+    void setStatusBarManager(StatusBarManagerInternal statusBar) {
+        mStatusBar = statusBar;
+    }
+
+    @VisibleForTesting
+    void setLights(Light light) {
+        mNotificationLight = light;
+        mAttentionLight = light;
+    }
+
+    @VisibleForTesting
+    void setScreenOn(boolean on) {
+        mScreenOn = on;
+    }
+
+    @VisibleForTesting
+    void addNotification(NotificationRecord r) {
+        mNotificationList.add(r);
+        mNotificationsByKey.put(r.sbn.getKey(), r);
+    }
+
+    @VisibleForTesting
     void setSystemReady(boolean systemReady) {
         mSystemReady = systemReady;
     }
@@ -1124,7 +1150,7 @@
             // Grab our optional AudioService
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
-            mVrManagerInternal = getLocalService(VrManagerInternal.class);
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -1144,8 +1170,8 @@
 
         // Now, cancel any outstanding notifications that are part of a just-disabled app
         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
-            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
-                    REASON_PACKAGE_BANNED, null);
+            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
+                    UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
         }
     }
 
@@ -1325,10 +1351,13 @@
                             }
                         }
 
-                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        Binder token = new Binder();
+                        mWindowManagerInternal.addWindowToken(token,
+                                WindowManager.LayoutParams.TYPE_TOAST);
+                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveLocked(callingPid);
+                        keepProcessAliveIfNeededLocked(callingPid);
                     }
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
@@ -1400,7 +1429,7 @@
             // Calling from user space, don't allow the canceling of actively
             // running foreground services.
             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
-                    pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
+                    pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
                     REASON_APP_CANCEL_ALL, null);
         }
 
@@ -1478,6 +1507,87 @@
             return mRankingHelper.getImportance(pkg, uid);
         }
 
+        @Override
+        public void createNotificationChannel(String pkg, NotificationChannel channel) {
+            Preconditions.checkNotNull(channel);
+            Preconditions.checkNotNull(channel.getId());
+            Preconditions.checkNotNull(channel.getName());
+            checkCallerIsSystemOrSameApp(pkg);
+            mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel);
+            savePolicyFile();
+        }
+
+        @Override
+        public void updateNotificationChannel(String pkg, NotificationChannel channel) {
+            Preconditions.checkNotNull(channel);
+            Preconditions.checkNotNull(channel.getId());
+            checkCallerIsSystemOrSameApp(pkg);
+            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
+                // cancel
+                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
+                        UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+            }
+            mRankingHelper.updateNotificationChannel(Binder.getCallingUid(), pkg,
+                    Binder.getCallingUid(), channel);
+            savePolicyFile();
+        }
+
+        @Override
+        public NotificationChannel getNotificationChannel(String pkg, String channelId) {
+            Preconditions.checkNotNull(channelId);
+            checkCallerIsSystemOrSameApp(pkg);
+            return mRankingHelper.getNotificationChannel(pkg, Binder.getCallingUid(), channelId);
+        }
+
+        @Override
+        public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
+                String channelId) {
+            Preconditions.checkNotNull(channelId);
+            checkCallerIsSystem();
+            return mRankingHelper.getNotificationChannel(pkg, uid, channelId);
+        }
+
+        @Override
+        public void deleteNotificationChannel(String pkg, String channelId) {
+            Preconditions.checkNotNull(channelId);
+            checkCallerIsSystemOrSameApp(pkg);
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+                throw new IllegalArgumentException("Cannot delete default channel");
+            }
+            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
+                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+            mRankingHelper.deleteNotificationChannel(pkg, Binder.getCallingUid(), channelId);
+            savePolicyFile();
+        }
+
+        @Override
+        public void updateNotificationChannelForPackage(String pkg, int uid,
+                NotificationChannel channel) {
+            Preconditions.checkNotNull(channel);
+            Preconditions.checkNotNull(channel.getId());
+            checkCallerIsSystem();
+            if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
+                // cancel
+                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
+                        UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+            }
+            mRankingHelper.updateNotificationChannel(Binder.getCallingUid(), pkg, uid, channel);
+            savePolicyFile();
+        }
+
+        @Override
+        public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
+                int uid) {
+            checkCallerIsSystem();
+            return mRankingHelper.getNotificationChannels(pkg, uid);
+        }
+
+        @Override
+        public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
+            checkCallerIsSystemOrSameApp(pkg);
+            return mRankingHelper.getNotificationChannels(pkg, Binder.getCallingUid());
+        }
+
         /**
          * System-only API for getting a list of current (i.e. not cleared) notifications.
          *
@@ -1947,6 +2057,29 @@
             });
         }
 
+        @Override
+        public void requestUnbindProvider(IConditionProvider provider) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                // allow bound services to disable themselves
+                final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
+                info.getOwner().setComponentState(info.component, false);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void requestBindProvider(ComponentName component) {
+            checkCallerIsSystemOrSameApp(component.getPackageName());
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mConditionProviders.setComponentState(component, true);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
         private void enforceSystemOrSystemUIOrVolume(String message) {
             if (mAudioManagerInternal != null) {
                 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
@@ -2304,7 +2437,10 @@
                                         summaryNotification, adjustedSbn.getUser(),
                                         newAutoBundleKey,
                                         System.currentTimeMillis());
-                        summaryRecord = new NotificationRecord(getContext(), summarySbn);
+                        summaryRecord = new NotificationRecord(getContext(), summarySbn,
+                                mRankingHelper.getNotificationChannel(adjustedSbn.getPackageName(),
+                                        adjustedSbn.getUid(),
+                                        adjustedSbn.getNotification().getNotificationChannel()));
                         summaries.put(adjustment.getPackage(), summarySbn.getKey());
                     }
                 }
@@ -2608,7 +2744,9 @@
                 Notification.PRIORITY_MAX);
 
         // setup local book-keeping
-        final NotificationRecord r = new NotificationRecord(getContext(), n);
+        final NotificationRecord r = new NotificationRecord(getContext(), n,
+                mRankingHelper.getNotificationChannel(pkg, callingUid,
+                        n.getNotification().getNotificationChannel()));
         mHandler.post(new EnqueueNotificationRunnable(userId, r));
 
         idOut[0] = id;
@@ -2666,7 +2804,8 @@
                 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
 
                 // blocked apps
-                if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
+                if (r.getImportance() == NotificationManager.IMPORTANCE_NONE
+                        || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
                         || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
                     if (!isSystemNotification) {
                         if (isPackageSuspended) {
@@ -2834,9 +2973,8 @@
             // DEFAULT_SOUND or because notification.sound is pointing at
             // Settings.System.NOTIFICATION_SOUND)
             final boolean useDefaultSound =
-                   (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
-                           Settings.System.DEFAULT_NOTIFICATION_URI
-                                   .equals(notification.sound);
+                    (notification.defaults & Notification.DEFAULT_SOUND) != 0
+                    || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound);
 
             Uri soundUri = null;
             if (useDefaultSound) {
@@ -2847,6 +2985,9 @@
             } else if (notification.sound != null) {
                 soundUri = notification.sound;
                 hasValidSound = (soundUri != null);
+            } else if (record.getChannel().getDefaultRingtone() != null) {
+                soundUri = record.getChannel().getDefaultRingtone();
+                hasValidSound = (soundUri != null);
             }
 
             // Does the notification want to specify its own vibration?
@@ -2863,8 +3004,10 @@
             final boolean useDefaultVibrate =
                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
 
+            final boolean hasChannelVibration = record.getChannel().shouldVibrate();
+
             hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
-                    hasCustomVibrate;
+                    hasCustomVibrate || hasChannelVibration;
 
             // We can alert, and we're allowed to alert, but if the developer asked us to only do
             // it once, and we already have, then don't.
@@ -2900,26 +3043,13 @@
                         }
                     }
                 }
-
                 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
                         == AudioManager.RINGER_MODE_SILENT)) {
                     mVibrateNotificationKey = key;
 
                     if (useDefaultVibrate || convertSoundToVibration) {
-                        // Escalate privileges so we can use the vibrator even if the
-                        // notifying app does not have the VIBRATE permission.
-                        long identity = Binder.clearCallingIdentity();
-                        try {
-                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
-                                    useDefaultVibrate ? mDefaultVibrationPattern
-                                            : mFallbackVibrationPattern,
-                                    ((notification.flags & Notification.FLAG_INSISTENT) != 0)
-                                            ? 0: -1, audioAttributesForNotification(notification));
-                            buzz = true;
-                        } finally {
-                            Binder.restoreCallingIdentity(identity);
-                        }
-                    } else if (notification.vibrate.length > 1) {
+                        playNonCustomVibration(record, useDefaultVibrate);
+                    } else if (notification.vibrate != null && notification.vibrate.length > 1) {
                         // If you want your own vibration pattern, you need the VIBRATE
                         // permission
                         mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
@@ -2927,6 +3057,8 @@
                                 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
                                         ? 0: -1, audioAttributesForNotification(notification));
                         buzz = true;
+                    } else if (hasChannelVibration) {
+                        playNonCustomVibration(record, useDefaultVibrate);
                     }
                 }
             }
@@ -2944,7 +3076,7 @@
         // light
         // release the light
         boolean wasShowLights = mLights.remove(key);
-        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
+        if (shouldShowLights(record) && aboveThreshold
                 && ((record.getSuppressedVisualEffects()
                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
             mLights.add(key);
@@ -2968,6 +3100,28 @@
         }
     }
 
+    private boolean shouldShowLights(final NotificationRecord record) {
+        return record.getChannel().shouldShowLights()
+                || (record.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0;
+    }
+
+    private boolean playNonCustomVibration(final NotificationRecord record,
+            boolean useDefaultVibrate) {
+        // Escalate privileges so we can use the vibrator even if the
+        // notifying app does not have the VIBRATE permission.
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                    useDefaultVibrate ? mDefaultVibrationPattern
+                            : mFallbackVibrationPattern,
+                    ((record.getNotification().flags & Notification.FLAG_INSISTENT) != 0)
+                            ? 0: -1, audioAttributesForNotification(record.getNotification()));
+            return true;
+        } finally{
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     private static AudioAttributes audioAttributesForNotification(Notification n) {
         if (n.audioAttributes != null
                 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
@@ -2991,7 +3145,7 @@
         while (record != null) {
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
-                record.callback.show();
+                record.callback.show(record.token);
                 scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
@@ -3002,7 +3156,7 @@
                 if (index >= 0) {
                     mToastQueue.remove(index);
                 }
-                keepProcessAliveLocked(record.pid);
+                keepProcessAliveIfNeededLocked(record.pid);
                 if (mToastQueue.size() > 0) {
                     record = mToastQueue.get(0);
                 } else {
@@ -3022,8 +3176,11 @@
             // don't worry about this, we're about to remove it from
             // the list anyway
         }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
+
+        ToastRecord lastToast = mToastQueue.remove(index);
+        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
+
+        keepProcessAliveIfNeededLocked(record.pid);
         if (mToastQueue.size() > 0) {
             // Show the next one. If the callback fails, this will remove
             // it from the list, so don't assume that the list hasn't changed
@@ -3067,7 +3224,7 @@
     }
 
     // lock on mToastQueue
-    void keepProcessAliveLocked(int pid)
+    void keepProcessAliveIfNeededLocked(int pid)
     {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
@@ -3455,8 +3612,8 @@
      * Cancels all notifications from a given package that have all of the
      * {@code mustHaveFlags}.
      */
-    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
-            int mustNotHaveFlags, boolean doit, int userId, int reason,
+    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
+            int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -3484,6 +3641,9 @@
                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
                     continue;
                 }
+                if (channelId == null || !channelId.equals(r.getChannel().getId())) {
+                    continue;
+                }
                 if (canceledNotifications == null) {
                     canceledNotifications = new ArrayList<>();
                 }
@@ -3602,7 +3762,8 @@
             int ledARGB = ledno.ledARGB;
             int ledOnMS = ledno.ledOnMS;
             int ledOffMS = ledno.ledOffMS;
-            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0
+                    || (ledno.flags & Notification.FLAG_SHOW_LIGHTS) == 0) {
                 ledARGB = mDefaultNotificationColor;
                 ledOnMS = mDefaultNotificationLedOn;
                 ledOffMS = mDefaultNotificationLedOff;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 7c89e9f..c5de93e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -23,12 +23,14 @@
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
+import android.net.Uri;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
@@ -101,8 +103,11 @@
     private String mUserExplanation;
     private String mPeopleExplanation;
 
+    private NotificationChannel mNotificationChannel;
+
     @VisibleForTesting
-    public NotificationRecord(Context context, StatusBarNotification sbn)
+    public NotificationRecord(Context context, StatusBarNotification sbn,
+            NotificationChannel channel)
     {
         this.sbn = sbn;
         mOriginalFlags = sbn.getNotification().flags;
@@ -111,6 +116,7 @@
         mUpdateTimeMs = mCreationTimeMs;
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
+        mNotificationChannel = channel;
         mImportance = defaultImportance();
     }
 
@@ -145,7 +151,9 @@
         boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
                 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
                 || n.sound != null
-                || n.vibrate != null;
+                || n.vibrate != null
+                || mNotificationChannel.shouldVibrate()
+                || mNotificationChannel.getDefaultRingtone() != null;
         stats.isNoisy = isNoisy;
 
         if (!isNoisy && importance > IMPORTANCE_LOW) {
@@ -203,6 +211,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);
@@ -282,6 +291,7 @@
         pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "  mSuppressedVisualEffects= " + mSuppressedVisualEffects);
+        pw.println(prefix + "  mNotificationChannel= " + mNotificationChannel);
     }
 
 
@@ -526,4 +536,8 @@
     public boolean isImportanceFromUser() {
         return mImportance == mUserImportance;
     }
+
+    public NotificationChannel getChannel() {
+        return mNotificationChannel;
+    }
 }
diff --git a/services/core/java/com/android/server/notification/PriorityExtractor.java b/services/core/java/com/android/server/notification/PriorityExtractor.java
index 6c76476..666cf00d 100644
--- a/services/core/java/com/android/server/notification/PriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PriorityExtractor.java
@@ -15,6 +15,7 @@
 */
 package com.android.server.notification;
 
+import android.app.Notification;
 import android.content.Context;
 import android.util.Slog;
 
@@ -42,8 +43,11 @@
             return null;
         }
 
-        record.setPackagePriority(
-                mConfig.getPriority(record.sbn.getPackageName(), record.sbn.getUid()));
+        int priority = mConfig.getPriority(record.sbn.getPackageName(), record.sbn.getUid());
+        if (priority == Notification.PRIORITY_DEFAULT && record.getChannel().canBypassDnd()){
+            priority = Notification.PRIORITY_MAX;
+        }
+        record.setPackagePriority(priority);
 
         return null;
     }
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b5cc2ef..2df4043 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.notification;
 
+import android.app.NotificationChannel;
+import android.content.pm.ParceledListSlice;
+
 public interface RankingConfig {
 
     int getPriority(String packageName, int uid);
@@ -28,4 +31,10 @@
     void setImportance(String packageName, int uid, int importance);
 
     int getImportance(String packageName, int uid);
+
+    void createNotificationChannel(String pkg, int uid, NotificationChannel channel);
+    void updateNotificationChannel(int callingUid, String pkg, int uid, NotificationChannel channel);
+    NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
+    void deleteNotificationChannel(String pkg, int uid, String channelId);
+    ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 32c5b13..7182da1 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -16,16 +16,19 @@
 package com.android.server.notification;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
+import android.os.Process;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 
-import com.android.server.notification.NotificationManagerService.DumpFilter;
+import com.android.internal.R;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -38,6 +41,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -48,15 +52,15 @@
 
     private static final String TAG_RANKING = "ranking";
     private static final String TAG_PACKAGE = "package";
-    private static final String ATT_VERSION = "version";
+    private static final String TAG_CHANNEL = "channel";
 
+    private static final String ATT_VERSION = "version";
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
+    private static final String ATT_ID = "id";
     private static final String ATT_PRIORITY = "priority";
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
-    private static final String ATT_TOPIC_ID = "id";
-    private static final String ATT_TOPIC_LABEL = "label";
 
     private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
     private static final int DEFAULT_VISIBILITY = Ranking.VISIBILITY_NO_OVERRIDE;
@@ -166,6 +170,28 @@
                         r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                         r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
                         r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
+
+                        final int innerDepth = parser.getDepth();
+                        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                                && (type != XmlPullParser.END_TAG
+                                || parser.getDepth() > innerDepth)) {
+                            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                                continue;
+                            }
+
+                            String tagName = parser.getName();
+                            if (TAG_CHANNEL.equals(tagName)) {
+                                String id = parser.getAttributeValue(null, ATT_ID);
+                                CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
+
+                                if (!TextUtils.isEmpty(id)) {
+                                    final NotificationChannel channel =
+                                            new NotificationChannel(id, channelName);
+                                    channel.populateFromXml(parser);
+                                    r.channels.put(id, channel);
+                                }
+                            }
+                        }
                     }
                 }
             }
@@ -184,11 +210,18 @@
             r = new Record();
             r.pkg = pkg;
             r.uid = uid;
+            NotificationChannel defaultChannel = createDefaultChannel();
+            r.channels.put(defaultChannel.getId(), defaultChannel);
             mRecords.put(key, r);
         }
         return r;
     }
 
+    private NotificationChannel createDefaultChannel() {
+        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID,
+                mContext.getString(R.string.default_notification_channel_label));
+    }
+
     public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
         out.startTag(null, TAG_RANKING);
         out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
@@ -201,7 +234,8 @@
                 continue;
             }
             final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
-                    || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
+                    || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY
+                    || r.channels.size() > 0;
             if (hasNonDefaultSettings) {
                 out.startTag(null, TAG_PACKAGE);
                 out.attribute(null, ATT_NAME, r.pkg);
@@ -219,6 +253,10 @@
                     out.attribute(null, ATT_UID, Integer.toString(r.uid));
                 }
 
+                for (NotificationChannel channel : r.channels.values()) {
+                    channel.writeXml(out);
+                }
+
                 out.endTag(null, TAG_PACKAGE);
             }
         }
@@ -309,11 +347,6 @@
         }
     }
 
-    private static boolean tryParseBool(String value, boolean defValue) {
-        if (TextUtils.isEmpty(value)) return defValue;
-        return Boolean.parseBoolean(value);
-    }
-
     /**
      * Gets priority.
      */
@@ -356,6 +389,65 @@
         return getOrCreateRecord(packageName, uid).importance;
     }
 
+    @Override
+    public void createNotificationChannel(String pkg, int uid, NotificationChannel channel) {
+        Record r = getOrCreateRecord(pkg, uid);
+        if (r.channels.containsKey(channel.getId()) || channel.getName().equals(
+                mContext.getString(R.string.default_notification_channel_label))) {
+            throw new IllegalArgumentException("Channel already exists");
+        }
+        if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+            channel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
+        }
+        r.channels.put(channel.getId(), channel);
+        updateConfig();
+    }
+
+    @Override
+    public void updateNotificationChannel(int callingUid, String pkg, int uid,
+            NotificationChannel updatedChannel) {
+        Record r = getOrCreateRecord(pkg, uid);
+        NotificationChannel channel = r.channels.get(updatedChannel.getId());
+        if (channel == null) {
+            throw new IllegalArgumentException("Channel does not exist");
+        }
+        if (!isUidSystem(callingUid)) {
+            updatedChannel.setImportance(channel.getImportance());
+            updatedChannel.setName(channel.getName());
+        }
+        if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+            updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
+        }
+        r.channels.put(updatedChannel.getId(), updatedChannel);
+        updateConfig();
+    }
+
+    @Override
+    public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId) {
+        Record r = getOrCreateRecord(pkg, uid);
+        if (channelId == null) {
+            channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
+        }
+        return r.channels.get(channelId);
+    }
+
+    @Override
+    public void deleteNotificationChannel(String pkg, int uid, String channelId) {
+        Record r = getOrCreateRecord(pkg, uid);
+        r.channels.remove(channelId);
+    }
+
+    @Override
+    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid) {
+        List<NotificationChannel> channels = new ArrayList<>();
+        Record r = getOrCreateRecord(pkg, uid);
+        int N = r.channels.size();
+        for (int i = 0; i < N; i++) {
+            channels.add(r.channels.valueAt(i));
+        }
+        return new ParceledListSlice<NotificationChannel>(channels);
+    }
+
     /**
      * Sets importance.
      */
@@ -420,6 +512,12 @@
                     pw.print(Notification.visibilityToString(r.visibility));
                 }
                 pw.println();
+                for (NotificationChannel channel : r.channels.values()) {
+                    pw.print(prefix);
+                    pw.print("  ");
+                    pw.print("  ");
+                    pw.println(channel);
+                }
             }
         }
     }
@@ -449,6 +547,9 @@
                     if (r.visibility != DEFAULT_VISIBILITY) {
                         record.put("visibility", Notification.visibilityToString(r.visibility));
                     }
+                    for (NotificationChannel channel : r.channels.values()) {
+                        record.put("channel", channel.toJson());
+                    }
                 } catch (JSONException e) {
                    // pass
                 }
@@ -530,6 +631,11 @@
         }
     }
 
+    private static boolean isUidSystem(int uid) {
+        final int appid = UserHandle.getAppId(uid);
+        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
+    }
+
     private static class Record {
         static int UNKNOWN_UID = UserHandle.USER_NULL;
 
@@ -538,5 +644,7 @@
         int importance = DEFAULT_IMPORTANCE;
         int priority = DEFAULT_PRIORITY;
         int visibility = DEFAULT_VISIBILITY;
+
+        ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
    }
 }
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 32d03ce..50a51b2 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -40,7 +40,9 @@
 import com.android.server.notification.NotificationManagerService.DumpFilter;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.List;
 import java.util.TimeZone;
 
 /**
@@ -91,12 +93,14 @@
         pw.print("      mRegistered="); pw.println(mRegistered);
         pw.println("      mSubscriptions=");
         final long now = System.currentTimeMillis();
-        for (Uri conditionId : mSubscriptions.keySet()) {
-            pw.print("        ");
-            pw.print(meetsSchedule(mSubscriptions.get(conditionId), now) ? "* " : "  ");
-            pw.println(conditionId);
-            pw.print("            ");
-            pw.println(mSubscriptions.get(conditionId).toString());
+        synchronized (mSubscriptions) {
+            for (Uri conditionId : mSubscriptions.keySet()) {
+                pw.print("        ");
+                pw.print(meetsSchedule(mSubscriptions.get(conditionId), now) ? "* " : "  ");
+                pw.println(conditionId);
+                pw.print("            ");
+                pw.println(mSubscriptions.get(conditionId).toString());
+            }
         }
         pw.println("      snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozed));
         dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
@@ -125,17 +129,21 @@
     public void onSubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
         if (!ZenModeConfig.isValidScheduleConditionId(conditionId)) {
-            notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
+            notifyCondition(createCondition(conditionId, Condition.STATE_FALSE, "badCondition"));
             return;
         }
-        mSubscriptions.put(conditionId, toScheduleCalendar(conditionId));
+        synchronized (mSubscriptions) {
+            mSubscriptions.put(conditionId, toScheduleCalendar(conditionId));
+        }
         evaluateSubscriptions();
     }
 
     @Override
     public void onUnsubscribe(Uri conditionId) {
         if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
-        mSubscriptions.remove(conditionId);
+        synchronized (mSubscriptions) {
+            mSubscriptions.remove(conditionId);
+        }
         removeSnoozed(conditionId);
         evaluateSubscriptions();
     }
@@ -154,36 +162,43 @@
         if (mAlarmManager == null) {
             mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         }
-        setRegistered(!mSubscriptions.isEmpty());
         final long now = System.currentTimeMillis();
         mNextAlarmTime = 0;
         long nextUserAlarmTime = getNextAlarm();
-        for (Uri conditionId : mSubscriptions.keySet()) {
-            final ScheduleCalendar cal = mSubscriptions.get(conditionId);
-            if (cal != null && cal.isInSchedule(now)) {
-                if (conditionSnoozed(conditionId) || cal.shouldExitForAlarm(now)) {
-                    notifyCondition(conditionId, Condition.STATE_FALSE, "alarmCanceled");
-                    addSnoozed(conditionId);
-                } else {
-                    notifyCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
-                }
-                cal.maybeSetNextAlarm(now, nextUserAlarmTime);
-            } else {
-                notifyCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
-                removeSnoozed(conditionId);
-                if (nextUserAlarmTime == 0) {
+        List<Condition> conditionsToNotify = new ArrayList<>();
+        synchronized (mSubscriptions) {
+            setRegistered(!mSubscriptions.isEmpty());
+            for (Uri conditionId : mSubscriptions.keySet()) {
+                final ScheduleCalendar cal = mSubscriptions.get(conditionId);
+                if (cal != null && cal.isInSchedule(now)) {
+                    if (conditionSnoozed(conditionId) || cal.shouldExitForAlarm(now)) {
+                        conditionsToNotify.add(createCondition(
+                                conditionId, Condition.STATE_FALSE, "alarmCanceled"));
+                        addSnoozed(conditionId);
+                    } else {
+                        conditionsToNotify.add(createCondition(
+                                conditionId, Condition.STATE_TRUE, "meetsSchedule"));
+                    }
                     cal.maybeSetNextAlarm(now, nextUserAlarmTime);
+                } else {
+                    conditionsToNotify.add(createCondition(
+                            conditionId, Condition.STATE_FALSE, "!meetsSchedule"));
+                    removeSnoozed(conditionId);
+                    if (cal != null && nextUserAlarmTime == 0) {
+                        cal.maybeSetNextAlarm(now, nextUserAlarmTime);
+                    }
                 }
-            }
-            if (cal != null) {
-                final long nextChangeTime = cal.getNextChangeTime(now);
-                if (nextChangeTime > 0 && nextChangeTime > now) {
-                    if (mNextAlarmTime == 0 || nextChangeTime < mNextAlarmTime) {
-                        mNextAlarmTime = nextChangeTime;
+                if (cal != null) {
+                    final long nextChangeTime = cal.getNextChangeTime(now);
+                    if (nextChangeTime > 0 && nextChangeTime > now) {
+                        if (mNextAlarmTime == 0 || nextChangeTime < mNextAlarmTime) {
+                            mNextAlarmTime = nextChangeTime;
+                        }
                     }
                 }
             }
         }
+        notifyConditions(conditionsToNotify.toArray(new Condition[conditionsToNotify.size()]));
         updateAlarm(now, mNextAlarmTime);
     }
 
@@ -240,14 +255,10 @@
         }
     }
 
-    private void notifyCondition(Uri conditionId, int state, String reason) {
-        if (DEBUG) Slog.d(TAG, "notifyCondition " + conditionId
+    private Condition createCondition(Uri id, int state, String reason) {
+        if (DEBUG) Slog.d(TAG, "notifyCondition " + id
                 + " " + Condition.stateToString(state)
                 + " reason=" + reason);
-        notifyCondition(createCondition(conditionId, state));
-    }
-
-    private Condition createCondition(Uri id, int state) {
         final String summary = NOT_SHOWN;
         final String line1 = NOT_SHOWN;
         final String line2 = NOT_SHOWN;
@@ -315,10 +326,12 @@
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction());
             if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
-                for (Uri conditionId : mSubscriptions.keySet()) {
-                    final ScheduleCalendar cal = mSubscriptions.get(conditionId);
-                    if (cal != null) {
-                        cal.setTimeZone(Calendar.getInstance().getTimeZone());
+                synchronized (mSubscriptions) {
+                    for (Uri conditionId : mSubscriptions.keySet()) {
+                        final ScheduleCalendar cal = mSubscriptions.get(conditionId);
+                        if (cal != null) {
+                            cal.setTimeZone(Calendar.getInstance().getTimeZone());
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/notification/VisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
index 2da2b2f..9d0e506 100644
--- a/services/core/java/com/android/server/notification/VisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -16,6 +16,7 @@
 package com.android.server.notification;
 
 import android.content.Context;
+import android.service.notification.NotificationListenerService;
 import android.util.Slog;
 
 /**
@@ -42,8 +43,12 @@
             return null;
         }
 
-        record.setPackageVisibilityOverride(
-                mConfig.getVisibilityOverride(record.sbn.getPackageName(), record.sbn.getUid()));
+        int visibility =
+                mConfig.getVisibilityOverride(record.sbn.getPackageName(), record.sbn.getUid());
+        if (visibility == NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
+            visibility = record.getChannel().getLockscreenVisibility();
+        }
+        record.setPackageVisibilityOverride(visibility);
 
         return null;
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 7badecf..63c0baf 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -102,7 +102,7 @@
     @Override
     public void onServiceAdded(ComponentName component) {
         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
-        mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
+        mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
     }
 
     @Override
@@ -116,7 +116,7 @@
             updated |= updateSnoozing(automaticRule);
         }
         if (updated) {
-            mHelper.setConfigAsync(config, "conditionChanged");
+            mHelper.setConfig(config, "conditionChanged");
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 4393761..29fa754 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -35,6 +35,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
@@ -490,7 +491,6 @@
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mZenMode=");
         pw.println(Global.zenModeToString(mZenMode));
-        dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
         final int N = mConfigs.size();
         for (int i = 0; i < N; i++) {
             dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
@@ -529,7 +529,7 @@
 
     public void readXml(XmlPullParser parser, boolean forRestore)
             throws XmlPullParserException, IOException {
-        final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
+        final ZenModeConfig config = ZenModeConfig.readXml(parser);
         if (config != null) {
             if (forRestore) {
                 //TODO: http://b/22388012
@@ -619,8 +619,10 @@
         return setConfigLocked(config, reason, true /*setRingerMode*/);
     }
 
-    public void setConfigAsync(ZenModeConfig config, String reason) {
-        mHandler.postSetConfig(config, reason);
+    public void setConfig(ZenModeConfig config, String reason) {
+        synchronized (mConfig) {
+            setConfigLocked(config, reason);
+        }
     }
 
     private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
@@ -736,13 +738,14 @@
         // total silence restrictions
         final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
 
-        for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) {
-            if (i == USAGE_NOTIFICATION) {
-                applyRestrictions(muteNotifications || muteEverything, i);
-            } else if (i == USAGE_NOTIFICATION_RINGTONE) {
-                applyRestrictions(muteCalls || muteEverything, i);
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
+            if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
+                applyRestrictions(muteNotifications || muteEverything, usage);
+            } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
+                applyRestrictions(muteCalls || muteEverything, usage);
             } else {
-                applyRestrictions(muteEverything, i);
+                applyRestrictions(muteEverything, usage);
             }
         }
     }
@@ -806,7 +809,7 @@
         try {
             parser = resources.getXml(R.xml.default_zen_mode_config);
             while (parser.next() != XmlPullParser.END_DOCUMENT) {
-                final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
+                final ZenModeConfig config = ZenModeConfig.readXml(parser);
                 if (config != null) return config;
             }
         } catch (Exception e) {
@@ -878,45 +881,6 @@
         }
     }
 
-    private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() {
-        @Override
-        public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) {
-            if (v1 == null) return null;
-            final ZenModeConfig rt = new ZenModeConfig();
-            rt.allowCalls = v1.allowCalls;
-            rt.allowEvents = v1.allowEvents;
-            rt.allowCallsFrom = v1.allowFrom;
-            rt.allowMessages = v1.allowMessages;
-            rt.allowMessagesFrom = v1.allowFrom;
-            rt.allowReminders = v1.allowReminders;
-            // don't migrate current exit condition
-            final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode);
-            if (days != null && days.length > 0) {
-                Log.i(TAG, "Migrating existing V1 downtime to single schedule");
-                final ScheduleInfo schedule = new ScheduleInfo();
-                schedule.days = days;
-                schedule.startHour = v1.sleepStartHour;
-                schedule.startMinute = v1.sleepStartMinute;
-                schedule.endHour = v1.sleepEndHour;
-                schedule.endMinute = v1.sleepEndMinute;
-                final ZenRule rule = new ZenRule();
-                rule.enabled = true;
-                rule.name = mContext.getResources()
-                        .getString(R.string.zen_mode_downtime_feature_name);
-                rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
-                rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
-                        : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-                rule.component = ScheduleConditionProvider.COMPONENT;
-                rt.automaticRules.put(ZenModeConfig.newRuleId(), rule);
-            } else {
-                Log.i(TAG, "No existing V1 downtime found, generating default schedules");
-                appendDefaultScheduleRules(rt);
-            }
-            appendDefaultEventRules(rt);
-            return rt;
-        }
-    };
-
     private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
         @Override
         public String toString() {
@@ -1082,7 +1046,6 @@
     private final class H extends Handler {
         private static final int MSG_DISPATCH = 1;
         private static final int MSG_METRICS = 2;
-        private static final int MSG_SET_CONFIG = 3;
         private static final int MSG_APPLY_CONFIG = 4;
 
         private final class ConfigMessageData {
@@ -1090,12 +1053,6 @@
             public final String reason;
             public final boolean setRingerMode;
 
-            ConfigMessageData(ZenModeConfig config, String reason) {
-                this.config = config;
-                this.reason = reason;
-                this.setRingerMode = false;
-            }
-
             ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
                 this.config = config;
                 this.reason = reason;
@@ -1119,10 +1076,6 @@
             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
         }
 
-        private void postSetConfig(ZenModeConfig config, String reason) {
-            sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
-        }
-
         private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
                     new ConfigMessageData(config, reason, setRingerMode)));
@@ -1137,12 +1090,6 @@
                 case MSG_METRICS:
                     mMetrics.emit();
                     break;
-                case MSG_SET_CONFIG:
-                    ConfigMessageData configData = (ConfigMessageData) msg.obj;
-                    synchronized (mConfig) {
-                        setConfigLocked(configData.config, configData.reason);
-                    }
-                    break;
                 case MSG_APPLY_CONFIG:
                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
                     applyConfig(applyConfigData.config, applyConfigData.reason,
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
new file mode 100644
index 0000000..759030b
--- /dev/null
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.os;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IDeviceIdentifiersPolicyService;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import com.android.server.SystemService;
+
+/**
+ * This service defines the policy for accessing device identifiers.
+ */
+public final class DeviceIdentifiersPolicyService extends SystemService {
+    public DeviceIdentifiersPolicyService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.DEVICE_IDENTIFIERS_SERVICE,
+                new DeviceIdentifiersPolicy(getContext()));
+    }
+
+    private static final class DeviceIdentifiersPolicy
+            extends IDeviceIdentifiersPolicyService.Stub {
+        private final @NonNull Context mContext;
+
+        public DeviceIdentifiersPolicy(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public @Nullable String getSerial() throws RemoteException {
+            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.READ_PHONE_STATE, "getSerial");
+            }
+            return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+        }
+    }
+}
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..ded85f3 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);
+                        continue;
+                    }
+
+                    // The package must support runtime permissions
+                    if (!doesPackageSupportRuntimePermissions(pkg)) {
+                        Log.w(TAG, "Skipping non supporting runtime permissions package:"
+                                + packageName);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    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/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 8d926f5..68b465a 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -60,7 +60,7 @@
 
     public EphemeralResolverConnection(Context context, ComponentName componentName) {
         mContext = context;
-        mIntent = new Intent().setComponent(componentName);
+        mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
     }
 
     public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 72c549f..2e18b1c 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -230,6 +230,11 @@
         mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
     }
 
+    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
+            throws InstallerException {
+        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 53e328c..48e000d8 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)) {
@@ -631,17 +631,20 @@
             public void onPackageAdded(String packageName, int uid) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
-                    try {
-                        listener.onPackageAdded(user, packageName);
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue;
+                        try {
+                            listener.onPackageAdded(user, packageName);
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackageAdded(packageName, uid);
             }
@@ -650,17 +653,20 @@
             public void onPackageRemoved(String packageName, int uid) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
-                    try {
-                        listener.onPackageRemoved(user, packageName);
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue;
+                        try {
+                            listener.onPackageRemoved(user, packageName);
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackageRemoved(packageName, uid);
             }
@@ -669,17 +675,20 @@
             public void onPackageModified(String packageName) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
-                    try {
-                        listener.onPackageChanged(user, packageName);
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue;
+                        try {
+                            listener.onPackageChanged(user, packageName);
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackageModified(packageName);
             }
@@ -688,17 +697,20 @@
             public void onPackagesAvailable(String[] packages) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
-                    try {
-                        listener.onPackagesAvailable(user, packages, isReplacing());
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue;
+                        try {
+                            listener.onPackagesAvailable(user, packages, isReplacing());
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackagesAvailable(packages);
             }
@@ -707,17 +719,20 @@
             public void onPackagesUnavailable(String[] packages) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
-                    try {
-                        listener.onPackagesUnavailable(user, packages, isReplacing());
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue;
+                        try {
+                            listener.onPackagesUnavailable(user, packages, isReplacing());
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackagesUnavailable(packages);
             }
@@ -726,17 +741,20 @@
             public void onPackagesSuspended(String[] packages) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
-                    try {
-                        listener.onPackagesSuspended(user, packages);
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue;
+                        try {
+                            listener.onPackagesSuspended(user, packages);
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackagesSuspended(packages);
             }
@@ -745,17 +763,20 @@
             public void onPackagesUnsuspended(String[] packages) {
                 UserHandle user = new UserHandle(getChangingUserId());
                 final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
-                    try {
-                        listener.onPackagesUnsuspended(user, packages);
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
+                try {
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue;
+                        try {
+                            listener.onPackagesUnsuspended(user, packages);
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
+                } finally {
+                    mListeners.finishBroadcast();
                 }
-                mListeners.finishBroadcast();
 
                 super.onPackagesUnsuspended(packages);
             }
@@ -768,10 +789,10 @@
 
             private void onShortcutChangedInner(@NonNull String packageName,
                     @UserIdInt int userId) {
+                final int n = mListeners.beginBroadcast();
                 try {
                     final UserHandle user = UserHandle.of(userId);
 
-                    final int n = mListeners.beginBroadcast();
                     for (int i = 0; i < n; i++) {
                         IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                         BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
@@ -803,10 +824,11 @@
                             Slog.d(TAG, "Callback failed ", re);
                         }
                     }
-                    mListeners.finishBroadcast();
                 } catch (RuntimeException e) {
                     // When the user is locked we get IllegalState, so just catch all.
                     Log.w(TAG, e.getMessage(), e);
+                } finally {
+                    mListeners.finishBroadcast();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 836b588..f777aae 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -28,10 +28,11 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.storage.StorageManager;
 import android.util.Log;
 import android.util.Slog;
-
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.InstallerConnection;
 import com.android.internal.os.InstallerConnection.InstallerException;
 
@@ -40,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A service for A/B OTA dexopting.
@@ -53,6 +55,10 @@
     // The synthetic library dependencies denoting "no checks."
     private final static String[] NO_LIBRARIES = new String[] { "&" };
 
+    // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
+    // not bulk-delete unused apps' odex files.
+    private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024;  // 1GB.
+
     private final Context mContext;
     private final PackageManagerService mPackageManagerService;
 
@@ -65,6 +71,25 @@
 
     private int completeSize;
 
+    // MetricsLogger properties.
+
+    // Space before and after.
+    private long availableSpaceBefore;
+    private long availableSpaceAfterBulkDelete;
+    private long availableSpaceAfterDexopt;
+
+    // Packages.
+    private int importantPackageCount;
+    private int otherPackageCount;
+
+    // Number of dexopt commands. This may be different from the count of packages.
+    private int dexoptCommandCountTotal;
+    private int dexoptCommandCountExecuted;
+
+    // For spent time.
+    private long otaDexoptTimeStart;
+
+
     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
         this.mContext = context;
         this.mPackageManagerService = packageManagerService;
@@ -83,9 +108,9 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
         (new OtaDexoptShellCommand(this)).exec(
-                this, in, out, err, args, resultReceiver);
+                this, in, out, err, args, callback, resultReceiver);
     }
 
     @Override
@@ -93,40 +118,53 @@
         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();
+
+        long spaceAvailable = getAvailableSpace();
+        if (spaceAvailable < BULK_DELETE_THRESHOLD) {
+            Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+                    + PackageManagerServiceUtils.packagesToString(others));
+            for (PackageParser.Package pkg : others) {
+                deleteOatArtifactsOfPackage(pkg);
+            }
+        }
+        long spaceAvailableNow = getAvailableSpace();
+
+        prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
     }
 
     @Override
@@ -135,6 +173,9 @@
             Log.i(TAG, "Cleaning up OTA Dexopt state.");
         }
         mDexoptCommands = null;
+        availableSpaceAfterDexopt = getAvailableSpace();
+
+        performMetricsLogging();
     }
 
     @Override
@@ -168,28 +209,67 @@
 
         String next = mDexoptCommands.remove(0);
 
-        if (IsFreeSpaceAvailable()) {
+        if (getAvailableSpace() > 0) {
+            dexoptCommandCountExecuted++;
+
             return next;
         } else {
+            if (DEBUG_DEXOPT) {
+                Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
+                        + (mDexoptCommands.size() + 1) + " commands left.");
+            }
             mDexoptCommands.clear();
             return "(no free space)";
         }
     }
 
-    /**
-     * Check for low space. Returns true if there's space left.
-     */
-    private boolean IsFreeSpaceAvailable() {
-        // TODO: If apps are not installed in the internal /data partition, we should compare
-        //       against that storage's free capacity.
+    private long getMainLowSpaceThreshold() {
         File dataDir = Environment.getDataDirectory();
         @SuppressWarnings("deprecation")
         long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
         if (lowThreshold == 0) {
             throw new IllegalStateException("Invalid low memory threshold");
         }
+        return lowThreshold;
+    }
+
+    /**
+     * Returns the difference of free space to the low-storage-space threshold. Positive values
+     * indicate free bytes.
+     */
+    private long getAvailableSpace() {
+        // TODO: If apps are not installed in the internal /data partition, we should compare
+        //       against that storage's free capacity.
+        long lowThreshold = getMainLowSpaceThreshold();
+
+        File dataDir = Environment.getDataDirectory();
         long usableSpace = dataDir.getUsableSpace();
-        return (usableSpace >= lowThreshold);
+
+        return usableSpace - lowThreshold;
+    }
+
+    private static String getOatDir(PackageParser.Package pkg) {
+        if (!pkg.canHaveOatDir()) {
+            return null;
+        }
+        File codePath = new File(pkg.codePath);
+        if (codePath.isDirectory()) {
+            return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
+        }
+        return null;
+    }
+
+    private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) {
+        String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        for (String codePath : pkg.getAllCodePaths()) {
+            for (String isa : instructionSets) {
+                try {
+                    mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg));
+                } catch (InstallerException e) {
+                    Log.e(TAG, "Failed deleting oat files for " + codePath, e);
+                }
+            }
+        }
     }
 
     /**
@@ -270,6 +350,55 @@
         }
     }
 
+    /**
+     * Initialize logging fields.
+     */
+    private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) {
+        availableSpaceBefore = spaceBegin;
+        availableSpaceAfterBulkDelete = spaceBulk;
+        availableSpaceAfterDexopt = 0;
+
+        importantPackageCount = important;
+        otherPackageCount = others;
+
+        dexoptCommandCountTotal = mDexoptCommands.size();
+        dexoptCommandCountExecuted = 0;
+
+        otaDexoptTimeStart = System.nanoTime();
+    }
+
+    private static int inMegabytes(long value) {
+        long in_mega_bytes = value / (1024 * 1024);
+        if (in_mega_bytes > Integer.MAX_VALUE) {
+            Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range");
+            return Integer.MAX_VALUE;
+        }
+        return (int)in_mega_bytes;
+    }
+
+    private void performMetricsLogging() {
+        long finalTime = System.nanoTime();
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
+                inMegabytes(availableSpaceBefore));
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
+                inMegabytes(availableSpaceAfterBulkDelete));
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
+                inMegabytes(availableSpaceAfterDexopt));
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
+                importantPackageCount);
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
+                dexoptCommandCountExecuted);
+
+        final int elapsedTimeSeconds =
+                (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
+        MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
+    }
+
     private static class OTADexoptPackageDexOptimizer extends
             PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 19b1201..1ef4a9f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -176,6 +176,16 @@
             isProfileGuidedFilter = false;
         }
 
+        // Disable profile guided compilation for vmSafeMode.
+        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE)
+                != 0;
+        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
+                != 0;
+        if (vmSafeMode) {
+            targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+            isProfileGuidedFilter = false;
+        }
+
         // If we're asked to take profile updates into account, check now.
         boolean newProfile = false;
         if (checkProfiles && isProfileGuidedFilter) {
@@ -187,9 +197,6 @@
             }
         }
 
-        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-
         boolean performedDexOpt = false;
         boolean successfulDexOpt = true;
 
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..0b8a347 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -44,6 +44,7 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.Signature;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.FileBridge;
 import android.os.FileUtils;
@@ -109,6 +110,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 +201,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 +272,14 @@
         } else {
             mPermissionsAccepted = false;
         }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+            defaultContainerGid = UserHandle.getSharedAppGid(uid);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     public SessionInfo generateInfo() {
@@ -520,7 +536,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 +555,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 +667,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 +747,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 +756,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 +773,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 +781,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 +792,7 @@
 
             // Inherit base if not overridden
             if (mResolvedBaseFile == null) {
-                mResolvedBaseFile = new File(app.getBaseCodePath());
+                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 mResolvedInheritedFiles.add(mResolvedBaseFile);
             }
 
@@ -794,7 +809,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 +837,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 +1051,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..df02b86 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;
@@ -111,6 +109,7 @@
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -186,6 +185,7 @@
 import android.os.ResultReceiver;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
@@ -199,6 +199,7 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.system.ErrnoException;
@@ -213,6 +214,7 @@
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.MathUtils;
+import android.util.Pair;
 import android.util.PrintStreamPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -367,7 +369,8 @@
     /** REMOVE. According to Svet, this was only used to reset permissions during development. */
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
-    private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE;
+    private static final boolean DISABLE_EPHEMERAL_APPS = false;
+    private static final boolean HIDE_EPHEMERAL_APIS = true;
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -459,7 +462,15 @@
 
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
 
+    private static final String PACKAGE_SCHEME = "package";
+
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
+    /**
+     * If VENDOR_OVERLAY_SKU_PROPERTY is set, search for runtime resource overlay APKs in
+     * VENDOR_OVERLAY_DIR/<value of VENDOR_OVERLAY_SKU_PROPERTY> rather than in
+     * VENDOR_OVERLAY_DIR.
+     */
+    private static final String VENDOR_OVERLAY_SKU_PROPERTY = "ro.boot.vendor.overlay.sku";
 
     private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
     private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5;
@@ -535,6 +546,10 @@
     final String[] mSeparateProcesses;
     final boolean mIsUpgrade;
     final boolean mIsPreNUpgrade;
+    final boolean mIsPreNMR1Upgrade;
+
+    @GuardedBy("mPackages")
+    private boolean mDexOptDialogShown;
 
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
@@ -739,8 +754,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;
@@ -1121,7 +1135,9 @@
 
     final @Nullable String mRequiredVerifierPackage;
     final @NonNull String mRequiredInstallerPackage;
+    final @NonNull String mRequiredUninstallerPackage;
     final @Nullable String mSetupWizardPackage;
+    final @Nullable String mStorageManagerPackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
     final @NonNull String mSharedSystemSharedLibraryPackageName;
 
@@ -2125,6 +2141,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");
@@ -2253,6 +2271,8 @@
             // as there is no profiling data available.
             mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
 
+            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
+
             // save off the names of pre-existing system packages prior to scanning; we don't
             // want to automatically grant runtime permissions for new system apps
             if (mPromoteSystemApps) {
@@ -2268,8 +2288,14 @@
             // Collect vendor overlay packages.
             // (Do this before scanning any apps.)
             // For security and version matching reason, only consider
-            // overlay packages if they reside in VENDOR_OVERLAY_DIR.
-            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
+            // overlay packages if they reside in the right directory.
+            File vendorOverlayDir;
+            String overlaySkuDir = SystemProperties.get(VENDOR_OVERLAY_SKU_PROPERTY);
+            if (!overlaySkuDir.isEmpty()) {
+                vendorOverlayDir = new File(VENDOR_OVERLAY_DIR, overlaySkuDir);
+            } else {
+                vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
+            }
             scanDirTracedLI(vendorOverlayDir, mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR
@@ -2472,6 +2498,9 @@
             }
             mExpectingBetter.clear();
 
+            // Resolve the storage manager.
+            mStorageManagerPackage = getStorageManagerPackageName();
+
             // Resolve protected action filters. Only the setup wizard is allowed to
             // have a high priority filter for these actions.
             mSetupWizardPackage = getSetupWizardPackageName();
@@ -2637,6 +2666,7 @@
             if (!mOnlyCore) {
                 mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
                 mRequiredInstallerPackage = getRequiredInstallerLPr();
+                mRequiredUninstallerPackage = getRequiredUninstallerLPr();
                 mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
                 mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                         mIntentFilterVerifierComponent);
@@ -2647,6 +2677,7 @@
             } else {
                 mRequiredVerifierPackage = null;
                 mRequiredInstallerPackage = null;
+                mRequiredUninstallerPackage = null;
                 mIntentFilterVerifierComponent = null;
                 mIntentFilterVerifier = null;
                 mServicesSystemSharedLibraryPackageName = null;
@@ -2727,10 +2758,11 @@
                 UserHandle.USER_SYSTEM);
         if (matches.size() == 1) {
             return matches.get(0).getComponentInfo().packageName;
-        } else {
-            Log.e(TAG, "There should probably be exactly one verifier; found " + matches);
+        } else if (matches.size() == 0) {
+            Log.e(TAG, "There should probably be a verifier, but, none were found");
             return null;
         }
+        throw new RuntimeException("There must be exactly one verifier; found " + matches);
     }
 
     private @NonNull String getRequiredSharedLibraryLPr(String libraryName) {
@@ -2762,6 +2794,22 @@
         }
     }
 
+    private @NonNull String getRequiredUninstallerLPr() {
+        final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null));
+
+        final ResolveInfo resolveInfo = resolveIntent(intent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+                UserHandle.USER_SYSTEM);
+        if (resolveInfo == null ||
+                mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) {
+            throw new RuntimeException("There must be exactly one uninstaller; found "
+                    + resolveInfo);
+        }
+        return resolveInfo.getComponentInfo().packageName;
+    }
+
     private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
         final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
 
@@ -3147,7 +3195,7 @@
         // reader
         synchronized (mPackages) {
             for (int i=names.length-1; i>=0; i--) {
-                String cur = mSettings.getRenamedPackage(names[i]);
+                String cur = mSettings.getRenamedPackageLPr(names[i]);
                 out[i] = cur != null ? cur : names[i];
             }
         }
@@ -3998,7 +4046,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 +4157,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;
@@ -4611,6 +4659,7 @@
 
     @Override
     public String[] getPackagesForUid(int uid) {
+        final int userId = UserHandle.getUserId(uid);
         uid = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
@@ -4618,9 +4667,16 @@
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 final int N = sus.packages.size();
-                final String[] res = new String[N];
-                for (int i = 0; i < N; i++) {
-                    res[i] = sus.packages.valueAt(i).name;
+                String[] res = new String[N];
+                final Iterator<PackageSetting> it = sus.packages.iterator();
+                int i = 0;
+                while (it.hasNext()) {
+                    PackageSetting ps = it.next();
+                    if (ps.getInstalled(userId)) {
+                        res[i++] = ps.name;
+                    } else {
+                        res = ArrayUtils.removeElement(String.class, res, res[i]);
+                    }
                 }
                 return res;
             } else if (obj instanceof PackageSetting) {
@@ -4783,11 +4839,28 @@
                 false, false, false, userId);
     }
 
+    private boolean isEphemeralDisabled() {
+        // ephemeral apps have been disabled across the board
+        if (DISABLE_EPHEMERAL_APPS) {
+            return true;
+        }
+        // system isn't up yet; can't read settings, so, assume no ephemeral apps
+        if (!mSystemReady) {
+            return true;
+        }
+        // we can't get a content resolver until the system is ready; these checks must happen last
+        final ContentResolver resolver = mContext.getContentResolver();
+        if (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) {
+            return true;
+        }
+        return Secure.getInt(resolver, Secure.WEB_ACTION_ENABLED, 1) == 0;
+    }
+
     private boolean isEphemeralAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
             boolean skipPackageCheck) {
         // Short circuit and return early if possible.
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return false;
         }
         final int callingUser = UserHandle.getCallingUserId();
@@ -6256,7 +6329,7 @@
 
     @Override
     public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
             return null;
         }
 
@@ -6280,7 +6353,7 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isEphemeral");
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
             return false;
         }
 
@@ -6298,7 +6371,7 @@
 
     @Override
     public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
             return null;
         }
 
@@ -6316,7 +6389,7 @@
 
     @Override
     public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
             return true;
         }
 
@@ -6334,7 +6407,7 @@
 
     @Override
     public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
             return null;
         }
 
@@ -6664,9 +6737,13 @@
 
     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
             final int policyFlags) throws PackageManagerException {
+        // When upgrading from pre-N MR1, verify the package time stamp using the package
+        // directory and not the APK file.
+        final long lastModifiedTime = mIsPreNMR1Upgrade
+                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
         if (ps != null
                 && ps.codePath.equals(srcFile)
-                && ps.timeStamp == getLastModifiedTime(pkg, srcFile)
+                && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(pkg)
                 && !isRecoverSignatureUpdateNeeded(pkg)) {
             long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
@@ -6688,7 +6765,7 @@
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+            Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
         }
 
         try {
@@ -6796,7 +6873,7 @@
         // reader
         synchronized (mPackages) {
             // Look to see if we already know about this package.
-            String oldName = mSettings.getRenamedPackage(pkg.packageName);
+            String oldName = mSettings.getRenamedPackageLPr(pkg.packageName);
             if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
                 // This package has been renamed to its original name.  Let's
                 // use that.
@@ -7130,7 +7207,11 @@
                     }
                 }
                 if (doTrim) {
-                    if (!isFirstBoot()) {
+                    final boolean dexOptDialogShown;
+                    synchronized (mPackages) {
+                        dexOptDialogShown = mDexOptDialogShown;
+                    }
+                    if (!isFirstBoot() && dexOptDialogShown) {
                         try {
                             ActivityManagerNative.getDefault().showBootMessage(
                                     mContext.getResources().getString(
@@ -7224,6 +7305,22 @@
                                     numberOfPackagesVisited, numberOfPackagesToDexopt), true);
                 } catch (RemoteException e) {
                 }
+                synchronized (mPackages) {
+                    mDexOptDialogShown = true;
+                }
+            }
+
+            // If the OTA updates a system app which was previously preopted to a non-preopted state
+            // the app might end up being verified at runtime. That's because by default the apps
+            // are verify-profile but for preopted apps there's no profile.
+            // Do a hacky check to ensure that if we have no profiles (a reasonable indication
+            // that before the OTA the app was preopted) the app gets compiled with a non-profile
+            // filter (by default interpret-only).
+            // Note that at this stage unused apps are already filtered.
+            if (isSystemApp(pkg) &&
+                    DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
+                    !Environment.getReferenceProfile(pkg.packageName).exists()) {
+                compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
             }
 
             // If the OTA updates a system app which was previously preopted to a non-preopted state
@@ -8105,7 +8202,7 @@
             if (pkg.mOriginalPackages != null) {
                 // This package may need to be renamed to a previously
                 // installed name.  Let's check on that...
-                final String renamed = mSettings.getRenamedPackage(pkg.mRealPackage);
+                final String renamed = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
                 if (pkg.mOriginalPackages.contains(renamed)) {
                     // This package had originally been installed as the
                     // original name, and we have already taken care of
@@ -8163,18 +8260,42 @@
                 }
             }
 
-            // Just create the setting, don't add it yet. For already existing packages
-            // the PkgSetting exists already and doesn't have to be created.
-            pkgSetting = mSettings.getPackageWithBenefitsLPw(pkg, origPackage, realName, suid,
-                    destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
-                    pkg.applicationInfo.primaryCpuAbi,
-                    pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
-                    user);
-            if (pkgSetting == null) {
-                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                        "Creating application package " + pkg.packageName + " failed");
+            pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+            if (pkgSetting != null && pkgSetting.sharedUser != suid) {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Package " + pkg.packageName + " shared user changed from "
+                        + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>")
+                        + " to "
+                        + (suid != null ? suid.name : "<nothing>")
+                        + "; replacing with new");
+                pkgSetting = null;
             }
+            final PackageSetting oldPkgSetting =
+                    pkgSetting == null ? null : new PackageSetting(pkgSetting);
+            final PackageSetting disabledPkgSetting =
+                    mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+            if (pkgSetting == null) {
+                final String parentPackageName = (pkg.parentPackage != null)
+                        ? pkg.parentPackage.packageName : null;
+                pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
+                        disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
+                        pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
+                        pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
+                        pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
+                        true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames(),
+                        UserManagerService.getInstance());
+                if (origPackage != null) {
+                    mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
+                }
+                mSettings.addUserToSettingLPw(pkgSetting);
+            } else {
+                Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
+                        pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
+                        pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
+                        pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(),
+                        UserManagerService.getInstance());
+            }
+            mSettings.writeUserRestrictions(pkgSetting, oldPkgSetting);
 
             if (pkgSetting.origPackage != null) {
                 // If we are first transitioning from an original package,
@@ -8423,6 +8544,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 +8831,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 +8841,9 @@
                         } else {
                             r.append(' ');
                         }
+                        if (isPackageUpdate) {
+                            r.append("UPD:");
+                        }
                         r.append(pg.info.name);
                     }
                 } else {
@@ -9947,8 +10077,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 +10163,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 +10172,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.
@@ -11233,6 +11361,19 @@
 
     private static final class EphemeralIntentResolver
             extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
+        /**
+         * The result that has the highest defined order. Ordering applies on a
+         * per-package basis. Mapping is from package name to Pair of order and
+         * EphemeralResolveInfo.
+         * <p>
+         * NOTE: This is implemented as a field variable for convenience and efficiency.
+         * By having a field variable, we're able to track filter ordering as soon as
+         * a non-zero order is defined. Otherwise, multiple loops across the result set
+         * would be needed to apply ordering. If the intent resolver becomes re-entrant,
+         * this needs to be contained entirely within {@link #filterResults()}.
+         */
+        final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
+
         @Override
         protected EphemeralResolveIntentInfo[] newArray(int size) {
             return new EphemeralResolveIntentInfo[size];
@@ -11249,7 +11390,51 @@
             if (!sUserManager.exists(userId)) {
                 return null;
             }
-            return info.getEphemeralResolveInfo();
+            final String packageName = info.getEphemeralResolveInfo().getPackageName();
+            final Integer order = info.getOrder();
+            final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
+                    mOrderResult.get(packageName);
+            // ordering is enabled and this item's order isn't high enough
+            if (lastOrderResult != null && lastOrderResult.first >= order) {
+                return null;
+            }
+            final EphemeralResolveInfo res = info.getEphemeralResolveInfo();
+            if (order > 0) {
+                // non-zero order, enable ordering
+                mOrderResult.put(packageName, new Pair<>(order, res));
+            }
+            return res;
+        }
+
+        @Override
+        protected void filterResults(List<EphemeralResolveInfo> results) {
+            // only do work if ordering is enabled [most of the time it won't be]
+            if (mOrderResult.size() == 0) {
+                return;
+            }
+            int resultSize = results.size();
+            for (int i = 0; i < resultSize; i++) {
+                final EphemeralResolveInfo info = results.get(i);
+                final String packageName = info.getPackageName();
+                final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
+                if (savedInfo == null) {
+                    // package doesn't having ordering
+                    continue;
+                }
+                if (savedInfo.second == info) {
+                    // circled back to the highest ordered item; remove from order list
+                    mOrderResult.remove(savedInfo);
+                    if (mOrderResult.size() == 0) {
+                        // no more ordered items
+                        break;
+                    }
+                    continue;
+                }
+                // item has a worse order, remove it from the result list
+                results.remove(i);
+                resultSize--;
+                i--;
+            }
         }
     }
 
@@ -11318,7 +11503,7 @@
                     }
                     for (int id : resolvedUserIds) {
                         final Intent intent = new Intent(action,
-                                pkg != null ? Uri.fromParts("package", pkg, null) : null);
+                                pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
                         if (extras != null) {
                             intent.putExtras(extras);
                         }
@@ -11814,6 +11999,12 @@
             return false;
         }
 
+        if (packageName.equals(mRequiredUninstallerPackage)) {
+            Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
+                    + "\": required for package uninstallation");
+            return false;
+        }
+
         if (packageName.equals(mRequiredVerifierPackage)) {
             Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
                     + "\": required for package verification");
@@ -14045,7 +14236,7 @@
         if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
 
         synchronized(mPackages) {
-            final String renamedPackage = mSettings.getRenamedPackage(pkgName);
+            final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
             if (renamedPackage != null) {
                 // A package with the same name is already installed, though
                 // it has been renamed to an older name.  The package we
@@ -14912,7 +15103,7 @@
         synchronized (mPackages) {
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
-                String oldName = mSettings.getRenamedPackage(pkgName);
+                String oldName = mSettings.getRenamedPackageLPr(pkgName);
                 if (pkg.mOriginalPackages != null
                         && pkg.mOriginalPackages.contains(oldName)
                         && mPackages.containsKey(oldName)) {
@@ -15379,6 +15570,17 @@
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(observer);
         final int uid = Binder.getCallingUid();
+        if (!isOrphaned(packageName)
+                && !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
+            try {
+                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+                intent.setData(Uri.fromParts(PACKAGE_SCHEME, 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 +15649,37 @@
         });
     }
 
+    private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
+              || callingUid == Process.SYSTEM_UID) {
+            return true;
+        }
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        // If the caller installed the pkgName, then allow it to silently uninstall.
+        if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) {
+            return true;
+        }
+
+        // Allow package verifier to silently uninstall.
+        if (mRequiredVerifierPackage != null &&
+                callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) {
+            return true;
+        }
+
+        // Allow package uninstaller to silently uninstall.
+        if (mRequiredUninstallerPackage != null &&
+                callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
+            return true;
+        }
+
+        // Allow storage manager to silently uninstall.
+        if (mStorageManagerPackage != null &&
+                callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
+            return true;
+        }
+        return false;
+    }
+
     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
         int[] result = EMPTY_INT_ARRAY;
         for (int userId : userIds) {
@@ -16533,7 +16766,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;
             }
@@ -17659,6 +17892,22 @@
         }
     }
 
+    private @Nullable String getStorageManagerPackageName() {
+        final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+                        | MATCH_DISABLED_COMPONENTS,
+                UserHandle.myUserId());
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            Slog.e(TAG, "There should probably be exactly one storage manager; found "
+                    + matches.size() + ": matches=" + matches);
+            return null;
+        }
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
@@ -18005,6 +18254,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) {
@@ -18154,9 +18410,10 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
         (new PackageManagerShellCommand(this)).exec(
-                this, in, out, err, args, resultReceiver);
+                this, in, out, err, args, callback, resultReceiver);
     }
 
     @Override
@@ -19616,8 +19873,6 @@
         final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
         final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
 
-        boolean restoreconNeeded = false;
-
         // First look for stale data that doesn't belong, and check if things
         // have changed since we did our last restorecon
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
@@ -19628,8 +19883,6 @@
                                 + " was still locked; this would have caused massive data loss!");
             }
 
-            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(ceDir);
-
             final File[] files = FileUtils.listFilesOrEmpty(ceDir);
             for (File file : files) {
                 final String packageName = file.getName();
@@ -19647,8 +19900,6 @@
             }
         }
         if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
-            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
-
             final File[] files = FileUtils.listFilesOrEmpty(deDir);
             for (File file : files) {
                 final String packageName = file.getName();
@@ -19683,29 +19934,19 @@
             }
 
             if (ps.getInstalled(userId)) {
-                prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
+                prepareAppDataLIF(ps.pkg, userId, flags);
 
                 if (migrateAppData && maybeMigrateAppDataLIF(ps.pkg, userId)) {
                     // We may have just shuffled around app data directories, so
                     // prepare them one more time
-                    prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
+                    prepareAppDataLIF(ps.pkg, userId, flags);
                 }
 
                 preparedCount++;
             }
         }
 
-        if (restoreconNeeded) {
-            if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
-                SELinuxMMAC.setRestoreconDone(ceDir);
-            }
-            if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
-                SELinuxMMAC.setRestoreconDone(deDir);
-            }
-        }
-
-        Slog.v(TAG, "reconcileAppsData finished " + preparedCount
-                + " packages; restoreconNeeded was " + restoreconNeeded);
+        Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
     }
 
     /**
@@ -19740,9 +19981,8 @@
             }
 
             if (ps.getInstalled(user.id)) {
-                // Whenever an app changes, force a restorecon of its data
                 // TODO: when user data is locked, mark that we're still dirty
-                prepareAppDataLIF(pkg, user.id, flags, true);
+                prepareAppDataLIF(pkg, user.id, flags);
             }
         }
     }
@@ -19755,24 +19995,22 @@
      * will try recovering system apps by wiping data; third-party app data is
      * left intact.
      */
-    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags,
-            boolean restoreconNeeded) {
+    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
-        prepareAppDataLeafLIF(pkg, userId, flags, restoreconNeeded);
+        prepareAppDataLeafLIF(pkg, userId, flags);
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
-            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags, restoreconNeeded);
+            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
         }
     }
 
-    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags,
-            boolean restoreconNeeded) {
+    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
         if (DEBUG_APP_DATA) {
             Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
-                    + Integer.toHexString(flags) + (restoreconNeeded ? " restoreconNeeded" : ""));
+                    + Integer.toHexString(flags));
         }
 
         final String volumeUuid = pkg.volumeUuid;
@@ -19802,15 +20040,6 @@
             }
         }
 
-        if (restoreconNeeded) {
-            try {
-                mInstaller.restoreconAppData(volumeUuid, packageName, userId, flags, appId,
-                        app.seinfo);
-            } catch (InstallerException e) {
-                Slog.e(TAG, "Failed to restorecon for " + packageName + ": " + e);
-            }
-        }
-
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
             try {
                 // CE storage is unlocked right now, so read out the inode and
@@ -20408,7 +20637,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 +21091,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;
                 }
 
@@ -20905,6 +21134,13 @@
         public boolean isPackageDataProtected(int userId, String packageName) {
             return mProtectedPackages.isPackageDataProtected(userId, packageName);
         }
+
+        @Override
+        public boolean wasPackageEverLaunched(String packageName, int userId) {
+            synchronized (mPackages) {
+                return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 751c585..cfd0af7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -19,6 +19,7 @@
 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
 import static com.android.server.pm.PackageManagerService.TAG;
 
+import android.annotation.NonNull;
 import android.app.AppGlobals;
 import android.content.Intent;
 import android.content.pm.PackageParser;
@@ -35,13 +36,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -67,34 +64,51 @@
         return pkgNames;
     }
 
-    private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
-            long estimatedPreviousSystemUseTime,
-            long dexOptLRUThresholdInMills) {
-        // Filter out packages that aren't recently used.
-        int total = pkgs.size();
-        int skipped = 0;
-        for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
-            PackageParser.Package pkg = i.next();
-            long then = pkg.getLatestForegroundPackageUseTimeInMills();
-            if (then < estimatedPreviousSystemUseTime - dexOptLRUThresholdInMills) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping dexopt of " + pkg.packageName +
-                            " last used in foreground: " +
-                            ((then == 0) ? "never" : new Date(then)));
-                }
-                i.remove();
-                skipped++;
-            } else {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Will dexopt " + pkg.packageName +
-                            " last used in foreground: " +
-                            ((then == 0) ? "never" : new Date(then)));
-                }
+    // Sort a list of apps by their last usage, most recently used apps first. The order of
+    // packages without usage data is undefined (but they will be sorted after the packages
+    // that do have usage data).
+    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
+            PackageManagerService packageManagerService) {
+        if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
+            return;
+        }
+
+        Collections.sort(pkgs, (pkg1, pkg2) ->
+                Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
+                        pkg1.getLatestForegroundPackageUseTimeInMills()));
+    }
+
+    // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
+    // package will be removed from {@code packages} and added to {@code result} with its
+    // dependencies. If usage data is available, the positive packages will be sorted by usage
+    // data (with {@code sortTemp} as temporary storage).
+    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
+            Collection<PackageParser.Package> result,
+            Collection<PackageParser.Package> packages,
+            @NonNull List<PackageParser.Package> sortTemp,
+            PackageManagerService packageManagerService) {
+        for (PackageParser.Package pkg : packages) {
+            if (filter.test(pkg)) {
+                sortTemp.add(pkg);
             }
         }
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
+
+        sortPackagesByUsageDate(sortTemp, packageManagerService);
+        packages.removeAll(sortTemp);
+
+        for (PackageParser.Package pkg : sortTemp) {
+            result.add(pkg);
+
+            Collection<PackageParser.Package> deps =
+                    packageManagerService.findSharedNonSystemLibraries(pkg);
+            if (!deps.isEmpty()) {
+                deps.removeAll(result);
+                result.addAll(deps);
+                packages.removeAll(deps);
+            }
         }
+
+        sortTemp.clear();
     }
 
     // Sort apps by importance for dexopt ordering. Important apps are given
@@ -104,46 +118,25 @@
             PackageManagerService packageManagerService) {
         ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
         LinkedList<PackageParser.Package> result = new LinkedList<>();
+        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
 
         // Give priority to core apps.
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (pkg.coreApp) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
+                packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-        ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (pkgNames.contains(pkg.packageName)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
-                            pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
+        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
+                sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (PackageDexOptimizer.isUsedByOtherApps(pkg)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding app used by other apps " + result.size() + ": " +
-                            pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
+                remainingPkgs, sortTemp, packageManagerService);
 
         // Filter out packages that aren't recently used, add all remaining apps.
         // TODO: add a property to control this?
+        Predicate<PackageParser.Package> remainingPredicate;
         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Looking at historical package use");
@@ -159,34 +152,24 @@
                     lastUsed.getLatestForegroundPackageUseTimeInMills();
             // Be defensive if for some reason package usage has bogus data.
             if (estimatedPreviousSystemUseTime != 0) {
-                filterRecentlyUsedApps(remainingPkgs, estimatedPreviousSystemUseTime,
-                        SEVEN_DAYS_IN_MILLISECONDS);
+                final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
+                remainingPredicate =
+                        (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
+            } else {
+                // No meaningful historical info. Take all.
+                remainingPredicate = (pkg) -> true;
             }
+            sortPackagesByUsageDate(remainingPkgs, packageManagerService);
+        } else {
+            // No historical info. Take all.
+            remainingPredicate = (pkg) -> true;
         }
-        result.addAll(remainingPkgs);
-
-        // Now go ahead and also add the libraries required for these packages.
-        // TODO: Think about interleaving things.
-        Set<PackageParser.Package> dependencies = new HashSet<>();
-        for (PackageParser.Package p : result) {
-            dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
-        }
-        if (!dependencies.isEmpty()) {
-            // We might have packages already in `result` that are dependencies
-            // of other packages. Make sure we don't add those to the list twice.
-            dependencies.removeAll(result);
-        }
-        result.addAll(dependencies);
+        applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
+                packageManagerService);
 
         if (DEBUG_DEXOPT) {
-            StringBuilder sb = new StringBuilder();
-            for (PackageParser.Package pkg : result) {
-                if (sb.length() > 0) {
-                    sb.append(", ");
-                }
-                sb.append(pkg.packageName);
-            }
-            Log.i(TAG, "Packages to be dexopted: " + sb.toString());
+            Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
+            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
         }
 
         return result;
@@ -203,4 +186,15 @@
             throw ee.rethrowAsIOException();
         }
     }
+
+    public static String packagesToString(Collection<PackageParser.Package> c) {
+        StringBuilder sb = new StringBuilder();
+        for (PackageParser.Package pkg : c) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+            sb.append(pkg.packageName);
+        }
+        return sb.toString();
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 61374f3..1d3471a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1160,14 +1160,15 @@
     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
-        if ("-".equals(inPath)) {
-            inPath = null;
-        } else if (inPath != null) {
-            final File file = new File(inPath);
-            if (file.isFile()) {
-                sizeBytes = file.length();
-            }
+        if (sizeBytes <= 0) {
+            pw.println("Error: must specify a APK size");
+            return 1;
         }
+        if (inPath != null && !"-".equals(inPath)) {
+            pw.println("Error: APK content must be streamed");
+            return 1;
+        }
+        inPath = null;
 
         final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
 
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index a4604a6..80a398a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -29,10 +29,14 @@
 final class PackageSetting extends PackageSettingBase {
     int appId;
     PackageParser.Package pkg;
+    /**
+     * WARNING. The object reference is important. We perform integer equality and NOT
+     * object equality to check whether shared user settings are the same.
+     */
     SharedUserSetting sharedUser;
     /**
      * Temporary holding space for the shared user ID. While parsing package settings, the
-     * shared users tag may be after the packages. In this case, we must delay linking the
+     * shared users tag may come after the packages. In this case, we must delay linking the
      * shared user setting with the package setting. The shared user ID lets us link the
      * two objects.
      */
@@ -54,7 +58,17 @@
      * Note that it keeps the same PackageParser.Package instance.
      */
     PackageSetting(PackageSetting orig) {
-        super(orig);
+        super(orig, orig.realName);
+        doCopy(orig);
+    }
+
+    /**
+     * New instance of PackageSetting replicating the original settings, but, allows specifying
+     * a real package name.
+     * Note that it keeps the same PackageParser.Package instance.
+     */
+    PackageSetting(PackageSetting orig, String realPkgName) {
+        super(orig, realPkgName);
         doCopy(orig);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index c08bc57..3ad2ae1 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -27,6 +27,8 @@
 import android.util.ArraySet;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
@@ -99,7 +101,7 @@
 
     boolean uidError;
 
-    PackageSignatures signatures = new PackageSignatures();
+    PackageSignatures signatures;
 
     boolean installPermissionsFixed;
 
@@ -147,11 +149,17 @@
                 secondaryCpuAbiString, cpuAbiOverrideString, pVersionCode);
     }
 
-    /** New instance of PackageSetting with one-level-deep cloning. */
-    PackageSettingBase(PackageSettingBase base) {
+    /**
+     * New instance of PackageSetting with one-level-deep cloning.
+     * <p>
+     * IMPORTANT: With a shallow copy, we do NOT create new contained objects.
+     * This means, for example, changes to the user state of the original PackageSetting
+     * will also change the user state in its copy.
+     */
+    PackageSettingBase(PackageSettingBase base, String realName) {
         super(base);
         name = base.name;
-        realName = base.realName;
+        this.realName = realName;
         doCopy(base);
     }
 
@@ -167,6 +175,7 @@
         this.secondaryCpuAbiString = secondaryCpuAbiString;
         this.cpuAbiOverrideString = cpuAbiOverrideString;
         this.versionCode = pVersionCode;
+        this.signatures = new PackageSignatures();
     }
 
     public void setInstallerPackageName(String packageName) {
@@ -280,6 +289,12 @@
         return readUserState(userId).installed;
     }
 
+    /** Only use for testing. Do NOT use in production code. */
+    @VisibleForTesting
+    SparseArray<PackageUserState> getUserState() {
+        return userState;
+    }
+
     boolean isAnyInstalled(int[] users) {
         for (int user: users) {
             if (readUserState(user).installed) {
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 8f9968ec..8a427cd 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -140,6 +140,36 @@
         }
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PermissionsState other = (PermissionsState) obj;
+
+        if (mPermissions == null) {
+            if (other.mPermissions != null) {
+                return false;
+            }
+        } else if (!mPermissions.equals(other.mPermissions)) {
+            return false;
+        }
+        if (mPermissionReviewRequired == null) {
+            if (other.mPermissionReviewRequired != null) {
+                return false;
+            }
+        } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
+            return false;
+        }
+        return Arrays.equals(mGlobalGids, other.mGlobalGids);
+    }
+
     public boolean isPermissionReviewRequired(int userId) {
         return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
     }
@@ -566,6 +596,7 @@
         return PERMISSION_OPERATION_SUCCESS;
     }
 
+    // TODO: fix this to use arraycopy and append all ints in one go
     private static int[] appendInts(int[] current, int[] added) {
         if (current != null && added != null) {
             for (int guid : added) {
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 8970556..2176eb1 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -19,10 +19,6 @@
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
 import android.os.Environment;
-import android.os.SystemProperties;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -34,10 +30,7 @@
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -65,24 +58,10 @@
     // to synchronize access during policy load and access attempts.
     private static List<Policy> sPolicies = new ArrayList<>();
 
-    private static final String PROP_FORCE_RESTORECON = "sys.force_restorecon";
-
-    /** Path to version on rootfs */
-    private static final File VERSION_FILE = new File("/selinux_version");
-
     /** Path to MAC permissions on system image */
     private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
             "/etc/security/mac_permissions.xml");
 
-    /** Path to app contexts on rootfs */
-    private static final File SEAPP_CONTEXTS = new File("/seapp_contexts");
-
-    /** Calculated hash of {@link #SEAPP_CONTEXTS} */
-    private static final byte[] SEAPP_CONTEXTS_HASH = returnHash(SEAPP_CONTEXTS);
-
-    /** Attribute where {@link #SEAPP_CONTEXTS_HASH} is stored */
-    private static final String XATTR_SEAPP_HASH = "user.seapp_hash";
-
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
 
@@ -313,66 +292,6 @@
                     "seinfo=" + pkg.applicationInfo.seinfo);
         }
     }
-
-    /**
-     * Determines if a recursive restorecon on the given package data directory
-     * is needed. It does this by comparing the SHA-1 of the seapp_contexts file
-     * against the stored hash in an xattr.
-     * <p>
-     * Note that the xattr isn't in the 'security' namespace, so this should
-     * only be run on directories owned by the system.
-     *
-     * @return Returns true if the restorecon should occur or false otherwise.
-     */
-    public static boolean isRestoreconNeeded(File file) {
-        // To investigate boot timing, allow a property to always force restorecon
-        if (SystemProperties.getBoolean(PROP_FORCE_RESTORECON, false)) {
-            return true;
-        }
-
-        try {
-            final byte[] buf = new byte[20];
-            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, buf);
-            if ((len == 20) && Arrays.equals(SEAPP_CONTEXTS_HASH, buf)) {
-                return false;
-            }
-        } catch (ErrnoException e) {
-            if (e.errno != OsConstants.ENODATA) {
-                Slog.e(TAG, "Failed to read seapp hash for " + file, e);
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Stores the SHA-1 of the seapp_contexts into an xattr.
-     * <p>
-     * Note that the xattr isn't in the 'security' namespace, so this should
-     * only be run on directories owned by the system.
-     */
-    public static void setRestoreconDone(File file) {
-        try {
-            Os.setxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, SEAPP_CONTEXTS_HASH, 0);
-        } catch (ErrnoException e) {
-            Slog.e(TAG, "Failed to persist seapp hash in " + file, e);
-        }
-    }
-
-    /**
-     * Return the SHA-1 of a file.
-     *
-     * @param file The path to the file given as a string.
-     * @return Returns the SHA-1 of the file as a byte array.
-     */
-    private static byte[] returnHash(File file) {
-        try {
-            final byte[] contents = IoUtils.readFileAsByteArray(file.getAbsolutePath());
-            return MessageDigest.getInstance("SHA-1").digest(contents);
-        } catch (IOException | NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        }
-    }
 }
 
 /**
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 52313b1..8cab355 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -24,6 +24,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
@@ -428,33 +429,22 @@
         mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
     }
 
-    PackageSetting getPackageLPw(String pkgName) {
+    PackageSetting getPackageLPr(String pkgName) {
         return peekPackageLPr(pkgName);
     }
 
-    PackageSetting getPackageWithBenefitsLPw(PackageParser.Package pkg, PackageSetting origPackage,
-            String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
-            int pkgFlags, int pkgPrivateFlags, UserHandle user)
-                    throws PackageManagerException {
-        final String name = pkg.packageName;
-        final String parentPackageName = (pkg.parentPackage != null)
-                ? pkg.parentPackage.packageName : null;
-        PackageSetting p = getPackageWithBenefitsLPw(name, origPackage, realName, sharedUser,
-                codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbi,
-                secondaryCpuAbi, pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user,
-                true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames());
-        return p;
-    }
-
     PackageSetting peekPackageLPr(String pkgName) {
         return mPackages.get(pkgName);
     }
 
-    String getRenamedPackage(String pkgName) {
+    String getRenamedPackageLPr(String pkgName) {
         return mRenamedPackages.get(pkgName);
     }
 
+    String addRenamedPackageLPw(String pkgName, String origPkgName) {
+        return mRenamedPackages.put(pkgName, origPkgName);
+    }
+
     void setInstallStatus(String pkgName, final int status) {
         PackageSetting p = mPackages.get(pkgName);
         if(p != null) {
@@ -684,280 +674,101 @@
         }
     }
 
-    private PackageSetting getPackageWithBenefitsLPw(String name, PackageSetting origPackage,
-            String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
-            String legacyNativeLibraryPathString, String primaryCpuAbiString,
-            String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags,
-            UserHandle installUser, boolean allowInstall, String parentPackage,
-            List<String> childPackageNames) throws PackageManagerException {
-        final UserManagerService userManager = UserManagerService.getInstance();
-        final PackageSetting disabledPackage = getDisabledSystemPkgLPr(name);
-        final PackageSetting peekPackage = peekPackageLPr(name);
-        final PackageSetting oldPackage =
-                peekPackage == null ? null : new PackageSetting(peekPackage);
-        final PackageSetting p = updatePackageSetting(peekPackage, name, realName,
-                origPackage, disabledPackage, sharedUser, codePath, resourcePath,
-                legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc,
-                pkgFlags, pkgPrivateFlags, installUser, allowInstall, parentPackage,
-                childPackageNames, userManager);
-        final boolean newPackageCreated = (peekPackage == null || p != peekPackage);
-        final boolean renamedPackage = newPackageCreated && origPackage != null;
-        if (renamedPackage) {
-            mRenamedPackages.put(name, origPackage.name);
-        }
-        if (newPackageCreated) {
-            if (p.appId == 0) {
-                // Assign new user ID
-                p.appId = newUserIdLPw(p);
-            } else {
-                // Add new setting to list of user IDs
-                addUserIdLPw(p.appId, p, name);
-            }
-            if (p.appId < 0) {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Package " + name + " could not be assigned a valid uid");
-                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                        "Creating application package " + name + " failed");
-            }
-        }
-        if (peekPackageLPr(name) != null) {
-            final List<UserInfo> allUsers = getAllUsers(UserManagerService.getInstance());
-            if (allUsers != null) {
-                for (UserInfo user : allUsers) {
-                    final PackageUserState oldUserState = oldPackage == null
-                            ? PackageSettingBase.DEFAULT_USER_STATE
-                            : oldPackage.readUserState(user.id);
-                    if (!oldUserState.equals(p.readUserState(user.id))) {
-                        writePackageRestrictionsLPr(user.id);
-                    }
-                }
-            }
-        }
-        return p;
-    }
-
     /**
-     * Updates the given package setting using the provided information.
-     * <p>
-     * WARNING: The provided PackageSetting object may be mutated.
-     *
-     * @param pkgSetting The package setting to update. If {@code null} a new PackageSetting
-     * object is created and populated.
-     * @param pkgName The name of the package.
-     * @param realPkgName The real name of the package. A package can change its name during
-     * an update. In that case, all references are to the package's original name, but, we
-     * still need it's real [new] name.
-     * @param originalPkg If the package name has changed, the package setting for the originally
-     * installed package. May be {@code null}.
-     * @param disabledPkg If the package is a system package that has been updated, the package
-     * setting for the disabled system package. May be {@code null}.
-     * @param sharedUser Shared user settings if the package declares a shared user ID.
-     * May be {@code null}.
-     * @param codePath The path to the applications code.
-     * @param resourcePath The path to the application's resources.
-     * @param legacyNativeLibraryPath The path where native libraries are unpacked.
-     * @param primaryCpuAbi The primary CPU architecture. May be {@code null}.
-     * @param secondaryCpuAbi The secondary CPU architecture, if one is defined.
-     * May be {@code null}.
-     * @param versionCode The version code of the package.
-     * @param pkgFlags Application flags for the package. {@link ApplicationInfo#flags}.
-     * @param pkgPrivateFlags Private application flags for the package.
-     * {@link ApplicationInfo#privateFlags}.
-     * @param installUser The user to install the package for. May be {@code null}.
-     * @param allowInstall Whether or not the user state for a newly created package setting can
-     * be installed.
-     * @param parentPkgName The name of the parent package. May be {@code null}.
-     * @param childPkgNames A list of child package names. May be {@code null}.
-     * @param userManager The user manager service.
-     * @return An updated package setting. It may be different than pkgSetting even when pkgSetting
-     * is not {@code null}.
-     * @throws PackageManagerException
+     * Creates a new {@code PackageSetting} object.
+     * Use this method instead of the constructor to ensure a settings object is created
+     * with the correct base.
      */
-    static PackageSetting updatePackageSetting(@Nullable PackageSetting pkgSetting,
-            @NonNull String pkgName, @Nullable String realPkgName,
-            @Nullable PackageSetting originalPkg, @Nullable PackageSetting disabledPkg,
-            @Nullable SharedUserSetting sharedUser, @NonNull File codePath,
-            @NonNull File resourcePath, @Nullable String legacyNativeLibraryPath,
-            @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int versionCode,
-            int pkgFlags, int pkgPrivateFlags, @Nullable UserHandle installUser,
-            boolean allowInstall, @Nullable String parentPkgName,
-            @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager)
-                    throws PackageManagerException {
-        if (pkgSetting != null) {
-            if (pkgSetting.sharedUser != sharedUser) {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Package " + pkgName + " shared user changed from "
-                        + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>")
-                        + " to "
-                        + (sharedUser != null ? sharedUser.name : "<nothing>")
-                        + "; replacing with new");
-                pkgSetting = null;
-            } else {
-                // If what we are scanning is a system (and possibly privileged) package,
-                // then make it so, regardless of whether it was previously installed only
-                // in the data partition.
-                pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
-                pkgSetting.pkgPrivateFlags |=
-                        pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-            }
-        }
-        if (pkgSetting != null) {
+    static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
+            PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
+            File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
+            String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
+            UserHandle installUser, boolean allowInstall, String parentPkgName,
+            List<String> childPkgNames, UserManagerService userManager) {
+        final PackageSetting pkgSetting;
+        if (originalPkg != null) {
+            if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+                    + pkgName + " is adopting original package " + originalPkg.name);
+            pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
+            pkgSetting.childPackageNames =
+                    (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
+            pkgSetting.codePath = codePath;
+            pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
+            pkgSetting.origPackage = originalPkg;
+            pkgSetting.parentPackageName = parentPkgName;
+            pkgSetting.pkgFlags = pkgFlags;
+            pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
             pkgSetting.primaryCpuAbiString = primaryCpuAbi;
+            pkgSetting.resourcePath = resourcePath;
             pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
-            if (childPkgNames != null) {
-                pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
-            }
-
-            if (!pkgSetting.codePath.equals(codePath)) {
-                // Check to see if its a disabled system app
-                if ((pkgSetting.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                    // This is an updated system app with versions in both system
-                    // and data partition. Just let the most recent version
-                    // take precedence.
-                    Slog.w(PackageManagerService.TAG,
-                            "Trying to update system app code path from "
-                            + pkgSetting.codePathString + " to " + codePath.toString());
-                } else {
-                    // Just a change in the code path is not an issue, but
-                    // let's log a message about it.
-                    Slog.i(PackageManagerService.TAG,
-                            "Package " + pkgName + " codePath changed from "
-                            + pkgSetting.codePath + " to " + codePath
-                            + "; Retaining data and using new");
-
-                    // The owner user's installed flag is set false
-                    // when the application was installed by other user
-                    // and the installed flag is not updated
-                    // when the application is appended as system app later.
-                    if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
-                            && disabledPkg == null) {
-                        List<UserInfo> allUserInfos = getAllUsers(userManager);
-                        if (allUserInfos != null) {
-                            for (UserInfo userInfo : allUserInfos) {
-                                pkgSetting.setInstalled(true, userInfo.id);
-                            }
-                        }
-                    }
-
-                    /*
-                     * Since we've changed paths, we need to prefer the new
-                     * native library path over the one stored in the
-                     * package settings since we might have moved from
-                     * internal to external storage or vice versa.
-                     */
-                    pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
-                }
-            }
-        }
-        // TODO: split package setting creation logic out; invoke where getPackageLPw() is
-        // called from
-        if (pkgSetting == null) {
-            if (originalPkg != null) {
-                // We are consuming the data from an existing package.
-                pkgSetting = new PackageSetting(originalPkg.name, pkgName, codePath, resourcePath,
-                        legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
-                        null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
-                        parentPkgName, childPkgNames, 0 /*sharedUserId*/);
-                if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
-                        + pkgName + " is adopting original package " + originalPkg.name);
-                // Note that we will retain the new package's signature so
-                // that we can keep its data.
-                PackageSignatures s = pkgSetting.signatures;
-                pkgSetting.copyFrom(originalPkg);
-                pkgSetting.signatures = s;
-                pkgSetting.sharedUser = originalPkg.sharedUser;
-                pkgSetting.appId = originalPkg.appId;
-                pkgSetting.origPackage = originalPkg;
-                pkgSetting.getPermissionsState().copyFrom(originalPkg.getPermissionsState());
-                pkgName = originalPkg.name;
-                // Update new package state.
-                pkgSetting.setTimeStamp(codePath.lastModified());
-            } else {
-                pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
-                        legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
-                        null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
-                        parentPkgName, childPkgNames, 0 /*sharedUserId*/);
-                pkgSetting.setTimeStamp(codePath.lastModified());
-                pkgSetting.sharedUser = sharedUser;
-                // If this is not a system app, it starts out stopped.
-                if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
-                    if (DEBUG_STOPPED) {
-                        RuntimeException e = new RuntimeException("here");
-                        e.fillInStackTrace();
-                        Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e);
-                    }
-                    List<UserInfo> users = getAllUsers(userManager);
-                    final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
-                    if (users != null && allowInstall) {
-                        for (UserInfo user : users) {
-                            // By default we consider this app to be installed
-                            // for the user if no user has been specified (which
-                            // means to leave it at its original value, and the
-                            // original default value is true), or we are being
-                            // asked to install for all users, or this is the
-                            // user we are installing for.
-                            final boolean installed = installUser == null
-                                    || (installUserId == UserHandle.USER_ALL
-                                        && !isAdbInstallDisallowed(userManager, user.id))
-                                    || installUserId == user.id;
-                            pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
-                                    installed,
-                                    true, // stopped,
-                                    true, // notLaunched
-                                    false, // hidden
-                                    false, // suspended
-                                    null, null, null,
-                                    false, // blockUninstall
-                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
-                        }
-                    }
-                }
-                if (sharedUser != null) {
-                    pkgSetting.appId = sharedUser.userId;
-                } else {
-                    // Clone the setting here for disabled system packages
-                    if (disabledPkg != null) {
-                        // For disabled packages a new setting is created
-                        // from the existing user id. This still has to be
-                        // added to list of user id's
-                        // Copy signatures from previous setting
-                        if (disabledPkg.signatures.mSignatures != null) {
-                            pkgSetting.signatures.mSignatures =
-                                    disabledPkg.signatures.mSignatures.clone();
-                        }
-                        pkgSetting.appId = disabledPkg.appId;
-                        // Clone permissions
-                        pkgSetting.getPermissionsState().copyFrom(
-                                disabledPkg.getPermissionsState());
-                        // Clone component info
-                        List<UserInfo> users = getAllUsers(userManager);
-                        if (users != null) {
-                            for (UserInfo user : users) {
-                                int userId = user.id;
-                                pkgSetting.setDisabledComponentsCopy(
-                                        disabledPkg.getDisabledComponents(userId), userId);
-                                pkgSetting.setEnabledComponentsCopy(
-                                        disabledPkg.getEnabledComponents(userId), userId);
-                            }
-                        }
-                    }
-                }
-            }
+            // NOTE: Create a deeper copy of the package signatures so we don't
+            // overwrite the signatures in the original package setting.
+            pkgSetting.signatures = new PackageSignatures();
+            pkgSetting.versionCode = versionCode;
+            // Update new package state.
+            pkgSetting.setTimeStamp(codePath.lastModified());
         } else {
-            if (installUser != null && allowInstall) {
-                // The caller has explicitly specified the user they want this
-                // package installed for, and the package already exists.
-                // Make sure it conforms to the new request.
+            pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
+                    legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
+                    null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
+                    parentPkgName, childPkgNames, 0 /*sharedUserId*/);
+            pkgSetting.setTimeStamp(codePath.lastModified());
+            pkgSetting.sharedUser = sharedUser;
+            // If this is not a system app, it starts out stopped.
+            if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                if (DEBUG_STOPPED) {
+                    RuntimeException e = new RuntimeException("here");
+                    e.fillInStackTrace();
+                    Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e);
+                }
                 List<UserInfo> users = getAllUsers(userManager);
-                if (users != null) {
+                final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
+                if (users != null && allowInstall) {
                     for (UserInfo user : users) {
-                        if ((installUser.getIdentifier() == UserHandle.USER_ALL
+                        // By default we consider this app to be installed
+                        // for the user if no user has been specified (which
+                        // means to leave it at its original value, and the
+                        // original default value is true), or we are being
+                        // asked to install for all users, or this is the
+                        // user we are installing for.
+                        final boolean installed = installUser == null
+                                || (installUserId == UserHandle.USER_ALL
                                     && !isAdbInstallDisallowed(userManager, user.id))
-                                || installUser.getIdentifier() == user.id) {
-                            boolean installed = pkgSetting.getInstalled(user.id);
-                            if (!installed) {
-                                pkgSetting.setInstalled(true, user.id);
-                            }
+                                || installUserId == user.id;
+                        pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
+                                installed,
+                                true, // stopped,
+                                true, // notLaunched
+                                false, // hidden
+                                false, // suspended
+                                null, null, null,
+                                false, // blockUninstall
+                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
+                    }
+                }
+            }
+            if (sharedUser != null) {
+                pkgSetting.appId = sharedUser.userId;
+            } else {
+                // Clone the setting here for disabled system packages
+                if (disabledPkg != null) {
+                    // For disabled packages a new setting is created
+                    // from the existing user id. This still has to be
+                    // added to list of user id's
+                    // Copy signatures from previous setting
+                    pkgSetting.signatures = new PackageSignatures(disabledPkg.signatures);
+                    pkgSetting.appId = disabledPkg.appId;
+                    // Clone permissions
+                    pkgSetting.getPermissionsState().copyFrom(disabledPkg.getPermissionsState());
+                    // Clone component info
+                    List<UserInfo> users = getAllUsers(userManager);
+                    if (users != null) {
+                        for (UserInfo user : users) {
+                            final int userId = user.id;
+                            pkgSetting.setDisabledComponentsCopy(
+                                    disabledPkg.getDisabledComponents(userId), userId);
+                            pkgSetting.setEnabledComponentsCopy(
+                                    disabledPkg.getEnabledComponents(userId), userId);
                         }
                     }
                 }
@@ -966,6 +777,124 @@
         return pkgSetting;
     }
 
+    /**
+     * Updates the given package setting using the provided information.
+     * <p>
+     * WARNING: The provided PackageSetting object may be mutated.
+     */
+    static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
+            @Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
+            @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
+            @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
+            int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
+            @NonNull UserManagerService userManager) throws PackageManagerException {
+        final String pkgName = pkgSetting.name;
+        if (pkgSetting.sharedUser != sharedUser) {
+            PackageManagerService.reportSettingsProblem(Log.WARN,
+                    "Package " + pkgName + " shared user changed from "
+                    + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>")
+                    + " to " + (sharedUser != null ? sharedUser.name : "<nothing>"));
+            throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+                    "Updating application package " + pkgName + " failed");
+        }
+
+        if (!pkgSetting.codePath.equals(codePath)) {
+            // Check to see if its a disabled system app
+            if ((pkgSetting.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                // This is an updated system app with versions in both system
+                // and data partition. Just let the most recent version
+                // take precedence.
+                Slog.w(PackageManagerService.TAG,
+                        "Trying to update system app code path from "
+                        + pkgSetting.codePathString + " to " + codePath.toString());
+            } else {
+                // Just a change in the code path is not an issue, but
+                // let's log a message about it.
+                Slog.i(PackageManagerService.TAG,
+                        "Package " + pkgName + " codePath changed from "
+                        + pkgSetting.codePath + " to " + codePath
+                        + "; Retaining data and using new");
+
+                // The owner user's installed flag is set false
+                // when the application was installed by other user
+                // and the installed flag is not updated
+                // when the application is appended as system app later.
+                if ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
+                        && disabledPkg == null) {
+                    List<UserInfo> allUserInfos = getAllUsers(userManager);
+                    if (allUserInfos != null) {
+                        for (UserInfo userInfo : allUserInfos) {
+                            pkgSetting.setInstalled(true, userInfo.id);
+                        }
+                    }
+                }
+
+                /*
+                 * Since we've changed paths, we need to prefer the new
+                 * native library path over the one stored in the
+                 * package settings since we might have moved from
+                 * internal to external storage or vice versa.
+                 */
+                pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
+            }
+        }
+        // If what we are scanning is a system (and possibly privileged) package,
+        // then make it so, regardless of whether it was previously installed only
+        // in the data partition.
+        pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+        pkgSetting.pkgPrivateFlags |=
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+        pkgSetting.primaryCpuAbiString = primaryCpuAbi;
+        pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
+        if (childPkgNames != null) {
+            pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
+        }
+    }
+
+    /**
+     * Registers a user ID with the system. Potentially allocates a new user ID.
+     * @throws PackageManagerException If a user ID could not be allocated.
+     */
+    void addUserToSettingLPw(PackageSetting p) throws PackageManagerException {
+        if (p.appId == 0) {
+            // Assign new user ID
+            p.appId = newUserIdLPw(p);
+        } else {
+            // Add new setting to list of user IDs
+            addUserIdLPw(p.appId, p, p.name);
+        }
+        if (p.appId < 0) {
+            PackageManagerService.reportSettingsProblem(Log.WARN,
+                    "Package " + p.name + " could not be assigned a valid uid");
+            throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+                    "Creating application package " + p.name + " failed");
+        }
+    }
+
+    /**
+     * Writes per-user package restrictions if the user state has changed. If the user
+     * state has not changed, this does nothing.
+     */
+    void writeUserRestrictions(PackageSetting newPackage, PackageSetting oldPackage) {
+        // package doesn't exist; do nothing
+        if (peekPackageLPr(newPackage.name) == null) {
+            return;
+        }
+        // no users defined; do nothing
+        final List<UserInfo> allUsers = getAllUsers(UserManagerService.getInstance());
+        if (allUsers == null) {
+            return;
+        }
+        for (UserInfo user : allUsers) {
+            final PackageUserState oldUserState = oldPackage == null
+                    ? PackageSettingBase.DEFAULT_USER_STATE
+                    : oldPackage.readUserState(user.id);
+            if (!oldUserState.equals(newPackage.readUserState(user.id))) {
+                writePackageRestrictionsLPr(user.id);
+            }
+        }
+    }
+
     static boolean isAdbInstallDisallowed(UserManagerService userManager, int userId) {
         return userManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
                 userId);
@@ -4232,6 +4161,14 @@
         return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
     }
 
+    boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
+        final PackageSetting pkgSetting = mPackages.get(packageName);
+        if (pkgSetting == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        return !pkgSetting.getNotLaunched(userId);
+    }
+
     boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
             boolean stopped, boolean allowedByPermission, int uid, int userId) {
         int appId = UserHandle.getAppId(uid);
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index df51923..2af1bcb 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -151,6 +152,16 @@
         return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
     }
 
+    public void ensureVersionInfo() {
+        final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(
+                getPackageName(), getPackageUserId());
+        if (pi == null) {
+            Slog.w(TAG, "Package not found: " + getPackageName());
+            return;
+        }
+        getPackageInfo().updateVersionInfo(pi);
+    }
+
     /**
      * Persist.
      */
@@ -202,7 +213,7 @@
                 fromBackup ? ownerUserId
                 : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
 
-        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, launcherUserId,
+        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, ownerUserId,
                 launcherPackageName, launcherUserId);
 
         ArraySet<String> ids = null;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 827b88a..d558b07 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -23,7 +23,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
-import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
@@ -145,30 +144,6 @@
         return mPackageUid;
     }
 
-    /**
-     * Called when a shortcut is about to be published.  At this point we know the publisher
-     * package
-     * exists (as opposed to Launcher trying to fetch shortcuts from a non-existent package), so
-     * we do some initialization for the package.
-     */
-    private void ensurePackageVersionInfo() {
-        // Make sure we have the version code for the app.  We need the version code in
-        // handlePackageUpdated().
-        if (getPackageInfo().getVersionCode() < 0) {
-            final ShortcutService s = mShortcutUser.mService;
-
-            final PackageInfo pi = s.getPackageInfo(getPackageName(), getOwnerUserId());
-            if (pi != null) {
-                if (ShortcutService.DEBUG) {
-                    Slog.d(TAG, String.format("Package %s version = %d", getPackageName(),
-                            pi.versionCode));
-                }
-                getPackageInfo().updateVersionInfo(pi);
-                s.scheduleSaveUser(getOwnerUserId());
-            }
-        }
-    }
-
     @Nullable
     public Resources getPackageResources() {
         return mShortcutUser.mService.injectGetResourcesForApplicationAsUser(
@@ -251,8 +226,6 @@
         Preconditions.checkArgument(newShortcut.isEnabled(),
                 "add/setDynamicShortcuts() cannot publish disabled shortcuts");
 
-        ensurePackageVersionInfo();
-
         newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
 
         final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
@@ -667,6 +640,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()) {
@@ -1145,6 +1124,17 @@
         }
     }
 
+    /** @return true if there's any shortcuts that are not manifest shortcuts. */
+    public boolean hasNonManifestShortcuts() {
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (!si.isDeclaredInManifest()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.println();
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index e7b66fc..4de15de 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageInfo;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.backup.BackupUtils;
 
 import libcore.io.Base64;
@@ -89,6 +90,7 @@
         return mLastUpdateTime;
     }
 
+    /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */
     public void updateVersionInfo(@NonNull PackageInfo pi) {
         if (pi != null) {
             mVersionCode = pi.versionCode;
@@ -119,7 +121,8 @@
         return true;
     }
 
-    public static ShortcutPackageInfo generateForInstalledPackage(
+    @VisibleForTesting
+    public static ShortcutPackageInfo generateForInstalledPackageForTest(
             ShortcutService s, String packageName, @UserIdInt int packageUserId) {
         final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
         if (pi.signatures == null || pi.signatures.length == 0) {
@@ -132,7 +135,7 @@
         return ret;
     }
 
-    public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
+    public void refreshSignature(ShortcutService s, ShortcutPackageItem pkg) {
         if (mIsShadow) {
             s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
                     + ", user=" + pkg.getOwnerUserId());
@@ -145,8 +148,6 @@
             Slog.w(TAG, "Package not found: " + pkg.getPackageName());
             return;
         }
-        mVersionCode = pi.versionCode;
-        mLastUpdateTime = pi.lastUpdateTime;
         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 79b5c4e..1f195a7 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -40,7 +40,7 @@
 
     private final ShortcutPackageInfo mPackageInfo;
 
-    protected final ShortcutUser mShortcutUser;
+    protected ShortcutUser mShortcutUser;
 
     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
             int packageUserId, @NonNull String packageName,
@@ -51,6 +51,13 @@
         mPackageInfo = Preconditions.checkNotNull(packageInfo);
     }
 
+    /**
+     * Change the parent {@link ShortcutUser}.  Need it in the restore code.
+     */
+    public void replaceUser(ShortcutUser user) {
+        mShortcutUser = user;
+    }
+
     public ShortcutUser getUser() {
         return mShortcutUser;
     }
@@ -58,8 +65,7 @@
     /**
      * ID of the user who actually has this package running on.  For {@link ShortcutPackage},
      * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and
-     * {@link #getOwnerUserId} is of a work profile, then this ID could be the user who owns the
-     * profile.
+     * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user.
      */
     public int getPackageUserId() {
         return mPackageUserId;
@@ -79,12 +85,12 @@
         return mPackageInfo;
     }
 
-    public void refreshPackageInfoAndSave() {
+    public void refreshPackageSignatureAndSave() {
         if (mPackageInfo.isShadow()) {
             return; // Don't refresh for shadow user.
         }
         final ShortcutService s = mShortcutUser.mService;
-        mPackageInfo.refresh(s, this);
+        mPackageInfo.refreshSignature(s, this);
         s.scheduleSaveUser(getOwnerUserId());
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c1fc7f1..19bf751 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;
@@ -66,6 +67,7 @@
 import android.os.ResultReceiver;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -324,10 +326,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")
@@ -359,6 +381,12 @@
     @GuardedBy("mLock")
     private Exception mLastWtfStacktrace;
 
+    static class InvalidFileFormatException extends Exception {
+        public InvalidFileFormatException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
     public ShortcutService(Context context) {
         this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
     }
@@ -533,19 +561,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 */
@@ -933,7 +968,7 @@
         try {
             final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
             return ret;
-        } catch (IOException | XmlPullParserException e) {
+        } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
             Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
             return null;
         } finally {
@@ -942,7 +977,8 @@
     }
 
     private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
-            boolean fromBackup) throws XmlPullParserException, IOException {
+            boolean fromBackup) throws XmlPullParserException, IOException,
+            InvalidFileFormatException {
 
         final BufferedInputStream bis = new BufferedInputStream(is);
 
@@ -1110,6 +1146,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;
     }
@@ -1120,7 +1159,10 @@
         }
     }
 
-    /** Return the per-user per-package state. */
+    /**
+     * Return the per-user per-package state.  If the caller is a publisher, use
+     * {@link #getPackageShortcutsForPublisherLocked} instead.
+     */
     @GuardedBy("mLock")
     @NonNull
     ShortcutPackage getPackageShortcutsLocked(
@@ -1128,6 +1170,16 @@
         return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
     }
 
+    /** Return the per-user per-package state.  Use this when the caller is a publisher. */
+    @GuardedBy("mLock")
+    @NonNull
+    ShortcutPackage getPackageShortcutsForPublisherLocked(
+            @NonNull String packageName, @UserIdInt int userId) {
+        final ShortcutPackage ret = getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
+        ret.getUser().onCalledByPublisher(packageName);
+        return ret;
+    }
+
     @GuardedBy("mLock")
     @NonNull
     ShortcutLauncher getLauncherShortcutsLocked(
@@ -1468,6 +1520,10 @@
         mHandler.post(r);
     }
 
+    void injectRunOnNewThread(Runnable r) {
+        new Thread(r).start();
+    }
+
     /**
      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
      *                                  {@link #getMaxActivityShortcuts()}.
@@ -1592,8 +1648,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
 
@@ -1644,8 +1699,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
 
@@ -1725,8 +1779,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
 
@@ -1775,8 +1828,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
 
@@ -1805,8 +1857,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
 
@@ -1828,8 +1879,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
 
@@ -1853,8 +1903,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
             ps.deleteAllDynamicShortcuts();
         }
         packageShortcutsChanged(packageName, userId);
@@ -1909,8 +1958,7 @@
 
         final ArrayList<ShortcutInfo> ret = new ArrayList<>();
 
-        final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-        ps.getUser().onCalledByPublisher(packageName);
+        final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
         ps.findAll(ret, query, cloneFlags);
 
         return new ParceledListSlice<>(ret);
@@ -1931,8 +1979,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
             return mMaxUpdatesPerInterval - ps.getApiCallCount();
         }
     }
@@ -1971,8 +2018,7 @@
         synchronized (mLock) {
             throwIfUserLockedL(userId);
 
-            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
-            ps.getUser().onCalledByPublisher(packageName);
+            final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
 
             if (ps.findShortcutById(shortcutId) == null) {
                 Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
@@ -2625,10 +2671,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 +2686,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 +2925,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 +2937,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);
                 }
@@ -3103,9 +3155,19 @@
                 return null;
             }
 
-            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave());
+            // Update the signatures for all packages.
+            user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
 
-            // Then save.
+            // Set the version code for the launchers.
+            // We shouldn't do this for publisher packages, because we don't want to update the
+            // version code without rescanning the manifest.
+            user.forAllLaunchers(launcher -> launcher.ensureVersionInfo());
+
+            // Save to the filesystem.
+            scheduleSaveUser(userId);
+            saveDirtyInfo();
+
+            // Then create the backup payload.
             final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
             try {
                 saveUserInternalLocked(userId, os, /* forBackup */ true);
@@ -3129,15 +3191,16 @@
                 wtf("Can't restore: user " + userId + " is locked or not running");
                 return;
             }
-            final ShortcutUser user;
+            // Actually do restore.
+            final ShortcutUser restored;
             final ByteArrayInputStream is = new ByteArrayInputStream(payload);
             try {
-                user = loadUserInternal(userId, is, /* fromBackup */ true);
-            } catch (XmlPullParserException | IOException e) {
+                restored = loadUserInternal(userId, is, /* fromBackup */ true);
+            } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
                 Slog.w(TAG, "Restoration failed.", e);
                 return;
             }
-            mUsers.put(userId, user);
+            getUserShortcutsLocked(userId).mergeRestoredFile(restored);
 
             // Rescan all packages to re-publish manifest shortcuts and do other checks.
             rescanUpdatedPackagesLocked(userId,
@@ -3218,23 +3281,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 +3326,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)));
     }
 
@@ -3318,13 +3367,14 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
 
         enforceShell();
 
         final long token = injectClearCallingIdentity();
         try {
-            final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
+            final int status = (new MyShellCommand()).exec(this, in, out, err, args, callback,
+                    resultReceiver);
             resultReceiver.send(status, null);
         } finally {
             injectRestoreCallingIdentity(token);
@@ -3578,6 +3628,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..5d4bfa4 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,12 +23,14 @@
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.server.pm.ShortcutService.InvalidFileFormatException;
 
 import libcore.util.Objects;
 
@@ -60,6 +62,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 +128,8 @@
 
     private long mLastAppScanTime;
 
+    private String mLastAppScanOsFingerprint;
+
     public ShortcutUser(ShortcutService service, int userId) {
         mService = service;
         mUserId = userId;
@@ -142,6 +147,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
@@ -153,6 +166,11 @@
         return mPackages.containsKey(packageName);
     }
 
+    private void addPackage(@NonNull ShortcutPackage p) {
+        p.replaceUser(this);
+        mPackages.put(p.getPackageName(), p);
+    }
+
     public ShortcutPackage removePackage(@NonNull String packageName) {
         final ShortcutPackage removed = mPackages.remove(packageName);
 
@@ -168,7 +186,8 @@
         return mLaunchers;
     }
 
-    public void addLauncher(ShortcutLauncher launcher) {
+    private void addLauncher(ShortcutLauncher launcher) {
+        launcher.replaceUser(this);
         mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
                 launcher.getPackageName()), launcher);
     }
@@ -315,11 +334,16 @@
             throws IOException, XmlPullParserException {
         out.startTag(null, TAG_ROOT);
 
-        ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
-        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
-                mLastAppScanTime);
+        if (!forBackup) {
+            // Don't have to back them up.
+            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);
+            ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
+        }
 
         // Can't use forEachPackageItem due to the checked exceptions.
         {
@@ -352,53 +376,59 @@
     }
 
     public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
-            boolean fromBackup) throws IOException, XmlPullParserException {
+            boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
         final ShortcutUser ret = new ShortcutUser(s, userId);
 
-        ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
-                ATTR_KNOWN_LOCALES);
+        try {
+            ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
+                    ATTR_KNOWN_LOCALES);
 
-        // If lastAppScanTime is in the future, that means the clock went backwards.
-        // Just scan all apps again.
-        final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
-                ATTR_LAST_APP_SCAN_TIME);
-        final long currentTime = s.injectCurrentTimeMillis();
-        ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
+            // If lastAppScanTime is in the future, that means the clock went backwards.
+            // Just scan all apps again.
+            final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
+                    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
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                final int depth = parser.getDepth();
+                final String tag = parser.getName();
 
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            final int depth = parser.getDepth();
-            final String tag = parser.getName();
+                if (depth == outerDepth + 1) {
+                    switch (tag) {
+                        case TAG_LAUNCHER: {
+                            ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
+                                    parser, ATTR_VALUE);
+                            continue;
+                        }
+                        case ShortcutPackage.TAG_ROOT: {
+                            final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
+                                    s, ret, parser, fromBackup);
 
-            if (depth == outerDepth + 1) {
-                switch (tag) {
-                    case TAG_LAUNCHER: {
-                        ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
-                                parser, ATTR_VALUE);
-                        continue;
-                    }
-                    case ShortcutPackage.TAG_ROOT: {
-                        final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
-                                s, ret, parser, fromBackup);
+                            // Don't use addShortcut(), we don't need to save the icon.
+                            ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
+                            continue;
+                        }
 
-                        // Don't use addShortcut(), we don't need to save the icon.
-                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
-                        continue;
-                    }
-
-                    case ShortcutLauncher.TAG_ROOT: {
-                        ret.addLauncher(
-                                ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
-                        continue;
+                        case ShortcutLauncher.TAG_ROOT: {
+                            ret.addLauncher(
+                                    ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
+                            continue;
+                        }
                     }
                 }
+                ShortcutService.warnForInvalidTag(depth, tag);
             }
-            ShortcutService.warnForInvalidTag(depth, tag);
+        } catch (RuntimeException e) {
+            throw new ShortcutService.InvalidFileFormatException(
+                    "Unable to parse file", e);
         }
         return ret;
     }
@@ -447,6 +477,51 @@
         }
     }
 
+    public void mergeRestoredFile(ShortcutUser restored) {
+        final ShortcutService s = mService;
+        // Note, a restore happens only at the end of setup wizard.  At this point, no apps are
+        // installed from Play Store yet, but it's still possible that system apps have already
+        // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
+        // When such a system app has allowbackup=true, then we go ahead and replace all existing
+        // shortcuts with the restored shortcuts.  (Then we'll re-publish manifest shortcuts later
+        // in the call site.)
+        // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
+        // already been published.  So we selectively add restored ShortcutPackages here.
+        //
+        // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
+        // without users interaction it's really not a big deal, so we just clear existing
+        // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
+
+        mLaunchers.clear();
+        restored.forAllLaunchers(sl -> {
+            // If the app is already installed and allowbackup = false, then ignore the restored
+            // data.
+            if (s.isPackageInstalled(sl.getPackageName(), getUserId())
+                    && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
+                return;
+            }
+            addLauncher(sl);
+        });
+        restored.forAllPackages(sp -> {
+            // If the app is already installed and allowbackup = false, then ignore the restored
+            // data.
+            if (s.isPackageInstalled(sp.getPackageName(), getUserId())
+                    && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
+                return;
+            }
+
+            final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
+            if (previous != null && previous.hasNonManifestShortcuts()) {
+                Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
+                        + " Existing non-manifeset shortcuts will be overwritten.");
+            }
+            addPackage(sp);
+        });
+        // Empty the launchers and packages in restored to avoid accidentally using them.
+        restored.mLaunchers.clear();
+        restored.mPackages.clear();
+    }
+
     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.print(prefix);
         pw.print("User: ");
@@ -457,6 +532,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/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index bdb138e..533d9b5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -62,6 +62,7 @@
 import android.os.ResultReceiver;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -113,6 +114,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -130,6 +132,8 @@
     private static final String LOG_TAG = "UserManagerService";
     static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
     private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
+    // Can be used for manual testing of id recycling
+    private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
 
     private static final String TAG_NAME = "name";
     private static final String TAG_ACCOUNT = "account";
@@ -180,11 +184,18 @@
             UserInfo.FLAG_MANAGED_PROFILE
             | UserInfo.FLAG_EPHEMERAL
             | UserInfo.FLAG_RESTRICTED
-            | UserInfo.FLAG_GUEST;
+            | UserInfo.FLAG_GUEST
+            | UserInfo.FLAG_DEMO;
 
-    private static final int MIN_USER_ID = 10;
+    @VisibleForTesting
+    static final int MIN_USER_ID = 10;
     // We need to keep process uid within Integer.MAX_VALUE.
-    private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+    @VisibleForTesting
+    static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+
+    // Max size of the queue of recently removed users
+    @VisibleForTesting
+    static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
 
     private static final int USER_VERSION = 6;
 
@@ -311,10 +322,17 @@
     /**
      * Set of user IDs being actively removed. Removed IDs linger in this set
      * for several seconds to work around a VFS caching issue.
+     * Use {@link #addRemovingUserIdLocked(int)} to add elements to this array
      */
     @GuardedBy("mUsersLock")
     private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
 
+    /**
+     * Queue of recently removed userIds. Used for recycling of userIds
+     */
+    @GuardedBy("mUsersLock")
+    private final LinkedList<Integer> mRecentlyRemovedIds = new LinkedList<>();
+
     @GuardedBy("mUsersLock")
     private int[] mUserIds;
     @GuardedBy("mPackagesLock")
@@ -400,9 +418,10 @@
         }
     }
 
+    // TODO b/28848102 Add support for test dependencies injection
     @VisibleForTesting
-    UserManagerService(File dataDir) {
-        this(null, null, new Object(), dataDir);
+    UserManagerService(Context context) {
+        this(context, null, new Object(), context.getCacheDir());
     }
 
     /**
@@ -471,7 +490,7 @@
                 UserInfo ui = mUsers.valueAt(i).info;
                 if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
                     partials.add(ui);
-                    mRemovingUserIds.append(ui.id, true);
+                    addRemovingUserIdLocked(ui.id);
                     ui.partial = true;
                 }
             }
@@ -1687,14 +1706,13 @@
                                         UserRestrictionsUtils
                                                 .readRestrictions(parser, mGuestRestrictions);
                                     }
-                                } else if (parser.getName().equals(TAG_DEVICE_POLICY_RESTRICTIONS)
-                                        ) {
-                                    UserRestrictionsUtils.readRestrictions(parser,
-                                            newDevicePolicyGlobalUserRestrictions);
                                 }
                                 break;
                             }
                         }
+                    } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
+                        UserRestrictionsUtils.readRestrictions(parser,
+                                newDevicePolicyGlobalUserRestrictions);
                     } else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
                         String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
                         if (ownerUserId != null) {
@@ -1790,11 +1808,7 @@
         }
         // Create the system user
         UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
-        UserData userData = new UserData();
-        userData.info = system;
-        synchronized (mUsersLock) {
-            mUsers.put(system.id, userData);
-        }
+        UserData userData = putUserInfo(system);
         mNextSerialNumber = MIN_USER_ID;
         mUserVersion = USER_VERSION;
 
@@ -2334,6 +2348,23 @@
         return userInfo;
     }
 
+    @VisibleForTesting
+    UserData putUserInfo(UserInfo userInfo) {
+        final UserData userData = new UserData();
+        userData.info = userInfo;
+        synchronized (mUsers) {
+            mUsers.put(userInfo.id, userData);
+        }
+        return userData;
+    }
+
+    @VisibleForTesting
+    void removeUserInfo(int userId) {
+        synchronized (mUsers) {
+            mUsers.remove(userId);
+        }
+    }
+
     /**
      * @hide
      */
@@ -2450,10 +2481,7 @@
                         return false;
                     }
 
-                    // We remember deleted user IDs to prevent them from being
-                    // reused during the current boot; they can still be reused
-                    // after a reboot.
-                    mRemovingUserIds.put(userHandle, true);
+                    addRemovingUserIdLocked(userHandle);
                 }
 
                 try {
@@ -2500,6 +2528,19 @@
         }
     }
 
+    @VisibleForTesting
+    void addRemovingUserIdLocked(int userId) {
+        // We remember deleted user IDs to prevent them from being
+        // reused during the current boot; they can still be reused
+        // after a reboot or recycling of userIds.
+        mRemovingUserIds.put(userId, true);
+        mRecentlyRemovedIds.add(userId);
+        // Keep LRU queue of recently removed IDs for recycling
+        if (mRecentlyRemovedIds.size() > MAX_RECENTLY_REMOVED_IDS_SIZE) {
+            mRecentlyRemovedIds.removeFirst();
+        }
+    }
+
     void finishRemoveUser(final int userHandle) {
         if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
         // Let other services shutdown any activity and clean up their state before completely
@@ -2585,6 +2626,11 @@
         AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
         userFile.delete();
         updateUserIds();
+        if (RELEASE_DELETED_USER_ID) {
+            synchronized (mUsers) {
+                mRemovingUserIds.delete(userHandle);
+            }
+        }
     }
 
     private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
@@ -2965,20 +3011,39 @@
 
     /**
      * Returns the next available user id, filling in any holes in the ids.
-     * TODO: May not be a good idea to recycle ids, in case it results in confusion
-     * for data and battery stats collection, or unexpected cross-talk.
      */
-    private int getNextAvailableId() {
+    @VisibleForTesting
+    int getNextAvailableId() {
+        int nextId;
         synchronized (mUsersLock) {
-            int i = MIN_USER_ID;
-            while (i < MAX_USER_ID) {
-                if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
-                    return i;
+            nextId = scanNextAvailableIdLocked();
+            if (nextId >= 0) {
+                return nextId;
+            }
+            // All ids up to MAX_USER_ID were used. Remove all mRemovingUserIds,
+            // except most recently removed
+            if (mRemovingUserIds.size() > 0) {
+                Slog.i(LOG_TAG, "All available IDs are used. Recycling LRU ids.");
+                mRemovingUserIds.clear();
+                for (Integer recentlyRemovedId : mRecentlyRemovedIds) {
+                    mRemovingUserIds.put(recentlyRemovedId, true);
                 }
-                i++;
+                nextId = scanNextAvailableIdLocked();
             }
         }
-        throw new IllegalStateException("No user id available!");
+        if (nextId < 0) {
+            throw new IllegalStateException("No user id available!");
+        }
+        return nextId;
+    }
+
+    private int scanNextAvailableIdLocked() {
+        for (int i = MIN_USER_ID; i < MAX_USER_ID; i++) {
+            if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
+                return i;
+            }
+        }
+        return -1;
     }
 
     private String packageToRestrictionsFileName(String packageName) {
@@ -3041,9 +3106,8 @@
      */
     private static int getSerialNumber(File file) throws IOException {
         try {
-            final byte[] buf = new byte[256];
-            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL, buf);
-            final String serial = new String(buf, 0, len);
+            final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SERIAL);
+            final String serial = new String(buf);
             try {
                 return Integer.parseInt(serial);
             } catch (NumberFormatException e) {
@@ -3145,8 +3209,9 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
-        (new Shell()).exec(this, in, out, err, args, resultReceiver);
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     int onShellCommand(Shell shell, String cmd) {
@@ -3284,6 +3349,10 @@
             synchronized (mUsersLock) {
                 pw.println();
                 pw.println("  Device managed: " + mIsDeviceManaged);
+                if (mRemovingUserIds.size() > 0) {
+                    pw.println();
+                    pw.println("  Recently removed userIds: " + mRecentlyRemovedIds);
+                }
             }
             synchronized (mUserStates) {
                 pw.println("  Started users state: " + mUserStates);
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index bb91f76..a8bd4d2 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -20,6 +20,7 @@
 import com.android.internal.app.AlertController.AlertParams;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.policy.EmergencyAffordanceManager;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.R;
@@ -27,7 +28,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -125,6 +125,7 @@
     private boolean mHasTelephony;
     private boolean mHasVibrator;
     private final boolean mShowSilentToggle;
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
 
     /**
      * @param context everything needs a context :(
@@ -159,6 +160,8 @@
 
         mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
+
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
     }
 
     /**
@@ -308,6 +311,10 @@
             addedKeys.add(actionKey);
         }
 
+        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+            mItems.add(getEmergencyAction());
+        }
+
         mAdapter = new MyAdapter();
 
         AlertParams params = new AlertParams(mContext);
@@ -493,6 +500,26 @@
         };
     }
 
+    private Action getEmergencyAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
+                R.string.global_action_emergency) {
+            @Override
+            public void onPress() {
+                mEmergencyAffordanceManager.performEmergencyCall();
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
     private Action getAssistAction() {
         return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
                 R.string.global_action_assist) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index c764833..9bf0476 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -25,7 +25,9 @@
 import android.content.IntentFilter;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -36,7 +38,6 @@
 import android.service.vr.IVrStateCallbacks;
 import android.util.DisplayMetrics;
 import android.util.Slog;
-import android.util.SparseBooleanArray;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -66,6 +67,7 @@
     private final H mHandler;
     private final long mShowDelayMs;
     private final long mPanicThresholdMs;
+    private final IBinder mWindowToken = new Binder();
 
     private boolean mConfirmed;
     private ClingWindowView mClingWindow;
@@ -190,13 +192,13 @@
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
                 0
                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                 ,
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("ImmersiveModeConfirmation");
         lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
+        lp.token = getWindowToken();
         return lp;
     }
 
@@ -208,6 +210,13 @@
                 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
     }
 
+    /**
+     * @return the window token that's used by all ImmersiveModeConfirmation windows.
+     */
+    public IBinder getWindowToken() {
+        return mWindowToken;
+    }
+
     private class ClingWindowView extends FrameLayout {
         private static final int BGCOLOR = 0x80000000;
         private static final int OFFSET_DP = 96;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7083ab7..b3430c6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -182,6 +182,8 @@
     // No longer recommended for desk docks;
     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
 
+    static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
+
     static final int SHORT_PRESS_POWER_NOTHING = 0;
     static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
     static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -306,6 +308,9 @@
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
+    /** Amount of time (in milliseconds) a toast window can be shown. */
+    public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
+
     /**
      * Lock protecting internal state.  Must not call out into window
      * manager with lock held.  (This lock will be acquired in places
@@ -644,6 +649,9 @@
     // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
     int mIncallPowerBehavior;
 
+    // Behavior of Back button while in-call and screen on
+    int mIncallBackBehavior;
+
     Display mDisplay;
 
     private int mDisplayRotation;
@@ -835,6 +843,9 @@
                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
@@ -1057,7 +1068,7 @@
             if (mBackKeyPressCounter <= PANIC_PRESS_BACK_COUNT) {
                 // This could be a multi-press.  Wait a little bit longer to confirm.
                 Message msg = mHandler.obtainMessage(MSG_BACK_DELAYED_PRESS,
-                        mBackKeyPressCounter, 0, eventTime);
+                    mBackKeyPressCounter, 0, eventTime);
                 msg.setAsynchronous(true);
                 mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
             }
@@ -1066,6 +1077,27 @@
         // Reset back long press state
         cancelPendingBackKeyAction();
 
+        if (mHasFeatureWatch) {
+            TelecomManager telecomManager = getTelecommService();
+
+            if (telecomManager != null) {
+                if (telecomManager.isRinging()) {
+                    // Pressing back while there's a ringing incoming
+                    // call should silence the ringer.
+                    telecomManager.silenceRinger();
+
+                    // It should not prevent navigating away
+                    return false;
+                } else if (
+                    (mIncallBackBehavior & Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_HANGUP) != 0
+                        && telecomManager.isInCall()) {
+                    // Otherwise, if "Back button ends call" is enabled,
+                    // the Back button will hang up any current active call.
+                    return telecomManager.endCall();
+                }
+            }
+        }
+
         return handled;
     }
 
@@ -1343,8 +1375,13 @@
             case LONG_PRESS_BACK_NOTHING:
                 break;
             case LONG_PRESS_BACK_GO_TO_VOICE_ASSIST:
-                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
-                startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                final boolean keyguardActive = mKeyguardDelegate == null
+                        ? false
+                        : mKeyguardDelegate.isShowing();
+                if (!keyguardActive) {
+                    Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                    startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+                }
                 break;
         }
     }
@@ -1902,6 +1939,7 @@
     public void setInitialDisplaySize(Display display, int width, int height, int density) {
         // This method might be called before the policy has been fully initialized
         // or for other displays we don't care about.
+        // TODO(multi-display): Define policy for secondary displays.
         if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
             return;
         }
@@ -1997,6 +2035,7 @@
 
     @Override
     public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+        // TODO(multi-display): Define policy for secondary displays.
         if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
             mOverscanLeft = left;
             mOverscanTop = top;
@@ -2017,6 +2056,10 @@
                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
                     UserHandle.USER_CURRENT);
+            mIncallBackBehavior = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
+                    Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT,
+                    UserHandle.USER_CURRENT);
 
             // Configure wake gesture.
             boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
@@ -2310,9 +2353,22 @@
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
+
             case TYPE_SCREENSHOT:
                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                 break;
+
+            case TYPE_TOAST:
+                // While apps should use the dedicated toast APIs to add such windows
+                // it possible legacy apps to add the window directly. Therefore, we
+                // make windows added directly by the app behave as a toast as much
+                // as possible in terms of timeout and animation.
+                if (attrs.hideTimeoutMilliseconds < 0
+                        || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
+                    attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
+                }
+                attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
+                break;
         }
 
         if (attrs.type != TYPE_STATUS_BAR) {
@@ -2381,6 +2437,7 @@
 
     @Override
     public void onConfigurationChanged() {
+        // TODO(multi-display): Define policy for secondary displays.
         final Resources res = mContext.getResources();
 
         mStatusBarHeight =
@@ -2401,22 +2458,24 @@
         mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
                 res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
 
-        // Height of the navigation bar when presented horizontally at bottom
-        mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
-        mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
-                res.getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_height_car_mode);
-        mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
-        mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
+        if (ALTERNATE_CAR_MODE_NAV_SIZE) {
+            // Height of the navigation bar when presented horizontally at bottom
+            mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
+            mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
+                    res.getDimensionPixelSize(
+                            com.android.internal.R.dimen.navigation_bar_height_car_mode);
+            mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
+            mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
 
-        // Width of the navigation bar when presented vertically along one side
-        mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
-        mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
-        mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
-        mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
-                res.getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_width_car_mode);
+            // Width of the navigation bar when presented vertically along one side
+            mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
+            mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
+            mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
+            mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
+                    res.getDimensionPixelSize(
+                            com.android.internal.R.dimen.navigation_bar_width_car_mode);
+        }
     }
 
     /** {@inheritDoc} */
@@ -2548,7 +2607,7 @@
     }
 
     private int getNavigationBarWidth(int rotation, int uiMode) {
-        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
             return mNavigationBarWidthForRotationInCarMode[rotation];
         } else {
             return mNavigationBarWidthForRotationDefault[rotation];
@@ -2569,7 +2628,7 @@
     }
 
     private int getNavigationBarHeight(int rotation, int uiMode) {
-        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
             return mNavigationBarHeightForRotationInCarMode[rotation];
         } else {
             return mNavigationBarHeightForRotationDefault[rotation];
@@ -2886,7 +2945,11 @@
             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
                 if (transit == TRANSIT_EXIT
                         || transit == TRANSIT_HIDE) {
-                    return R.anim.dock_bottom_exit;
+                    if (isKeyguardShowingAndNotOccluded()) {
+                        return R.anim.dock_bottom_exit_keyguard;
+                    } else {
+                        return R.anim.dock_bottom_exit;
+                    }
                 } else if (transit == TRANSIT_ENTER
                         || transit == TRANSIT_SHOW) {
                     return R.anim.dock_bottom_enter;
@@ -3913,11 +3976,19 @@
     };
 
     @Override
+    public void setRecentsVisibilityLw(boolean visible) {
+        mRecentsVisible = visible;
+    }
+
+    @Override
+    public void setTvPipVisibilityLw(boolean visible) {
+        mTvPictureInPictureVisible = visible;
+    }
+
+    @Override
     public int adjustSystemUiVisibilityLw(int visibility) {
         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
-        mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
-        mTvPictureInPictureVisible = (visibility & View.TV_PICTURE_IN_PICTURE_VISIBLE) > 0;
 
         // Reset any bits in mForceClearingStatusBarVisibility that
         // are now clear.
@@ -5399,12 +5470,18 @@
         boolean showing = mKeyguardDelegate.isShowing();
         if (wasOccluded && !isOccluded && showing) {
             mKeyguardOccluded = false;
-            mKeyguardDelegate.setOccluded(false);
+            mKeyguardDelegate.setOccluded(false, true /* animate */);
             mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+            if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
+                mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            }
+            Animation anim = AnimationUtils.loadAnimation(mContext,
+                    com.android.internal.R.anim.wallpaper_open_exit);
+            mWindowManagerFuncs.overridePlayingAppAnimationsLw(anim);
             return true;
         } else if (!wasOccluded && isOccluded && showing) {
             mKeyguardOccluded = true;
-            mKeyguardDelegate.setOccluded(true);
+            mKeyguardDelegate.setOccluded(true, false /* animate */);
             mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
             mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
             return true;
@@ -5589,7 +5666,14 @@
 
                 @Override
                 public void onServiceDisconnected(ComponentName name) {
-                    notifyScreenshotError();
+                    synchronized (mScreenshotLock) {
+                        if (mScreenshotConnection != null) {
+                            mContext.unbindService(mScreenshotConnection);
+                            mScreenshotConnection = null;
+                            mHandler.removeCallbacks(mScreenshotTimeout);
+                            notifyScreenshotError();
+                        }
+                    }
                 }
             };
             if (mContext.bindServiceAsUser(serviceIntent, conn,
@@ -7469,11 +7553,20 @@
     private int updateSystemUiVisibilityLw() {
         // If there is no window focused, there will be nobody to handle the events
         // anyway, so just hang on in whatever state we're in until things settle down.
-        final WindowState win = mFocusedWindow != null ? mFocusedWindow
+        WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
                 : mTopFullscreenOpaqueWindowState;
-        if (win == null) {
+        if (winCandidate == null) {
             return 0;
         }
+        if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
+            // The immersive mode confirmation should never affect the system bar visibility,
+            // otherwise it will unhide the navigation bar and hide itself.
+            winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
+            if (winCandidate == null) {
+                return 0;
+            }
+        }
+        final WindowState win = winCandidate;
         if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
             // We are updating at a point where the keyguard has gotten
             // focus, but we were last in a state where the top window is
@@ -7823,7 +7916,7 @@
         int delta = newRotation - oldRotation;
         if (delta < 0) delta += 4;
         // Likewise we don't rotate seamlessly for 180 degree rotations
-        // in this case the surfaces never resize, and our logic to 
+        // in this case the surfaces never resize, and our logic to
         // revert the transformations on size change will fail. We could
         // fix this in the future with the "tagged" frames idea.
         if (delta == Surface.ROTATION_180) {
@@ -7831,6 +7924,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
@@ -8017,6 +8113,7 @@
                 pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
         pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior);
                 pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior);
+                pw.print(" mIncallBackBehavior="); pw.print(mIncallBackBehavior);
                 pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior);
         pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation);
                 pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
diff --git a/services/core/java/com/android/server/policy/RecentApplicationsBackground.java b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
deleted file mode 100644
index 694a110..0000000
--- a/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 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.policy;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.LinearLayout;
-
-/**
- * A vertical linear layout.  However, instead of drawing the background
- * behnd the items, it draws the background outside the items based on the
- * padding.  If there isn't enough room to draw both, it clips the background
- * instead of the contents.
- */
-public class RecentApplicationsBackground extends LinearLayout {
-    private static final String TAG = "RecentApplicationsBackground";
-
-    private boolean mBackgroundSizeChanged;
-    private Drawable mBackground;
-    private Rect mTmp0 = new Rect();
-    private Rect mTmp1 = new Rect();
-
-    public RecentApplicationsBackground(Context context) {
-        this(context, null);
-        init();
-    }
-
-    public RecentApplicationsBackground(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
-    }
-
-    private void init() {
-        mBackground = getBackground();
-        setBackgroundDrawable(null);
-        setPadding(0, 0, 0, 0);
-        setGravity(Gravity.CENTER);
-    }
-
-    @Override
-    protected boolean setFrame(int left, int top, int right, int bottom) {
-        setWillNotDraw(false);
-        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
-            mBackgroundSizeChanged = true;
-        }
-        return super.setFrame(left, top, right, bottom);
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return who == mBackground || super.verifyDrawable(who);
-    }
-
-    @Override
-    public void jumpDrawablesToCurrentState() {
-        super.jumpDrawablesToCurrentState();
-        if (mBackground != null) mBackground.jumpToCurrentState();
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        Drawable d = mBackground;
-        if (d != null && d.isStateful()) {
-            d.setState(getDrawableState());
-        }
-        super.drawableStateChanged();
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        final Drawable background = mBackground;
-        if (background != null) {
-            if (mBackgroundSizeChanged) {
-                mBackgroundSizeChanged = false;
-                Rect chld = mTmp0;
-                Rect bkg = mTmp1;
-                mBackground.getPadding(bkg);
-                getChildBounds(chld);
-                // This doesn't clamp to this view's bounds, which is what we want,
-                // so that the drawing is clipped.
-                final int top = chld.top - bkg.top;
-                final int bottom = chld.bottom + bkg.bottom;
-                // The background here is a gradient that wants to
-                // extend the full width of the screen (whatever that
-                // may be).
-                int left, right;
-                if (false) {
-                    // This limits the width of the drawable.
-                    left = chld.left - bkg.left;
-                    right = chld.right + bkg.right;
-                } else {
-                    // This expands it to full width.
-                    left = 0;
-                    right = getRight();
-                }
-                background.setBounds(left, top, right, bottom);
-            }
-        }
-        mBackground.draw(canvas);
-
-        if (false) {
-            android.graphics.Paint p = new android.graphics.Paint();
-            p.setColor(0x88ffff00);
-            canvas.drawRect(background.getBounds(), p);
-        }
-        canvas.drawARGB((int)(0.75*0xff), 0, 0, 0);
-
-        super.draw(canvas);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mBackground.setCallback(this);
-        setWillNotDraw(false);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mBackground.setCallback(null);
-    }
-    
-    private void getChildBounds(Rect r) {
-        r.left = r.top = Integer.MAX_VALUE;
-        r.bottom = r.right = Integer.MIN_VALUE;
-        final int N = getChildCount();
-        for (int i=0; i<N; i++) {
-            View v = getChildAt(i);
-            if (v.getVisibility() == View.VISIBLE) {
-                r.left = Math.min(r.left, v.getLeft());
-                r.top = Math.min(r.top, v.getTop());
-                r.right = Math.max(r.right, v.getRight());
-                r.bottom = Math.max(r.bottom, v.getBottom());
-            }
-        }
-    }
-}
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..2069f24 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -181,7 +181,7 @@
                 mKeyguardService.onBootCompleted();
             }
             if (mKeyguardState.occluded) {
-                mKeyguardService.setOccluded(mKeyguardState.occluded);
+                mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
             }
             if (!mKeyguardState.enabled) {
                 mKeyguardService.setKeyguardEnabled(mKeyguardState.enabled);
@@ -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();
@@ -229,10 +236,10 @@
         }
     }
 
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         if (mKeyguardService != null) {
-            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
-            mKeyguardService.setOccluded(isOccluded);
+            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
+            mKeyguardService.setOccluded(isOccluded, animate);
         }
         mKeyguardState.occluded = isOccluded;
     }
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..1d85f34 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -63,9 +63,9 @@
     }
 
     @Override // Binder interface
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         try {
-            mService.setOccluded(isOccluded);
+            mService.setOccluded(isOccluded, animate);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
@@ -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/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ced84f6..7576cddad 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -650,10 +650,12 @@
                     false, mSettingsObserver, UserHandle.USER_ALL);
             IVrManager vrManager =
                     (IVrManager) getBinderService(VrManagerService.VR_MANAGER_BINDER_SERVICE);
-            try {
-                vrManager.registerListener(mVrStateCallbacks);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            if (vrManager != null) {
+                try {
+                    vrManager.registerListener(mVrStateCallbacks);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+                }
             }
             // Go.
             readConfigurationLocked();
@@ -808,9 +810,10 @@
     }
 
     private void updateLowPowerModeLocked() {
-        if (mIsPowered && mLowPowerModeSetting) {
+        if ((mIsPowered || !mBatteryLevelLow && !mBootCompleted) && mLowPowerModeSetting) {
             if (DEBUG_SPEW) {
-                Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
+                Slog.d(TAG, "updateLowPowerModeLocked: powered or booting with sufficient battery,"
+                        + " turning setting off");
             }
             // Turn setting off if powered
             Settings.Global.putInt(mContext.getContentResolver(),
@@ -2539,18 +2542,18 @@
 
     boolean setDeviceIdleModeInternal(boolean enabled) {
         synchronized (mLock) {
-            if (mDeviceIdleMode != enabled) {
-                mDeviceIdleMode = enabled;
-                updateWakeLockDisabledStatesLocked();
-                if (enabled) {
-                    EventLogTags.writeDeviceIdleOnPhase("power");
-                } else {
-                    EventLogTags.writeDeviceIdleOffPhase("power");
-                }
-                return true;
+            if (mDeviceIdleMode == enabled) {
+                return false;
             }
-            return false;
+            mDeviceIdleMode = enabled;
+            updateWakeLockDisabledStatesLocked();
         }
+        if (enabled) {
+            EventLogTags.writeDeviceIdleOnPhase("power");
+        } else {
+            EventLogTags.writeDeviceIdleOffPhase("power");
+        }
+        return true;
     }
 
     boolean setLightDeviceIdleModeInternal(boolean enabled) {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 1dbc6d9..badee82 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -717,6 +717,14 @@
         }
         if (!done[0]) {
             Log.w(TAG, "Timed out waiting for uncrypt.");
+            final int uncryptTimeoutError = 100;
+            String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
+                    MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
+            try {
+                FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
+            } catch (IOException e) {
+                Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
new file mode 100644
index 0000000..0b80d81
--- /dev/null
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -0,0 +1,67 @@
+/*
+ * 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.security;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.security.keymaster.KeyAttestationPackageInfo;
+import android.security.keymaster.KeyAttestationApplicationId;
+import android.security.keymaster.IKeyAttestationApplicationIdProvider;
+
+/**
+ * @hide
+ * The KeyAttestationApplicationIdProviderService provides information describing the possible
+ * applications identified by a UID. Due to UID sharing, this KeyAttestationApplicationId can
+ * comprise information about multiple packages. The Information is used by keystore to describe
+ * the initiating application of a key attestation procedure.
+ */
+public class KeyAttestationApplicationIdProviderService
+        extends IKeyAttestationApplicationIdProvider.Stub {
+
+    public KeyAttestationApplicationIdProviderService(Context context) {
+        mPackageManager = context.getPackageManager();
+    }
+
+    private PackageManager mPackageManager;
+
+    public KeyAttestationApplicationId getKeyAttestationApplicationId(int uid)
+            throws RemoteException {
+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
+        if (packageNames == null) {
+            throw new RemoteException("No packages for uid");
+        }
+        int userId = UserHandle.getUserId(uid);
+        KeyAttestationPackageInfo[] keyAttestationPackageInfos =
+                new KeyAttestationPackageInfo[packageNames.length];
+        try {
+            for (int i = 0; i < packageNames.length; ++i) {
+                PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
+                        PackageManager.GET_SIGNATURES, userId);
+                keyAttestationPackageInfos[i] = new KeyAttestationPackageInfo(packageNames[i],
+                        packageInfo.versionCode, packageInfo.signatures);
+            }
+        } catch (NameNotFoundException nnfe) {
+            throw new RemoteException(nnfe.getMessage());
+        }
+        return new KeyAttestationApplicationId(keyAttestationPackageInfos);
+    }
+}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 552803f..7b7db0e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -28,23 +28,21 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
-import android.view.KeyEvent;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.FastPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationDelegate;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
-import java.io.FileOutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -849,9 +847,9 @@
 
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
         (new StatusBarShellCommand(this)).exec(
-                this, in, out, err, args, resultReceiver);
+                this, in, out, err, args, callback, resultReceiver);
     }
 
     // ================================================================================
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 0ae1717..90c711a 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -87,6 +87,11 @@
     private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
     private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
 
+    // com.android.internal.R.string.low_internal_storage_view_text_no_boot
+    // hard codes 250MB in the message as the storage space required for the
+    // boot image.
+    private static final long BOOT_IMAGE_STORAGE_REQUIREMENT = 250 * 1024 * 1024;
+
     private long mFreeMem;  // on /data
     private long mFreeMemAfterLastCacheClear;  // on /data
     private long mLastReportedFreeMem;
@@ -290,9 +295,10 @@
                     mLowMemFlag = false;
                 }
             }
-            if (!mLowMemFlag && !mIsBootImageOnDisk) {
+            if (!mLowMemFlag && !mIsBootImageOnDisk && mFreeMem < BOOT_IMAGE_STORAGE_REQUIREMENT) {
                 Slog.i(TAG, "No boot image on disk due to lack of space. Sending notification");
                 sendNotification();
+                mLowMemFlag = true;
             }
             if (mFreeMem < mMemFullThreshold) {
                 if (!mMemFullFlag) {
@@ -383,7 +389,7 @@
 
         @Override
         public boolean isMemoryLow() {
-            return mLowMemFlag || !mIsBootImageOnDisk;
+            return mLowMemFlag;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c952ee6..353d663 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -860,16 +860,26 @@
         @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) {
+                        }
+                    }
+                    final Intent lockIntent = new Intent(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+                    lockIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    lockIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                    mContext.sendBroadcastAsUser(lockIntent, UserHandle.SYSTEM,
+                            Manifest.permission.TRUST_LISTENER, /* options */ null);
                 }
+            } 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/updates/CertificateTransparencyLogInstallReceiver.java b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
new file mode 100644
index 0000000..ec65f8d
--- /dev/null
+++ b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
@@ -0,0 +1,181 @@
+/*
+ * 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.updates;
+
+import com.android.internal.util.HexDump;
+import android.os.FileUtils;
+import android.system.Os;
+import android.system.ErrnoException;
+import android.util.Base64;
+import android.util.Slog;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringBufferInputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.NoSuchAlgorithmException;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInstallReceiver {
+
+    private static final String TAG = "CTLogInstallReceiver";
+    private static final String LOGDIR_PREFIX = "logs-";
+
+    public CertificateTransparencyLogInstallReceiver() {
+        super("/data/misc/keychain/trusted_ct_logs/", "ct_logs", "metadata/", "version");
+    }
+
+    @Override
+    protected void install(byte[] content, int version) throws IOException {
+        /* Install is complicated here because we translate the input, which is a JSON file
+         * containing log information to a directory with a file per log. To support atomically
+         * replacing the old configuration directory with the new there's a bunch of steps. We
+         * create a new directory with the logs and then do an atomic update of the current symlink
+         * to point to the new directory.
+         */
+
+        // 1. Ensure that the update dir exists and is readable
+        updateDir.mkdir();
+        if (!updateDir.isDirectory()) {
+            throw new IOException("Unable to make directory " + updateDir.getCanonicalPath());
+        }
+        if (!updateDir.setReadable(true, false)) {
+            throw new IOException("Unable to set permissions on " +
+                    updateDir.getCanonicalPath());
+        }
+        File currentSymlink = new File(updateDir, "current");
+        File newVersion = new File(updateDir, LOGDIR_PREFIX + String.valueOf(version));
+        File oldDirectory;
+        // 2. Handle the corner case where the new directory already exists.
+        if (newVersion.exists()) {
+            // If the symlink has already been updated then the update died between steps 7 and 8
+            // and so we cannot delete the directory since its in use. Instead just bump the version
+            // and return.
+            if (newVersion.getCanonicalPath().equals(currentSymlink.getCanonicalPath())) {
+                writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
+                deleteOldLogDirectories();
+                return;
+            } else {
+                FileUtils.deleteContentsAndDir(newVersion);
+            }
+        }
+        try {
+            // 3. Create /data/misc/keychain/trusted_ct_logs/<new_version>/ .
+            newVersion.mkdir();
+            if (!newVersion.isDirectory()) {
+                throw new IOException("Unable to make directory " + newVersion.getCanonicalPath());
+            }
+            if (!newVersion.setReadable(true, false)) {
+                throw new IOException("Failed to set " +newVersion.getCanonicalPath() +
+                        " readable");
+            }
+
+            // 4. For each log in the log file create the corresponding file in <new_version>/ .
+            try {
+                JSONObject json = new JSONObject(new String(content, StandardCharsets.UTF_8));
+                JSONArray logs = json.getJSONArray("logs");
+                for (int i = 0; i < logs.length(); i++) {
+                    JSONObject log = logs.getJSONObject(i);
+                    installLog(newVersion, log);
+                }
+            } catch (JSONException e) {
+                throw new IOException("Failed to parse logs", e);
+            }
+
+            // 5. Create the temp symlink. We'll rename this to the target symlink to get an atomic
+            // update.
+            File tempSymlink = new File(updateDir, "new_symlink");
+            try {
+                Os.symlink(newVersion.getCanonicalPath(), tempSymlink.getCanonicalPath());
+            } catch (ErrnoException e) {
+                throw new IOException("Failed to create symlink", e);
+            }
+
+            // 6. Update the symlink target, this is the actual update step.
+            tempSymlink.renameTo(currentSymlink.getAbsoluteFile());
+        } catch (IOException | RuntimeException e) {
+            FileUtils.deleteContentsAndDir(newVersion);
+            throw e;
+        }
+        Slog.i(TAG, "CT log directory updated to " + newVersion.getAbsolutePath());
+        // 7. Update the current version information
+        writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
+        // 8. Cleanup
+        deleteOldLogDirectories();
+    }
+
+    private void installLog(File directory, JSONObject logObject) throws IOException {
+        try {
+            String logFilename = getLogFileName(logObject.getString("key"));
+            File file = new File(directory, logFilename);
+            try (OutputStreamWriter out =
+                    new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
+                writeLogEntry(out, "key", logObject.getString("key"));
+                writeLogEntry(out, "url", logObject.getString("url"));
+                writeLogEntry(out, "description", logObject.getString("description"));
+            }
+            if (!file.setReadable(true, false)) {
+                throw new IOException("Failed to set permissions on " + file.getCanonicalPath());
+            }
+        } catch (JSONException e) {
+            throw new IOException("Failed to parse log", e);
+        }
+
+    }
+
+    /**
+     * Get the filename for a log based on its public key. This must be kept in sync with
+     * org.conscrypt.ct.CTLogStoreImpl.
+     */
+    private String getLogFileName(String base64PublicKey) {
+        byte[] keyBytes = Base64.decode(base64PublicKey, Base64.DEFAULT);
+        try {
+            byte[] id = MessageDigest.getInstance("SHA-256").digest(keyBytes);
+            return HexDump.toHexString(id, false);
+        } catch (NoSuchAlgorithmException e) {
+            // SHA-256 is guaranteed to be available.
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void writeLogEntry(OutputStreamWriter out, String key, String value)
+            throws IOException {
+        out.write(key + ":" + value + "\n");
+    }
+
+    private void deleteOldLogDirectories() throws IOException {
+        if (!updateDir.exists()) {
+            return;
+        }
+        File currentTarget = new File(updateDir, "current").getCanonicalFile();
+        FileFilter filter = new FileFilter() {
+            @Override
+            public boolean accept(File file) {
+                return !currentTarget.equals(file) && file.getName().startsWith(LOGDIR_PREFIX);
+            }
+        };
+        for (File f : updateDir.listFiles(filter)) {
+            FileUtils.deleteContentsAndDir(f);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 76f2f0e..5514551 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -27,10 +27,10 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.IUserSwitchObserver;
 import android.app.IWallpaperManager;
 import android.app.IWallpaperManagerCallback;
 import android.app.PendingIntent;
+import android.app.UserSwitchObserver;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
@@ -89,6 +89,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.server.EventLogTags;
+import com.android.server.FgThread;
 import com.android.server.SystemService;
 
 import libcore.io.IoUtils;
@@ -352,9 +353,17 @@
                         (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
                         (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
 
+                // If the crop hint was larger than the image we just overshot. Patch things up.
+                if (cropHint.left < 0) {
+                    cropHint.left = 0;
+                }
+                if (cropHint.top < 0) {
+                    cropHint.top = 0;
+                }
+
                 // Don't bother cropping if what we're left with is identity
                 needCrop = (options.outHeight > cropHint.height()
-                        && options.outWidth > cropHint.width());
+                        || options.outWidth > cropHint.width());
             }
 
             // scale if the crop height winds up not matching the recommended metrics
@@ -581,6 +590,11 @@
 
     class WallpaperConnection extends IWallpaperConnection.Stub
             implements ServiceConnection {
+
+        /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
+         *  middle of an update). If exceeded, the wallpaper gets reset to the system default. */
+        private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 5000;
+
         final WallpaperInfo mInfo;
         final Binder mToken = new Binder();
         IWallpaperService mService;
@@ -591,6 +605,18 @@
         boolean mDimensionsChanged = false;
         boolean mPaddingChanged = false;
 
+        private Runnable mResetRunnable = () -> {
+            synchronized (mLock) {
+                if (!mWallpaper.wallpaperUpdating
+                        && mWallpaper.userId == mCurrentUserId) {
+                    Slog.w(TAG, "Wallpaper reconnect timed out, "
+                            + "reverting to built-in wallpaper!");
+                    clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
+                            null);
+                }
+            }
+        };
+
         public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
             mInfo = info;
             mWallpaper = wallpaper;
@@ -607,6 +633,7 @@
                     // locking there and anyway we always need to be able to
                     // recover if there is something wrong.
                     saveSettingsLocked(mWallpaper.userId);
+                    FgThread.getHandler().removeCallbacks(mResetRunnable);
                 }
             }
         }
@@ -633,6 +660,12 @@
                             clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
                         } else {
                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
+
+                            // If we didn't reset it right away, do so after we couldn't connect to
+                            // it for an extended amount of time to avoid having a black wallpaper.
+                            FgThread.getHandler().removeCallbacks(mResetRunnable);
+                            FgThread.getHandler().postDelayed(mResetRunnable,
+                                    WALLPAPER_RECONNECT_TIMEOUT_MS);
                         }
                         final String flattened = name.flattenToString();
                         EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
@@ -744,6 +777,10 @@
                     if (wallpaper.wallpaperComponent != null
                             && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
                         wallpaper.wallpaperUpdating = true;
+                        if (wallpaper.connection != null) {
+                            FgThread.getHandler().removeCallbacks(
+                                    wallpaper.connection.mResetRunnable);
+                        }
                     }
                 }
             }
@@ -896,20 +933,11 @@
 
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new IUserSwitchObserver.Stub() {
+                    new UserSwitchObserver() {
                         @Override
                         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
                             switchUser(newUserId, reply);
                         }
-
-                        @Override
-                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                        }
-
-                        @Override
-                        public void onForegroundProfileSwitch(int newProfileId) {
-                            // Ignore.
-                        }
                     }, TAG);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
@@ -1350,7 +1378,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 +1404,6 @@
             }
         }
 
-        final int userId = UserHandle.getCallingUserId();
-
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
             WallpaperData wallpaper;
@@ -1757,8 +1785,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/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 846169c..43cdf59 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -25,10 +25,10 @@
 import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.util.Slog;
 import android.webkit.IWebViewUpdateService;
-import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
 
@@ -140,9 +140,10 @@
 
         @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
-                FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+                FileDescriptor err, String[] args, ShellCallback callback,
+                ResultReceiver resultReceiver) {
             (new WebViewUpdateServiceShellCommand(this)).exec(
-                    this, in, out, err, args, resultReceiver);
+                    this, in, out, err, args, callback, resultReceiver);
         }
 
 
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/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index d4d6f32..cd46165 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -374,6 +374,7 @@
 
     void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
             ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
+        int appTransition = mNextAppTransition;
         mNextAppTransition = TRANSIT_UNSET;
         mAppTransitionState = APP_STATE_RUNNING;
         notifyAppTransitionStartingLocked(
@@ -382,7 +383,7 @@
                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
         mService.getDefaultDisplayContentLocked().getDockedDividerController()
-                .notifyAppTransitionStarting();
+                .notifyAppTransitionStarting(openingApps, appTransition);
 
         // Prolong the start for the transition when docking a task from recents, unless recents
         // ended it already then we don't need to wait.
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 5ddf283..305e47f 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -119,7 +118,7 @@
             int stackClip) {
         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
                 + ": " + anim + " wxh=" + width + "x" + height
-                + " isVisible=" + mAppToken.isVisible());
+                + " hasContentToDisplay=" + mAppToken.hasContentToDisplay());
         animation = anim;
         animating = false;
         if (!anim.isInitialized()) {
@@ -141,13 +140,13 @@
         }
         // Start out animation gone if window is gone, or visible if window is visible.
         transformation.clear();
-        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
+        transformation.setAlpha(mAppToken.hasContentToDisplay() ? 1 : 0);
         hasTransformation = true;
         mStackClip = stackClip;
 
         this.mSkipFirstFrame = skipFirstFrame;
 
-        if (!mAppToken.appFullscreen) {
+        if (!mAppToken.fillsParent()) {
             anim.setBackgroundColor(0);
         }
         if (mClearProlongedAnimation) {
@@ -164,11 +163,11 @@
 
     public void setDummyAnimation() {
         if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
-                + " isVisible=" + mAppToken.isVisible());
+                + " hasContentToDisplay=" + mAppToken.hasContentToDisplay());
         animation = sDummyAnimation;
         hasTransformation = true;
         transformation.clear();
-        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
+        transformation.setAlpha(mAppToken.hasContentToDisplay() ? 1 : 0);
     }
 
     void setNullAnimation() {
@@ -384,8 +383,8 @@
             return false;
         }
 
-        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                "AppWindowToken", displayId);
+        mAppToken.setAppLayoutChanges(
+                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM, "AppWindowToken", displayId);
 
         clearAnimation();
         animating = false;
@@ -398,8 +397,7 @@
             mService.moveInputMethodWindowsIfNeededLocked(true);
         }
 
-        if (DEBUG_ANIM) Slog.v(TAG,
-                "Animation done in " + mAppToken
+        if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
                 + ": reportedVisible=" + mAppToken.reportedVisible);
 
         transformation.clear();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 05c05b1..508cf24 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,44 +17,44 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.Display.DEFAULT_DISPLAY;
+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.WindowManagerPolicy.TRANSIT_ENTER;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.wm.WindowManagerService.H;
 
 import android.annotation.NonNull;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.IApplicationToken;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -67,7 +67,7 @@
  * Version of WindowToken that is specifically for a particular application (or
  * really activity) that is displaying windows.
  */
-class AppWindowToken extends WindowToken {
+class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
 
     // Non-null only for application tokens.
@@ -77,9 +77,10 @@
 
     final boolean voiceInteraction;
 
+    // TODO: Use getParent instead?
     Task mTask;
-    boolean appFullscreen;
-    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    /** @see WindowContainer#fillsParent() */
+    private boolean mFillsParent;
     boolean layoutConfigChanges;
     boolean showForAllUsers;
     int targetSdk;
@@ -91,19 +92,22 @@
     // an activity have been drawn, so they can be made visible together
     // at the same time.
     // initialize so that it doesn't match mTransactionSequence which is an int.
-    long lastTransactionSequence = Long.MIN_VALUE;
-    int numInterestingWindows;
-    int numDrawnWindows;
+    private long mLastTransactionSequence = Long.MIN_VALUE;
+    private int mNumInterestingWindows;
+    private int mNumDrawnWindows;
     boolean inPendingTransaction;
     boolean allDrawn;
     // Set to true when this app creates a surface while in the middle of an animation. In that
     // case do not clear allDrawn until the animation completes.
     boolean deferClearAllDrawn;
 
-    // These are to track the app's real drawing status if there were no saved surfaces.
+    /**
+     * These are to track the app's real drawing status if there were no saved surfaces.
+     * @see #updateDrawnWindowStates
+     */
     boolean allDrawnExcludingSaved;
-    int numInterestingWindowsExcludingSaved;
-    int numDrawnWindowsExclusingSaved;
+    private int mNumInterestingWindowsExcludingSaved;
+    private int mNumDrawnWindowsExcludingSaved;
 
     // Is this window's surface needed?  This is almost like hidden, except
     // it will sometimes be true a little earlier: when the token has
@@ -118,7 +122,7 @@
     boolean reportedVisible;
 
     // Last drawn state we reported to the app token.
-    boolean reportedDrawn;
+    private boolean reportedDrawn;
 
     // Set to true when the token has been removed from the window mgr.
     boolean removed;
@@ -130,10 +134,13 @@
     boolean startingDisplayed;
     boolean startingMoved;
     boolean firstWindowDrawn;
+    private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
+            new WindowState.UpdateReportedVisibilityResults();
 
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
+    // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
     boolean mIsExiting;
 
     boolean mLaunchTaskBehind;
@@ -143,7 +150,7 @@
 
     boolean mAppStopped;
     int mRotationAnimationHint;
-    int mPendingRelaunchCount;
+    private int mPendingRelaunchCount;
 
     private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
         new ArrayList<>();
@@ -151,43 +158,19 @@
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
-    AppWindowToken(WindowManagerService service, IApplicationToken _token, boolean _voiceInteraction) {
-        super(service, _token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION, true);
-        appToken = _token;
+    AppWindowToken(WindowManagerService service, IApplicationToken token, boolean _voiceInteraction) {
+        super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true);
+        appToken = token;
         voiceInteraction = _voiceInteraction;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAppAnimator = new AppWindowAnimator(this, service);
     }
 
-    void sendAppVisibilityToClients() {
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            if (win == startingWindow && clientHidden) {
-                // Don't hide the starting window.
-                continue;
-            }
-            try {
-                if (DEBUG_VISIBILITY) Slog.v(TAG,
-                        "Setting visibility of " + win + ": " + (!clientHidden));
-                win.mClient.dispatchAppVisibility(!clientHidden);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    void setVisibleBeforeClientHidden() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            w.setVisibleBeforeClientHidden();
-        }
-    }
-
     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
         firstWindowDrawn = true;
 
         // We now have a good window to show, remove dead placeholders
-        removeAllDeadWindows();
+        removeDeadWindows();
 
         if (startingData != null) {
             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
@@ -207,50 +190,21 @@
             return;
         }
 
-        int numInteresting = 0;
-        int numVisible = 0;
-        int numDrawn = 0;
-        boolean nowGone = true;
+        if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
+        final int count = mChildren.size();
 
-        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                "Update reported visibility: " + this);
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            if (win == startingWindow || win.mAppFreezing
-                    || win.mViewVisibility != View.VISIBLE
-                    || win.mAttrs.type == TYPE_APPLICATION_STARTING
-                    || win.mDestroying) {
-                continue;
-            }
-            if (DEBUG_VISIBILITY) {
-                Slog.v(TAG, "Win " + win + ": isDrawn="
-                        + win.isDrawnLw()
-                        + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
-                if (!win.isDrawnLw()) {
-                    Slog.v(TAG, "Not displayed: s=" +
-                            win.mWinAnimator.mSurfaceController
-                            + " pv=" + win.mPolicyVisibility
-                            + " mDrawState=" + win.mWinAnimator.mDrawState
-                            + " ph=" + win.isParentWindowHidden()
-                            + " th="
-                            + (win.mAppToken != null
-                                    ? win.mAppToken.hiddenRequested : false)
-                            + " a=" + win.mWinAnimator.mAnimating);
-                }
-            }
-            numInteresting++;
-            if (win.isDrawnLw()) {
-                numDrawn++;
-                if (!win.mWinAnimator.isAnimationSet()) {
-                    numVisible++;
-                }
-                nowGone = false;
-            } else if (win.mWinAnimator.isAnimationSet()) {
-                nowGone = false;
-            }
+        mReportedVisibilityResults.reset();
+
+        for (int i = 0; i < count; i++) {
+            final WindowState win = mChildren.get(i);
+            win.updateReportedVisibility(mReportedVisibilityResults);
         }
 
+        int numInteresting = mReportedVisibilityResults.numInteresting;
+        int numVisible = mReportedVisibilityResults.numVisible;
+        int numDrawn = mReportedVisibilityResults.numDrawn;
+        boolean nowGone = mReportedVisibilityResults.nowGone;
+
         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
         if (!nowGone) {
@@ -266,23 +220,16 @@
                 + numInteresting + " visible=" + numVisible);
         if (nowDrawn != reportedDrawn) {
             if (nowDrawn) {
-                Message m = mService.mH.obtainMessage(
-                        H.REPORT_APPLICATION_TOKEN_DRAWN, this);
-                mService.mH.sendMessage(m);
+                mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
             }
             reportedDrawn = nowDrawn;
         }
         if (nowVisible != reportedVisible) {
-            if (DEBUG_VISIBILITY) Slog.v(
-                    TAG, "Visibility changed in " + this
-                    + ": vis=" + nowVisible);
+            if (DEBUG_VISIBILITY) Slog.v(TAG,
+                    "Visibility changed in " + this + ": vis=" + nowVisible);
             reportedVisible = nowVisible;
-            Message m = mService.mH.obtainMessage(
-                    H.REPORT_APPLICATION_TOKEN_WINDOWS,
-                    nowVisible ? 1 : 0,
-                    nowGone ? 1 : 0,
-                    this);
-            mService.mH.sendMessage(m);
+            mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
+                    nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
         }
     }
 
@@ -327,48 +274,10 @@
                 changed = true;
             }
 
-            final int windowsCount = windows.size();
+            final int windowsCount = mChildren.size();
             for (int i = 0; i < windowsCount; i++) {
-                final WindowState win = windows.get(i);
-                if (win == startingWindow) {
-                    // Starting window that's exiting will be removed when the animation finishes.
-                    // Mark all relevant flags for that onExitAnimationDone will proceed all the way
-                    // to actually remove it.
-                    if (!visible && win.isVisibleNow() && mAppAnimator.isAnimating()) {
-                        win.mAnimatingExit = true;
-                        win.mRemoveOnExit = true;
-                        win.mWindowRemovalAllowed = true;
-                    }
-                    continue;
-                }
-
-                //Slog.i(TAG_WM, "Window " + win + ": vis=" + win.isVisible());
-                //win.dump("  ");
-                if (visible) {
-                    if (!win.isVisibleNow()) {
-                        if (!runningAppAnimation) {
-                            win.mWinAnimator.applyAnimationLocked(TRANSIT_ENTER, true);
-                            //TODO (multidisplay): Magnification is supported only for the default
-                            if (accessibilityController != null
-                                    && win.getDisplayId() == DEFAULT_DISPLAY) {
-                                accessibilityController.onWindowTransitionLocked(win, TRANSIT_ENTER);
-                            }
-                        }
-                        changed = true;
-                        win.setDisplayLayoutNeeded();
-                    }
-                } else if (win.isVisibleNow()) {
-                    if (!runningAppAnimation) {
-                        win.mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-                        //TODO (multidisplay): Magnification is supported only for the default
-                        if (accessibilityController != null
-                                && win.getDisplayId() == DEFAULT_DISPLAY) {
-                            accessibilityController.onWindowTransitionLocked(win,TRANSIT_EXIT);
-                        }
-                    }
-                    changed = true;
-                    win.setDisplayLayoutNeeded();
-                }
+                final WindowState win = mChildren.get(i);
+                changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
             }
 
             hidden = hiddenRequested = !visible;
@@ -376,12 +285,11 @@
             if (!visible) {
                 stopFreezingScreen(true, true);
             } else {
-                // If we are being set visible, and the starting window is
-                // not yet displayed, then make sure it doesn't get displayed.
-                WindowState swin = startingWindow;
-                if (swin != null && !swin.isDrawnLw()) {
-                    swin.mPolicyVisibility = false;
-                    swin.mPolicyVisibilityAfterAnim = false;
+                // If we are being set visible, and the starting window is not yet displayed,
+                // then make sure it doesn't get displayed.
+                if (startingWindow != null && !startingWindow.isDrawnLw()) {
+                    startingWindow.mPolicyVisibility = false;
+                    startingWindow.mPolicyVisibilityAfterAnim = false;
                 }
             }
 
@@ -403,8 +311,8 @@
             delayed = true;
         }
 
-        for (int i = windows.size() - 1; i >= 0 && !delayed; i--) {
-            if (windows.get(i).mWinAnimator.isWindowAnimationSet()) {
+        for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
+            if ((mChildren.get(i)).isWindowAnimationSet()) {
                 delayed = true;
             }
         }
@@ -421,6 +329,8 @@
                 // The token is not closing nor opening, so even if there is an animation set, that
                 // doesn't mean that it goes through the normal app transition cycle so we have
                 // to inform the docked controller about visibility change.
+                // TODO(multi-display): notify docked divider on all displays where visibility was
+                // affected.
                 mService.getDefaultDisplayContentLocked().getDockedDividerController()
                         .notifyAppVisibilityChanged();
             }
@@ -431,12 +341,14 @@
 
     WindowState findMainWindow() {
         WindowState candidate = null;
-        int j = windows.size();
+        int j = mChildren.size();
         while (j > 0) {
             j--;
-            WindowState win = windows.get(j);
-            if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
-                    || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
+            final WindowState win = mChildren.get(j);
+            final int type = win.mAttrs.type;
+            // No need to loop through child window as base application and starting types can't be
+            // child windows.
+            if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
                 // happens for example when replacing windows during an activity relaunch. When
                 // constructing the animation, we want the new window, not the exiting one.
@@ -454,82 +366,36 @@
         return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
     }
 
+    @Override
     boolean isVisible() {
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            // If we're animating with a saved surface, we're already visible.
-            // Return true so that the alpha doesn't get cleared.
-            if (!win.mAppFreezing
-                    && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface()
-                            || (win.mWinAnimator.isAnimationSet()
-                                    && !mService.mAppTransition.isTransitionSet()))
-                    && !win.mDestroying
-                    && win.isDrawnLw()) {
-                return true;
-            }
-        }
-        return false;
+        // If the app token isn't hidden then it is considered visible and there is no need to check
+        // its children windows to see if they are visible.
+        return !hidden;
     }
 
-    boolean isVisibleForUser() {
-        for (int j = windows.size() - 1; j >= 0; j--) {
-            final WindowState w = windows.get(j);
-            if (!w.isHiddenFromUserLocked()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void removeAppFromTaskLocked() {
+    @Override
+    void removeIfPossible() {
         mIsExiting = false;
         removeAllWindows();
-
-        // Use local variable because removeAppToken will null out mTask.
-        final Task task = mTask;
-        if (task != null) {
-            if (!task.removeAppToken(this)) {
-                Slog.e(TAG, "removeAppFromTaskLocked: token=" + this
-                        + " not found.");
-            }
-            task.mStack.mExitingAppTokens.remove(this);
+        if (mTask != null) {
+            mTask.mStack.mExitingAppTokens.remove(this);
+            mTask.removeChild(this);
         }
     }
 
+    @Override
+    boolean checkCompleteDeferredRemoval() {
+        if (mIsExiting) {
+            removeIfPossible();
+        }
+        return super.checkCompleteDeferredRemoval();
+    }
+
     void clearAnimatingFlags() {
         boolean wallpaperMightChange = false;
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-            // We don't want to clear it out for windows that get replaced, because the
-            // animation depends on the flag to remove the replaced window.
-            //
-            // We also don't clear the mAnimatingExit flag for windows which have the
-            // mRemoveOnExit flag. This indicates an explicit remove request has been issued
-            // by the client. We should let animation proceed and not clear this flag or
-            // they won't eventually be removed by WindowStateAnimator#finishExit.
-            if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
-                // Clear mAnimating flag together with mAnimatingExit. When animation
-                // changes from exiting to entering, we need to clear this flag until the
-                // new animation gets applied, so that isAnimationStarting() becomes true
-                // until then.
-                // Otherwise applySurfaceChangesTransaction will faill to skip surface
-                // placement for this window during this period, one or more frame will
-                // show up with wrong position or scale.
-                if (win.mAnimatingExit) {
-                    win.mAnimatingExit = false;
-                    wallpaperMightChange = true;
-                }
-                if (win.mWinAnimator.mAnimating) {
-                    win.mWinAnimator.mAnimating = false;
-                    wallpaperMightChange = true;
-                }
-                if (win.mDestroying) {
-                    win.mDestroying = false;
-                    mService.mDestroySurface.remove(win);
-                    wallpaperMightChange = true;
-                }
-            }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            wallpaperMightChange |= win.clearAnimatingFlags();
         }
         if (wallpaperMightChange) {
             requestUpdateWallpaperIfNeeded();
@@ -549,47 +415,23 @@
      * others so that they are ready to be reused. If set to false (common case), destroy all
      * surfaces that's eligible, if the app is already stopped.
      */
-
     private void destroySurfaces(boolean cleanupOnResume) {
-        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) windows.clone();
         final DisplayContentList displayList = new DisplayContentList();
-        for (int i = allWindows.size() - 1; i >= 0; i--) {
-            final WindowState win = allWindows.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            final boolean destroyed = win.destroySurface(cleanupOnResume, mAppStopped);
 
-            if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) {
-                continue;
+            if (destroyed) {
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
             }
-
-            win.mWinAnimator.destroyPreservedSurfaceLocked();
-
-            if (!win.mDestroying) {
-                continue;
-            }
-
-            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
-                    + " destroySurfaces: mAppStopped=" + mAppStopped
-                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
-                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
-
-            if (!cleanupOnResume || win.mRemoveOnExit) {
-                win.destroyOrSaveSurface();
-            }
-            if (win.mRemoveOnExit) {
-                win.remove();
-            }
-            final DisplayContent displayContent = win.getDisplayContent();
-            if (displayContent != null && !displayList.contains(displayContent)) {
-                displayList.add(displayContent);
-            }
-            if (cleanupOnResume) {
-                win.requestUpdateWallpaperIfNeeded();
-            }
-            win.mDestroying = false;
         }
         for (int i = 0; i < displayList.size(); i++) {
             final DisplayContent displayContent = displayList.get(i);
             mService.mLayersController.assignLayersLocked(displayContent.getWindowList());
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
         }
     }
 
@@ -597,12 +439,16 @@
      * Notify that the app is now resumed, and it was not stopped before, perform a clean
      * up of the surfaces
      */
-    void notifyAppResumed(boolean wasStopped) {
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped + " " + this);
+    void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
+                + " allowSavedSurface=" + allowSavedSurface + " " + this);
         mAppStopped = false;
         if (!wasStopped) {
             destroySurfaces(true /*cleanupOnResume*/);
         }
+        if (!allowSavedSurface) {
+            destroySavedSurfaces();
+        }
     }
 
     /**
@@ -630,9 +476,9 @@
         return allDrawn;
     }
 
-    boolean canRestoreSurfaces() {
-        for (int i = windows.size() -1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
+    private boolean canRestoreSurfaces() {
+        for (int i = mChildren.size() -1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
             if (w.canRestoreSurface()) {
                 return true;
             }
@@ -640,10 +486,10 @@
         return false;
     }
 
-    void clearVisibleBeforeClientHidden() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            w.clearVisibleBeforeClientHidden();
+    private void clearWasVisibleBeforeClientHidden() {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.clearWasVisibleBeforeClientHidden();
         }
     }
 
@@ -652,8 +498,8 @@
      * animating with saved surface.
      */
     boolean isAnimatingInvisibleWithSavedSurface() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
             if (w.isAnimatingInvisibleWithSavedSurface()) {
                 return true;
             }
@@ -666,68 +512,50 @@
      * with a saved surface, and mark them destroying.
      */
     void stopUsingSavedSurfaceLocked() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            if (w.isAnimatingInvisibleWithSavedSurface()) {
-                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
-                        "stopUsingSavedSurfaceLocked: " + w);
-                w.clearAnimatingWithSavedSurface();
-                w.mDestroying = true;
-                w.mWinAnimator.hide("stopUsingSavedSurfaceLocked");
-                mService.mWallpaperControllerLocked.hideWallpapers(w);
-            }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.stopUsingSavedSurface();
         }
         destroySurfaces();
     }
 
     void markSavedSurfaceExiting() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            if (w.isAnimatingInvisibleWithSavedSurface()) {
-                w.mAnimatingExit = true;
-                w.mWinAnimator.mAnimating = true;
-            }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.markSavedSurfaceExiting();
         }
     }
 
-    void restoreSavedSurfaces() {
+    void restoreSavedSurfaceForInterestingWindows() {
         if (!canRestoreSurfaces()) {
-            clearVisibleBeforeClientHidden();
+            clearWasVisibleBeforeClientHidden();
             return;
         }
-        // Check if we have enough drawn windows to mark allDrawn= true.
-        int numInteresting = 0;
-        int numDrawn = 0;
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState w = windows.get(i);
-            if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
-                    && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
-                numInteresting++;
-                if (w.hasSavedSurface()) {
-                    w.restoreSavedSurface();
-                }
-                if (w.isDrawnLw()) {
-                    numDrawn++;
-                }
-            }
+
+        // Check if all interesting windows are drawn and we can mark allDrawn=true.
+        int interestingNotDrawn = -1;
+
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
         }
 
         if (!allDrawn) {
-            allDrawn = (numInteresting > 0) && (numInteresting == numDrawn);
+            allDrawn = (interestingNotDrawn == 0);
             if (allDrawn) {
                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
             }
         }
-        clearVisibleBeforeClientHidden();
+        clearWasVisibleBeforeClientHidden();
 
         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
-                "restoreSavedSurfaces: " + this + " allDrawn=" + allDrawn
-                + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
+                "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
+                + " interestingNotDrawn=" + interestingNotDrawn);
     }
 
     void destroySavedSurfaces() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState win = windows.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
             win.destroySavedSurface();
         }
     }
@@ -738,96 +566,88 @@
         allDrawnExcludingSaved = false;
     }
 
-    @Override
-    void removeWindow(WindowState win) {
-        super.removeWindow(win);
-
+    void postWindowRemoveStartingWindowCleanup(WindowState win) {
         // TODO: Something smells about the code below...Is there a better way?
         if (startingWindow == win) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
             mService.scheduleRemoveStartingWindowLocked(this);
-        } else if (windows.size() == 0 && startingData != null) {
+        } else if (mChildren.size() == 0 && startingData != null) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow");
             startingData = null;
-        } else if (windows.size() == 1 && startingView != null) {
+        } else if (mChildren.size() == 1 && startingView != null) {
             // If this is the last window except for a starting transition window,
             // we need to get rid of the starting transition.
             mService.scheduleRemoveStartingWindowLocked(this);
         }
     }
 
-    void removeAllDeadWindows() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0;
-            // WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
-            // windows if the window to be removed has child windows. It also may
-            // not remove any windows from windows at all if win is exiting and
-            // currently animating away. This ensures that winNdx is monotonically decreasing
-            // and never beyond windows bounds.
-            winNdx = Math.min(winNdx - 1, windows.size() - 1)) {
-            WindowState win = windows.get(winNdx);
+    void removeDeadWindows() {
+        for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
+            WindowState win = mChildren.get(winNdx);
             if (win.mAppDied) {
                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
-                        "removeAllDeadWindows: " + win);
+                        "removeDeadWindows: " + win);
                 // Set mDestroying, we don't want any animation or delayed removal here.
                 win.mDestroying = true;
+                // Also removes child windows.
                 win.removeIfPossible();
             }
         }
     }
 
     boolean hasWindowsAlive() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            if (!windows.get(i).mAppDied) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            // No need to loop through child windows as the answer should be the same as that of the
+            // parent window.
+            if (!(mChildren.get(i)).mAppDied) {
                 return true;
             }
         }
         return false;
     }
 
-    void setReplacingWindows(boolean animate) {
+    void setWillReplaceWindows(boolean animate) {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Marking app token " + this + " with replacing windows.");
 
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            w.setReplacing(animate);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.setWillReplaceWindow(animate);
         }
         if (animate) {
             // Set-up dummy animation so we can start treating windows associated with this
             // token like they are in transition before the new app window is ready for us to
             // run the real transition animation.
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
-                    "setReplacingWindow() Setting dummy animation on: " + this);
+                    "setWillReplaceWindow() Setting dummy animation on: " + this);
             mAppAnimator.setDummyAnimation();
         }
     }
 
-    void setReplacingChildren() {
+    void setWillReplaceChildWindows() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
                 + " with replacing child windows.");
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            if (w.shouldBeReplacedWithChildren()) {
-                w.setReplacing(false /* animate */);
-            }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.setWillReplaceChildWindows();
         }
     }
 
-    void resetReplacingWindows() {
+    void clearWillReplaceWindows() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Resetting app token " + this + " of replacing window marks.");
 
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
-            w.resetReplacing();
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.clearWillReplaceWindow();
         }
     }
 
     void requestUpdateWallpaperIfNeeded() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState w = windows.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
             w.requestUpdateWallpaperIfNeeded();
         }
     }
@@ -866,49 +686,31 @@
     void addWindow(WindowState w) {
         super.addWindow(w);
 
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState candidate = windows.get(i);
-            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null
-                    && candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
+        boolean gotReplacementWindow = false;
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState candidate = mChildren.get(i);
+            gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
+        }
 
-                candidate.mReplacingWindow = w;
-                w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
-                // if we got a replacement window, reset the timeout to give drawing more time
-                mService.scheduleReplacingWindowTimeouts(this);
-            }
+        // if we got a replacement window, reset the timeout to give drawing more time
+        if (gotReplacementWindow) {
+            mService.scheduleWindowReplacementTimeouts(this);
         }
     }
 
     boolean waitingForReplacement() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState candidate = windows.get(i);
-            if (candidate.mWillReplaceWindow) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState candidate = mChildren.get(i);
+            if (candidate.waitingForReplacement()) {
                 return true;
             }
         }
         return false;
     }
 
-    void clearTimedoutReplacesLocked() {
-        for (int i = windows.size() - 1; i >= 0;
-             // WindowState#remove() at bottom of loop may remove multiple entries from windows if
-             // the window to be removed has child windows. It also may not remove any windows from
-             // windows at all if win is exiting and currently animating away. This ensures that
-             // winNdx is monotonically decreasing and never beyond windows bounds.
-             i = Math.min(i - 1, windows.size() - 1)) {
-            final WindowState candidate = windows.get(i);
-            if (!candidate.mWillReplaceWindow) {
-                continue;
-            }
-            candidate.mWillReplaceWindow = false;
-            if (candidate.mReplacingWindow != null) {
-                candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
-            }
-            // Since the window already timed out, remove it immediately now.
-            // Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
-            // delays removal on certain conditions, which will leave the stale window in the
-            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
-            candidate.remove();
+    void onWindowReplacementTimeout() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            (mChildren.get(i)).onWindowReplacementTimeout();
         }
     }
 
@@ -929,13 +731,12 @@
 
         if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
             // We didn't call prepareFreezingBounds on the task, so use the current value.
-            final Configuration config = new Configuration(mService.mCurConfiguration);
-            config.updateFrom(mTask.mOverrideConfig);
-            mFrozenMergedConfig.offer(config);
+            mFrozenMergedConfig.offer(new Configuration(mTask.getConfiguration()));
         } else {
             mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig));
         }
-        mTask.mPreparedFrozenMergedConfig.setToDefaults();
+        // Calling unset() to make it equal to Configuration.EMPTY.
+        mTask.mPreparedFrozenMergedConfig.unset();
     }
 
     /**
@@ -948,16 +749,9 @@
         if (!mFrozenMergedConfig.isEmpty()) {
             mFrozenMergedConfig.remove();
         }
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-            if (!win.mHasSurface) {
-                continue;
-            }
-            win.mLayoutNeeded = true;
-            win.setDisplayLayoutNeeded();
-            if (!mService.mResizingWindows.contains(win)) {
-                mService.mResizingWindows.add(win);
-            }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            win.onUnfreezeBounds();
         }
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
@@ -992,115 +786,39 @@
         }
     }
 
+    /**
+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
+     */
+    void overridePlayingAppAnimations(Animation a) {
+        if (mAppAnimator.isAnimating()) {
+            final WindowState win = findMainWindow();
+            if (win == null) {
+                return;
+            }
+            final int width = win.mContainingFrame.width();
+            final int height = win.mContainingFrame.height();
+            mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
+        }
+    }
+
     void resetJustMovedInStack() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            windows.get(i).resetJustMovedInStack();
-        }
-    }
-
-    void setWaitingForDrawnIfResizingChanged() {
-        for (int i = windows.size() - 1; i >= 0; --i) {
-            final WindowState win = windows.get(i);
-            if (win.isDragResizeChanged()) {
-                mService.mWaitingForDrawn.add(win);
-            }
-        }
-    }
-
-    void resizeWindows() {
-        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
-        // Some windows won't go through the resizing process, if they don't have a surface, so
-        // destroy all saved surfaces here.
-        destroySavedSurfaces();
-
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = windows.get(winNdx);
-            if (win.mHasSurface && !resizingWindows.contains(win)) {
-                if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
-                resizingWindows.add(win);
-
-                // If we are not drag resizing, force recreating of a new surface so updating
-                // the content and positioning that surface will be in sync.
-                //
-                // 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
-                // still like to manipulate their frame to update crop, etc...
-                //
-                // Anyway we don't need to synchronize position and content updates for these
-                // windows since they aren't at the base layer and could be moved around anyway.
-                if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
-                        !mTask.mStack.getBoundsAnimating() && !win.isGoneForLayoutLw() &&
-                        !mTask.inPinnedWorkspace()) {
-                    win.setResizedWhileNotDragResizing(true);
-                }
-            }
-            if (win.isGoneForLayoutLw()) {
-                win.mResizedWhileGone = true;
-            }
-        }
-    }
-
-    void moveWindows() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = windows.get(winNdx);
-            if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
-            win.mMovedByResize = true;
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            (mChildren.get(i)).resetJustMovedInStack();
         }
     }
 
     void notifyMovedInStack() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = windows.get(winNdx);
+        for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = mChildren.get(winNdx);
             win.notifyMovedInStack();
         }
     }
 
-    void resetDragResizingChangeReported() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowState win = windows.get(winNdx);
-            win.resetDragResizingChangeReported();
-        }
-    }
-
-    void detachDisplay() {
-        boolean doAnotherLayoutPass = false;
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            // We are in the middle of changing the state of displays/stacks/tasks. We need
-            // to finish that, before we let layout interfere with it.
-            windows.get(winNdx).removeIfPossible();
-            doAnotherLayoutPass = true;
-        }
-        if (doAnotherLayoutPass) {
-            mService.mWindowPlacerLocked.requestTraversal();
-        }
-    }
-
-    void forceWindowsScaleableInTransaction(boolean force) {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-            if (winAnimator == null || !winAnimator.hasSurface()) {
-                continue;
-            }
-            winAnimator.mSurfaceController.forceScaleableInTransaction(force);
-        }
-    }
-
-    boolean isAnimating() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-            if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     void setAppLayoutChanges(int changes, String reason, int displayId) {
         final WindowAnimator windowAnimator = mAppAnimator.mAnimator;
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            if (displayId == windows.get(i).getDisplayId()) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            // Child windows will be on the same display as their parents.
+            if (displayId == (mChildren.get(i)).getDisplayId()) {
                 windowAnimator.setPendingLayoutChanges(displayId, changes);
                 if (DEBUG_LAYOUT_REPEATS) {
                     mService.mWindowPlacerLocked.debugLayoutRepeats(
@@ -1112,22 +830,22 @@
     }
 
     void removeReplacedWindowIfNeeded(WindowState replacement) {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-            if (win.mWillReplaceWindow && win.mReplacingWindow == replacement
-                    && replacement.hasDrawnLw()) {
-                replacement.mSkipEnterAnimationForSeamlessReplacement = false;
-                win.removeReplacedWindow();
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            if (win.removeReplacedWindowIfNeeded(replacement)) {
+                return;
             }
         }
     }
 
     void startFreezingScreen() {
         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
-                + hidden + " freezing=" + mAppAnimator.freezingScreen);
+                + hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested="
+                + hiddenRequested);
         if (!hiddenRequested) {
             if (!mAppAnimator.freezingScreen) {
                 mAppAnimator.freezingScreen = true;
+                mService.registerAppFreezeListener(this);
                 mAppAnimator.lastFreezeDuration = 0;
                 mService.mAppsFreezingScreen++;
                 if (mService.mAppsFreezingScreen == 1) {
@@ -1136,10 +854,10 @@
                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
             }
-            final int count = windows.size();
+            final int count = mChildren.size();
             for (int i = 0; i < count; i++) {
-                final WindowState w = windows.get(i);
-                w.mAppFreezing = true;
+                final WindowState w = mChildren.get(i);
+                w.onStartFreezingScreen();
             }
         }
     }
@@ -1149,26 +867,16 @@
             return;
         }
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
-        final int count = windows.size();
+        final int count = mChildren.size();
         boolean unfrozeWindows = false;
         for (int i = 0; i < count; i++) {
-            final WindowState w = windows.get(i);
-            if (w.mAppFreezing) {
-                w.mAppFreezing = false;
-                if (w.mHasSurface && !w.mOrientationChanging
-                        && mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + w);
-                    w.mOrientationChanging = true;
-                    mService.mWindowPlacerLocked.mOrientationChangeComplete = false;
-                }
-                w.mLastFreezeDuration = 0;
-                unfrozeWindows = true;
-                w.setDisplayLayoutNeeded();
-            }
+            final WindowState w = mChildren.get(i);
+            unfrozeWindows |= w.onStopFreezingScreen();
         }
         if (force || unfrozeWindows) {
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
             mAppAnimator.freezingScreen = false;
+            mService.unregisterAppFreezeListener(this);
             mAppAnimator.lastFreezeDuration =
                     (int)(SystemClock.elapsedRealtime() - mService.mDisplayFreezeTime);
             mService.mAppsFreezingScreen--;
@@ -1182,6 +890,12 @@
         }
     }
 
+    @Override
+    public void onAppFreezeTimeout() {
+        Slog.w(TAG_WM, "Force clearing freeze: " + this);
+        stopFreezingScreen(true, true);
+    }
+
     boolean transferStartingWindow(IBinder transferFrom) {
         final AppWindowToken fromToken = mService.findAppWindowToken(transferFrom);
         if (fromToken == null) {
@@ -1219,7 +933,8 @@
             mService.mWindowsChanged = true;
             if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                     "Removing starting " + tStartingWindow + " from " + fromToken);
-            fromToken.removeWindow(tStartingWindow);
+            fromToken.removeChild(tStartingWindow);
+            fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
             addWindow(tStartingWindow);
 
             // Propagate other interesting state between the tokens. If the old token is displayed,
@@ -1245,7 +960,7 @@
 
             mService.updateFocusedWindowLocked(
                     UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
-            mService.getDefaultDisplayContentLocked().layoutNeeded = true;
+            mService.getDefaultDisplayContentLocked().setLayoutNeeded();
             mService.mWindowPlacerLocked.performSurfacePlacement();
             Binder.restoreCallingIdentity(origId);
             return true;
@@ -1279,35 +994,230 @@
         return false;
     }
 
-    int getWindowsCount() {
-        return windows.size();
+    boolean isLastWindow(WindowState win) {
+        return mChildren.size() == 1 && mChildren.get(0) == win;
     }
 
     void setAllAppWinAnimators() {
         final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators;
         allAppWinAnimators.clear();
 
-        final int windowsCount = windows.size();
+        final int windowsCount = mChildren.size();
         for (int j = 0; j < windowsCount; j++) {
-            allAppWinAnimators.add(windows.get(j).mWinAnimator);
+            (mChildren.get(j)).addWinAnimatorToList(allAppWinAnimators);
         }
     }
 
     @Override
+    void onAppTransitionDone() {
+        sendingToBottom = false;
+    }
+
+    /**
+     * We override because this class doesn't want its children affecting its reported orientation
+     * in anyway.
+     */
+    @Override
+    int getOrientation() {
+        if (hidden || hiddenRequested) {
+            return SCREEN_ORIENTATION_UNSET;
+        }
+        return mOrientation;
+    }
+
+    @Override
+    void checkAppWindowsReadyToShow(int displayId) {
+        if (allDrawn == mAppAnimator.allDrawn) {
+            return;
+        }
+
+        mAppAnimator.allDrawn = allDrawn;
+        if (!allDrawn) {
+            return;
+        }
+
+        // The token has now changed state to having all windows shown...  what to do, what to do?
+        if (mAppAnimator.freezingScreen) {
+            mAppAnimator.showAllWindowsLocked();
+            stopFreezingScreen(false, true);
+            if (DEBUG_ORIENTATION) Slog.i(TAG,
+                    "Setting mOrientationChangeComplete=true because wtoken " + this
+                    + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
+            // This will set mOrientationChangeComplete and cause a pass through layout.
+            setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
+                    "checkAppWindowsReadyToShow: freezingScreen", displayId);
+        } else {
+            setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow", displayId);
+
+            // We can now show all of the drawn windows!
+            if (!mService.mOpeningApps.contains(this)) {
+                mService.mAnimator.orAnimating(mAppAnimator.showAllWindowsLocked());
+            }
+        }
+    }
+
+    void updateAllDrawn(DisplayContent dc) {
+        if (!allDrawn) {
+            final int numInteresting = mNumInterestingWindows;
+            if (numInteresting > 0 && mNumDrawnWindows >= numInteresting) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
+                        + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
+                allDrawn = true;
+                // Force an additional layout pass where
+                // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
+                dc.setLayoutNeeded();
+                mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
+            }
+        }
+
+        if (!allDrawnExcludingSaved) {
+            int numInteresting = mNumInterestingWindowsExcludingSaved;
+            if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this
+                        + " interesting=" + numInteresting
+                        + " drawn=" + mNumDrawnWindowsExcludingSaved);
+                allDrawnExcludingSaved = true;
+                dc.setLayoutNeeded();
+                if (isAnimatingInvisibleWithSavedSurface()
+                        && !mService.mFinishedEarlyAnim.contains(this)) {
+                    mService.mFinishedEarlyAnim.add(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * Updated this app token tracking states for interesting and drawn windows based on the window.
+     *
+     * @return Returns true if the input window is considered interesting and drawn while all the
+     *         windows in this app token where not considered drawn as of the last pass.
+     */
+    boolean updateDrawnWindowStates(WindowState w) {
+        if (DEBUG_STARTING_WINDOW && w == startingWindow) {
+            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
+                    + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
+        }
+
+        if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) {
+            return false;
+        }
+
+        if (mLastTransactionSequence != mService.mTransactionSequence) {
+            mLastTransactionSequence = mService.mTransactionSequence;
+            mNumInterestingWindows = mNumDrawnWindows = 0;
+            mNumInterestingWindowsExcludingSaved = 0;
+            mNumDrawnWindowsExcludingSaved = 0;
+            startingDisplayed = false;
+        }
+
+        final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+        boolean isInterestingAndDrawn = false;
+
+        if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
+            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+                        + ", isAnimationSet=" + winAnimator.isAnimationSet());
+                if (!w.isDrawnLw()) {
+                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
+                            + " pv=" + w.mPolicyVisibility
+                            + " mDrawState=" + winAnimator.drawStateToString()
+                            + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
+                            + " a=" + winAnimator.mAnimating);
+                }
+            }
+
+            if (w != startingWindow) {
+                if (w.isInteresting()) {
+                    mNumInterestingWindows++;
+                    if (w.isDrawnLw()) {
+                        mNumDrawnWindows++;
+
+                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
+                                + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
+                                + " freezingScreen=" + mAppAnimator.freezingScreen
+                                + " mAppFreezing=" + w.mAppFreezing);
+
+                        isInterestingAndDrawn = true;
+                    }
+                }
+            } else if (w.isDrawnLw()) {
+                mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
+                startingDisplayed = true;
+            }
+        }
+
+        if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) {
+            if (w != startingWindow && w.isInteresting()) {
+                mNumInterestingWindowsExcludingSaved++;
+                if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
+                    mNumDrawnWindowsExcludingSaved++;
+
+                    if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
+                            "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w
+                            + " numInteresting=" + mNumInterestingWindowsExcludingSaved
+                            + " freezingScreen=" + mAppAnimator.freezingScreen
+                            + " mAppFreezing=" + w.mAppFreezing);
+
+                    isInterestingAndDrawn = true;
+                }
+            }
+        }
+
+        return isInterestingAndDrawn;
+    }
+
+    @Override
+    void stepAppWindowsAnimation(long currentTime, int displayId) {
+        mAppAnimator.wasAnimating = mAppAnimator.animating;
+        if (mAppAnimator.stepAnimationLocked(currentTime, displayId)) {
+            mAppAnimator.animating = true;
+            mService.mAnimator.setAnimating(true);
+            mService.mAnimator.mAppWindowAnimating = true;
+        } else if (mAppAnimator.wasAnimating) {
+            // stopped animating, do one more pass through the layout
+            setAppLayoutChanges(
+                    FINISH_LAYOUT_REDO_WALLPAPER, "appToken " + this + " done", displayId);
+            if (DEBUG_ANIM) Slog.v(TAG, "updateWindowsApps...: done animating " + this);
+        }
+    }
+
+    int rebuildWindowListUnchecked(DisplayContent dc, int addIndex) {
+        return super.rebuildWindowList(dc, addIndex);
+    }
+
+    @Override
+    int rebuildWindowList(DisplayContent dc, int addIndex) {
+        if (mIsExiting && !waitingForReplacement()) {
+            return addIndex;
+        }
+        return rebuildWindowListUnchecked(dc, addIndex);
+    }
+
+    @Override
     AppWindowToken asAppWindowToken() {
         // I am an app window token!
         return this;
     }
 
     @Override
+    boolean fillsParent() {
+        return mFillsParent;
+    }
+
+    void setFillsParent(boolean fillsParent) {
+        mFillsParent = fillsParent;
+    }
+
+    @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
         if (appToken != null) {
             pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
         }
         pw.print(prefix); pw.print("task="); pw.println(mTask);
-        pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
-                pw.print(" requestedOrientation="); pw.println(requestedOrientation);
+        pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
+                pw.print(" mOrientation="); pw.println(mOrientation);
         pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
                 pw.print(" clientHidden="); pw.print(clientHidden);
                 pw.print(" reportedDrawn="); pw.print(reportedDrawn);
@@ -1318,11 +1228,11 @@
         if (mAppStopped) {
             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
         }
-        if (numInterestingWindows != 0 || numDrawnWindows != 0
+        if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
                 || allDrawn || mAppAnimator.allDrawn) {
-            pw.print(prefix); pw.print("numInterestingWindows=");
-                    pw.print(numInterestingWindows);
-                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
+            pw.print(prefix); pw.print("mNumInterestingWindows=");
+                    pw.print(mNumInterestingWindows);
+                    pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
                     pw.print(" allDrawn="); pw.print(allDrawn);
                     pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
@@ -1363,6 +1273,6 @@
             sb.append(" token="); sb.append(token); sb.append('}');
             stringName = sb.toString();
         }
-        return stringName;
+        return stringName + ((mIsExiting) ? " mIsExiting=" : "");
     }
 }
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 052b2f5..b99dda1 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -95,7 +95,7 @@
     }
 
     private void constructSurface(WindowManagerService service) {
-        SurfaceControl.openTransaction();
+        service.openSurfaceTransaction();
         try {
             if (DEBUG_SURFACE_TRACE) {
                 mDimSurface = new WindowSurfaceController.SurfaceTrace(service.mFxSession,
@@ -116,7 +116,7 @@
         } catch (Exception e) {
             Slog.e(TAG_WM, "Exception creating Dim surface", e);
         } finally {
-            SurfaceControl.closeTransaction();
+            service.closeSurfaceTransaction();
         }
     }
 
@@ -227,12 +227,12 @@
         mBounds.set(bounds);
         if (isDimming() && !mLastBounds.equals(bounds)) {
             try {
-                SurfaceControl.openTransaction();
+                mService.openSurfaceTransaction();
                 adjustBounds();
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failure setting size", e);
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 7f97c46..da2c6a7 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -256,7 +256,7 @@
                 // on whether a dim layer is showing or not.
                 if (targetAlpha == 0) {
                     mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
-                    mDisplayContent.layoutNeeded = true;
+                    mDisplayContent.setLayoutNeeded();
                 }
             }
         } else if (state.dimLayer.getLayer() != dimLayer) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0a60608..42e9e23 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,28 +17,56 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+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_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager.StackId;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManagerInternal;
+import android.os.Debug;
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.IWindow;
 import android.view.Surface;
+import com.android.internal.util.FastPrintWriter;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 class DisplayContentList extends ArrayList<DisplayContent> {
 }
@@ -50,7 +78,7 @@
  * IMPORTANT: No method from this class should ever be used without holding
  * WindowManagerService.mWindowMap.
  */
-class DisplayContent {
+class DisplayContent extends WindowContainer<TaskStack> {
 
     /** Unique identifier of this stack. */
     private final int mDisplayId;
@@ -71,20 +99,16 @@
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
     Rect mBaseDisplayRect = new Rect();
-    Rect mContentRect = new Rect();
+    private Rect mContentRect = new Rect();
 
     // Accessed directly by all users.
-    boolean layoutNeeded;
+    private boolean mLayoutNeeded;
     int pendingLayoutChanges;
     final boolean isDefaultDisplay;
 
     /** Window tokens that are in the process of exiting, but still on screen for animations. */
     final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
 
-    /** Array containing all TaskStacks on this display.  Array
-     * is stored in display order with the current bottom stack at 0. */
-    private final ArrayList<TaskStack> mStacks = new ArrayList<>();
-
     /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
      * (except a future lockscreen TaskStack) moves to the top. */
     private TaskStack mHomeStack = null;
@@ -93,16 +117,13 @@
     TaskTapPointerEventListener mTapDetector;
 
     /** Detect user tapping outside of current focused stack bounds .*/
-    Region mTouchExcludeRegion = new Region();
+    private Region mTouchExcludeRegion = new Region();
 
     /** Save allocating when calculating rects */
     private final Rect mTmpRect = new Rect();
     private final Rect mTmpRect2 = new Rect();
     private final Region mTmpRegion = new Region();
 
-    /** For gathering Task objects in order. */
-    final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
-
     final WindowManagerService mService;
 
     /** Remove this display when animation on it has completed. */
@@ -114,6 +135,14 @@
 
     final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
 
+    /** Used when rebuilding window list to keep track of windows that have been removed. */
+    private WindowState[] mRebuildTmp = new WindowState[20];
+
+    private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult =
+            new TaskForResizePointSearchResult();
+    private final GetWindowOnDisplaySearchResult mTmpGetWindowOnDisplaySearchResult =
+            new GetWindowOnDisplaySearchResult();
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -157,31 +186,14 @@
     /**
      * Returns true if the specified UID has access to this display.
      */
-    public boolean hasAccess(int uid) {
+    boolean hasAccess(int uid) {
         return mDisplay.hasAccess(uid);
     }
 
-    public boolean isPrivate() {
+    boolean isPrivate() {
         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
     }
 
-    ArrayList<TaskStack> getStacks() {
-        return mStacks;
-    }
-
-    /**
-     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
-     * @return All the Tasks, in order, on this display.
-     */
-    ArrayList<Task> getTasks() {
-        mTmpTaskHistory.clear();
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
-        }
-        return mTmpTaskHistory;
-    }
-
     TaskStack getHomeStack() {
         if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
             Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
@@ -190,8 +202,8 @@
     }
 
     TaskStack getStackById(int stackId) {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final TaskStack stack = mStacks.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
             if (stack.mStackId == stackId) {
                 return stack;
             }
@@ -199,11 +211,91 @@
         return null;
     }
 
+    @Override
+    void onConfigurationChanged(Configuration newParentConfig) {
+        super.onConfigurationChanged(newParentConfig);
+
+        // The display size information is heavily dependent on the resources in the current
+        // configuration, so we need to reconfigure it every time the configuration changes.
+        // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
+        mService.reconfigureDisplayLocked(this);
+
+        getDockedDividerController().onConfigurationChanged();
+    }
+
+    /**
+     * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+     * bounds were updated.
+     */
+    void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            if (stack.updateBoundsAfterConfigChange()) {
+                changedStackList.add(stack.mStackId);
+            }
+        }
+    }
+
+    void checkAppWindowsReadyToShow() {
+        super.checkAppWindowsReadyToShow(mDisplayId);
+    }
+
+    void stepAppWindowsAnimation(long currentTime) {
+        super.stepAppWindowsAnimation(currentTime, mDisplayId);
+    }
+
+    @Override
+    boolean fillsParent() {
+        return true;
+    }
+
+    @Override
+    boolean isVisible() {
+        return true;
+    }
+
+    @Override
+    void onAppTransitionDone() {
+        super.onAppTransitionDone();
+        rebuildAppWindowList();
+    }
+
+    @Override
+    int getOrientation() {
+        if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
+                || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
+            // Apps and their containers are not allowed to specify an orientation while the docked
+            // or freeform stack is visible...except for the home stack/task if the docked stack is
+            // minimized and it actually set something.
+            if (mHomeStack != null && mHomeStack.isVisible()
+                    && mDividerControllerLocked.isMinimizedDock()) {
+                final int orientation = mHomeStack.getOrientation();
+                if (orientation != SCREEN_ORIENTATION_UNSET) {
+                    return orientation;
+                }
+            }
+            return SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+
+        final int orientation = super.getOrientation();
+        if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) {
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+                    "App is requesting an orientation, return " + orientation);
+            return orientation;
+        }
+
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+                "No app is requesting an orientation, return " + mService.mLastOrientation);
+        // The next app has not been requested to be visible, so we keep the current orientation
+        // to prevent freezing/unfreezing the display too early.
+        return mService.mLastOrientation;
+    }
+
     void updateDisplayInfo() {
         mDisplay.getDisplayInfo(mDisplayInfo);
         mDisplay.getMetrics(mDisplayMetrics);
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            mStacks.get(i).updateDisplayInfo(null);
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            mChildren.get(i).updateDisplayInfo(null);
         }
     }
 
@@ -249,12 +341,7 @@
             }
             mHomeStack = stack;
         }
-        if (onTop) {
-            mStacks.add(stack);
-        } else {
-            mStacks.add(0, stack);
-        }
-        layoutNeeded = true;
+        addChild(stack, onTop);
     }
 
     void moveStack(TaskStack stack, boolean toTop) {
@@ -264,11 +351,15 @@
             return;
         }
 
-        if (!mStacks.remove(stack)) {
+        if (!mChildren.contains(stack)) {
             Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable());
         }
+        removeChild(stack);
+        addChild(stack, toTop);
+    }
 
-        int addIndex = toTop ? mStacks.size() : 0;
+    private void addChild(TaskStack stack, boolean toTop) {
+        int addIndex = toTop ? mChildren.size() : 0;
 
         if (toTop
                 && mService.isStackVisibleLocked(PINNED_STACK_ID)
@@ -276,17 +367,13 @@
             // The pinned stack is always the top most stack (always-on-top) when it is visible.
             // So, stack is moved just below the pinned stack.
             addIndex--;
-            TaskStack topStack = mStacks.get(addIndex);
+            TaskStack topStack = mChildren.get(addIndex);
             if (topStack.mStackId != PINNED_STACK_ID) {
-                throw new IllegalStateException("Pinned stack isn't top stack??? " + mStacks);
+                throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
             }
         }
-        mStacks.add(addIndex, stack);
-    }
-
-    void detachStack(TaskStack stack) {
-        mDimLayerController.removeDimLayerUser(stack);
-        mStacks.remove(stack);
+        addChild(stack, addIndex);
+        setLayoutNeeded();
     }
 
     /**
@@ -298,28 +385,11 @@
     }
 
     int taskIdFromPoint(int x, int y) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            TaskStack stack = mStacks.get(stackNdx);
-            stack.getBounds(mTmpRect);
-            if (!mTmpRect.contains(x, y) || stack.isAdjustedForMinimizedDockedStack()) {
-                continue;
-            }
-            final ArrayList<Task> tasks = stack.getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                final WindowState win = task.getTopVisibleAppMainWindow();
-                if (win == null) {
-                    continue;
-                }
-                // We need to use the task's dim bounds (which is derived from the visible
-                // bounds of its apps windows) for any touch-related tests. Can't use
-                // the task's original bounds because it might be adjusted to fit the
-                // content frame. For example, the presence of the IME adjusting the
-                // windows frames when the app window is the IME target.
-                task.getDimBounds(mTmpRect);
-                if (mTmpRect.contains(x, y)) {
-                    return task.mTaskId;
-                }
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mChildren.get(stackNdx);
+            final int taskId = stack.taskIdFromPoint(x, y);
+            if (taskId != -1) {
+                return taskId;
             }
         }
         return -1;
@@ -329,37 +399,18 @@
      * Find the task whose outside touch area (for resizing) (x, y) falls within.
      * Returns null if the touch doesn't fall into a resizing area.
      */
-    Task findTaskForControlPoint(int x, int y) {
+    Task findTaskForResizePoint(int x, int y) {
         final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            TaskStack stack = mStacks.get(stackNdx);
+        mTmpTaskForResizePointSearchResult.reset();
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            TaskStack stack = mChildren.get(stackNdx);
             if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
-                break;
+                return null;
             }
-            final ArrayList<Task> tasks = stack.getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                if (task.isFullscreen()) {
-                    return null;
-                }
 
-                // We need to use the task's dim bounds (which is derived from the visible
-                // bounds of its apps windows) for any touch-related tests. Can't use
-                // the task's original bounds because it might be adjusted to fit the
-                // content frame. One example is when the task is put to top-left quadrant,
-                // the actual visible area would not start at (0,0) after it's adjusted
-                // for the status bar.
-                task.getDimBounds(mTmpRect);
-                mTmpRect.inset(-delta, -delta);
-                if (mTmpRect.contains(x, y)) {
-                    mTmpRect.inset(delta, delta);
-                    if (!mTmpRect.contains(x, y)) {
-                        return task;
-                    }
-                    // User touched inside the task. No need to look further,
-                    // focus transfer will be handled in ACTION_UP.
-                    return null;
-                }
+            stack.findTaskForResizePoint(x, y, delta, mTmpTaskForResizePointSearchResult);
+            if (mTmpTaskForResizePointSearchResult.searchDone) {
+                return mTmpTaskForResizePointSearchResult.taskForResize;
             }
         }
         return null;
@@ -368,54 +419,16 @@
     void setTouchExcludeRegion(Task focusedTask) {
         mTouchExcludeRegion.set(mBaseDisplayRect);
         final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
-        boolean addBackFocusedTask = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            TaskStack stack = mStacks.get(stackNdx);
-            final ArrayList<Task> tasks = stack.getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                AppWindowToken token = task.getTopVisibleAppToken();
-                if (token == null || !token.isVisible()) {
-                    continue;
-                }
-
-                /**
-                 * Exclusion region is the region that TapDetector doesn't care about.
-                 * Here we want to remove all non-focused tasks from the exclusion region.
-                 * We also remove the outside touch area for resizing for all freeform
-                 * tasks (including the focused).
-                 *
-                 * We save the focused task region once we find it, and add it back at the end.
-                 */
-
-                task.getDimBounds(mTmpRect);
-
-                if (task == focusedTask) {
-                    addBackFocusedTask = true;
-                    mTmpRect2.set(mTmpRect);
-                }
-
-                final boolean isFreeformed = task.inFreeformWorkspace();
-                if (task != focusedTask || isFreeformed) {
-                    if (isFreeformed) {
-                        // If the task is freeformed, enlarge the area to account for outside
-                        // touch area for resize.
-                        mTmpRect.inset(-delta, -delta);
-                        // Intersect with display content rect. If we have system decor (status bar/
-                        // navigation bar), we want to exclude that from the tap detection.
-                        // Otherwise, if the app is partially placed under some system button (eg.
-                        // Recents, Home), pressing that button would cause a full series of
-                        // unwanted transfer focus/resume/pause, before we could go home.
-                        mTmpRect.intersect(mContentRect);
-                    }
-                    mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
-                }
-            }
+        mTmpRect2.setEmpty();
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mChildren.get(stackNdx);
+            stack.setTouchExcludeRegion(
+                    focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
         }
         // If we removed the focused task above, add it back and only leave its
         // outside touch area in the exclusion. TapDectector is not interested in
         // any touch inside the focused task itself.
-        if (addBackFocusedTask) {
+        if (!mTmpRect2.isEmpty()) {
             mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
         }
         final WindowState inputMethod = mService.mInputMethodWindow;
@@ -441,7 +454,7 @@
         }
     }
 
-    void switchUserStacks() {
+    void switchUser() {
         final WindowList windows = getWindowList();
         for (int i = 0; i < windows.size(); i++) {
             final WindowState win = windows.get(i);
@@ -452,14 +465,16 @@
             }
         }
 
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).switchUser();
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            mChildren.get(stackNdx).switchUser();
         }
+
+        rebuildAppWindowList();
     }
 
     void resetAnimationBackgroundAnimator() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            mChildren.get(stackNdx).resetAnimationBackgroundAnimator();
         }
     }
 
@@ -479,48 +494,138 @@
         mDimLayerController.stopDimmingIfNeeded();
     }
 
-    void close() {
+    @Override
+    void removeIfPossible() {
+        if (isAnimating()) {
+            mDeferredRemoval = true;
+            return;
+        }
+        removeImmediately();
+    }
+
+    @Override
+    void removeImmediately() {
+        super.removeImmediately();
+        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
         mDimLayerController.close();
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).close();
+        if (mDisplayId == Display.DEFAULT_DISPLAY) {
+            mService.unregisterPointerEventListener(mTapDetector);
+            mService.unregisterPointerEventListener(mService.mMousePositionTracker);
         }
     }
 
-    boolean isAnimating() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
-            if (stack.isAnimating()) {
-                return true;
-            }
-        }
-        return false;
-    }
+    /** Returns true if a removal action is still being deferred. */
+    @Override
+    boolean checkCompleteDeferredRemoval() {
+        final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval();
 
-    void checkForDeferredActions() {
-        boolean animating = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
-            if (stack.isAnimating()) {
-                animating = true;
-            } else {
-                if (stack.mDeferDetach) {
-                    mService.detachStackLocked(this, stack);
-                }
-                final ArrayList<Task> tasks = stack.getTasks();
-                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                    final Task task = tasks.get(taskNdx);
-                    AppTokenList tokens = task.mAppTokens;
-                    for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                        AppWindowToken wtoken = tokens.get(tokenNdx);
-                        if (wtoken.mIsExiting) {
-                            wtoken.removeAppFromTaskLocked();
-                        }
-                    }
-                }
-            }
-        }
-        if (!animating && mDeferredRemoval) {
+        if (!stillDeferringRemoval && mDeferredRemoval) {
+            removeImmediately();
             mService.onDisplayRemoved(mDisplayId);
+            return false;
+        }
+        return true;
+    }
+
+    boolean animateForIme(float interpolatedValue, float animationTarget,
+            float dividerAnimationTarget) {
+        boolean updated = false;
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            if (stack == null || !stack.isAdjustedForIme()) {
+                continue;
+            }
+
+            if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) {
+                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+                updated = true;
+            } else {
+                mDividerControllerLocked.mLastAnimationProgress =
+                        mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue);
+                mDividerControllerLocked.mLastDividerProgress =
+                        mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue);
+                updated |= stack.updateAdjustForIme(
+                        mDividerControllerLocked.mLastAnimationProgress,
+                        mDividerControllerLocked.mLastDividerProgress,
+                        false /* force */);
+            }
+            if (interpolatedValue >= 1f) {
+                stack.endImeAdjustAnimation();
+            }
+        }
+
+        return updated;
+    }
+
+    boolean clearImeAdjustAnimation() {
+        boolean changed = false;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            if (stack != null && stack.isAdjustedForIme()) {
+                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+                changed  = true;
+            }
+        }
+        return changed;
+    }
+
+    void beginImeAdjustAnimation() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            if (stack.isVisible() && stack.isAdjustedForIme()) {
+                stack.beginImeAdjustAnimation();
+            }
+        }
+    }
+
+    void adjustForImeIfNeeded() {
+        final WindowState imeWin = mService.mInputMethodWindow;
+        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
+                && !mDividerControllerLocked.isImeHideRequested();
+        final boolean dockVisible = mService.isStackVisibleLocked(DOCKED_STACK_ID);
+        final TaskStack imeTargetStack = mService.getImeFocusStackLocked();
+        final int imeDockSide = (dockVisible && imeTargetStack != null) ?
+                imeTargetStack.getDockSide() : DOCKED_INVALID;
+        final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
+        final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
+        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
+        final int imeHeight = mService.mPolicy.getInputMethodWindowVisibleHeightLw();
+        final boolean imeHeightChanged = imeVisible &&
+                imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
+
+        // The divider could be adjusted for IME position, or be thinner than usual,
+        // or both. There are three possible cases:
+        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
+        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
+        // - If IME is not visible, divider is not moved and is normal width.
+
+        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final TaskStack stack = mChildren.get(i);
+                final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
+                if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)) {
+                    stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
+                } else {
+                    stack.resetAdjustedForIme(false);
+                }
+            }
+            mDividerControllerLocked.setAdjustedForIme(
+                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
+        } else {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final TaskStack stack = mChildren.get(i);
+                stack.resetAdjustedForIme(!dockVisible);
+            }
+            mDividerControllerLocked.setAdjustedForIme(
+                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
+        }
+    }
+
+    void prepareFreezingTaskBounds() {
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mChildren.get(stackNdx);
+            stack.prepareFreezingTaskBounds();
         }
     }
 
@@ -585,13 +690,13 @@
             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-            pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
-                pw.print(" layoutNeeded="); pw.println(layoutNeeded);
+            pw.println(subPrefix + "deferred=" + mDeferredRemoval
+                    + " mLayoutNeeded=" + mLayoutNeeded);
 
         pw.println();
         pw.println("  Application tokens in top down Z order:");
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
+        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mChildren.get(stackNdx);
             stack.dump(prefix + "  ", pw);
         }
 
@@ -615,7 +720,11 @@
 
     @Override
     public String toString() {
-        return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
+        return getName() + " stacks=" + mChildren;
+    }
+
+    String getName() {
+        return "Display " + mDisplayId + " info=" + mDisplayInfo;
     }
 
     /**
@@ -623,7 +732,7 @@
      */
     TaskStack getDockedStackLocked() {
         final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
-        return (stack != null && stack.isVisibleLocked()) ? stack : null;
+        return (stack != null && stack.isVisible()) ? stack : null;
     }
 
     /**
@@ -632,12 +741,10 @@
      */
     TaskStack getDockedStackVisibleForUserLocked() {
         final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
-        return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
+        return (stack != null && stack.isVisible(true /* ignoreKeyguard */)) ? stack : null;
     }
 
-    /**
-     * Find the visible, touch-deliverable window under the given point
-     */
+    /** Find the visible, touch-deliverable window under the given point */
     WindowState getTouchableWinAtPointLocked(float xf, float yf) {
         WindowState touchedWin = null;
         final int x = (int) xf;
@@ -669,4 +776,499 @@
 
         return touchedWin;
     }
+
+    boolean canAddToastWindowForUid(int uid) {
+        // We allow one toast window per UID being shown at a time.
+        WindowList windows = getWindowList();
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            WindowState window = windows.get(i);
+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
+                    && !window.mPermanentlyHidden && !window.mAnimatingExit
+                    && !window.mRemoveOnExit) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
+                                                   WindowState newFocus) {
+        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
+            return;
+        }
+        final int lostFocusUid = oldFocus.mOwnerUid;
+        WindowList windows = getWindowList();
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            WindowState window = windows.get(i);
+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
+                if (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
+                    mService.mH.sendMessageDelayed(
+                            mService.mH.obtainMessage(
+                                    WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
+                            window.mAttrs.hideTimeoutMilliseconds);
+                }
+            }
+        }
+    }
+
+    WindowState findFocusedWindow() {
+        final AppWindowToken focusedApp = mService.mFocusedApp;
+
+        for (int i = mWindows.size() - 1; i >= 0; i--) {
+            final WindowState win = mWindows.get(i);
+
+            if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + i + " = " + win
+                    + ", flags=" + win.mAttrs.flags + ", canReceive=" + win.canReceiveKeys());
+
+            if (!win.canReceiveKeys()) {
+                continue;
+            }
+
+            final AppWindowToken wtoken = win.mAppToken;
+
+            // If this window's application has been removed, just skip it.
+            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
+                if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
+                        + (wtoken.removed ? "removed" : "sendingToBottom"));
+                continue;
+            }
+
+            if (focusedApp == null) {
+                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null"
+                        + " using new focus @ " + i + " = " + win);
+                return win;
+            }
+
+            if (!focusedApp.windowsAreFocusable()) {
+                // Current focused app windows aren't focusable...
+                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not"
+                        + " focusable using new focus @ " + i + " = " + win);
+                return win;
+            }
+
+            // Descend through all of the app tokens and find the first that either matches
+            // win.mAppToken (return win) or mFocusedApp (return null).
+            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
+                if (focusedApp.compareTo(wtoken) > 0) {
+                    // App stack below focused app stack. No focus for you!!!
+                    if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
+                            "findFocusedWindow: Reached focused app=" + focusedApp);
+                    return null;
+                }
+            }
+
+            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ "
+                    + i + " = " + win);
+            return win;
+        }
+
+        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
+        return null;
+    }
+
+    int addAppWindowToWindowList(final WindowState win) {
+        final IWindow client = win.mClient;
+
+        WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken);
+        if (!tokenWindowList.isEmpty()) {
+            return addAppWindowExisting(win, tokenWindowList);
+        }
+
+        // No windows from this token on this display
+        if (mService.localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window "
+                + client.asBinder() + " (token=" + this + ")");
+
+        final WindowToken wToken = win.mToken;
+
+        // Figure out where the window should go, based on the order of applications.
+        mTmpGetWindowOnDisplaySearchResult.reset();
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            stack.getWindowOnDisplayBeforeToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
+            if (mTmpGetWindowOnDisplaySearchResult.reachedToken) {
+                // We have reach the token we are interested in. End search.
+                break;
+            }
+        }
+
+        WindowState pos = mTmpGetWindowOnDisplaySearchResult.foundWindow;
+
+        // We now know the index into the apps. If we found an app window above, that gives us the
+        // position; else we need to look some more.
+        if (pos != null) {
+            // Move behind any windows attached to this one.
+            final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
+            if (atoken != null) {
+                tokenWindowList = getTokenWindowsOnDisplay(atoken);
+                final int NC = tokenWindowList.size();
+                if (NC > 0) {
+                    WindowState bottom = tokenWindowList.get(0);
+                    if (bottom.mSubLayer < 0) {
+                        pos = bottom;
+                    }
+                }
+            }
+            addWindowToListBefore(win, pos);
+            return 0;
+        }
+
+        // Continue looking down until we find the first token that has windows on this display.
+        mTmpGetWindowOnDisplaySearchResult.reset();
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskStack stack = mChildren.get(i);
+            stack.getWindowOnDisplayAfterToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
+            if (mTmpGetWindowOnDisplaySearchResult.foundWindow != null) {
+                // We have found a window after the token. End search.
+                break;
+            }
+        }
+
+        pos = mTmpGetWindowOnDisplaySearchResult.foundWindow;
+
+        if (pos != null) {
+            // Move in front of any windows attached to this one.
+            final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
+            if (atoken != null) {
+                final WindowState top = atoken.getTopWindow();
+                if (top != null && top.mSubLayer >= 0) {
+                    pos = top;
+                }
+            }
+            addWindowToListAfter(win, pos);
+            return 0;
+        }
+
+        // Just search for the start of this layer.
+        final int myLayer = win.mBaseLayer;
+        int i;
+        for (i = mWindows.size() - 1; i >= 0; --i) {
+            final WindowState w = mWindows.get(i);
+            // Dock divider shares the base layer with application windows, but we want to always
+            // keep it above the application windows. The sharing of the base layer is intended
+            // for window animations, which need to be above the dock divider for the duration
+            // of the animation.
+            if (w.mBaseLayer <= myLayer && w.mAttrs.type != TYPE_DOCK_DIVIDER) {
+                break;
+            }
+        }
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                "Based on layer: Adding window " + win + " at " + (i + 1) + " of "
+                + mWindows.size());
+        mWindows.add(i + 1, win);
+        mService.mWindowsChanged = true;
+        return 0;
+    }
+
+    /** Adds this non-app window to the window list. */
+    void addNonAppWindowToWindowList(WindowState win) {
+        // Figure out where window should go, based on layer.
+        int i;
+        for (i = mWindows.size() - 1; i >= 0; i--) {
+            final WindowState otherWin = mWindows.get(i);
+            if (otherWin.getBaseType() != TYPE_WALLPAPER && otherWin.mBaseLayer <= win.mBaseLayer) {
+                // Wallpaper wanders through the window list, for example to position itself
+                // directly behind keyguard. Because of this it will break the ordering based on
+                // WindowState.mBaseLayer. There might windows with higher mBaseLayer behind it and
+                // we don't want the new window to appear above them. An example of this is adding
+                // of the docked stack divider. Consider a scenario with the following ordering (top
+                // to bottom): keyguard, wallpaper, assist preview, apps. We want the dock divider
+                // to land below the assist preview, so the dock divider must ignore the wallpaper,
+                // with which it shares the base layer.
+                break;
+            }
+        }
+
+        i++;
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                "Free window: Adding window " + this + " at " + i + " of " + mWindows.size());
+        mWindows.add(i, win);
+        mService.mWindowsChanged = true;
+    }
+
+    void addChildWindowToWindowList(WindowState win) {
+        final WindowState parentWindow = win.getParentWindow();
+
+        WindowList windowsOnSameDisplay = getTokenWindowsOnDisplay(win.mToken);
+
+        // Figure out this window's ordering relative to the parent window.
+        final int wCount = windowsOnSameDisplay.size();
+        final int sublayer = win.mSubLayer;
+        int largestSublayer = Integer.MIN_VALUE;
+        WindowState windowWithLargestSublayer = null;
+        int i;
+        for (i = 0; i < wCount; i++) {
+            WindowState w = windowsOnSameDisplay.get(i);
+            final int wSublayer = w.mSubLayer;
+            if (wSublayer >= largestSublayer) {
+                largestSublayer = wSublayer;
+                windowWithLargestSublayer = w;
+            }
+            if (sublayer < 0) {
+                // For negative sublayers, we go below all windows in the same sublayer.
+                if (wSublayer >= sublayer) {
+                    addWindowToListBefore(win, wSublayer >= 0 ? parentWindow : w);
+                    break;
+                }
+            } else {
+                // For positive sublayers, we go above all windows in the same sublayer.
+                if (wSublayer > sublayer) {
+                    addWindowToListBefore(win, w);
+                    break;
+                }
+            }
+        }
+        if (i >= wCount) {
+            if (sublayer < 0) {
+                addWindowToListBefore(win, parentWindow);
+            } else {
+                addWindowToListAfter(win,
+                        largestSublayer >= 0 ? windowWithLargestSublayer : parentWindow);
+            }
+        }
+    }
+
+    /**
+     * Z-orders the display window list so that:
+     * <ul>
+     * <li>Any windows that are currently below the wallpaper window stay below the wallpaper
+     *      window.
+     * <li>Exiting application windows are at the bottom, but above the wallpaper window.
+     * <li>All other application windows are above the exiting application windows and ordered based
+     *      on the ordering of their stacks and tasks on the display.
+     * <li>Non-application windows are at the very top.
+     * </ul>
+     * <p>
+     * NOTE: This isn't a complete picture of what the user see. Further manipulation of the window
+     *       surface layering is done in {@link WindowLayersController}.
+     */
+    void rebuildAppWindowList() {
+        int count = mWindows.size();
+        int i;
+        int lastBelow = -1;
+        int numRemoved = 0;
+
+        if (mRebuildTmp.length < count) {
+            mRebuildTmp = new WindowState[count + 10];
+        }
+
+        // First remove all existing app windows.
+        i = 0;
+        while (i < count) {
+            final WindowState w = mWindows.get(i);
+            if (w.mAppToken != null) {
+                final WindowState win = mWindows.remove(i);
+                win.mRebuilding = true;
+                mRebuildTmp[numRemoved] = win;
+                mService.mWindowsChanged = true;
+                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win);
+                count--;
+                numRemoved++;
+                continue;
+            } else if (lastBelow == i-1) {
+                if (w.mAttrs.type == TYPE_WALLPAPER) {
+                    lastBelow = i;
+                }
+            }
+            i++;
+        }
+
+        // Keep whatever windows were below the app windows still below, by skipping them.
+        lastBelow++;
+        i = lastBelow;
+
+        // First add all of the exiting app tokens...  these are no longer in the main app list,
+        // but still have windows shown. We put them in the back because now that the animation is
+        // over we no longer will care about them.
+        final int numStacks = mChildren.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            AppTokenList exitingAppTokens = mChildren.get(stackNdx).mExitingAppTokens;
+            int NT = exitingAppTokens.size();
+            for (int j = 0; j < NT; j++) {
+                i = exitingAppTokens.get(j).rebuildWindowListUnchecked(this, i);
+            }
+        }
+
+        // And add in the still active app tokens in Z order.
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            i = mChildren.get(stackNdx).rebuildWindowList(this, i);
+        }
+
+        i -= lastBelow;
+        if (i != numRemoved) {
+            setLayoutNeeded();
+            Slog.w(TAG_WM, "On display=" + mDisplayId + " Rebuild removed " + numRemoved
+                    + " windows but added " + i + " rebuildAppWindowListLocked() "
+                    + " callers=" + Debug.getCallers(10));
+            for (i = 0; i < numRemoved; i++) {
+                WindowState ws = mRebuildTmp[i];
+                if (ws.mRebuilding) {
+                    StringWriter sw = new StringWriter();
+                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
+                    ws.dump(pw, "", true);
+                    pw.flush();
+                    Slog.w(TAG_WM, "This window was lost: " + ws);
+                    Slog.w(TAG_WM, sw.toString());
+                    ws.mWinAnimator.destroySurfaceLocked();
+                }
+            }
+            Slog.w(TAG_WM, "Current window hierarchy:");
+            dumpChildrenNames();
+            Slog.w(TAG_WM, "Final window list:");
+            dumpWindows();
+        }
+        Arrays.fill(mRebuildTmp, null);
+    }
+
+    /** Return the list of Windows on this display associated with the input token. */
+    WindowList getTokenWindowsOnDisplay(WindowToken token) {
+        final WindowList windowList = new WindowList();
+        final int count = mWindows.size();
+        for (int i = 0; i < count; i++) {
+            final WindowState win = mWindows.get(i);
+            if (win.mToken == token) {
+                windowList.add(win);
+            }
+        }
+        return windowList;
+    }
+
+    void setLayoutNeeded() {
+        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
+        mLayoutNeeded = true;
+    }
+
+    void clearLayoutNeeded() {
+        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "clearLayoutNeeded: callers=" + Debug.getCallers(3));
+        mLayoutNeeded = false;
+    }
+
+    boolean isLayoutNeeded() {
+        return mLayoutNeeded;
+    }
+
+    private int addAppWindowExisting(WindowState win, WindowList tokenWindowList) {
+
+        int tokenWindowsPos;
+        // If this application has existing windows, we simply place the new window on top of
+        // them... but keep the starting window on top.
+        if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
+            // Base windows go behind everything else.
+            final WindowState lowestWindow = tokenWindowList.get(0);
+            addWindowToListBefore(win, lowestWindow);
+            tokenWindowsPos = win.mToken.getWindowIndex(lowestWindow);
+        } else {
+            final AppWindowToken atoken = win.mAppToken;
+            final int windowListPos = tokenWindowList.size();
+            final WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
+            if (atoken != null && lastWindow == atoken.startingWindow) {
+                addWindowToListBefore(win, lastWindow);
+                tokenWindowsPos = win.mToken.getWindowIndex(lastWindow);
+            } else {
+                int newIdx = findIdxBasedOnAppTokens(win);
+                // There is a window above this one associated with the same apptoken note that the
+                // window could be a floating window that was created later or a window at the top
+                // of the list of windows associated with this token.
+                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                        "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
+                                + mWindows.size());
+                mWindows.add(newIdx + 1, win);
+                if (newIdx < 0) {
+                    // No window from token found on win's display.
+                    tokenWindowsPos = 0;
+                } else {
+                    tokenWindowsPos = win.mToken.getWindowIndex(mWindows.get(newIdx)) + 1;
+                }
+                mService.mWindowsChanged = true;
+            }
+        }
+        return tokenWindowsPos;
+    }
+
+    /** Places the first input window after the second input window in the window list. */
+    private void addWindowToListAfter(WindowState first, WindowState second) {
+        final int i = mWindows.indexOf(second);
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                "Adding window " + this + " at " + (i + 1) + " of " + mWindows.size()
+                + " (after " + second + ")");
+        mWindows.add(i + 1, first);
+        mService.mWindowsChanged = true;
+    }
+
+    /** Places the first input window before the second input window in the window list. */
+    private void addWindowToListBefore(WindowState first, WindowState second) {
+        int i = mWindows.indexOf(second);
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                "Adding window " + this + " at " + i + " of " + mWindows.size()
+                + " (before " + second + ")");
+        if (i < 0) {
+            Slog.w(TAG_WM, "addWindowToListBefore: Unable to find " + second + " in " + mWindows);
+            i = 0;
+        }
+        mWindows.add(i, first);
+        mService.mWindowsChanged = true;
+    }
+
+    /**
+     * This method finds out the index of a window that has the same app token as win. used for z
+     * ordering the windows in mWindows
+     */
+    private int findIdxBasedOnAppTokens(WindowState win) {
+        for(int j = mWindows.size() - 1; j >= 0; j--) {
+            final WindowState wentry = mWindows.get(j);
+            if(wentry.mAppToken == win.mAppToken) {
+                return j;
+            }
+        }
+        return -1;
+    }
+
+    private void dumpChildrenNames() {
+        StringBuilder output = new StringBuilder();
+        dumpChildrenNames(output, " ");
+        Slog.v(TAG_WM, output.toString());
+    }
+
+    private void dumpWindows() {
+        Slog.v(TAG_WM, " Display #" + mDisplayId);
+        final WindowList windows = getWindowList();
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            Slog.v(TAG_WM, "  #" + winNdx + ": " + windows.get(winNdx));
+        }
+    }
+
+    static final class GetWindowOnDisplaySearchResult {
+        boolean reachedToken;
+        WindowState foundWindow;
+
+        void reset() {
+            reachedToken = false;
+            foundWindow = null;
+        }
+    }
+
+    static final class TaskForResizePointSearchResult {
+        boolean searchDone;
+        Task taskForResize;
+
+        void reset() {
+            searchDone = false;
+            taskForResize = null;
+        }
+    }
+
+    void enableSurfaceTrace(FileDescriptor fd) {
+        for (int i = mWindows.size()  - 1; i >= 0; i--) {
+            final WindowState win = mWindows.get(i);
+            win.mWinAnimator.enableSurfaceTrace(fd);
+        }
+    }
+
+    void disableSurfaceTrace() {
+        for (int i = mWindows.size()  - 1; i >= 0; i--) {
+            final WindowState win = mWindows.get(i);
+            win.mWinAnimator.disableSurfaceTrace();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 641bae2..5854197 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.DOCKED_TOP;
 import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
 import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.AppTransition.TRANSIT_NONE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
@@ -38,6 +39,7 @@
 import android.graphics.Rect;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.IDockedStackListener;
@@ -130,8 +132,8 @@
     private boolean mAdjustedForDivider;
     private float mDividerAnimationStart;
     private float mDividerAnimationTarget;
-    private float mLastAnimationProgress;
-    private float mLastDividerProgress;
+    float mLastAnimationProgress;
+    float mLastDividerProgress;
     private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
     private boolean mImeHideRequested;
 
@@ -152,7 +154,7 @@
         // If the bounds are fullscreen, return the value of the fullscreen configuration
         if (bounds == null || (bounds.left == 0 && bounds.top == 0
                 && bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
-            return mService.mCurConfiguration.smallestScreenWidthDp;
+            return mDisplayContent.getConfiguration().smallestScreenWidthDp;
         }
         final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
         final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
@@ -189,7 +191,7 @@
     }
 
     private void initSnapAlgorithmForRotations() {
-        final Configuration baseConfig = mService.mCurConfiguration;
+        final Configuration baseConfig = mDisplayContent.getConfiguration();
 
         // Initialize the snap algorithms for all 4 screen orientations.
         final Configuration config = new Configuration();
@@ -202,7 +204,7 @@
                     ? mDisplayContent.mBaseDisplayWidth
                     : mDisplayContent.mBaseDisplayHeight;
             mService.mPolicy.getStableInsetsLw(rotation, dw, dh, mTmpRect);
-            config.setToDefaults();
+            config.unset();
             config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
             config.screenWidthDp = (int)
                     (mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, baseConfig.uiMode) /
@@ -464,7 +466,7 @@
     }
 
     void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         final TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
         final TaskStack dockedStack = mDisplayContent.getDockedStackLocked();
         boolean visibleAndValid = visible && stack != null && dockedStack != null;
@@ -481,7 +483,7 @@
         if (!visibleAndValid) {
             mDimLayer.hide();
         }
-        SurfaceControl.closeTransaction();
+        mService.closeSurfaceTransaction();
     }
 
     /**
@@ -492,8 +494,32 @@
         checkMinimizeChanged(false /* animate */);
     }
 
-    void notifyAppTransitionStarting() {
+    void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
+        final boolean wasMinimized = mMinimizedDock;
         checkMinimizeChanged(true /* animate */);
+
+        // We were minimized, and now we are still minimized, but somebody is trying to launch an
+        // app in docked stack, better show recent apps so we actually get unminimized! This catches
+        // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
+        // we couldn't retrace the launch of the app in the docked stack to the launch from
+        // homescreen.
+        if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
+                && appTransition != TRANSIT_NONE) {
+            mService.showRecentApps(true /* fromHome */);
+        }
+    }
+
+    /**
+     * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
+     */
+    private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) {
+        for (int i = apps.size() - 1; i >= 0; i--) {
+            final AppWindowToken token = apps.valueAt(i);
+            if (token.mTask != null && token.mTask.mStack.mStackId == DOCKED_STACK_ID) {
+                return true;
+            }
+        }
+        return false;
     }
 
     boolean isMinimizedDock() {
@@ -514,15 +540,13 @@
         }
         final TaskStack fullscreenStack
                 = mService.mStackIdToStack.get(FULLSCREEN_WORKSPACE_STACK_ID);
-        final ArrayList<Task> homeStackTasks = homeStack.getTasks();
-        final Task topHomeStackTask = homeStackTasks.get(homeStackTasks.size() - 1);
         final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
-        final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisibleLocked())
-                || (homeStackTasks.size() > 1 && topHomeStackTask != homeTask);
+        final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
+                || (homeStack.hasMultipleTaskWithHomeTaskNotTop());
         // If the home task is an on-top launcher, we don't want to minimize the docked stack.
         // Instead we want everything underneath that was visible to remain visible.
         // See android.R.attr#onTopLauncher.
-        final boolean isOnTopLauncher = topHomeStackTask.isOnTopLauncher();
+        final boolean isOnTopLauncher = homeStack.topTaskIsOnTopLauncher();
         setMinimizedDockedStack(homeVisible && !homeBehind && !isOnTopLauncher, animate);
     }
 
@@ -572,15 +596,7 @@
     }
 
     private boolean clearImeAdjustAnimation() {
-        boolean changed = false;
-        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
-        for (int i = stacks.size() - 1; i >= 0; --i) {
-            final TaskStack stack = stacks.get(i);
-            if (stack != null && stack.isAdjustedForIme()) {
-                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
-                changed  = true;
-            }
-        }
+        final boolean changed = mDisplayContent.clearImeAdjustAnimation();
         mAnimatingForIme = false;
         return changed;
     }
@@ -612,13 +628,7 @@
         mAnimationTarget = adjustedForIme ? 1 : 0;
         mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
 
-        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
-        for (int i = stacks.size() - 1; i >= 0; --i) {
-            final TaskStack stack = stacks.get(i);
-            if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
-                stack.beginImeAdjustAnimation();
-            }
-        }
+        mDisplayContent.beginImeAdjustAnimation();
 
         // We put all tasks into drag resizing mode - wait until all of them have completed the
         // drag resizing switch.
@@ -699,27 +709,8 @@
         float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
         t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
                 .getInterpolation(t);
-        final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
-        boolean updated = false;
-        for (int i = stacks.size() - 1; i >= 0; --i) {
-            final TaskStack stack = stacks.get(i);
-            if (stack != null && stack.isAdjustedForIme()) {
-                if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
-                    stack.resetAdjustedForIme(true /* adjustBoundsNow */);
-                    updated = true;
-                } else {
-                    mLastAnimationProgress = getInterpolatedAnimationValue(t);
-                    mLastDividerProgress = getInterpolatedDividerValue(t);
-                    updated |= stack.updateAdjustForIme(
-                            mLastAnimationProgress,
-                            mLastDividerProgress,
-                            false /* force */);
-                }
-                if (t >= 1f) {
-                    stack.endImeAdjustAnimation();
-                }
-            }
-        }
+        final boolean updated =
+                mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
         if (updated) {
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
@@ -763,11 +754,11 @@
         }
     }
 
-    private float getInterpolatedAnimationValue(float t) {
+    float getInterpolatedAnimationValue(float t) {
         return t * mAnimationTarget + (1 - t) * mAnimationStart;
     }
 
-    private float getInterpolatedDividerValue(float t) {
+    float getInterpolatedDividerValue(float t) {
         return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
     }
 
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index d0167bb..588bb76 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -432,14 +432,14 @@
         // Move the surface to the given touch
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                 TAG_WM, ">>> OPEN TRANSACTION notifyMoveLw");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
             mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
             if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  DRAG "
                     + mSurfaceControl + ": pos=(" +
                     (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                     TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLw");
         }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 535ce9d..a5387bd 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -165,7 +165,7 @@
         return 0; // abort dispatching
     }
 
-    private void addInputWindowHandleLw(final InputWindowHandle windowHandle) {
+    void addInputWindowHandle(final InputWindowHandle windowHandle) {
         if (mInputWindowHandles == null) {
             mInputWindowHandles = new InputWindowHandle[16];
         }
@@ -176,7 +176,7 @@
         mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
     }
 
-    private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle,
+    void addInputWindowHandle(final InputWindowHandle inputWindowHandle,
             final WindowState child, int flags, final int type, final boolean isVisible,
             final boolean hasFocus, final boolean hasWallpaper) {
         // Add a window to our list of input windows.
@@ -214,7 +214,7 @@
             Slog.d(TAG_WM, "addInputWindowHandle: "
                     + child + ", " + inputWindowHandle);
         }
-        addInputWindowHandleLw(inputWindowHandle);
+        addInputWindowHandle(inputWindowHandle);
     }
 
     private void clearInputWindowHandlesLw() {
@@ -241,9 +241,8 @@
         // As an optimization, we could try to prune the list of windows but this turns
         // out to be difficult because only the native code knows for sure which window
         // currently has touch focus.
-        boolean disableWallpaperTouchEvents = false;
 
-        // If there's a drag in flight, provide a pseudowindow to catch drag input
+        // If there's a drag in flight, provide a pseudo-window to catch drag input
         final boolean inDrag = (mService.mDragState != null);
         if (inDrag) {
             if (DEBUG_DRAG) {
@@ -251,7 +250,7 @@
             }
             final InputWindowHandle dragWindowHandle = mService.mDragState.getInputWindowHandle();
             if (dragWindowHandle != null) {
-                addInputWindowHandleLw(dragWindowHandle);
+                addInputWindowHandle(dragWindowHandle);
             } else {
                 Slog.w(TAG_WM, "Drag is in progress but there is no "
                         + "drag window handle.");
@@ -265,78 +264,15 @@
             }
             final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
             if (dragWindowHandle != null) {
-                addInputWindowHandleLw(dragWindowHandle);
+                addInputWindowHandle(dragWindowHandle);
             } else {
                 Slog.e(TAG_WM,
                         "Repositioning is in progress but there is no drag window handle.");
             }
         }
 
-        boolean addInputConsumerHandle = mService.mInputConsumer != null;
-
-        boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
-
         // Add all windows on the default display.
-        final int numDisplays = mService.mDisplayContents.size();
-        final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            final WindowList windows = displayContent.getWindowList();
-            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState child = windows.get(winNdx);
-                final InputChannel inputChannel = child.mInputChannel;
-                final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
-                if (inputChannel == null || inputWindowHandle == null || child.mRemoved
-                        || child.isAdjustedForMinimizedDock()) {
-                    // Skip this window because it cannot possibly receive input.
-                    continue;
-                }
-                if (addInputConsumerHandle
-                        && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) {
-                    addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle);
-                    addInputConsumerHandle = false;
-                }
-
-                if (addWallpaperInputConsumerHandle) {
-                    if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER &&
-                            child.isVisibleLw()) {
-                        // Add the wallpaper input consumer above the first visible wallpaper.
-                        addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
-                        addWallpaperInputConsumerHandle = false;
-                    }
-                }
-
-                final int flags = child.mAttrs.flags;
-                final int privateFlags = child.mAttrs.privateFlags;
-                final int type = child.mAttrs.type;
-
-                final boolean hasFocus = (child == mInputFocus);
-                final boolean isVisible = child.isVisibleLw();
-                if ((privateFlags
-                        & WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS)
-                            != 0) {
-                    disableWallpaperTouchEvents = true;
-                }
-                final boolean hasWallpaper = wallpaperController.isWallpaperTarget(child)
-                        && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0
-                        && !disableWallpaperTouchEvents;
-                final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
-
-                // If there's a drag in progress and 'child' is a potential drop target,
-                // make sure it's been told about the drag
-                if (inDrag && isVisible && onDefaultDisplay) {
-                    mService.mDragState.sendDragStartedIfNeededLw(child);
-                }
-
-                addInputWindowHandleLw(
-                        inputWindowHandle, child, flags, type, isVisible, hasFocus, hasWallpaper);
-            }
-        }
-
-        if (addWallpaperInputConsumerHandle) {
-            // No visible wallpaper found, add the wallpaper input consumer at the end.
-            addInputWindowHandleLw(mService.mWallpaperInputConsumer.mWindowHandle);
-        }
+        mService.mRoot.updateInputWindows(this, mInputFocus, inDrag);
 
         // Send windows to native code.
         mService.mInputManager.setInputWindows(mInputWindowHandles);
diff --git a/services/core/java/com/android/server/wm/RemoteEventTrace.java b/services/core/java/com/android/server/wm/RemoteEventTrace.java
new file mode 100644
index 0000000..9f65ba3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RemoteEventTrace.java
@@ -0,0 +1,69 @@
+/*
+ * 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.wm;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.DataOutputStream;
+
+import android.util.Slog;
+import android.os.Debug;
+
+// Counterpart to remote surface trace for events which are not tied to a particular surface.
+class RemoteEventTrace {
+    private static final String TAG = "RemoteEventTrace";
+
+    // We terminate all our messages with a recognizable marker, to avoid issues
+    // with partial reads (which ADB makes impossible to avoid).
+    static final byte[] sigil = {(byte)0xfc, (byte)0xfc, (byte)0xfc, (byte)0xfc};
+
+    private final WindowManagerService mService;
+    private final DataOutputStream mOut;
+
+    RemoteEventTrace(WindowManagerService service, FileDescriptor fd) {
+        mService = service;
+        mOut = new DataOutputStream(new FileOutputStream(fd, false));
+    }
+
+    void openSurfaceTransaction() {
+        try {
+            mOut.writeUTF("OpenTransaction");
+            writeSigil();
+        } catch (Exception e) {
+            logException(e);
+            mService.disableSurfaceTrace();
+        }
+    }
+
+    void closeSurfaceTransaction() {
+        try {
+            mOut.writeUTF("CloseTransaction");
+            writeSigil();
+        } catch (Exception e) {
+            logException(e);
+            mService.disableSurfaceTrace();
+        }
+    }
+
+    private void writeSigil() throws Exception {
+        mOut.write(RemoteEventTrace.sigil, 0, 4);
+    }
+
+    static void logException(Exception e) {
+        Slog.i(TAG, "Exception writing to SurfaceTrace (client vanished?): " + e.toString());
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
new file mode 100644
index 0000000..0508fdf
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java
@@ -0,0 +1,166 @@
+/*
+ * 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.wm;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.Slog;
+import android.view.SurfaceControl;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.DataOutputStream;
+
+// A surface control subclass which logs events to a FD in binary format.
+// This can be used in our CTS tests to enable a pattern similar to mocking
+// the surface control.
+//
+// See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side.
+class RemoteSurfaceTrace extends SurfaceControl {
+    static final String TAG = "RemoteSurfaceTrace";
+
+    final FileDescriptor mWriteFd;
+    final DataOutputStream mOut;
+
+    final WindowManagerService mService;
+    final WindowState mWindow;
+
+    RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped, WindowState window) {
+        super(wrapped);
+
+        mWriteFd = fd;
+        mOut = new DataOutputStream(new FileOutputStream(fd, false));
+
+        mWindow = window;
+        mService = mWindow.mService;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        writeFloatEvent("Alpha", alpha);
+        super.setAlpha(alpha);
+    }
+
+    @Override
+    public void setLayer(int zorder) {
+        writeIntEvent("Layer", zorder);
+        super.setLayer(zorder);
+    }
+
+    @Override
+    public void setPosition(float x, float y) {
+        writeFloatEvent("Position", x, y);
+        super.setPosition(x, y);
+    }
+
+    @Override
+    public void setGeometryAppliesWithResize() {
+        writeEvent("GeometryAppliesWithResize");
+        super.setGeometryAppliesWithResize();
+    }
+
+    @Override
+    public void setSize(int w, int h) {
+        writeIntEvent("Size", w, h);
+        super.setSize(w, h);
+    }
+
+    @Override
+    public void setWindowCrop(Rect crop) {
+        writeRectEvent("Crop", crop);
+        super.setWindowCrop(crop);
+    }
+
+    @Override
+    public void setFinalCrop(Rect crop) {
+        writeRectEvent("FinalCrop", crop);
+        super.setFinalCrop(crop);
+    }
+
+    @Override
+    public void setLayerStack(int layerStack) {
+        writeIntEvent("LayerStack", layerStack);
+        super.setLayerStack(layerStack);
+    }
+
+    @Override
+    public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+        writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy);
+        super.setMatrix(dsdx, dtdx, dsdy, dtdy);
+    }
+
+    @Override
+    public void hide() {
+        writeEvent("Hide");
+        super.hide();
+    }
+
+    @Override
+    public void show() {
+        writeEvent("Show");
+        super.show();
+    }
+
+    private void writeEvent(String tag) {
+        try {
+            mOut.writeUTF(tag);
+            mOut.writeUTF(mWindow.getWindowTag().toString());
+            writeSigil();
+        } catch (Exception e) {
+            RemoteEventTrace.logException(e);
+            mService.disableSurfaceTrace();
+        }
+    }
+
+    private void writeIntEvent(String tag, int... values) {
+        try {
+            mOut.writeUTF(tag);
+            mOut.writeUTF(mWindow.getWindowTag().toString());
+            for (int value: values) {
+                mOut.writeInt(value);
+            }
+            writeSigil();
+        } catch (Exception e) {
+            RemoteEventTrace.logException(e);
+            mService.disableSurfaceTrace();
+        }
+    }
+
+    private void writeFloatEvent(String tag, float... values) {
+        try {
+            mOut.writeUTF(tag);
+            mOut.writeUTF(mWindow.getWindowTag().toString());
+            for (float value: values) {
+                mOut.writeFloat(value);
+            }
+            writeSigil();
+        } catch (Exception e) {
+            RemoteEventTrace.logException(e);
+            mService.disableSurfaceTrace();
+        }
+    }
+
+    private void writeRectEvent(String tag, Rect value) {
+        writeFloatEvent(tag, value.left, value.top, value.right, value.bottom);
+    }
+
+    private void writeSigil() throws Exception {
+        mOut.write(RemoteEventTrace.sigil, 0, 4);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
new file mode 100644
index 0000000..1700bca
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -0,0 +1,1367 @@
+/*
+ * 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.wm;
+
+import android.app.AppOpsManager;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.EventLog;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.InputChannel;
+import android.view.WindowManager;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.EventLogTags;
+import com.android.server.input.InputWindowHandle;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
+import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.logSurface;
+import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
+import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
+
+/** Root {@link WindowContainer} for the device. */
+// TODO: Several methods in here are accessing children of this container's children through various
+// references (WindowList I am looking at you :/). See if we can delegate instead.
+class RootWindowContainer extends WindowContainer<DisplayContent> {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "RootWindowContainer" : TAG_WM;
+
+    WindowManagerService mService;
+
+    private boolean mWallpaperForceHidingChanged = false;
+    private Object mLastWindowFreezeSource = null;
+    private Session mHoldScreen = null;
+    private float mScreenBrightness = -1;
+    private float mButtonBrightness = -1;
+    private long mUserActivityTimeout = -1;
+    private boolean mUpdateRotation = false;
+    private boolean mObscured = false;
+    boolean mSyswin = false;
+    // Set to true when the display contains content to show the user.
+    // When false, the display manager may choose to mirror or blank the display.
+    private boolean mDisplayHasContent = false;
+    private float mPreferredRefreshRate = 0;
+    private int mPreferredModeId = 0;
+    // Following variables are for debugging screen wakelock only.
+    // Last window that requires screen wakelock
+    WindowState mHoldScreenWindow = null;
+    // Last window that obscures all windows below
+    WindowState mObsuringWindow = null;
+    // Only set while traversing the default display based on its content.
+    // Affects the behavior of mirroring on secondary displays.
+    private boolean mObscureApplicationContentOnSecondaryDisplays = false;
+
+    private boolean mSustainedPerformanceModeEnabled = false;
+    private boolean mSustainedPerformanceModeCurrent = false;
+
+    boolean mWallpaperMayChange = false;
+    // During an orientation change, we track whether all windows have rendered
+    // at the new orientation, and this will be false from changing orientation until that occurs.
+    // For seamless rotation cases this always stays true, as the windows complete their orientation
+    // changes 1 by 1 without disturbing global state.
+    boolean mOrientationChangeComplete = true;
+    boolean mWallpaperActionPending = false;
+
+    private final ArrayList<Integer> mChangedStackList = new ArrayList();
+
+    private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList();
+
+    // State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl
+    // instances will be replaced with an instance that writes a binary representation of all
+    // commands to mSurfaceTraceFd.
+    boolean mSurfaceTraceEnabled;
+    ParcelFileDescriptor mSurfaceTraceFd;
+    RemoteEventTrace mRemoteEventTrace;
+
+    RootWindowContainer(WindowManagerService service) {
+        mService = service;
+    }
+
+    WindowState computeFocusedWindow() {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; i++) {
+            final DisplayContent dc = mChildren.get(i);
+            final WindowState win = dc.findFocusedWindow();
+            if (win != null) {
+                return win;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
+     * there is a Display for the displayId.
+     *
+     * @param displayId The display the caller is interested in.
+     * @return The DisplayContent associated with displayId or null if there is no Display for it.
+     */
+    DisplayContent getDisplayContentOrCreate(int displayId) {
+        DisplayContent dc = getDisplayContent(displayId);
+
+        if (dc == null) {
+            final Display display = mService.mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                dc = createDisplayContent(display);
+            }
+        }
+        return dc;
+    }
+
+    private DisplayContent getDisplayContent(int displayId) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final DisplayContent current = mChildren.get(i);
+            if (current.getDisplayId() == displayId) {
+                return current;
+            }
+        }
+        return null;
+    }
+
+    private DisplayContent createDisplayContent(final Display display) {
+        final DisplayContent dc = new DisplayContent(display, mService);
+        final int displayId = display.getDisplayId();
+
+        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
+        addChild(dc, null);
+
+        final DisplayInfo displayInfo = dc.getDisplayInfo();
+        final Rect rect = new Rect();
+        mService.mDisplaySettings.getOverscanLocked(displayInfo.name, displayInfo.uniqueId, rect);
+        displayInfo.overscanLeft = rect.left;
+        displayInfo.overscanTop = rect.top;
+        displayInfo.overscanRight = rect.right;
+        displayInfo.overscanBottom = rect.bottom;
+        if (mService.mDisplayManagerInternal != null) {
+            mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
+                    displayId, displayInfo);
+            mService.configureDisplayPolicyLocked(dc);
+
+            // TODO(multi-display): Create an input channel for each display with touch capability.
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                dc.mTapDetector = new TaskTapPointerEventListener(
+                        mService, dc);
+                mService.registerPointerEventListener(dc.mTapDetector);
+                mService.registerPointerEventListener(mService.mMousePositionTracker);
+            }
+        }
+
+        return dc;
+    }
+
+    /** Adds the input stack id to the input display id and returns the bounds of the added stack.*/
+    Rect addStackToDisplay(int stackId, int displayId, boolean onTop) {
+        final DisplayContent dc = getDisplayContent(displayId);
+        if (dc == null) {
+            Slog.w(TAG_WM, "addStackToDisplay: Trying to add stackId=" + stackId
+                    + " to unknown displayId=" + displayId + " callers=" + Debug.getCallers(6));
+            return null;
+        }
+
+        boolean attachedToDisplay = false;
+        TaskStack stack = mService.mStackIdToStack.get(stackId);
+        if (stack == null) {
+            if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
+
+            stack = dc.getStackById(stackId);
+            if (stack != null) {
+                // It's already attached to the display...clear mDeferRemoval and move stack to
+                // appropriate z-order on display as needed.
+                stack.mDeferRemoval = false;
+                dc.moveStack(stack, onTop);
+                attachedToDisplay = true;
+            } else {
+                stack = new TaskStack(mService, stackId);
+            }
+
+            mService.mStackIdToStack.put(stackId, stack);
+            if (stackId == DOCKED_STACK_ID) {
+                mService.getDefaultDisplayContentLocked().mDividerControllerLocked
+                        .notifyDockedStackExistsChanged(true);
+            }
+        }
+
+        if (!attachedToDisplay) {
+            stack.attachDisplayContent(dc);
+            dc.attachStack(stack, onTop);
+        }
+
+        if (stack.getRawFullscreen()) {
+            return null;
+        }
+        final Rect bounds = new Rect();
+        stack.getRawBounds(bounds);
+        return bounds;
+    }
+
+    boolean isLayoutNeeded() {
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mChildren.get(displayNdx);
+            if (displayContent.isLayoutNeeded()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void getWindows(WindowList output) {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final DisplayContent dc = mChildren.get(i);
+            output.addAll(dc.getWindowList());
+        }
+    }
+
+    void getWindows(WindowList output, boolean visibleOnly, boolean appsOnly) {
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final WindowList windowList = mChildren.get(displayNdx).getWindowList();
+            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState w = windowList.get(winNdx);
+                if ((!visibleOnly || w.mWinAnimator.getShown())
+                        && (!appsOnly || w.mAppToken != null)) {
+                    output.add(w);
+                }
+            }
+        }
+    }
+
+    void getWindowsByName(WindowList output, String name) {
+        int objectId = 0;
+        // See if this is an object ID.
+        try {
+            objectId = Integer.parseInt(name, 16);
+            name = null;
+        } catch (RuntimeException e) {
+        }
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final WindowList windowList = mChildren.get(displayNdx).getWindowList();
+            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState w = windowList.get(winNdx);
+                if (name != null) {
+                    if (w.mAttrs.getTitle().toString().contains(name)) {
+                        output.add(w);
+                    }
+                } else if (System.identityHashCode(w) == objectId) {
+                    output.add(w);
+                }
+            }
+        }
+    }
+
+    WindowState findWindow(int hashCode) {
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final WindowList windows = mChildren.get(displayNdx).getWindowList();
+            final int numWindows = windows.size();
+            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                final WindowState w = windows.get(winNdx);
+                if (System.identityHashCode(w) == hashCode) {
+                    return w;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    // TODO: Users would have their own window containers under the display container?
+    void switchUser() {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final DisplayContent dc = mChildren.get(i);
+            dc.switchUser();
+        }
+    }
+
+    /** Set new config and return array of ids of stacks that were changed during update. */
+    int[] setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
+        final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
+        if (!configChanged) {
+            return null;
+        }
+        onConfigurationChanged(newConfiguration);
+        return updateStackBoundsAfterConfigChange();
+    }
+
+    @Override
+    void onConfigurationChanged(Configuration newParentConfig) {
+        prepareFreezingTaskBounds();
+        super.onConfigurationChanged(newParentConfig);
+
+        mService.mPolicy.onConfigurationChanged();
+    }
+
+    /**
+     * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+     * bounds were updated.
+     */
+    int[] updateStackBoundsAfterConfigChange() {
+        mChangedStackList.clear();
+
+        final int numDisplays = mChildren.size();
+        for (int i = 0; i < numDisplays; ++i) {
+            final DisplayContent dc = mChildren.get(i);
+            dc.updateStackBoundsAfterConfigChange(mChangedStackList);
+        }
+
+        return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList);
+    }
+
+    private void prepareFreezingTaskBounds() {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            mChildren.get(i).prepareFreezingTaskBounds();
+        }
+    }
+
+    void setSecureSurfaceState(int userId, boolean disabled) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowList windows = mChildren.get(i).getWindowList();
+            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState win = windows.get(winNdx);
+                if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) {
+                    win.mWinAnimator.setSecureLocked(disabled);
+                }
+            }
+        }
+    }
+
+    void updateAppOpsState() {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final WindowList windows = mChildren.get(i).getWindowList();
+            final int numWindows = windows.size();
+            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                final WindowState win = windows.get(winNdx);
+                if (win.mAppOp == AppOpsManager.OP_NONE) {
+                    continue;
+                }
+                final int mode = mService.mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
+                        win.getOwningPackage());
+                win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
+                        mode == AppOpsManager.MODE_DEFAULT);
+            }
+        }
+    }
+
+    boolean canShowStrictModeViolation(int pid) {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final WindowList windows = mChildren.get(i).getWindowList();
+            final int numWindows = windows.size();
+            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                final WindowState ws = windows.get(winNdx);
+                if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    void closeSystemDialogs(String reason) {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final WindowList windows = mChildren.get(i).getWindowList();
+            final int numWindows = windows.size();
+            for (int j = 0; j < numWindows; ++j) {
+                final WindowState w = windows.get(j);
+                if (w.mHasSurface) {
+                    try {
+                        w.mClient.closeSystemDialogs(reason);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+    }
+
+    void removeReplacedWindows() {
+        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows");
+        mService.openSurfaceTransaction();
+        try {
+            for (int i = mChildren.size() - 1; i >= 0; i--) {
+                DisplayContent dc = mChildren.get(i);
+                final WindowList windows = dc.getWindowList();
+                for (int j = windows.size() - 1; j >= 0; j--) {
+                    final WindowState win = windows.get(j);
+                    final AppWindowToken aToken = win.mAppToken;
+                    if (aToken != null) {
+                        aToken.removeReplacedWindowIfNeeded(win);
+                    }
+                }
+            }
+        } finally {
+            mService.closeSurfaceTransaction();
+            if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
+        }
+    }
+
+    boolean hasPendingLayoutChanges(WindowAnimator animator) {
+        boolean hasChanges = false;
+
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final DisplayContent dc = mChildren.get(i);
+            final int pendingChanges = animator.getPendingLayoutChanges(dc.getDisplayId());
+            if ((pendingChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                animator.mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
+            }
+            if (pendingChanges != 0) {
+                hasChanges = true;
+            }
+        }
+
+        return hasChanges;
+    }
+
+    void updateInputWindows(InputMonitor inputMonitor, WindowState inputFocus, boolean inDrag) {
+        boolean addInputConsumerHandle = mService.mInputConsumer != null;
+        boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+        final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
+        boolean disableWallpaperTouchEvents = false;
+
+        final int count = mChildren.size();
+        for (int i = 0; i < count; ++i) {
+            final DisplayContent dc = mChildren.get(i);
+            final WindowList windows = dc.getWindowList();
+            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState child = windows.get(winNdx);
+                final InputChannel inputChannel = child.mInputChannel;
+                final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+                if (inputChannel == null || inputWindowHandle == null || child.mRemoved
+                        || child.isAdjustedForMinimizedDock()) {
+                    // Skip this window because it cannot possibly receive input.
+                    continue;
+                }
+                if (addInputConsumerHandle
+                        && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) {
+                    inputMonitor.addInputWindowHandle(mService.mInputConsumer.mWindowHandle);
+                    addInputConsumerHandle = false;
+                }
+
+                if (addWallpaperInputConsumerHandle) {
+                    if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER &&
+                            child.isVisibleLw()) {
+                        // Add the wallpaper input consumer above the first visible wallpaper.
+                        inputMonitor.addInputWindowHandle(
+                                mService.mWallpaperInputConsumer.mWindowHandle);
+                        addWallpaperInputConsumerHandle = false;
+                    }
+                }
+
+                final int flags = child.mAttrs.flags;
+                final int privateFlags = child.mAttrs.privateFlags;
+                final int type = child.mAttrs.type;
+
+                final boolean hasFocus = child == inputFocus;
+                final boolean isVisible = child.isVisibleLw();
+                if ((privateFlags
+                        & WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS)
+                        != 0) {
+                    disableWallpaperTouchEvents = true;
+                }
+                final boolean hasWallpaper = wallpaperController.isWallpaperTarget(child)
+                        && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0
+                        && !disableWallpaperTouchEvents;
+                final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
+
+                // If there's a drag in progress and 'child' is a potential drop target,
+                // make sure it's been told about the drag
+                if (inDrag && isVisible && onDefaultDisplay) {
+                    mService.mDragState.sendDragStartedIfNeededLw(child);
+                }
+
+                inputMonitor.addInputWindowHandle(
+                        inputWindowHandle, child, flags, type, isVisible, hasFocus, hasWallpaper);
+            }
+        }
+
+        if (addWallpaperInputConsumerHandle) {
+            // No visible wallpaper found, add the wallpaper input consumer at the end.
+            inputMonitor.addInputWindowHandle(mService.mWallpaperInputConsumer.mWindowHandle);
+        }
+    }
+
+    boolean reclaimSomeSurfaceMemory(WindowStateAnimator winAnimator, String operation,
+            boolean secure) {
+        final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
+        boolean leakedSurface = false;
+        boolean killedApps = false;
+
+        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
+                winAnimator.mSession.mPid, operation);
+
+        final long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            // There was some problem...   first, do a sanity check of the window list to make sure
+            // we haven't left any dangling surfaces around.
+
+            Slog.i(TAG_WM, "Out of memory for surface!  Looking for leaks...");
+            final int numDisplays = mChildren.size();
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                final WindowList windows = mChildren.get(displayNdx).getWindowList();
+                final int numWindows = windows.size();
+                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                    final WindowState ws = windows.get(winNdx);
+                    final WindowStateAnimator wsa = ws.mWinAnimator;
+                    if (wsa.mSurfaceController == null) {
+                        continue;
+                    }
+                    if (!mService.mSessions.contains(wsa.mSession)) {
+                        Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
+                                + ws + " surface=" + wsa.mSurfaceController
+                                + " token=" + ws.mToken
+                                + " pid=" + ws.mSession.mPid
+                                + " uid=" + ws.mSession.mUid);
+                        wsa.destroySurface();
+                        mService.mForceRemoves.add(ws);
+                        leakedSurface = true;
+                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
+                        Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+                                + ws + " surface=" + wsa.mSurfaceController
+                                + " token=" + ws.mAppToken
+                                + " saved=" + ws.hasSavedSurface());
+                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
+                        wsa.destroySurface();
+                        leakedSurface = true;
+                    }
+                }
+            }
+
+            if (!leakedSurface) {
+                Slog.w(TAG_WM, "No leaked surfaces; killing applications!");
+                SparseIntArray pidCandidates = new SparseIntArray();
+                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                    final WindowList windows = mChildren.get(displayNdx).getWindowList();
+                    final int numWindows = windows.size();
+                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+                        final WindowState ws = windows.get(winNdx);
+                        if (mService.mForceRemoves.contains(ws)) {
+                            continue;
+                        }
+                        WindowStateAnimator wsa = ws.mWinAnimator;
+                        if (wsa.mSurfaceController != null) {
+                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
+                        }
+                    }
+                    if (pidCandidates.size() > 0) {
+                        int[] pids = new int[pidCandidates.size()];
+                        for (int i = 0; i < pids.length; i++) {
+                            pids[i] = pidCandidates.keyAt(i);
+                        }
+                        try {
+                            if (mService.mActivityManager.killPids(pids, "Free memory", secure)) {
+                                killedApps = true;
+                            }
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+            }
+
+            if (leakedSurface || killedApps) {
+                // We managed to reclaim some memory, so get rid of the trouble surface and ask the
+                // app to request another one.
+                Slog.w(TAG_WM,
+                        "Looks like we have reclaimed some memory, clearing surface for retry.");
+                if (surfaceController != null) {
+                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
+                            "RECOVER DESTROY", false);
+                    winAnimator.destroySurface();
+                    mService.scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
+                }
+
+                try {
+                    winAnimator.mWin.mClient.dispatchGetNewSurface();
+                } catch (RemoteException e) {
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+
+        return leakedSurface || killedApps;
+    }
+
+    // "Something has changed!  Let's make it correct now."
+    // TODO: Super crazy long method that should be broken down...
+    void performSurfacePlacement(boolean recoveringMemory) {
+        if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+                + Debug.getCallers(3));
+
+        int i;
+        boolean updateInputWindowsNeeded = false;
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            updateInputWindowsNeeded = mService.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
+        }
+
+        // Initialize state of exiting tokens.
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mChildren.get(displayNdx);
+            for (i = displayContent.mExitingTokens.size() - 1; i >= 0; i--) {
+                displayContent.mExitingTokens.get(i).hasVisible = false;
+            }
+        }
+
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                exitingAppTokens.get(tokenNdx).hasVisible = false;
+            }
+        }
+
+        mHoldScreen = null;
+        mScreenBrightness = -1;
+        mButtonBrightness = -1;
+        mUserActivityTimeout = -1;
+        mObscureApplicationContentOnSecondaryDisplays = false;
+        mSustainedPerformanceModeCurrent = false;
+        mService.mTransactionSequence++;
+
+        // TODO(multi-display):
+        final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
+        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
+        final int defaultDw = defaultInfo.logicalWidth;
+        final int defaultDh = defaultInfo.logicalHeight;
+
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        mService.openSurfaceTransaction();
+        try {
+            applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
+        } catch (RuntimeException e) {
+            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            mService.closeSurfaceTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+        }
+
+        final WindowList defaultWindows = defaultDisplay.getWindowList();
+        final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
+
+        // If we are ready to perform an app transition, check through all of the app tokens to be
+        // shown and see if they are ready to go.
+        if (mService.mAppTransition.isReady()) {
+            defaultDisplay.pendingLayoutChanges |=
+                    surfacePlacer.handleAppTransitionReadyLocked(defaultWindows);
+            if (DEBUG_LAYOUT_REPEATS)
+                surfacePlacer.debugLayoutRepeats("after handleAppTransitionReadyLocked",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (!mService.mAnimator.mAppWindowAnimating && mService.mAppTransition.isRunning()) {
+            // We have finished the animation of an app transition. To do this, we have delayed a
+            // lot of operations like showing and hiding apps, moving apps in Z-order, etc. The app
+            // token list reflects the correct Z-order, but the window list may now be out of sync
+            // with it. So here we will just rebuild the entire app window list. Fun!
+            defaultDisplay.pendingLayoutChanges |=
+                    mService.handleAnimatingStoppedAndTransitionLocked();
+            if (DEBUG_LAYOUT_REPEATS)
+                surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
+                && !mService.mAppTransition.isReady()) {
+            // At this point, there was a window with a wallpaper that was force hiding other
+            // windows behind it, but now it is going away. This may be simple -- just animate away
+            // the wallpaper and its window -- or it may be hard -- the wallpaper now needs to be
+            // shown behind something that was hidden.
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
+                    "after animateAwayWallpaperLocked", defaultDisplay.pendingLayoutChanges);
+        }
+        mWallpaperForceHidingChanged = false;
+
+        if (mWallpaperMayChange) {
+            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            if (mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/)) {
+                updateInputWindowsNeeded = true;
+                defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
+            }
+        }
+
+        if (isLayoutNeeded()) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("mLayoutNeeded",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        for (i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
+            WindowState win = mService.mResizingWindows.get(i);
+            if (win.mAppFreezing) {
+                // Don't remove this window until rotation has completed.
+                continue;
+            }
+            // Discard the saved surface if window size is changed, it can't be reused.
+            if (win.mAppToken != null) {
+                win.mAppToken.destroySavedSurfaces();
+            }
+            win.reportResized();
+            mService.mResizingWindows.remove(i);
+        }
+
+        if (DEBUG_ORIENTATION && mService.mDisplayFrozen) Slog.v(TAG,
+                "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete);
+        if (mOrientationChangeComplete) {
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+                mService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
+                mService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
+            }
+            mService.stopFreezingDisplayLocked();
+        }
+
+        // Destroy the surface of any windows that are no longer visible.
+        boolean wallpaperDestroyed = false;
+        i = mService.mDestroySurface.size();
+        if (i > 0) {
+            do {
+                i--;
+                WindowState win = mService.mDestroySurface.get(i);
+                win.mDestroying = false;
+                if (mService.mInputMethodWindow == win) {
+                    mService.mInputMethodWindow = null;
+                }
+                if (mService.mWallpaperControllerLocked.isWallpaperTarget(win)) {
+                    wallpaperDestroyed = true;
+                }
+                win.destroyOrSaveSurface();
+            } while (i > 0);
+            mService.mDestroySurface.clear();
+        }
+
+        // Time to remove any exiting tokens?
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mChildren.get(displayNdx);
+            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
+            for (i = exitingTokens.size() - 1; i >= 0; i--) {
+                WindowToken token = exitingTokens.get(i);
+                if (!token.hasVisible) {
+                    exitingTokens.remove(i);
+                    if (token.windowType == TYPE_WALLPAPER) {
+                        mService.mWallpaperControllerLocked.removeWallpaperToken(token);
+                    }
+                }
+            }
+        }
+
+        // Time to remove any exiting applications?
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
+                final AppWindowToken token = exitingAppTokens.get(i);
+                if (!token.hasVisible && !mService.mClosingApps.contains(token) &&
+                        (!token.mIsExiting || token.isEmpty())) {
+                    // Make sure there is no animation running on this token, so any windows
+                    // associated with it will be removed as soon as their animations are complete
+                    token.mAppAnimator.clearAnimation();
+                    token.mAppAnimator.animating = false;
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
+                            "performLayout: App token exiting now removed" + token);
+                    token.removeIfPossible();
+                }
+            }
+        }
+
+        if (wallpaperDestroyed) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            defaultDisplay.setLayoutNeeded();
+        }
+
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mChildren.get(displayNdx);
+            if (displayContent.pendingLayoutChanges != 0) {
+                displayContent.setLayoutNeeded();
+            }
+        }
+
+        // Finally update all input windows now that the window changes have stabilized.
+        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+        mService.setHoldScreenLocked(mHoldScreen);
+        if (!mService.mDisplayFrozen) {
+            if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mScreenBrightness));
+            }
+            if (mButtonBrightness < 0 || mButtonBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mButtonBrightness));
+            }
+            mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
+                    mUserActivityTimeout);
+        }
+
+        if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
+            mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
+            mService.mPowerManagerInternal.powerHint(
+                    mService.mPowerManagerInternal.POWER_HINT_SUSTAINED_PERFORMANCE_MODE,
+                    (mSustainedPerformanceModeEnabled ? 1 : 0));
+        }
+
+        if (mService.mTurnOnScreen) {
+            if (mService.mAllowTheaterModeWakeFromLayout
+                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
+                    Settings.Global.THEATER_MODE_ON, 0) == 0) {
+                if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                    Slog.v(TAG, "Turning screen on after layout!");
+                }
+                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                        "android.server.wm:TURN_ON");
+            }
+            mService.mTurnOnScreen = false;
+        }
+
+        if (mUpdateRotation) {
+            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
+            if (mService.updateRotationUncheckedLocked(false)) {
+                mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
+            } else {
+                mUpdateRotation = false;
+            }
+        }
+
+        if (mService.mWaitingForDrawnCallback != null ||
+                (mOrientationChangeComplete && !defaultDisplay.isLayoutNeeded()
+                        && !mUpdateRotation)) {
+            mService.checkDrawnWindowsLocked();
+        }
+
+        final int N = mService.mPendingRemove.size();
+        if (N > 0) {
+            if (mService.mPendingRemoveTmp.length < N) {
+                mService.mPendingRemoveTmp = new WindowState[N+10];
+            }
+            mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
+            mService.mPendingRemove.clear();
+            DisplayContentList displayList = new DisplayContentList();
+            for (i = 0; i < N; i++) {
+                final WindowState w = mService.mPendingRemoveTmp[i];
+                w.removeImmediately();
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
+            }
+
+            for (DisplayContent displayContent : displayList) {
+                mService.mLayersController.assignLayersLocked(displayContent.getWindowList());
+                displayContent.setLayoutNeeded();
+            }
+        }
+
+        // Remove all deferred displays stacks, tasks, and activities.
+        for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
+            mChildren.get(displayNdx).checkCompleteDeferredRemoval();
+        }
+
+        if (updateInputWindowsNeeded) {
+            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
+        mService.setFocusTaskRegionLocked();
+
+        // Check to see if we are now in a state where the screen should
+        // be enabled, because the window obscured flags have changed.
+        mService.enableScreenIfNeededLocked();
+
+        mService.scheduleAnimationLocked();
+        mService.mWindowPlacerLocked.destroyPendingSurfaces();
+
+        if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
+                "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
+    }
+
+    // TODO: Super crazy long method that should be broken down...
+    private void applySurfaceChangesTransaction(boolean recoveringMemory, int defaultDw, int defaultDh) {
+        mHoldScreenWindow = null;
+        mObsuringWindow = null;
+
+        if (mService.mWatermark != null) {
+            mService.mWatermark.positionSurface(defaultDw, defaultDh);
+        }
+        if (mService.mStrictModeFlash != null) {
+            mService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
+        }
+        if (mService.mCircularDisplayMask != null) {
+            mService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mService.mRotation);
+        }
+        if (mService.mEmulatorDisplayOverlay != null) {
+            mService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
+                    mService.mRotation);
+        }
+
+        boolean focusDisplayed = false;
+
+        final int count = mChildren.size();
+        for (int j = 0; j < count; ++j) {
+            final DisplayContent dc = mChildren.get(j);
+            WindowList windows = dc.getWindowList();
+            DisplayInfo displayInfo = dc.getDisplayInfo();
+            final int displayId = dc.getDisplayId();
+            final int dw = displayInfo.logicalWidth;
+            final int dh = displayInfo.logicalHeight;
+            final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+            final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
+
+            // Reset for each display.
+            mDisplayHasContent = false;
+            mPreferredRefreshRate = 0;
+            mPreferredModeId = 0;
+            mTmpUpdateAllDrawn.clear();
+
+            int repeats = 0;
+            do {
+                repeats++;
+                if (repeats > 6) {
+                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
+                    dc.clearLayoutNeeded();
+                    break;
+                }
+
+                if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
+                        "On entry to LockedInner", dc.pendingLayoutChanges);
+
+                if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0
+                        && mService.mWallpaperControllerLocked.adjustWallpaperWindows()) {
+                    mService.mLayersController.assignLayersLocked(windows);
+                    dc.setLayoutNeeded();
+                }
+
+                if (isDefaultDisplay
+                        && (dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+                    if (mService.updateOrientationFromAppTokensLocked(true)) {
+                        dc.setLayoutNeeded();
+                        mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
+                    }
+                }
+
+                if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                    dc.setLayoutNeeded();
+                }
+
+                // FIRST LOOP: Perform a layout, if needed.
+                if (repeats < LAYOUT_REPEAT_THRESHOLD) {
+                    surfacePlacer.performLayoutLockedInner(dc, repeats == 1,
+                            false /* updateInputWindows */);
+                } else {
+                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
+                }
+
+                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
+                // it is animating.
+                dc.pendingLayoutChanges = 0;
+
+                if (isDefaultDisplay) {
+                    mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
+                    for (int i = windows.size() - 1; i >= 0; i--) {
+                        WindowState w = windows.get(i);
+                        if (w.mHasSurface) {
+                            mService.mPolicy.applyPostLayoutPolicyLw(
+                                    w, w.mAttrs, w.getParentWindow());
+                        }
+                    }
+                    dc.pendingLayoutChanges |=
+                            mService.mPolicy.finishPostLayoutPolicyLw();
+                    if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
+                            "after finishPostLayoutPolicyLw", dc.pendingLayoutChanges);
+                }
+            } while (dc.pendingLayoutChanges != 0);
+
+            mObscured = false;
+            mSyswin = false;
+            dc.resetDimming();
+
+            // Only used if default window
+            final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty();
+
+            for (int i = windows.size() - 1; i >= 0; i--) {
+                WindowState w = windows.get(i);
+                final Task task = w.getTask();
+                final boolean obscuredChanged = w.mObscured != mObscured;
+
+                // Update effect.
+                w.mObscured = mObscured;
+                if (!mObscured) {
+                    handleNotObscuredLocked(w, displayInfo);
+                }
+
+                w.applyDimLayerIfNeeded();
+
+                if (isDefaultDisplay && obscuredChanged && w.isVisibleLw()
+                        && mService.mWallpaperControllerLocked.isWallpaperTarget(w)) {
+                    // This is the wallpaper target and its obscured state changed... make sure the
+                    // current wallpaper's visibility has been updated accordingly.
+                    mService.mWallpaperControllerLocked.updateWallpaperVisibility();
+                }
+
+                w.handleWindowMovedIfNeeded();
+
+                final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+                w.mContentChanged = false;
+
+                // Moved from updateWindowsAndWallpaperLocked().
+                if (w.mHasSurface) {
+                    // Take care of the window being ready to display.
+                    final boolean committed = winAnimator.commitFinishDrawingLocked();
+                    if (isDefaultDisplay && committed) {
+                        if (w.mAttrs.type == TYPE_DREAM) {
+                            // HACK: When a dream is shown, it may at that point hide the lock
+                            // screen. So we need to redo the layout to let the phone window manager
+                            // make this happen.
+                            dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+                            if (DEBUG_LAYOUT_REPEATS) {
+                                surfacePlacer.debugLayoutRepeats(
+                                        "dream and commitFinishDrawingLocked true",
+                                        dc.pendingLayoutChanges);
+                            }
+                        }
+                        if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
+                            if (DEBUG_WALLPAPER_LIGHT)
+                                Slog.v(TAG, "First draw done in potential wallpaper target " + w);
+                            mWallpaperMayChange = true;
+                            dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                            if (DEBUG_LAYOUT_REPEATS) {
+                                surfacePlacer.debugLayoutRepeats(
+                                        "wallpaper and commitFinishDrawingLocked true",
+                                        dc.pendingLayoutChanges);
+                            }
+                        }
+                    }
+                    if (!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) {
+                        // Updates the shown frame before we set up the surface. This is needed
+                        // because the resizing could change the top-left position (in addition to
+                        // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
+                        // position the surface.
+                        //
+                        // If an animation is being started, we can't call this method because the
+                        // animation hasn't processed its initial transformation yet, but in general
+                        // we do want to update the position if the window is animating.
+                        winAnimator.computeShownFrameLocked();
+                    }
+                    winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
+                }
+
+                final AppWindowToken atoken = w.mAppToken;
+                if (atoken != null) {
+                    final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
+                    if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
+                        mTmpUpdateAllDrawn.add(atoken);
+                    }
+                }
+
+                if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus
+                        && w.isDisplayedLw()) {
+                    focusDisplayed = true;
+                }
+
+                w.updateResizingWindowIfNeeded();
+            }
+
+            mService.mDisplayManagerInternal.setDisplayProperties(displayId,
+                    mDisplayHasContent,
+                    mPreferredRefreshRate,
+                    mPreferredModeId,
+                    true /* inTraversal, must call performTraversalInTrans... below */);
+
+            dc.stopDimmingIfNeeded();
+
+            while (!mTmpUpdateAllDrawn.isEmpty()) {
+                final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
+                // See if any windows have been drawn, so they (and others associated with them)
+                // can now be shown.
+                atoken.updateAllDrawn(dc);
+            }
+        }
+
+        if (focusDisplayed) {
+            mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS);
+        }
+
+        // Give the display manager a chance to adjust properties
+        // like display rotation if it needs to.
+        mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+    }
+
+    /**
+     * @param w WindowState this method is applied to.
+     * @param dispInfo info of the display that the window's obscuring state is checked against.
+     */
+    private void handleNotObscuredLocked(final WindowState w, final DisplayInfo dispInfo) {
+        final WindowManager.LayoutParams attrs = w.mAttrs;
+        final int attrFlags = attrs.flags;
+        final boolean canBeSeen = w.isDisplayedLw();
+        final int privateflags = attrs.privateFlags;
+
+        if (canBeSeen && w.isObscuringFullscreen(dispInfo)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as undimmed (for
+            // performance reasons).
+            if (!mObscured) {
+                mObsuringWindow = w;
+            }
+
+            mObscured = true;
+        }
+
+        if (w.mHasSurface && canBeSeen) {
+            if ((attrFlags & FLAG_KEEP_SCREEN_ON) != 0) {
+                mHoldScreen = w.mSession;
+                mHoldScreenWindow = w;
+            } else if (DEBUG_KEEP_SCREEN_ON && w == mService.mLastWakeLockHoldingWindow) {
+                Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked: " + w + " was holding "
+                        + "screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by"
+                        + Debug.getCallers(10));
+            }
+            if (!mSyswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
+                mScreenBrightness = w.mAttrs.screenBrightness;
+            }
+            if (!mSyswin && w.mAttrs.buttonBrightness >= 0 && mButtonBrightness < 0) {
+                mButtonBrightness = w.mAttrs.buttonBrightness;
+            }
+            if (!mSyswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
+                mUserActivityTimeout = w.mAttrs.userActivityTimeout;
+            }
+
+            final int type = attrs.type;
+            if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
+                    || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                mSyswin = true;
+            }
+
+            // This function assumes that the contents of the default display are processed first
+            // before secondary displays.
+            final DisplayContent displayContent = w.getDisplayContent();
+            if (displayContent != null && displayContent.isDefaultDisplay) {
+                // While a dream or keyguard is showing, obscure ordinary application content on
+                // secondary displays (by forcibly enabling mirroring unless there is other content
+                // we want to show) but still allow opaque keyguard dialogs to be shown.
+                if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                    mObscureApplicationContentOnSecondaryDisplays = true;
+                }
+                mDisplayHasContent = true;
+            } else if (displayContent != null &&
+                    (!mObscureApplicationContentOnSecondaryDisplays
+                            || (mObscured && type == TYPE_KEYGUARD_DIALOG))) {
+                // Allow full screen keyguard presentation dialogs to be seen.
+                mDisplayHasContent = true;
+            }
+            if (mPreferredRefreshRate == 0 && w.mAttrs.preferredRefreshRate != 0) {
+                mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
+            }
+            if (mPreferredModeId == 0 && w.mAttrs.preferredDisplayModeId != 0) {
+                mPreferredModeId = w.mAttrs.preferredDisplayModeId;
+            }
+            if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
+                mSustainedPerformanceModeCurrent = true;
+            }
+        }
+    }
+
+    boolean copyAnimToLayoutParams() {
+        boolean doRequest = false;
+
+        final int bulkUpdateParams = mService.mAnimator.mBulkUpdateParams;
+        if ((bulkUpdateParams & SET_UPDATE_ROTATION) != 0) {
+            mUpdateRotation = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_MAY_CHANGE) != 0) {
+            mWallpaperMayChange = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+            mWallpaperForceHidingChanged = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
+            mOrientationChangeComplete = false;
+        } else {
+            mOrientationChangeComplete = true;
+            mLastWindowFreezeSource = mService.mAnimator.mLastWindowFreezeSource;
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                doRequest = true;
+            }
+        }
+        if ((bulkUpdateParams & SET_TURN_ON_SCREEN) != 0) {
+            mService.mTurnOnScreen = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
+            mWallpaperActionPending = true;
+        }
+
+        return doRequest;
+    }
+
+    private static int toBrightnessOverride(float value) {
+        return (int)(value * PowerManager.BRIGHTNESS_ON);
+    }
+
+    void enableSurfaceTrace(ParcelFileDescriptor pfd) {
+        final FileDescriptor fd = pfd.getFileDescriptor();
+        if (mSurfaceTraceEnabled) {
+            disableSurfaceTrace();
+        }
+        mSurfaceTraceEnabled = true;
+        mRemoteEventTrace = new RemoteEventTrace(mService, fd);
+        mSurfaceTraceFd = pfd;
+        for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent dc = mChildren.get(displayNdx);
+            dc.enableSurfaceTrace(fd);
+        }
+    }
+
+    void disableSurfaceTrace() {
+        mSurfaceTraceEnabled = false;
+        mRemoteEventTrace = null;
+        mSurfaceTraceFd = null;
+        for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent dc = mChildren.get(displayNdx);
+            dc.disableSurfaceTrace();
+        }
+    }
+
+    void dumpDisplayContents(PrintWriter pw) {
+        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
+        if (mService.mDisplayReady) {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; ++i) {
+                final DisplayContent displayContent = mChildren.get(i);
+                displayContent.dump("  ", pw);
+            }
+        } else {
+            pw.println("  NO DISPLAY");
+        }
+    }
+
+    void dumpLayoutNeededDisplayIds(PrintWriter pw) {
+        if (!isLayoutNeeded()) {
+            return;
+        }
+        pw.print("  mLayoutNeeded on displays=");
+        final int count = mChildren.size();
+        for (int displayNdx = 0; displayNdx < count; ++displayNdx) {
+            final DisplayContent displayContent = mChildren.get(displayNdx);
+            if (displayContent.isLayoutNeeded()) {
+                pw.print(displayContent.getDisplayId());
+            }
+        }
+        pw.println();
+    }
+
+    void dumpWindowsNoHeader(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) {
+        final int numDisplays = mChildren.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final WindowList windowList = mChildren.get(displayNdx).getWindowList();
+            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+                final WindowState w = windowList.get(winNdx);
+                if (windows == null || windows.contains(w)) {
+                    pw.println("  Window #" + winNdx + " " + w + ":");
+                    w.dump(pw, "    ", dumpAll || windows != null);
+                }
+            }
+        }
+    }
+
+    @Override
+    String getName() {
+        return "ROOT";
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index c118a21..83337ca 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -147,6 +147,8 @@
     private boolean mMoreStartFrame;
     long mHalfwayPoint;
 
+    private final WindowManagerService mService;
+
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
                 pw.print(" mWidth="); pw.print(mWidth);
@@ -216,7 +218,8 @@
 
     public ScreenRotationAnimation(Context context, DisplayContent displayContent,
             SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation,
-            boolean isSecure) {
+            boolean isSecure, WindowManagerService service) {
+        mService = service;
         mContext = context;
         mDisplayContent = displayContent;
         displayContent.getLogicalDisplayRect(mOriginalDisplayRect);
@@ -253,7 +256,7 @@
         if (!inTransaction) {
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
         }
 
         try {
@@ -295,7 +298,7 @@
             setRotationInTransaction(originalRotation);
         } finally {
             if (!inTransaction) {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation");
             }
@@ -546,7 +549,7 @@
             if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     TAG_WM,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
 
             // Compute the transformation matrix that must be applied
             // the the black frame to make it stay in the initial position
@@ -566,7 +569,7 @@
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         TAG_WM,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -577,7 +580,7 @@
             if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     TAG_WM,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
             try {
                 // Compute the transformation matrix that must be applied
                 // the the black frame to make it stay in the initial position
@@ -606,7 +609,7 @@
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         TAG_WM,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -617,7 +620,7 @@
             if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                     TAG_WM,
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
 
             try {
                 Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
@@ -628,7 +631,7 @@
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                         TAG_WM,
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index cb99461..edd3a3b 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -202,7 +202,7 @@
 
     @Override
     public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
-        mService.setReplacingWindows(appToken, childrenOnly);
+        mService.setWillReplaceWindows(appToken, childrenOnly);
     }
 
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
@@ -346,7 +346,7 @@
             final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl;
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                     TAG_WM, ">>> OPEN TRANSACTION performDrag");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
             try {
                 surfaceControl.setPosition(touchX - thumbCenterX,
                         touchY - thumbCenterY);
@@ -354,7 +354,7 @@
                 surfaceControl.setLayerStack(display.getLayerStack());
                 surfaceControl.show();
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                         TAG_WM, "<<< CLOSE TRANSACTION performDrag");
             }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 048d980..f6598c1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,18 +17,14 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import android.app.ActivityManager.StackId;
 import android.content.pm.ActivityInfo;
@@ -43,9 +39,8 @@
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
-class Task implements DimLayer.DimLayerUser {
+class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
     // Return value from {@link setBounds} indicating no change was made to the Task bounds.
     static final int BOUNDS_CHANGE_NONE = 0;
@@ -54,8 +49,8 @@
     // Return value from {@link setBounds} indicating the size of the Task bounds changed.
     static final int BOUNDS_CHANGE_SIZE = 1 << 1;
 
+    // TODO: Track parent marks like this in WindowContainer.
     TaskStack mStack;
-    final AppTokenList mAppTokens = new AppTokenList();
     final int mTaskId;
     final int mUserId;
     boolean mDeferRemoval = false;
@@ -73,11 +68,7 @@
     int mRotation;
 
     // Whether mBounds is fullscreen
-    private boolean mFullscreen = true;
-
-    // Contains configurations settings that are different from the global configuration due to
-    // stack specific operations. E.g. {@link #setBounds}.
-    Configuration mOverrideConfig = Configuration.EMPTY;
+    private boolean mFillsParent = true;
 
     // For comparison with DisplayContent bounds.
     private Rect mTmpRect = new Rect();
@@ -97,13 +88,13 @@
     private boolean mIsOnTopLauncher;
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
-            Configuration config, boolean isOnTopLauncher) {
+            Configuration overrideConfig, boolean isOnTopLauncher) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
         mIsOnTopLauncher = isOnTopLauncher;
-        setBounds(bounds, config);
+        setBounds(bounds, overrideConfig);
     }
 
     DisplayContent getDisplayContent() {
@@ -111,18 +102,23 @@
     }
 
     void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
-        final int lastPos = mAppTokens.size();
+        final int lastPos = mChildren.size();
         if (addPos >= lastPos) {
             addPos = lastPos;
         } else {
             for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
-                if (mAppTokens.get(pos).removed) {
+                if (mChildren.get(pos).removed) {
                     // addPos assumes removed tokens are actually gone.
                     ++addPos;
                 }
             }
         }
-        mAppTokens.add(addPos, wtoken);
+
+        final WindowContainer parent = wtoken.getParent();
+        if (parent != null) {
+            parent.removeChild(wtoken);
+        }
+        addChild(wtoken, addPos);
         wtoken.mTask = this;
         mDeferRemoval = false;
         mResizeMode = resizeMode;
@@ -130,15 +126,16 @@
     }
 
     private boolean hasWindowsAlive() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            if (mAppTokens.get(i).hasWindowsAlive()) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if (mChildren.get(i).hasWindowsAlive()) {
                 return true;
             }
         }
         return false;
     }
 
-    void removeLocked() {
+    @Override
+    void removeIfPossible() {
         if (hasWindowsAlive() && mStack.isAnimating()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
             mDeferRemoval = true;
@@ -151,10 +148,11 @@
         if (content != null) {
             content.mDimLayerController.removeDimLayerUser(this);
         }
-        mStack.removeTask(this);
+        getParent().removeChild(this);
         mService.mTaskIdToTask.delete(mTaskId);
     }
 
+    // Change to use reparenting in WC when TaskStack is switched to use WC.
     void moveTaskToStack(TaskStack stack, boolean toTop) {
         if (stack == mStack) {
             return;
@@ -162,9 +160,7 @@
         if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
-        if (mStack != null) {
-            mStack.removeTask(this);
-        }
+        getParent().removeChild(this);
         stack.addTask(this, toTop);
     }
 
@@ -173,57 +169,60 @@
             if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
                     + " from stack=" + mStack);
             EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
-            mStack.removeTask(this);
+            mStack.removeChild(this);
         }
         stack.positionTask(this, position, showForAllUsers());
         resizeLocked(bounds, config, false /* force */);
 
-        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            mAppTokens.get(activityNdx).notifyMovedInStack();
+        for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
+            mChildren.get(activityNdx).notifyMovedInStack();
         }
     }
 
-    boolean removeAppToken(AppWindowToken wtoken) {
-        boolean removed = mAppTokens.remove(wtoken);
-        if (mAppTokens.size() == 0) {
+    @Override
+    void removeChild(AppWindowToken token) {
+        if (!mChildren.contains(token)) {
+            Slog.e(TAG, "removeChild: token=" + this + " not found.");
+            return;
+        }
+
+        super.removeChild(token);
+
+        if (mChildren.isEmpty()) {
             EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
             if (mDeferRemoval) {
-                removeLocked();
+                removeIfPossible();
             }
         }
-        wtoken.mTask = null;
-        /* Leave mTaskId for now, it might be useful for debug
-        wtoken.mTaskId = -1;
-         */
-        return removed;
+        token.mTask = null;
     }
 
     void setSendingToBottom(boolean toBottom) {
-        for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
-            mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
+        for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
+            mChildren.get(appTokenNdx).sendingToBottom = toBottom;
         }
     }
 
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    private int setBounds(Rect bounds, Configuration config) {
-        if (config == null) {
-            config = Configuration.EMPTY;
+    private int setBounds(Rect bounds, Configuration overrideConfig) {
+        if (overrideConfig == null) {
+            overrideConfig = Configuration.EMPTY;
         }
-        if (bounds == null && !Configuration.EMPTY.equals(config)) {
+        if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) {
             throw new IllegalArgumentException("null bounds but non empty configuration: "
-                    + config);
+                    + overrideConfig);
         }
-        if (bounds != null && Configuration.EMPTY.equals(config)) {
+        if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) {
             throw new IllegalArgumentException("non null bounds, but empty configuration");
         }
-        boolean oldFullscreen = mFullscreen;
+        boolean oldFullscreen = mFillsParent;
         int rotation = Surface.ROTATION_0;
         final DisplayContent displayContent = mStack.getDisplayContent();
         if (displayContent != null) {
             displayContent.getLogicalDisplayRect(mTmpRect);
             rotation = displayContent.getDisplayInfo().rotation;
-            mFullscreen = bounds == null;
-            if (mFullscreen) {
+            mFillsParent = bounds == null;
+            if (mFillsParent) {
                 bounds = mTmpRect;
             }
         }
@@ -232,7 +231,7 @@
             // Can't set to fullscreen if we don't have a display to get bounds from...
             return BOUNDS_CHANGE_NONE;
         }
-        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+        if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
             return BOUNDS_CHANGE_NONE;
         }
 
@@ -250,7 +249,7 @@
         if (displayContent != null) {
             displayContent.mDimLayerController.updateDimLayer(this);
         }
-        mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
+        onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
         return boundsChange;
     }
 
@@ -295,12 +294,8 @@
         return mHomeTask;
     }
 
-    private boolean inCropWindowsResizeMode() {
-        return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
-    }
-
-    boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
-        int boundsChanged = setBounds(bounds, configuration);
+    boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) {
+        int boundsChanged = setBounds(bounds, overrideConfig);
         if (forced) {
             boundsChanged |= BOUNDS_CHANGE_SIZE;
         }
@@ -308,9 +303,9 @@
             return false;
         }
         if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
-            resizeWindows();
+            onResize();
         } else {
-            moveWindows();
+            onMovedByResize();
         }
         return true;
     }
@@ -321,8 +316,7 @@
      */
     void prepareFreezingBounds() {
         mPreparedFrozenBounds.set(mBounds);
-        mPreparedFrozenMergedConfig.setTo(mService.mCurConfiguration);
-        mPreparedFrozenMergedConfig.updateFrom(mOverrideConfig);
+        mPreparedFrozenMergedConfig.setTo(getConfiguration());
     }
 
     /**
@@ -334,9 +328,9 @@
      *                    bounds's bottom; false if the task's top should be aligned
      *                    the adjusted bounds's top.
      */
-    void alignToAdjustedBounds(
-            Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
-        if (!isResizeable() || mOverrideConfig == Configuration.EMPTY) {
+    void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
+        final Configuration overrideConfig = getOverrideConfiguration();
+        if (!isResizeable() || Configuration.EMPTY.equals(overrideConfig)) {
             return;
         }
 
@@ -348,19 +342,16 @@
             mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
         }
         setTempInsetBounds(tempInsetBounds);
-        resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
+        resizeLocked(mTmpRect2, overrideConfig, false /* forced */);
     }
 
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
         final DisplayContent displayContent = mStack.getDisplayContent();
-        if (mFullscreen
+        return mFillsParent
                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
                 || displayContent == null
-                || displayContent.getDockedStackVisibleForUserLocked() != null) {
-            return true;
-        }
-        return false;
+                || displayContent.getDockedStackVisibleForUserLocked() != null;
     }
 
     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
@@ -391,8 +382,8 @@
      */
     boolean getMaxVisibleBounds(Rect out) {
         boolean foundTop = false;
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken token = mAppTokens.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final AppWindowToken token = mChildren.get(i);
             // skip hidden (or about to hide) apps
             if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
                 continue;
@@ -428,14 +419,14 @@
         final DisplayContent displayContent = mStack.getDisplayContent();
         // It doesn't matter if we in particular are part of the resize, since we couldn't have
         // a DimLayer anyway if we weren't visible.
-        final boolean dockedResizing = displayContent != null ?
-                displayContent.mDividerControllerLocked.isResizing() : false;
+        final boolean dockedResizing = displayContent != null
+                && displayContent.mDividerControllerLocked.isResizing();
         if (useCurrentBounds()) {
             if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
                 return;
             }
 
-            if (!mFullscreen) {
+            if (!mFillsParent) {
                 // When minimizing the docked stack when going home, we don't adjust the task bounds
                 // so we need to intersect the task bounds with the stack bounds here.
                 //
@@ -455,10 +446,11 @@
             return;
         }
 
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
-        displayContent.getLogicalDisplayRect(out);
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
+        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
+        if (displayContent != null) {
+            displayContent.getLogicalDisplayRect(out);
+        }
     }
 
     void setDragResizing(boolean dragResizing, int dragResizeMode) {
@@ -473,41 +465,19 @@
         }
     }
 
-    void resetDragResizingChangeReported() {
-        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            mAppTokens.get(activityNdx).resetDragResizingChangeReported();
-        }
-    }
-
     boolean isDragResizing() {
-        return mDragResizing || (mStack != null && mStack.isDragResizing());
+        return mDragResizing;
     }
 
     int getDragResizeMode() {
         return mDragResizeMode;
     }
 
-    /**
-     * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
-     * resizing state of the window has been changed.
-     */
-    void setWaitingForDrawnIfResizingChanged() {
-        for (int i = mAppTokens.size() - 1; i >= 0; --i) {
-            mAppTokens.get(i).setWaitingForDrawnIfResizingChanged();
-        }
-    }
-
-    void detachDisplay() {
-        for (int i = mAppTokens.size() - 1; i >= 0; --i) {
-            mAppTokens.get(i).detachDisplay();
-        }
-    }
-
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
-        if (mFullscreen) {
+        if (mFillsParent) {
             setBounds(null, Configuration.EMPTY);
             return;
         }
@@ -524,12 +494,12 @@
         mTmpRect2.set(mBounds);
 
         if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
-            setBounds(mTmpRect2, mOverrideConfig);
+            setBounds(mTmpRect2, getOverrideConfiguration());
             return;
         }
 
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
-        if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
+        if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
             // Post message to inform activity manager of the bounds change simulating a one-way
             // call. We do this to prevent a deadlock between window manager lock and activity
             // manager lock been held.
@@ -538,59 +508,23 @@
         }
     }
 
-    void resizeWindows() {
-        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            mAppTokens.get(activityNdx).resizeWindows();
-        }
-    }
-
-    void moveWindows() {
-        for (int i = mAppTokens.size() - 1; i >= 0; --i) {
-            mAppTokens.get(i).moveWindows();
-        }
-    }
-
-    /**
-     * Cancels any running app transitions associated with the task.
-     */
+    /** Cancels any running app transitions associated with the task. */
     void cancelTaskWindowTransition() {
-        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            mAppTokens.get(activityNdx).mAppAnimator.clearAnimation();
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            mChildren.get(i).mAppAnimator.clearAnimation();
         }
     }
 
-    /**
-     * Cancels any running thumbnail transitions associated with the task.
-     */
+    /** Cancels any running thumbnail transitions associated with the task. */
     void cancelTaskThumbnailTransition() {
-        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
-            mAppTokens.get(activityNdx).mAppAnimator.clearThumbnail();
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            mChildren.get(i).mAppAnimator.clearThumbnail();
         }
     }
 
     boolean showForAllUsers() {
-        final int tokensCount = mAppTokens.size();
-        return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
-    }
-
-    boolean isVisibleForUser() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken appToken = mAppTokens.get(i);
-            if (appToken.isVisibleForUser()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    boolean isVisible() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken appToken = mAppTokens.get(i);
-            if (appToken.isVisible()) {
-                return true;
-            }
-        }
-        return false;
+        final int tokensCount = mChildren.size();
+        return (tokensCount != 0) && mChildren.get(tokensCount - 1).showForAllUsers;
     }
 
     boolean inHomeStack() {
@@ -615,8 +549,8 @@
     }
 
     AppWindowToken getTopVisibleAppToken() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken token = mAppTokens.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final AppWindowToken token = mChildren.get(i);
             // skip hidden (or about to hide) apps
             if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
                 return token;
@@ -625,10 +559,6 @@
         return null;
     }
 
-    AppWindowToken getTopAppToken() {
-        return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null;
-    }
-
     @Override
     public boolean dimFullscreen() {
         return isHomeTask() || isFullscreen();
@@ -636,7 +566,7 @@
 
     boolean isFullscreen() {
         if (useCurrentBounds()) {
-            return mFullscreen;
+            return mFillsParent;
         }
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
@@ -650,29 +580,68 @@
     }
 
     void forceWindowsScaleable(boolean force) {
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
-            for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-                mAppTokens.get(i).forceWindowsScaleableInTransaction(force);
+            for (int i = mChildren.size() - 1; i >= 0; i--) {
+                mChildren.get(i).forceWindowsScaleableInTransaction(force);
             }
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
         }
     }
 
-    boolean isAnimating() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken aToken = mAppTokens.get(i);
-            if (aToken.isAnimating()) {
-                return true;
+    void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token,
+            DisplayContent.GetWindowOnDisplaySearchResult result) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final AppWindowToken current = mChildren.get(i);
+            if (current == token) {
+                // We have reach the token we are interested in. End search.
+                result.reachedToken = true;
+                return;
+            }
+
+            // We haven't reached the token yet; if this token is not going to the bottom and
+            // has windows on this display, then it is a candidate for what we are looking for.
+            final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current);
+            if (!current.sendingToBottom && tokenWindowList.size() > 0) {
+                result.foundWindow = tokenWindowList.get(0);
             }
         }
-        return false;
+    }
+
+    void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token,
+            DisplayContent.GetWindowOnDisplaySearchResult result) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final AppWindowToken current = mChildren.get(i);
+            if (!result.reachedToken) {
+                if (current == token) {
+                    // We have reached the token we are interested in. Get whichever window occurs
+                    // after it that is on the same display.
+                    result.reachedToken = true;
+                }
+                continue;
+            }
+
+            final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current);
+            if (tokenWindowList.size() > 0) {
+                result.foundWindow = tokenWindowList.get(tokenWindowList.size() - 1);
+                return;
+            }
+        }
+    }
+
+    @Override
+    boolean fillsParent() {
+        return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
     }
 
     @Override
     public String toString() {
-        return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
+        return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
+    }
+
+    String getName() {
+        return toShortString();
     }
 
     @Override
@@ -684,16 +653,16 @@
         final String doublePrefix = prefix + "  ";
 
         pw.println(prefix + "taskId=" + mTaskId);
-        pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
+        pw.println(doublePrefix + "mFillsParent=" + mFillsParent);
         pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
         pw.println(doublePrefix + "mdr=" + mDeferRemoval);
-        pw.println(doublePrefix + "appTokens=" + mAppTokens);
+        pw.println(doublePrefix + "appTokens=" + mChildren);
         pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
 
         final String triplePrefix = doublePrefix + "  ";
 
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken wtoken = mAppTokens.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final AppWindowToken wtoken = mChildren.get(i);
             pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
             wtoken.dump(pw, triplePrefix);
         }
diff --git a/services/core/java/com/android/server/wm/TaskGroup.java b/services/core/java/com/android/server/wm/TaskGroup.java
deleted file mode 100644
index 1f1dd58..0000000
--- a/services/core/java/com/android/server/wm/TaskGroup.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2013 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.wm;
-
-import android.view.IApplicationToken;
-
-import java.util.ArrayList;
-
-public class TaskGroup {
-    public int taskId = -1;
-    public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
-
-    @Override
-    public String toString() {
-        return "id=" + taskId + " tokens=" + tokens;
-    }
-}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 5c321a1..6887312 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -459,13 +459,13 @@
         mCurrentDimSide = dimSide;
 
         if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION updateDimLayerVisibility");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         if (mCurrentDimSide == CTRL_NONE) {
             mDimLayer.hide();
         } else {
             showDimLayer();
         }
-        SurfaceControl.closeTransaction();
+        mService.closeSurfaceTransaction();
     }
 
     /**
@@ -477,8 +477,8 @@
      */
     private int getDimSide(int x) {
         if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
-                || !mTask.mStack.isFullscreen()
-                || mService.mCurConfiguration.orientation != ORIENTATION_LANDSCAPE) {
+                || !mTask.mStack.fillsParent()
+                || mTask.mStack.getConfiguration().orientation != ORIENTATION_LANDSCAPE) {
             return CTRL_NONE;
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index d2ec792..e98fc39 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,7 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.DOCKED_BOTTOM;
@@ -29,6 +30,7 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
@@ -36,6 +38,7 @@
 import android.app.ActivityManager.StackId;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Debug;
 import android.os.RemoteException;
 import android.util.EventLog;
@@ -43,17 +46,16 @@
 import android.util.SparseArray;
 import android.view.DisplayInfo;
 import android.view.Surface;
-import android.view.SurfaceControl;
 
+import android.view.WindowManagerPolicy;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
-public class TaskStack implements DimLayer.DimLayerUser,
+public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLayerUser,
         BoundsAnimationController.AnimateBoundsUser {
     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
      * restrict IME adjustment so that a min portion of top stack remains visible.*/
@@ -69,12 +71,9 @@
     private final WindowManagerService mService;
 
     /** The display this stack sits under. */
+    // TODO: Track parent marks like this in WindowContainer.
     private DisplayContent mDisplayContent;
 
-    /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
-     * mTaskHistory in the ActivityStack with the same mStackId */
-    private final ArrayList<Task> mTasks = new ArrayList<>();
-
     /** For comparison with DisplayContent bounds. */
     private Rect mTmpRect = new Rect();
     private Rect mTmpRect2 = new Rect();
@@ -92,7 +91,7 @@
     private final Rect mFullyAdjustedImeBounds = new Rect();
 
     /** Whether mBounds is fullscreen */
-    private boolean mFullscreen = true;
+    private boolean mFillsParent = true;
 
     // Device rotation as of the last time {@link #mBounds} was set.
     int mRotation;
@@ -110,10 +109,8 @@
     final AppTokenList mExitingAppTokens = new AppTokenList();
 
     /** Detach this stack from its display when animation completes. */
-    boolean mDeferDetach;
-
-    // Whether the stack and all its tasks is currently being drag-resized
-    private boolean mDragResizing;
+    // TODO: maybe tie this to WindowContainer#removeChild some how...
+    boolean mDeferRemoval;
 
     private final Rect mTmpAdjustedBounds = new Rect();
     private boolean mAdjustedForIme;
@@ -124,11 +121,9 @@
     private float mAdjustDividerAmount;
     private final int mDockedStackMinimizeThickness;
 
-    // If this is true, we are in the bounds animating mode.
-    // The task will be down or upscaled to perfectly fit the
-    // region it would have been cropped to. We may also avoid
-    // certain logic we would otherwise apply while resizing,
-    // while resizing in the bounds animating mode.
+    // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
+    // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
+    // would otherwise apply while resizing, while resizing in the bounds animating mode.
     private boolean mBoundsAnimating = false;
 
     // Temporary storage for the new bounds that should be used after the configuration change.
@@ -147,23 +142,27 @@
         return mDisplayContent;
     }
 
-    ArrayList<Task> getTasks() {
-        return mTasks;
-    }
-
     Task findHomeTask() {
         if (mStackId != HOME_STACK_ID) {
             return null;
         }
 
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            if (mTasks.get(i).isHomeTask()) {
-                return mTasks.get(i);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            if (mChildren.get(i).isHomeTask()) {
+                return mChildren.get(i);
             }
         }
         return null;
     }
 
+    boolean hasMultipleTaskWithHomeTaskNotTop() {
+        return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
+    }
+
+    boolean topTaskIsOnTopLauncher() {
+        return mChildren.get(mChildren.size() - 1).isOnTopLauncher();
+    }
+
     /**
      * Set the bounds of the stack and its containing tasks.
      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
@@ -177,8 +176,8 @@
         setBounds(stackBounds);
 
         // Update bounds of containing tasks.
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mTasks.get(taskNdx);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
             Configuration config = configs.get(task.mTaskId);
             if (config != null) {
                 Rect bounds = taskBounds.get(task.mTaskId);
@@ -193,8 +192,8 @@
     }
 
     void prepareFreezingTaskBounds() {
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mTasks.get(taskNdx);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
             task.prepareFreezingBounds();
         }
     }
@@ -231,33 +230,33 @@
             }
         }
         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
-        mDisplayContent.layoutNeeded = true;
+        mDisplayContent.setLayoutNeeded();
     }
 
     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
-        if (mFullscreen) {
+        if (mFillsParent) {
             return;
         }
 
         final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
 
         // Update bounds of containing tasks.
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mTasks.get(taskNdx);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
             task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
         }
     }
 
     private boolean setBounds(Rect bounds) {
-        boolean oldFullscreen = mFullscreen;
+        boolean oldFullscreen = mFillsParent;
         int rotation = Surface.ROTATION_0;
         int density = DENSITY_DPI_UNDEFINED;
         if (mDisplayContent != null) {
             mDisplayContent.getLogicalDisplayRect(mTmpRect);
             rotation = mDisplayContent.getDisplayInfo().rotation;
             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
-            mFullscreen = bounds == null;
-            if (mFullscreen) {
+            mFillsParent = bounds == null;
+            if (mFillsParent) {
                 bounds = mTmpRect;
             }
         }
@@ -266,7 +265,7 @@
             // Can't set to fullscreen if we don't have a display to get bounds from...
             return false;
         }
-        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+        if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
             return false;
         }
 
@@ -294,7 +293,7 @@
 
     /** Return true if the current bound can get outputted to the rest of the system as-is. */
     private boolean useCurrentBounds() {
-        if (mFullscreen
+        if (mFillsParent
                 || !StackId.isResizeableByDockedStack(mStackId)
                 || mDisplayContent == null
                 || mDisplayContent.getDockedStackLocked() != null) {
@@ -334,13 +333,13 @@
             return;
         }
 
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            mChildren.get(taskNdx).updateDisplayInfo(mDisplayContent);
         }
         if (bounds != null) {
             setBounds(bounds);
             return;
-        } else if (mFullscreen) {
+        } else if (mFillsParent) {
             setBounds(null);
             return;
         }
@@ -355,11 +354,8 @@
         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
     }
 
-    boolean onConfigurationChanged() {
-        return updateBoundsAfterConfigChange();
-    }
-
-    private boolean updateBoundsAfterConfigChange() {
+    /** @return true if bounds were updated to some non-empty value. */
+    boolean updateBoundsAfterConfigChange() {
         if (mDisplayContent == null) {
             // If the stack is already detached we're not updating anything,
             // as it's going away soon anyway.
@@ -373,30 +369,28 @@
             return false;
         }
 
-        if (mFullscreen) {
+        if (mFillsParent) {
             // Update stack bounds again since rotation changed since updateDisplayInfo().
             setBounds(null);
             // Return false since we don't need the client to resize.
             return false;
         }
 
-        final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
         mTmpRect2.set(mBounds);
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (mStackId == DOCKED_STACK_ID) {
             repositionDockedStackAfterRotation(mTmpRect2);
             snapDockedStackAfterRotation(mTmpRect2);
             final int newDockSide = getDockSide(mTmpRect2);
-            if (oldDockSide != newDockSide) {
-                // Update the dock create mode and clear the dock create bounds, these
-                // might change after a rotation and the original values will be invalid.
-                mService.setDockedStackCreateStateLocked(
-                        (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
-                        ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
-                        : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
-                        null);
-                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
-            }
+
+            // Update the dock create mode and clear the dock create bounds, these
+            // might change after a rotation and the original values will be invalid.
+            mService.setDockedStackCreateStateLocked(
+                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
+                    ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
+                    : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
+                    null);
+            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
         }
 
         mBoundsAfterRotation.set(mTmpRect2);
@@ -462,7 +456,7 @@
 
         // Snap the position to a target.
         final int rotation = displayInfo.rotation;
-        final int orientation = mService.mCurConfiguration.orientation;
+        final int orientation = mDisplayContent.getConfiguration().orientation;
         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
                 mService.mContext.getResources(), displayWidth, displayHeight,
@@ -475,16 +469,7 @@
                 dividerSize);
     }
 
-    boolean isAnimating() {
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mTasks.get(taskNdx);
-            if (task.isAnimating()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
+    // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
     void addTask(Task task, boolean toTop) {
         addTask(task, toTop, task.showForAllUsers());
     }
@@ -496,14 +481,19 @@
      * @param showForAllUsers Whether to show the task regardless of the current user.
      */
     void addTask(Task task, boolean toTop, boolean showForAllUsers) {
-        positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
+        positionTask(task, toTop ? mChildren.size() : 0, showForAllUsers);
     }
 
+    // TODO: We should really have users as a window container in the hierarchy so that we don't
+    // have to do complicated things like we are doing in this method and also also the method to
+    // just be WindowContainer#addChild
     void positionTask(Task task, int position, boolean showForAllUsers) {
         final boolean canShowTask =
                 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
-        mTasks.remove(task);
-        int stackSize = mTasks.size();
+        if (mChildren.contains(task)) {
+            super.removeChild(task);
+        }
+        int stackSize = mChildren.size();
         int minPosition = 0;
         int maxPosition = stackSize;
 
@@ -517,11 +507,13 @@
 
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
                 "positionTask: task=" + task + " position=" + position);
-        mTasks.add(position, task);
+        addChild(task, position);
         task.mStack = this;
         task.updateDisplayInfo(mDisplayContent);
-        boolean toTop = position == mTasks.size() - 1;
+        boolean toTop = position == mChildren.size() - 1;
         if (toTop) {
+            // TODO: Have a WidnowContainer method that moves all parents of a container to the
+            // front for cases like this.
             mDisplayContent.moveStack(this, true);
         }
 
@@ -543,7 +535,7 @@
      */
     private int computeMinPosition(int minPosition, int size) {
         while (minPosition < size) {
-            final Task tmpTask = mTasks.get(minPosition);
+            final Task tmpTask = mChildren.get(minPosition);
             final boolean canShowTmpTask =
                     tmpTask.showForAllUsers()
                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
@@ -562,7 +554,7 @@
      */
     private int computeMaxPosition(int maxPosition) {
         while (maxPosition > 0) {
-            final Task tmpTask = mTasks.get(maxPosition - 1);
+            final Task tmpTask = mChildren.get(maxPosition - 1);
             final boolean canShowTmpTask =
                     tmpTask.showForAllUsers()
                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
@@ -574,16 +566,17 @@
         return maxPosition;
     }
 
+    // TODO: Have functionality in WC to move things to the bottom or top. Also, look at the call
+    // points for this methods to see if we need functionality to move something to the front/bottom
+    // with its parents.
     void moveTaskToTop(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
                 + Debug.getCallers(6));
-        mTasks.remove(task);
         addTask(task, true);
     }
 
     void moveTaskToBottom(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
-        mTasks.remove(task);
         addTask(task, false);
     }
 
@@ -592,14 +585,17 @@
      * back.
      * @param task The Task to delete.
      */
-    void removeTask(Task task) {
-        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
-        mTasks.remove(task);
+    @Override
+    void removeChild(Task task) {
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
+
+        super.removeChild(task);
+
         if (mDisplayContent != null) {
-            if (mTasks.isEmpty()) {
+            if (mChildren.isEmpty()) {
                 mDisplayContent.moveStack(this, false);
             }
-            mDisplayContent.layoutNeeded = true;
+            mDisplayContent.setLayoutNeeded();
         }
         for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
             final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
@@ -623,7 +619,7 @@
         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
         if (mStackId == DOCKED_STACK_ID
                 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
-                        && !dockedStack.isFullscreen())) {
+                        && !dockedStack.fillsParent())) {
             // The existence of a docked stack affects the size of other static stack created since
             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
             // not fullscreen. If it's fullscreen, it means that we are in the transition of
@@ -657,7 +653,7 @@
             throw new IllegalStateException(
                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
         }
-        if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
+        if (!ignoreVisibility && !dockedStack.isVisible()) {
             // The docked stack is being dismissed, but we caught before it finished being
             // dismissed. In that case we want to treat it as if it is not occupying any space and
             // let others occupy the whole display.
@@ -714,7 +710,7 @@
                     di.logicalWidth,
                     di.logicalHeight,
                     dockDividerWidth,
-                    mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
+                    mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
                     mTmpRect2).getMiddleTarget().position;
 
             if (dockOnTopOrLeft) {
@@ -763,14 +759,34 @@
                 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
     }
 
-    void detachDisplay() {
+    @Override
+    void removeIfPossible() {
+        if (isAnimating()) {
+            mDeferRemoval = true;
+            return;
+        }
+        removeImmediately();
+    }
+
+    @Override
+    void removeImmediately() {
+        super.removeImmediately();
+
+        mDisplayContent.mDimLayerController.removeDimLayerUser(this);
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
 
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            mTasks.get(taskNdx).detachDisplay();
+        if (mAnimationBackgroundSurface != null) {
+            mAnimationBackgroundSurface.destroySurface();
+            mAnimationBackgroundSurface = null;
         }
+        mDisplayContent = null;
 
-        close();
+        mService.mWindowPlacerLocked.requestTraversal();
+
+        if (mStackId == DOCKED_STACK_ID) {
+            mService.getDefaultDisplayContentLocked().mDividerControllerLocked
+                    .notifyDockedStackExistsChanged(false);
+        }
     }
 
     void resetAnimationBackgroundAnimator() {
@@ -789,26 +805,19 @@
         }
     }
 
+    // TODO: Should each user have there own stacks?
     void switchUser() {
-        int top = mTasks.size();
+        int top = mChildren.size();
         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
-            Task task = mTasks.get(taskNdx);
+            Task task = mChildren.get(taskNdx);
             if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
-                mTasks.remove(taskNdx);
-                mTasks.add(task);
+                mChildren.remove(taskNdx);
+                mChildren.add(task);
                 --top;
             }
         }
     }
 
-    void close() {
-        if (mAnimationBackgroundSurface != null) {
-            mAnimationBackgroundSurface.destroySurface();
-            mAnimationBackgroundSurface = null;
-        }
-        mDisplayContent = null;
-    }
-
     /**
      * Adjusts the stack bounds if the IME is visible.
      *
@@ -847,7 +856,7 @@
             mAdjustImeAmount = adjustAmount;
             mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
-            return isVisibleForUserLocked();
+            return isVisible(true /* ignoreKeyguard */);
         } else {
             return false;
         }
@@ -883,7 +892,7 @@
         if (minimizeAmount != mMinimizeAmount) {
             mMinimizeAmount = minimizeAmount;
             updateAdjustedBounds();
-            return isVisibleForUserLocked();
+            return isVisible(true /* ignoreKeyguard */);
         } else {
             return false;
         }
@@ -898,9 +907,9 @@
      * to the list of to be drawn windows the service is waiting for.
      */
     void beginImeAdjustAnimation() {
-        for (int j = mTasks.size() - 1; j >= 0; j--) {
-            final Task task = mTasks.get(j);
-            if (task.isVisibleForUser()) {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final Task task = mChildren.get(j);
+            if (task.hasContentToDisplay()) {
                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
                 task.setWaitingForDrawnIfResizingChanged();
             }
@@ -911,8 +920,8 @@
      * Resets the resizing state of all windows.
      */
     void endImeAdjustAnimation() {
-        for (int j = mTasks.size() - 1; j >= 0; j--) {
-            mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
         }
     }
 
@@ -1068,7 +1077,7 @@
 
         final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
-        mDisplayContent.layoutNeeded = true;
+        mDisplayContent.setLayoutNeeded();
     }
 
     boolean isAdjustedForMinimizedDockedStack() {
@@ -1077,11 +1086,11 @@
 
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "mStackId=" + mStackId);
-        pw.println(prefix + "mDeferDetach=" + mDeferDetach);
-        pw.println(prefix + "mFullscreen=" + mFullscreen);
+        pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
+        pw.println(prefix + "mFillsParent=" + mFillsParent);
         pw.println(prefix + "mBounds=" + mBounds.toShortString());
         if (mMinimizeAmount != 0f) {
-            pw.println(prefix + "mMinimizeAmout=" + mMinimizeAmount);
+            pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
         }
         if (mAdjustedForIme) {
             pw.println(prefix + "mAdjustedForIme=true");
@@ -1091,8 +1100,8 @@
         if (!mAdjustedBounds.isEmpty()) {
             pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
         }
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
-            mTasks.get(taskNdx).dump(prefix + "  ", pw);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
+            mChildren.get(taskNdx).dump(prefix + "  ", pw);
         }
         if (mAnimationBackgroundSurface.isDimming()) {
             pw.println(prefix + "mWindowAnimationBackgroundSurface:");
@@ -1113,20 +1122,21 @@
 
     /** Fullscreen status of the stack without adjusting for other factors in the system like
      * visibility of docked stack.
-     * Most callers should be using {@link #isFullscreen} as it take into consideration other
+     * Most callers should be using {@link #fillsParent} as it take into consideration other
      * system factors. */
     boolean getRawFullscreen() {
-        return mFullscreen;
+        return mFillsParent;
     }
 
     @Override
     public boolean dimFullscreen() {
-        return mStackId == HOME_STACK_ID || isFullscreen();
+        return mStackId == HOME_STACK_ID || fillsParent();
     }
 
-    boolean isFullscreen() {
+    @Override
+    boolean fillsParent() {
         if (useCurrentBounds()) {
-            return mFullscreen;
+            return mFillsParent;
         }
         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
@@ -1141,7 +1151,11 @@
 
     @Override
     public String toString() {
-        return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
+        return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
+    }
+
+    String getName() {
+        return toShortString();
     }
 
     @Override
@@ -1165,7 +1179,7 @@
             return DOCKED_INVALID;
         }
         mDisplayContent.getLogicalDisplayRect(mTmpRect);
-        final int orientation = mService.mCurConfiguration.orientation;
+        final int orientation = mDisplayContent.getConfiguration().orientation;
         return getDockSideUnchecked(bounds, mTmpRect, orientation);
     }
 
@@ -1189,51 +1203,134 @@
         }
     }
 
-    boolean isVisibleLocked() {
+    boolean isVisible() {
+        return isVisible(false /* ignoreKeyguard */);
+    }
+
+    boolean isVisible(boolean ignoreKeyguard) {
         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
                 && !mService.mAnimator.mKeyguardGoingAway;
-        if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
+        if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
             return false;
         }
 
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            final Task task = mTasks.get(i);
-            for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
-                if (!task.mAppTokens.get(j).hidden) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
+        return super.isVisible();
     }
 
-    /**
-     * @return true if a the stack is visible for the current in user, ignoring any other visibility
-     *         aspects, and false otherwise
-     */
-    boolean isVisibleForUserLocked() {
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            final Task task = mTasks.get(i);
-            if (task.isVisibleForUser()) {
+    boolean hasTaskForUser(int userId) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final Task task = mChildren.get(i);
+            if (task.mUserId == userId) {
                 return true;
             }
         }
         return false;
     }
 
-    boolean isDragResizing() {
-        return mDragResizing;
+    int taskIdFromPoint(int x, int y) {
+        getBounds(mTmpRect);
+        if (!mTmpRect.contains(x, y) || isAdjustedForMinimizedDockedStack()) {
+            return -1;
+        }
+
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
+            final WindowState win = task.getTopVisibleAppMainWindow();
+            if (win == null) {
+                continue;
+            }
+            // We need to use the task's dim bounds (which is derived from the visible bounds of its
+            // apps windows) for any touch-related tests. Can't use the task's original bounds
+            // because it might be adjusted to fit the content frame. For example, the presence of
+            // the IME adjusting the windows frames when the app window is the IME target.
+            task.getDimBounds(mTmpRect);
+            if (mTmpRect.contains(x, y)) {
+                return task.mTaskId;
+            }
+        }
+
+        return -1;
     }
 
-    void setDragResizingLocked(boolean resizing) {
-        if (mDragResizing == resizing) {
+    void findTaskForResizePoint(int x, int y, int delta,
+            DisplayContent.TaskForResizePointSearchResult results) {
+        if (!StackId.isTaskResizeAllowed(mStackId)) {
+            results.searchDone = true;
             return;
         }
-        mDragResizing = resizing;
-        for (int i = mTasks.size() - 1; i >= 0 ; i--) {
-            mTasks.get(i).resetDragResizingChangeReported();
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            if (task.isFullscreen()) {
+                results.searchDone = true;
+                return;
+            }
+
+            // We need to use the task's dim bounds (which is derived from the visible bounds of
+            // its apps windows) for any touch-related tests. Can't use the task's original
+            // bounds because it might be adjusted to fit the content frame. One example is when
+            // the task is put to top-left quadrant, the actual visible area would not start at
+            // (0,0) after it's adjusted for the status bar.
+            task.getDimBounds(mTmpRect);
+            mTmpRect.inset(-delta, -delta);
+            if (mTmpRect.contains(x, y)) {
+                mTmpRect.inset(delta, delta);
+
+                results.searchDone = true;
+
+                if (!mTmpRect.contains(x, y)) {
+                    results.taskForResize = task;
+                    return;
+                }
+                // User touched inside the task. No need to look further,
+                // focus transfer will be handled in ACTION_UP.
+                return;
+            }
+        }
+    }
+
+    void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
+            Rect contentRect, Rect postExclude) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            AppWindowToken token = task.getTopVisibleAppToken();
+            if (token == null || !token.hasContentToDisplay()) {
+                continue;
+            }
+
+            /**
+             * Exclusion region is the region that TapDetector doesn't care about.
+             * Here we want to remove all non-focused tasks from the exclusion region.
+             * We also remove the outside touch area for resizing for all freeform
+             * tasks (including the focused).
+             *
+             * We save the focused task region once we find it, and add it back at the end.
+             */
+
+            task.getDimBounds(mTmpRect);
+
+            if (task == focusedTask) {
+                // Add the focused task rect back into the exclude region once we are done
+                // processing stacks.
+                postExclude.set(mTmpRect);
+            }
+
+            final boolean isFreeformed = task.inFreeformWorkspace();
+            if (task != focusedTask || isFreeformed) {
+                if (isFreeformed) {
+                    // If the task is freeformed, enlarge the area to account for outside
+                    // touch area for resize.
+                    mTmpRect.inset(-delta, -delta);
+                    // Intersect with display content rect. If we have system decor (status bar/
+                    // navigation bar), we want to exclude that from the tap detection.
+                    // Otherwise, if the app is partially placed under some system button (eg.
+                    // Recents, Home), pressing that button would cause a full series of
+                    // unwanted transfer focus/resume/pause, before we could go home.
+                    mTmpRect.intersect(contentRect);
+                }
+                touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            }
         }
     }
 
@@ -1317,4 +1414,69 @@
     public boolean getBoundsAnimating() {
         return mBoundsAnimating;
     }
+
+    /** Returns true if a removal action is still being deferred. */
+    boolean checkCompleteDeferredRemoval() {
+        if (isAnimating()) {
+            return true;
+        }
+        if (mDeferRemoval) {
+            removeImmediately();
+        }
+
+        return super.checkCompleteDeferredRemoval();
+    }
+
+    void stepAppWindowsAnimation(long currentTime, int displayId) {
+        super.stepAppWindowsAnimation(currentTime, displayId);
+
+        // TODO: Why aren't we just using the loop above for this? mAppAnimator.animating isn't set
+        // below but is set in the loop above. See if it really matters...
+        final int exitingCount = mExitingAppTokens.size();
+        for (int i = 0; i < exitingCount; i++) {
+            final AppWindowAnimator appAnimator = mExitingAppTokens.get(i).mAppAnimator;
+            appAnimator.wasAnimating = appAnimator.animating;
+            if (appAnimator.stepAnimationLocked(currentTime, displayId)) {
+                mService.mAnimator.setAnimating(true);
+                mService.mAnimator.mAppWindowAnimating = true;
+            } else if (appAnimator.wasAnimating) {
+                // stopped animating, do one more pass through the layout
+                appAnimator.mAppToken.setAppLayoutChanges(
+                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
+                if (DEBUG_ANIM) Slog.v(TAG_WM,
+                        "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
+            }
+        }
+    }
+
+    void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token,
+            DisplayContent.GetWindowOnDisplaySearchResult result) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            task.getWindowOnDisplayBeforeToken(dc, token, result);
+            if (result.reachedToken) {
+                // We have reach the token we are interested in. End search.
+                return;
+            }
+        }
+    }
+
+    void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token,
+            DisplayContent.GetWindowOnDisplaySearchResult result) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            task.getWindowOnDisplayAfterToken(dc, token, result);
+            if (result.foundWindow != null) {
+                // We have found a window after the token. End search.
+                return;
+            }
+        }
+    }
+
+    @Override
+    int getOrientation() {
+        return (StackId.canSpecifyOrientation(mStackId))
+                ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 0310b97..dd9ba73 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -64,7 +64,7 @@
             case MotionEvent.ACTION_HOVER_MOVE: {
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
-                final Task task = mDisplayContent.findTaskForControlPoint(x, y);
+                final Task task = mDisplayContent.findTaskForResizePoint(x, y);
                 int iconType = TYPE_NOT_SPECIFIED;
                 if (task != null) {
                     task.getDimBounds(mTmpRect);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index b269d4c..58439eb 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -641,7 +641,7 @@
     }
 
     boolean adjustWallpaperWindows() {
-        mService.mWindowPlacerLocked.mWallpaperMayChange = false;
+        mService.mRoot.mWallpaperMayChange = false;
 
         final WindowList windows = mService.getDefaultWindowListLocked();
         // First find top-most window that has asked to be on top of the wallpaper;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 34fa1b0..fb6b09a 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -29,7 +29,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -41,7 +40,6 @@
 import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
 
 import android.content.Context;
@@ -121,6 +119,9 @@
 
     private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
 
+    /** The window that was previously hiding the Keyguard. */
+    private WindowState mLastShowWinWhenLocked;
+
     private String forceHidingToString() {
         switch (mForceHiding) {
             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
@@ -166,59 +167,21 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    private void updateAppWindowsLocked(int displayId) {
-        ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = stacks.get(stackNdx);
-            final ArrayList<Task> tasks = stack.getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
-                    appAnimator.wasAnimating = appAnimator.animating;
-                    if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
-                        appAnimator.animating = true;
-                        setAnimating(true);
-                        mAppWindowAnimating = true;
-                    } else if (appAnimator.wasAnimating) {
-                        // stopped animating, do one more pass through the layout
-                        setAppLayoutChanges(appAnimator,
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                "appToken " + appAnimator.mAppToken + " done", displayId);
-                        if (DEBUG_ANIM) Slog.v(TAG,
-                                "updateWindowsApps...: done animating " + appAnimator.mAppToken);
-                    }
-                }
-            }
-
-            mTmpExitingAppTokens.clear();
-            mTmpExitingAppTokens.addAll(stack.mExitingAppTokens);
-
-            final int exitingCount = mTmpExitingAppTokens.size();
-            for (int i = 0; i < exitingCount; i++) {
-                final AppWindowAnimator appAnimator = mTmpExitingAppTokens.get(i).mAppAnimator;
-                // stepAnimation can trigger finishExit->removeWindowInnerLocked
-                // ->performSurfacePlacement
-                // performSurfacePlacement will directly manipulate the mExitingAppTokens list
-                // so we need to iterate over a copy and check for modifications.
-                if (!stack.mExitingAppTokens.contains(appAnimator)) {
-                    continue;
-                }
-                appAnimator.wasAnimating = appAnimator.animating;
-                if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
-                    setAnimating(true);
-                    mAppWindowAnimating = true;
-                } else if (appAnimator.wasAnimating) {
-                    // stopped animating, do one more pass through the layout
-                    setAppLayoutChanges(appAnimator,
-                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                            "exiting appToken " + appAnimator.mAppToken + " done", displayId);
-                    if (DEBUG_ANIM) Slog.v(TAG,
-                            "updateWindowsApps...: done animating exiting "
-                                    + appAnimator.mAppToken);
-                }
-            }
+    /**
+     * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard,
+     *         and it's still animating.
+     */
+    private WindowState getWinShowWhenLockedOrAnimating() {
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        if (winShowWhenLocked != null) {
+            return winShowWhenLocked;
         }
+        if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen()
+                && mLastShowWinWhenLocked.isAnimatingLw()
+                && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+            return mLastShowWinWhenLocked;
+        }
+        return null;
     }
 
     private boolean shouldForceHide(WindowState win) {
@@ -227,7 +190,7 @@
                 ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
                         || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
 
-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating();
         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
                 null : winShowWhenLocked.mAppToken;
 
@@ -241,7 +204,7 @@
             allowWhenLocked |= appShowWhenLocked == win.mAppToken
                     // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen
                     || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
-                    // Show error dialogs over apps that dismiss keyguard.
+                    // Show error dialogs over apps that are shown on lockscreen
                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
         }
 
@@ -556,10 +519,15 @@
                 mPostKeyguardExitAnimation = null;
             }
         }
+
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        if (winShowWhenLocked != null) {
+            mLastShowWinWhenLocked = winShowWhenLocked;
+        }
     }
 
     private void updateWallpaperLocked(int displayId) {
-        mService.getDisplayContentLocked(displayId).resetAnimationBackgroundAnimator();
+        mService.mRoot.getDisplayContentOrCreate(displayId).resetAnimationBackgroundAnimator();
 
         final WindowList windows = mService.getWindowListLocked(displayId);
         WindowState detachedWallpaper = null;
@@ -623,54 +591,6 @@
         }
     }
 
-    /** See if any windows have been drawn, so they (and others associated with them) can now be
-     *  shown. */
-    private void testTokenMayBeDrawnLocked(int displayId) {
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        final ArrayList<Task> tasks = mService.getDisplayContentLocked(displayId).getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-                final boolean allDrawn = wtoken.allDrawn;
-                if (allDrawn != appAnimator.allDrawn) {
-                    appAnimator.allDrawn = allDrawn;
-                    if (allDrawn) {
-                        // The token has now changed state to having all
-                        // windows shown...  what to do, what to do?
-                        if (appAnimator.freezingScreen) {
-                            appAnimator.showAllWindowsLocked();
-                            wtoken.stopFreezingScreen(false, true);
-                            if (DEBUG_ORIENTATION) Slog.i(TAG,
-                                    "Setting mOrientationChangeComplete=true because wtoken "
-                                    + wtoken + " numInteresting=" + wtoken.numInterestingWindows
-                                    + " numDrawn=" + wtoken.numDrawnWindows);
-                            // This will set mOrientationChangeComplete and cause a pass through
-                            // layout.
-                            setAppLayoutChanges(appAnimator,
-                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                    "testTokenMayBeDrawnLocked: freezingScreen", displayId);
-                        } else {
-                            setAppLayoutChanges(appAnimator,
-                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                                    "testTokenMayBeDrawnLocked", displayId);
-
-                            // We can now show all of the drawn windows!
-                            if (!mService.mOpeningApps.contains(wtoken)) {
-                                orAnimating(appAnimator.showAllWindowsLocked());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-
     /** Locked on mService.mWindowMap. */
     private void animateLocked(long frameTimeNs) {
         if (!mInitialized) {
@@ -688,13 +608,15 @@
 
         if (SHOW_TRANSACTIONS) Slog.i(
                 TAG, ">>> OPEN TRANSACTION animateLocked");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         SurfaceControl.setAnimationTransaction();
         try {
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
-                updateAppWindowsLocked(displayId);
+                final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(
+                        displayId);
+                displayContent.stepAppWindowsAnimation(mCurrentTime);
                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                 final ScreenRotationAnimation screenRotationAnimation =
@@ -732,8 +654,10 @@
 
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
+                final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(
+                        displayId);
 
-                testTokenMayBeDrawnLocked(displayId);
+                displayContent.checkAppWindowsReadyToShow();
 
                 final ScreenRotationAnimation screenRotationAnimation =
                         mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
@@ -741,12 +665,10 @@
                     screenRotationAnimation.updateSurfacesInTransaction();
                 }
 
-                orAnimating(mService.getDisplayContentLocked(displayId).animateDimLayers());
-                orAnimating(mService.getDisplayContentLocked(displayId).getDockedDividerController()
-                        .animate(mCurrentTime));
+                orAnimating(displayContent.animateDimLayers());
+                orAnimating(displayContent.getDockedDividerController().animate(mCurrentTime));
                 //TODO (multidisplay): Magnification is supported only for the default display.
-                if (mService.mAccessibilityController != null
-                        && displayId == Display.DEFAULT_DISPLAY) {
+                if (mService.mAccessibilityController != null && displayContent.isDefaultDisplay) {
                     mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
                 }
             }
@@ -765,27 +687,15 @@
         } catch (RuntimeException e) {
             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_TRANSACTIONS) Slog.i(
                     TAG, "<<< CLOSE TRANSACTION animateLocked");
         }
 
-        boolean hasPendingLayoutChanges = false;
-        final int numDisplays = mService.mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
-            if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
-            }
-            if (pendingChanges != 0) {
-                hasPendingLayoutChanges = true;
-            }
-        }
-
+        boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
         boolean doRequest = false;
         if (mBulkUpdateParams != 0) {
-            doRequest = mWindowPlacerLocked.copyAnimToLayoutParamsLocked();
+            doRequest = mService.mRoot.copyAnimToLayoutParams();
         }
 
         if (hasPendingLayoutChanges || doRequest) {
@@ -804,7 +714,8 @@
         }
 
         if (mRemoveReplacedWindows) {
-            removeReplacedWindowsLocked();
+            mService.mRoot.removeReplacedWindows();
+            mRemoveReplacedWindows = false;
         }
 
         mService.stopUsingSavedSurfaceLocked();
@@ -819,28 +730,6 @@
         }
     }
 
-    private void removeReplacedWindowsLocked() {
-        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows");
-        SurfaceControl.openTransaction();
-        try {
-            for (int i = mService.mDisplayContents.size() - 1; i >= 0; i--) {
-                DisplayContent display = mService.mDisplayContents.valueAt(i);
-                final WindowList windows = mService.getWindowListLocked(display.getDisplayId());
-                for (int j = windows.size() - 1; j >= 0; j--) {
-                    final WindowState win = windows.get(j);
-                    final AppWindowToken aToken = win.mAppToken;
-                    if (aToken != null) {
-                        aToken.removeReplacedWindowIfNeeded(win);
-                    }
-                }
-            }
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
-        }
-        mRemoveReplacedWindows = false;
-    }
-
     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
         StringBuilder builder = new StringBuilder(128);
         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
@@ -911,7 +800,7 @@
         if (displayId < 0) {
             return 0;
         }
-        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
@@ -919,17 +808,12 @@
         if (displayId < 0) {
             return;
         }
-        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
         if (displayContent != null) {
             displayContent.pendingLayoutChanges |= changes;
         }
     }
 
-    void setAppLayoutChanges(
-            AppWindowAnimator appAnimator, int changes, String reason, int displayId) {
-        appAnimator.mAppToken.setAppLayoutChanges(changes, reason, displayId);
-    }
-
     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
         if (displayAnimator == null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8cf89ec..902f4ae 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -17,29 +17,70 @@
 package com.android.server.wm;
 
 import android.annotation.CallSuper;
+import android.content.res.Configuration;
+import android.view.animation.Animation;
 
 import java.util.Comparator;
 import java.util.LinkedList;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
 /**
  * Defines common functionality for classes that can hold windows directly or through their
- * children.
+ * children in a hierarchy form.
  * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
  * changes are made to this class.
  */
-class WindowContainer {
+class WindowContainer<E extends WindowContainer> implements Comparable<WindowContainer> {
 
-    // The parent of this window container.
+    /**
+     * The parent of this window container.
+     * For removing or setting new parent {@link #setParent} should be used, because it also
+     * performs configuration updates based on new parent's settings.
+     */
     private WindowContainer mParent = null;
 
     // List of children for this window container. List is in z-order as the children appear on
     // screen with the top-most window container at the tail of the list.
-    protected final LinkedList<WindowContainer> mChildren = new LinkedList();
+    protected final LinkedList<E> mChildren = new LinkedList();
 
-    protected WindowContainer getParent() {
+    /** Contains override configuration settings applied to this window container. */
+    private Configuration mOverrideConfiguration = new Configuration();
+
+    /**
+     * Contains full configuration applied to this window container. Corresponds to full parent's
+     * config with applied {@link #mOverrideConfiguration}.
+     */
+    private Configuration mFullConfiguration = new Configuration();
+
+    /**
+     * Contains merged override configuration settings from the top of the hierarchy down to this
+     * particular instance. It is different from {@link #mFullConfiguration} because it starts from
+     * topmost container's override config instead of global config.
+     */
+    private Configuration mMergedOverrideConfiguration = new Configuration();
+
+    // The specified orientation for this window container.
+    protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+    final protected WindowContainer getParent() {
         return mParent;
     }
 
+    final protected void setParent(WindowContainer parent) {
+        mParent = parent;
+        // Update full configuration of this container and all its children.
+        onConfigurationChanged(mParent != null ? mParent.mFullConfiguration : Configuration.EMPTY);
+        // Update merged override configuration of this container and all its children.
+        onMergedOverrideConfigurationChanged();
+    }
+
+    // Temp. holders for a chain of containers we are currently processing.
+    private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
+    private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
+
     /**
      * Adds the input window container has a child of this container in order based on the input
      * comparator.
@@ -48,8 +89,13 @@
      *                   If null, the child will be added to the top.
      */
     @CallSuper
-    protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
-        child.mParent = this;
+    protected void addChild(E child, Comparator<E> comparator) {
+        if (child.getParent() != null) {
+            throw new IllegalArgumentException("addChild: container=" + child.getName()
+                    + " is already a child of container=" + child.getParent().getName()
+                    + " can't add to container=" + getName());
+        }
+        child.setParent(this);
 
         if (mChildren.isEmpty() || comparator == null) {
             mChildren.add(child);
@@ -67,17 +113,66 @@
         mChildren.add(child);
     }
 
-    /** Removes this window container and its children */
+    /** Adds the input window container has a child of this container at the input index. */
     @CallSuper
-    void remove() {
+    protected void addChild(E child, int index) {
+        if (child.getParent() != null) {
+            throw new IllegalArgumentException("addChild: container=" + child.getName()
+                    + " is already a child of container=" + child.getParent().getName()
+                    + " can't add to container=" + getName());
+        }
+        child.setParent(this);
+        mChildren.add(index, child);
+    }
+
+    /**
+     * Removes the input child container from this container which is its parent.
+     *
+     * @return True if the container did contain the input child and it was detached.
+     */
+    @CallSuper
+    void removeChild(E child) {
+        if (mChildren.remove(child)) {
+            child.setParent(null);
+        } else {
+            throw new IllegalArgumentException("removeChild: container=" + child.getName()
+                    + " is not a child of container=" + getName());
+        }
+    }
+
+    /**
+     * Removes this window container and its children with no regard for what else might be going on
+     * in the system. For example, the container will be removed during animation if this method is
+     * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
+     * which allows the system to defer removal until a suitable time.
+     */
+    @CallSuper
+    void removeImmediately() {
         while (!mChildren.isEmpty()) {
-            final WindowContainer child = mChildren.removeLast();
-            child.remove();
+            final WindowContainer child = mChildren.peekLast();
+            child.removeImmediately();
+            // Need to do this after calling remove on the child because the child might try to
+            // remove/detach itself from its parent which will cause an exception if we remove
+            // it before calling remove on the child.
+            mChildren.remove(child);
         }
 
         if (mParent != null) {
-            mParent.mChildren.remove(this);
-            mParent = null;
+            mParent.removeChild(this);
+        }
+    }
+
+    /**
+     * Removes this window container and its children taking care not to remove them during a
+     * critical stage in the system. For example, some containers will not be removed during
+     * animation if this method is called.
+     */
+    // TODO: figure-out implementation that works best for this.
+    // E.g. when do we remove from parent list? maybe not...
+    void removeIfPossible() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.removeIfPossible();
         }
     }
 
@@ -91,4 +186,384 @@
         }
         return false;
     }
+
+    /**
+     * Returns full configuration applied to this window container.
+     * This method should be used for getting settings applied in each particular level of the
+     * hierarchy.
+     */
+    Configuration getConfiguration() {
+        return mFullConfiguration;
+    }
+
+    /**
+     * Notify that parent config changed and we need to update full configuration.
+     * @see #mFullConfiguration
+     */
+    void onConfigurationChanged(Configuration newParentConfig) {
+        mFullConfiguration.setTo(newParentConfig);
+        mFullConfiguration.updateFrom(mOverrideConfiguration);
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mChildren.get(i);
+            child.onConfigurationChanged(mFullConfiguration);
+        }
+    }
+
+    /** Returns override configuration applied to this window container. */
+    Configuration getOverrideConfiguration() {
+        return mOverrideConfiguration;
+    }
+
+    /**
+     * Update override configuration and recalculate full config.
+     * @see #mOverrideConfiguration
+     * @see #mFullConfiguration
+     */
+    void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+        mOverrideConfiguration.setTo(overrideConfiguration);
+        // Update full configuration of this container and all its children.
+        onConfigurationChanged(mParent != null ? mParent.getConfiguration() : Configuration.EMPTY);
+        // Update merged override config of this container and all its children.
+        onMergedOverrideConfigurationChanged();
+    }
+
+    /**
+     * Get merged override configuration from the top of the hierarchy down to this
+     * particular instance. This should be reported to client as override config.
+     */
+    Configuration getMergedOverrideConfiguration() {
+        return mMergedOverrideConfiguration;
+    }
+
+    /**
+     * Update merged override configuration based on corresponding parent's config and notify all
+     * its children. If there is no parent, merged override configuration will set equal to current
+     * override config.
+     * @see #mMergedOverrideConfiguration
+     */
+    private void onMergedOverrideConfigurationChanged() {
+        if (mParent != null) {
+            mMergedOverrideConfiguration.setTo(mParent.getMergedOverrideConfiguration());
+            mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
+        } else {
+            mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
+        }
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mChildren.get(i);
+            child.onMergedOverrideConfigurationChanged();
+        }
+    }
+
+    void setWaitingForDrawnIfResizingChanged() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.setWaitingForDrawnIfResizingChanged();
+        }
+    }
+
+    void onResize() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.onResize();
+        }
+    }
+
+    void onMovedByResize() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.onMovedByResize();
+        }
+    }
+
+    void resetDragResizingChangeReported() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.resetDragResizingChangeReported();
+        }
+    }
+
+    void forceWindowsScaleableInTransaction(boolean force) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.forceWindowsScaleableInTransaction(force);
+        }
+    }
+
+    boolean isAnimating() {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final WindowContainer wc = mChildren.get(j);
+            if (wc.isAnimating()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void sendAppVisibilityToClients() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.sendAppVisibilityToClients();
+        }
+    }
+
+    void setVisibleBeforeClientHidden() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.setVisibleBeforeClientHidden();
+        }
+    }
+
+    /**
+     * Returns true if the container or one of its children as some content it can display or wants
+     * to display (e.g. app views or saved surface).
+     *
+     * NOTE: While this method will return true if the there is some content to display, it doesn't
+     * mean the container is visible. Use {@link #isVisible()} to determine if the container is
+     * visible.
+     */
+    boolean hasContentToDisplay() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            if (wc.hasContentToDisplay()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the container or one of its children is considered visible from the
+     * WindowManager perspective which usually means valid surface and some other internal state
+     * are true.
+     *
+     * NOTE: While this method will return true if the surface is visible, it doesn't mean the
+     * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
+     * the container has any content to display.
+     */
+    boolean isVisible() {
+        // TODO: Will this be more correct if it checks the visibility of its parents?
+        // It depends...For example, Tasks and Stacks are only visible if there children are visible
+        // but, WindowState are not visible if there parent are not visible. Maybe have the
+        // container specify which direction to treverse for for visibility?
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            if (wc.isVisible()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Returns the top child container or this container if there are no children. */
+    WindowContainer getTop() {
+        return mChildren.isEmpty() ? this : mChildren.peekLast();
+    }
+
+    /** Returns true if there is still a removal being deferred */
+    boolean checkCompleteDeferredRemoval() {
+        boolean stillDeferringRemoval = false;
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            stillDeferringRemoval |= wc.checkCompleteDeferredRemoval();
+        }
+
+        return stillDeferringRemoval;
+    }
+
+    /** Checks if all windows in an app are all drawn and shows them if needed. */
+    // TODO: The displayId shouldn't be needed as there shouldn't be a container on more than one
+    // display. Remove once we migrate DisplayContent to use WindowContainer.
+    void checkAppWindowsReadyToShow(int displayId) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.checkAppWindowsReadyToShow(displayId);
+        }
+    }
+
+    /** Step currently ongoing animation for App window containers. */
+    // TODO: The displayId shouldn't be needed as there shouldn't be a container on more than one
+    // display. Remove once we migrate DisplayContent to use WindowContainer.
+    void stepAppWindowsAnimation(long currentTime, int displayId) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.stepAppWindowsAnimation(currentTime, displayId);
+        }
+    }
+
+    void onAppTransitionDone() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+            wc.onAppTransitionDone();
+        }
+    }
+
+    void overridePlayingAppAnimations(Animation a) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            mChildren.get(i).overridePlayingAppAnimations(a);
+        }
+    }
+
+    void setOrientation(int orientation) {
+        mOrientation = orientation;
+    }
+
+    /**
+     * Returns the specified orientation for this window container or one of its children is there
+     * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
+     * specification is set.
+     * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
+     * specification...
+     */
+    int getOrientation() {
+
+        if (!fillsParent() || !isVisible()) {
+            // Ignore invisible containers or containers that don't completely fills their parents.
+            return SCREEN_ORIENTATION_UNSET;
+        }
+
+        // The container fills its parent so we can use it orientation if it has one specified,
+        // otherwise we prefer to use the orientation of its topmost child that has one
+        // specified and fall back on this container's unset or unspecified value as a candidate
+        // if none of the children have a better candidate for the orientation.
+        if (mOrientation != SCREEN_ORIENTATION_UNSET
+                && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+            return mOrientation;
+        }
+        int candidate = mOrientation;
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = mChildren.get(i);
+
+            final int orientation = wc.getOrientation();
+            if (orientation == SCREEN_ORIENTATION_BEHIND) {
+                // container wants us to use the orientation of the container behind it. See if we
+                // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
+                // look behind this container.
+                candidate = orientation;
+                continue;
+            }
+
+            if (orientation == SCREEN_ORIENTATION_UNSET) {
+                continue;
+            }
+
+            if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+                // Use the orientation if the container fills its parent or requested an explicit
+                // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
+                return orientation;
+            }
+        }
+
+        return candidate;
+    }
+
+    /**
+     * Returns true if this container is opaque and fills all the space made available by its parent
+     * container.
+     *
+     * NOTE: It is possible for this container to occupy more space than the parent has (or less),
+     * this is just a signal from the client to window manager stating its intent, but not what it
+     * actually does.
+     */
+    boolean fillsParent() {
+        return false;
+    }
+
+    /**
+     * Rebuilds the WindowList for the input display content.
+     * @param dc The display content to rebuild the window list for.
+     * @param addIndex The index in the window list to add the next entry to.
+     * @return The next index in the window list to.
+     */
+    // TODO: Hoping we can get rid of WindowList so this method wouldn't be needed.
+    int rebuildWindowList(DisplayContent dc, int addIndex) {
+        final int count = mChildren.size();
+        for (int i = 0; i < count; i++) {
+            final WindowContainer wc = mChildren.get(i);
+            addIndex = wc.rebuildWindowList(dc, addIndex);
+        }
+        return addIndex;
+    }
+
+    /**
+     * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
+     * the input container in terms of z-order.
+     */
+    @Override
+    public int compareTo(WindowContainer other) {
+        if (this == other) {
+            return 0;
+        }
+
+        if (mParent != null && mParent == other.mParent) {
+            final LinkedList<WindowContainer> list = mParent.mChildren;
+            return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
+        }
+
+        final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
+        final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
+        getParents(thisParentChain);
+        other.getParents(otherParentChain);
+
+        // Find the common ancestor of both containers.
+        WindowContainer commonAncestor = null;
+        WindowContainer thisTop = thisParentChain.peekLast();
+        WindowContainer otherTop = otherParentChain.peekLast();
+        while (thisTop != null && otherTop != null && thisTop == otherTop) {
+            commonAncestor = thisParentChain.removeLast();
+            otherParentChain.removeLast();
+            thisTop = thisParentChain.peekLast();
+            otherTop = otherParentChain.peekLast();
+        }
+
+        // Containers don't belong to the same hierarchy???
+        if (commonAncestor == null) {
+            throw new IllegalArgumentException("No in the same hierarchy this="
+                    + thisParentChain + " other=" + otherParentChain);
+        }
+
+        // Children are always considered greater than their parents, so if one of the containers
+        // we are comparing it the parent of the other then whichever is the child is greater.
+        if (commonAncestor == this) {
+            return -1;
+        } else if (commonAncestor == other) {
+            return 1;
+        }
+
+        // The position of the first non-common ancestor in the common ancestor list determines
+        // which is greater the which.
+        final LinkedList<WindowContainer> list = commonAncestor.mChildren;
+        return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
+                ? 1 : -1;
+    }
+
+    private void getParents(LinkedList<WindowContainer> parents) {
+        parents.clear();
+        WindowContainer current = this;
+        do {
+            parents.addLast(current);
+            current = current.mParent;
+        } while (current != null);
+    }
+
+    /**
+     * Dumps the names of this container children in the input print writer indenting each
+     * level with the input prefix.
+     */
+    void dumpChildrenNames(StringBuilder out, String prefix) {
+        final String childPrefix = prefix + " ";
+        out.append(getName() + "\n");
+        final int count = mChildren.size();
+        for (int i = 0; i < count; i++) {
+            final WindowContainer wc = mChildren.get(i);
+            out.append(childPrefix + "#" + i + " ");
+            wc.dumpChildrenNames(out, childPrefix);
+        }
+    }
+
+    String getName() {
+        return toString();
+    }
+
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 19ad5e4..5970998 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
@@ -35,6 +36,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -127,7 +129,6 @@
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IShortcutService;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -160,7 +161,6 @@
 import java.net.Socket;
 import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -168,14 +168,11 @@
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -192,6 +189,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;
@@ -199,6 +197,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -212,11 +211,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -239,7 +236,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
@@ -429,7 +425,7 @@
      * List of app window tokens that are waiting for replacing windows. If the
      * replacement doesn't come in time the stale windows needs to be disposed of.
      */
-    final ArrayList<AppWindowToken> mReplacingWindowTimeouts = new ArrayList<>();
+    final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
 
     /**
      * The input consumer added to the window manager which consumes input events to windows below
@@ -493,12 +489,6 @@
     Runnable mWaitingForDrawnCallback;
 
     /**
-     * Used when rebuilding window list to keep track of windows that have
-     * been removed.
-     */
-    WindowState[] mRebuildTmp = new WindowState[20];
-
-    /**
      * Stores for each user whether screencapture is disabled
      * This array is essentially a cache for all userId for
      * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
@@ -539,9 +529,10 @@
      * LAST_ANR_LIFETIME_DURATION_MSECS */
     String mLastANRState;
 
-    /** All DisplayContents in the world, kept here */
-    SparseArray<DisplayContent> mDisplayContents = new SparseArray<>(2);
+    // The root of the device window hierarchy.
+    RootWindowContainer mRoot;
 
+    // TODO: Move several of this states to the RootWindowContainer
     int mRotation = 0;
     int mLastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean mAltOrientation = false;
@@ -553,8 +544,6 @@
 
     private final SparseIntArray mTmpTaskIds = new SparseIntArray();
 
-    private final ArrayList<Integer> mChangedStackList = new ArrayList();
-
     boolean mForceResizableTasks = false;
 
     int getDragLayerLocked() {
@@ -603,8 +592,6 @@
     // State while inside of layoutAndPlaceSurfacesLocked().
     boolean mFocusMayChange;
 
-    Configuration mCurConfiguration = new Configuration();
-
     // This is held as long as we have the screen frozen, to give us time to
     // perform a rotation animation when turning off shows the lock screen which
     // changes the orientation.
@@ -704,6 +691,7 @@
 
     boolean mAnimateWallpaperWithTarget;
 
+    // TODO: Move to RootWindowContainer
     AppWindowToken mFocusedApp = null;
 
     PowerManager mPowerManager;
@@ -748,6 +736,7 @@
 
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
      * DisplayContent.getStacks(). */
+    // TODO: Don't believe this is needed with the WindowContainer model.
     SparseArray<TaskStack> mStackIdToStack = new SparseArray<>();
 
     private final PointerEventDispatcher mPointerEventDispatcher;
@@ -887,12 +876,24 @@
     // since they won't be notified through the app window animator.
     final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
-    // List of displays to reconfigure after configuration changes.
-    // Some of the information reported for a display is dependent on resources to do the right
-    // calculations. For example, {@link DisplayInfo#smallestNominalAppWidth} and company are
-    // dependent on the height and width of the status and nav bar which change depending on the
-    // current configuration.
-    private final DisplayContentList mReconfigureOnConfigurationChanged = new DisplayContentList();
+
+    void openSurfaceTransaction() {
+        synchronized (mWindowMap) {
+            if (mRoot.mSurfaceTraceEnabled) {
+                mRoot.mRemoteEventTrace.openSurfaceTransaction();
+            }
+            SurfaceControl.openTransaction();
+        }
+    }
+
+    void closeSurfaceTransaction() {
+        synchronized (mWindowMap) {
+            if (mRoot.mSurfaceTraceEnabled) {
+                mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+            }
+            SurfaceControl.closeTransaction();
+        }
+    }
 
     /** Listener to notify activity manager about app transitions. */
     final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
@@ -929,6 +930,12 @@
         }
     };
 
+    final ArrayList<AppFreezeListener> mAppFreezeListeners = new ArrayList<>();
+
+    interface AppFreezeListener {
+        void onAppFreezeTimeout();
+    }
+
     public static WindowManagerService main(final Context context,
             final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs,
@@ -955,6 +962,7 @@
     private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
             WindowManagerPolicy policy) {
+        mRoot = new RootWindowContainer(this);
         mContext = context;
         mHaveInputMethods = haveInputMethods;
         mAllowBootMessages = showBootMsgs;
@@ -1060,11 +1068,11 @@
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
-        SurfaceControl.openTransaction();
+        openSurfaceTransaction();
         try {
             createWatermarkInTransaction();
         } finally {
-            SurfaceControl.closeTransaction();
+            closeSurfaceTransaction();
         }
 
         showEmulatorDisplayOverlayIfNeeded();
@@ -1473,6 +1481,7 @@
         boolean reportNewConfig = false;
         WindowState parentWindow = null;
         long origId;
+        final int callingUid = Binder.getCallingUid();
         final int type = attrs.type;
 
         synchronized(mWindowMap) {
@@ -1480,7 +1489,7 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent == null) {
                 Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                         + displayId + ".  Aborting.");
@@ -1525,6 +1534,9 @@
             // If this is a child window, we want to apply the same type checking rules as the
             // parent window type.
             final int rootType = hasParent ? parentWindow.mAttrs.type : type;
+
+            boolean addToastWindowRequiresToken = false;
+
             if (token == null) {
                 if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
@@ -1561,6 +1573,15 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+                if (type == TYPE_TOAST) {
+                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
+                            parentWindow)) {
+                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
+                                + attrs.token + ".  Aborting.");
+                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    }
+                }
                 token = new WindowToken(this, attrs.token, -1, false);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
@@ -1609,7 +1630,16 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
-            } else if (rootType == TYPE_QS_DIALOG) {
+            } else if (type == TYPE_TOAST) {
+                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
+                        callingUid, parentWindow);
+                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
+                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
+                            + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
+            } else if (type == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
                             + attrs.token + ".  Aborting.");
@@ -1652,6 +1682,36 @@
                 win.openInputChannel(outInputChannel);
             }
 
+            // If adding a toast requires a token for this app we always schedule hiding
+            // toast windows to make sure they don't stick around longer then necessary.
+            // We hide instead of remove such windows as apps aren't prepared to handle
+            // windows being removed under them.
+            //
+            // If the app is older it can add toasts without a token and hence overlay
+            // other apps. To be maximally compatible with these apps we will hide the
+            // window after the toast timeout only if the focused window is from another
+            // UID, otherwise we allow unlimited duration. When a UID looses focus we
+            // schedule hiding all of its toast windows.
+            if (type == TYPE_TOAST) {
+                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
+                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
+                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
+                }
+                // Make sure this happens before we moved focus as one can make the
+                // toast focusable to force it not being hidden after the timeout.
+                // Focusable toasts are always timed out to prevent a focused app to
+                // show a focusable toasts while it has focus which will be kept on
+                // the screen after the activity goes away.
+                if (addToastWindowRequiresToken
+                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
+                        || mCurrentFocus == null
+                        || mCurrentFocus.mOwnerUid != callingUid) {
+                    mH.sendMessageDelayed(
+                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
+                            win.mAttrs.hideTimeoutMilliseconds);
+                }
+            }
+
             // From now on, no exceptions or errors allowed!
 
             res = WindowManagerGlobal.ADD_OKAY;
@@ -1784,11 +1844,6 @@
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
             }
-            if (attrs.removeTimeoutMilliseconds > 0) {
-                mH.sendMessageDelayed(
-                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
-                        attrs.removeTimeoutMilliseconds);
-            }
         }
 
         if (reportNewConfig) {
@@ -1800,6 +1855,32 @@
         return res;
     }
 
+    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
+            WindowState attachedWindow) {
+        // Try using the target SDK of the root window
+        if (attachedWindow != null) {
+            return attachedWindow.mAppToken != null
+                    && attachedWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1;
+        } else {
+            // Otherwise, look at the package
+            try {
+                ApplicationInfo appInfo = mContext.getPackageManager()
+                        .getApplicationInfoAsUser(packageName, 0,
+                                UserHandle.getUserId(callingUid));
+                if (appInfo.uid != callingUid) {
+                    throw new SecurityException("Package " + packageName + " not in UID "
+                            + callingUid);
+                }
+                if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+                    return true;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                /* ignore */
+            }
+        }
+        return false;
+    }
+
     /**
      * Returns true if we're done setting up any transitions.
      */
@@ -1857,6 +1938,30 @@
         return false;
     }
 
+    @Override
+    public void enableSurfaceTrace(ParcelFileDescriptor pfd) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
+            throw new SecurityException("Only shell can call enableSurfaceTrace");
+        }
+
+        synchronized (mWindowMap) {
+            mRoot.enableSurfaceTrace(pfd);
+        }
+    }
+
+    @Override
+    public void disableSurfaceTrace() {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID &&
+            callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException("Only shell can call disableSurfaceTrace");
+        }
+        synchronized (mWindowMap) {
+            mRoot.disableSurfaceTrace();
+        }
+    }
+
     /**
      * Set mScreenCaptureDisabled for specific user
      */
@@ -1870,15 +1975,7 @@
         synchronized(mWindowMap) {
             mScreenCaptureDisabled.put(userId, disabled);
             // Update secure surface for all windows belonging to this user.
-            for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
-                WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                    final WindowState win = windows.get(winNdx);
-                    if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) {
-                        win.mWinAnimator.setSecureLocked(disabled);
-                    }
-                }
-            }
+            mRoot.setSecureSurfaceState(userId, disabled);
         }
     }
 
@@ -1894,7 +1991,10 @@
 
     /**
      * Performs some centralized bookkeeping clean-up on the window that is being removed.
-     * NOTE: Should only be called from {@link WindowState#remove()}
+     * NOTE: Should only be called from {@link WindowState#removeImmediately()}
+     * TODO: Maybe better handled with a method {@link WindowContainer#removeChild} if we can
+     * figure-out a good way to have all parents of a WindowState doing the same thing without
+     * forgetting to add the wiring when a new parent of WindowState is added.
      */
     void postWindowRemoveCleanupLocked(WindowState win) {
         if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win);
@@ -1917,7 +2017,7 @@
         final WindowToken token = win.mToken;
         final AppWindowToken atoken = win.mAppToken;
         if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Removing " + win + " from " + token);
-        token.removeWindow(win);
+        // Window will already be removed from token before this post clean-up method is called.
         if (token.isEmpty()) {
             if (!token.explicit) {
                 mTokenMap.remove(token.token);
@@ -1930,7 +2030,7 @@
         }
 
         if (atoken != null) {
-            atoken.removeWindow(win);
+            atoken.postWindowRemoveStartingWindowCleanup(win);
         }
 
         if (win.mAttrs.type == TYPE_WALLPAPER) {
@@ -1958,20 +2058,7 @@
 
     public void updateAppOpsState() {
         synchronized(mWindowMap) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                final int numWindows = windows.size();
-                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                    final WindowState win = windows.get(winNdx);
-                    if (win.mAppOp != AppOpsManager.OP_NONE) {
-                        final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
-                                win.getOwningPackage());
-                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
-                                mode == AppOpsManager.MODE_DEFAULT);
-                    }
-                }
-            }
+            mRoot.updateAppOpsState();
         }
     }
 
@@ -2115,7 +2202,7 @@
                         Slog.i(TAG_WM, ">>> OPEN TRANSACTION repositionChild");
                     }
 
-                    SurfaceControl.openTransaction();
+                    openSurfaceTransaction();
 
                     try {
 
@@ -2129,7 +2216,7 @@
                         }
 
                     } finally {
-                        SurfaceControl.closeTransaction();
+                        closeSurfaceTransaction();
                         if (SHOW_TRANSACTIONS) {
                             Slog.i(TAG_WM, "<<< CLOSE TRANSACTION repositionChild");
                         }
@@ -2300,12 +2387,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);
 
@@ -2538,7 +2624,7 @@
     }
 
     public boolean outOfMemoryWindow(Session session, IWindow client) {
-        long origId = Binder.clearCallingIdentity();
+        final long origId = Binder.clearCallingIdentity();
 
         try {
             synchronized (mWindowMap) {
@@ -2546,7 +2632,7 @@
                 if (win == null) {
                     return false;
                 }
-                return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false);
+                return mRoot.reclaimSomeSurfaceMemory(win.mWinAnimator, "from-client", false);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -2582,7 +2668,8 @@
         // is running.
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
         if (okToDisplay()) {
-            DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
+            final DisplayContent displayContent = atoken.mTask.getDisplayContent();
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             final int width = displayInfo.appWidth;
             final int height = displayInfo.appHeight;
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
@@ -2619,8 +2706,9 @@
             if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
                     + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
                     + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
-            Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.uiMode,
-                    mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets,
+            final Configuration displayConfig = displayContent.getConfiguration();
+            Animation a = mAppTransition.loadAnimation(lp, transit, enter, displayConfig.uiMode,
+                    displayConfig.orientation, frame, displayFrame, insets, surfaceInsets,
                     isVoiceInteraction, freeform, atoken.mTask.mTaskId);
             if (a != null) {
                 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
@@ -2637,74 +2725,6 @@
         return atoken.mAppAnimator.animation != null;
     }
 
-    // -------------------------------------------------------------
-    // Application Window Tokens
-    // -------------------------------------------------------------
-
-    public void validateAppTokens(int stackId, List<TaskGroup> tasks) {
-        synchronized (mWindowMap) {
-            int t = tasks.size() - 1;
-            if (t < 0) {
-                Slog.w(TAG_WM, "validateAppTokens: empty task list");
-                return;
-            }
-
-            TaskGroup task = tasks.get(0);
-            int taskId = task.taskId;
-            Task targetTask = mTaskIdToTask.get(taskId);
-            DisplayContent displayContent = targetTask.getDisplayContent();
-            if (displayContent == null) {
-                Slog.w(TAG_WM, "validateAppTokens: no Display for taskId=" + taskId);
-                return;
-            }
-
-            final ArrayList<Task> localTasks = mStackIdToStack.get(stackId).getTasks();
-            int taskNdx;
-            for (taskNdx = localTasks.size() - 1; taskNdx >= 0 && t >= 0; --taskNdx, --t) {
-                AppTokenList localTokens = localTasks.get(taskNdx).mAppTokens;
-                task = tasks.get(t);
-                List<IApplicationToken> tokens = task.tokens;
-
-                DisplayContent lastDisplayContent = displayContent;
-                displayContent = mTaskIdToTask.get(taskId).getDisplayContent();
-                if (displayContent != lastDisplayContent) {
-                    Slog.w(TAG_WM, "validateAppTokens: displayContent changed in TaskGroup list!");
-                    return;
-                }
-
-                int tokenNdx;
-                int v;
-                for (tokenNdx = localTokens.size() - 1, v = task.tokens.size() - 1;
-                        tokenNdx >= 0 && v >= 0; ) {
-                    final AppWindowToken atoken = localTokens.get(tokenNdx);
-                    if (atoken.removed) {
-                        --tokenNdx;
-                        continue;
-                    }
-                    if (tokens.get(v) != atoken.token) {
-                        break;
-                    }
-                    --tokenNdx;
-                    v--;
-                }
-
-                if (tokenNdx >= 0 || v >= 0) {
-                    break;
-                }
-            }
-
-            if (taskNdx >= 0 || t >= 0) {
-                Slog.w(TAG_WM, "validateAppTokens: Mismatch! ActivityManager=" + tasks);
-                Slog.w(TAG_WM, "validateAppTokens: Mismatch! WindowManager=" + localTasks);
-                Slog.w(TAG_WM, "validateAppTokens: Mismatch! Callers=" + Debug.getCallers(4));
-            }
-        }
-    }
-
-    public void validateStackOrder(Integer[] remoteStackIds) {
-        // TODO:
-    }
-
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -2780,7 +2800,7 @@
     }
 
     private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
-            Rect bounds, Configuration config, boolean isOnTopLauncher) {
+            Rect bounds, Configuration overrideConfig, boolean isOnTopLauncher) {
         if (DEBUG_STACK) Slog.i(TAG_WM, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
                 + " atoken=" + atoken + " bounds=" + bounds);
         final TaskStack stack = mStackIdToStack.get(stackId);
@@ -2788,7 +2808,7 @@
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(taskId, stack, userId, this, bounds, config, isOnTopLauncher);
+        Task task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
         return task;
@@ -2798,9 +2818,9 @@
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,
-            boolean homeTask, int targetSdkVersion, int rotationAnimationHint,
-            boolean isOnTopLauncher) {
+            Rect taskBounds, Configuration overrideConfig, int taskResizeMode,
+            boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
+            int rotationAnimationHint, boolean isOnTopLauncher) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -2828,10 +2848,10 @@
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-            atoken.appFullscreen = fullscreen;
+            atoken.setFillsParent(fullscreen);
             atoken.showForAllUsers = showForAllUsers;
             atoken.targetSdk = targetSdkVersion;
-            atoken.requestedOrientation = requestedOrientation;
+            atoken.setOrientation(requestedOrientation);
             atoken.layoutConfigChanges = (configChanges &
                     (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
             atoken.mLaunchTaskBehind = launchTaskBehind;
@@ -2842,7 +2862,7 @@
 
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config,
+                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, overrideConfig,
                         isOnTopLauncher);
             }
             task.addAppToken(addPos, atoken, taskResizeMode, homeTask);
@@ -2855,7 +2875,8 @@
 
     @Override
     public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
-            Configuration config, int taskResizeMode, boolean homeTask, boolean isOnTopLauncher) {
+            Configuration overrideConfig, int taskResizeMode, boolean homeTask,
+            boolean isOnTopLauncher) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -2867,14 +2888,11 @@
                 Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token);
                 return;
             }
-            final Task oldTask = atoken.mTask;
-            oldTask.removeAppToken(atoken);
 
             Task newTask = mTaskIdToTask.get(taskId);
             if (newTask == null) {
-                newTask = createTaskLocked(
-                        taskId, stackId, oldTask.mUserId, atoken, taskBounds, config,
-                        isOnTopLauncher);
+                newTask = createTaskLocked(taskId, stackId, atoken.mTask.mUserId, atoken,
+                        taskBounds, overrideConfig, isOnTopLauncher);
             }
             newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken, taskResizeMode, homeTask);
         }
@@ -2936,7 +2954,7 @@
                 AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
                         null : winShowWhenLocked.mAppToken;
                 if (appShowWhenLocked != null) {
-                    int req = appShowWhenLocked.requestedOrientation;
+                    int req = appShowWhenLocked.getOrientation();
                     if (req == SCREEN_ORIENTATION_BEHIND) {
                         req = mLastKeyguardForcedOrientation;
                     }
@@ -2951,91 +2969,7 @@
         }
 
         // Top system windows are not requesting an orientation. Start searching from apps.
-        return getAppSpecifiedOrientation();
-    }
-
-    private int getAppSpecifiedOrientation() {
-        int lastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-        boolean findingBehind = false;
-        boolean lastFullscreen = false;
-        DisplayContent displayContent = getDefaultDisplayContentLocked();
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final boolean inMultiWindow = isStackVisibleLocked(DOCKED_STACK_ID)
-                || isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID);
-        final boolean dockMinimized =
-                getDefaultDisplayContentLocked().mDividerControllerLocked.isMinimizedDock();
-        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int firstToken = tokens.size() - 1;
-            for (int tokenNdx = firstToken; tokenNdx >= 0; --tokenNdx) {
-                final AppWindowToken atoken = tokens.get(tokenNdx);
-
-                if (DEBUG_APP_ORIENTATION) Slog.v(TAG_WM, "Checking app orientation: " + atoken);
-
-                // if we're about to tear down this window and not seek for
-                // the behind activity, don't use it for orientation
-                if (!findingBehind && !atoken.hidden && atoken.hiddenRequested) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Skipping " + atoken + " -- going to hide");
-                    continue;
-                }
-
-                if (tokenNdx == firstToken) {
-                    // If we have hit a new Task, and the bottom of the previous group didn't
-                    // explicitly say to use the orientation behind it, and the last app was
-                    // full screen, then we'll stick with the user's orientation.
-                    if (lastOrientation != SCREEN_ORIENTATION_BEHIND && lastFullscreen) {
-                        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Done at " + atoken
-                                + " -- end of group, return " + lastOrientation);
-                        return lastOrientation;
-                    }
-                }
-
-                // We ignore any hidden applications on the top.
-                if (atoken.hiddenRequested) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Skipping " + atoken + " -- hidden on top");
-                    continue;
-                }
-
-                // No app except the home app may specify the screen orientation in multi-window,
-                // and only if the docked stack is minimized to avoid weirdness when home task
-                // temporarily gets moved to the front.
-                if (inMultiWindow && (!atoken.mTask.isHomeTask() || !dockMinimized)) {
-                    continue;
-                }
-
-                if (tokenNdx == 0) {
-                    // Last token in this task.
-                    lastOrientation = atoken.requestedOrientation;
-                }
-
-                int or = atoken.requestedOrientation;
-                // If this application is fullscreen, and didn't explicitly say
-                // to use the orientation behind it, then just take whatever
-                // orientation it has and ignores whatever is under it.
-                lastFullscreen = atoken.appFullscreen;
-                if (lastFullscreen && or != SCREEN_ORIENTATION_BEHIND) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Done at " + atoken + " -- full screen, return " + or);
-                    return or;
-                }
-                // If this application has requested an explicit orientation, then use it.
-                if (or != SCREEN_ORIENTATION_UNSPECIFIED && or != SCREEN_ORIENTATION_BEHIND) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Done at " + atoken + " -- explicitly set, return " + or);
-                    return or;
-                }
-                findingBehind |= (or == SCREEN_ORIENTATION_BEHIND);
-            }
-        }
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                "No app is requesting an orientation, return " + mLastOrientation);
-        // The next app has not been requested to be visible, so we keep the current orientation
-        // to prevent freezing/unfreezing the display too early unless we are in multi-window, in
-        // which we don't let the app customize the orientation unless it was the home task that
-        // is handled above.
-        return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mLastOrientation;
+        return getDefaultDisplayContentLocked().getOrientation();
     }
 
     @Override
@@ -3066,7 +3000,11 @@
         Configuration config = null;
 
         if (updateOrientationFromAppTokensLocked(false)) {
-            if (freezeThisOneIfNeeded != null) {
+            // If we changed the orientation but mOrientationChangeComplete is
+            // already true, we used seamless rotation, and we don't need
+            // to freeze the screen.
+            if (freezeThisOneIfNeeded != null &&
+                    !mRoot.mOrientationChangeComplete) {
                 final AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
                 if (atoken != null) {
                     atoken.startFreezingScreen();
@@ -3075,17 +3013,18 @@
             config = computeNewConfigurationLocked();
 
         } else if (currentConfig != null) {
-            // No obvious action we need to take, but if our current
-            // state mismatches the activity manager's, update it,
-            // disregarding font scale, which should remain set to
-            // the value of the previous configuration.
-            mTempConfiguration.setToDefaults();
+            // No obvious action we need to take, but if our current state mismatches the activity
+            // manager's, update it, disregarding font scale, which should remain set to the value
+            // of the previous configuration.
+            // Here we're calling Configuration#unset() instead of setToDefaults() because we need
+            // to keep override configs clear of non-empty values (e.g. fontSize).
+            mTempConfiguration.unset();
             mTempConfiguration.updateFrom(currentConfig);
             computeScreenConfigurationLocked(mTempConfiguration);
             if (currentConfig.diff(mTempConfiguration) != 0) {
                 mWaitingForConfig = true;
                 final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                displayContent.layoutNeeded = true;
+                displayContent.setLayoutNeeded();
                 int anim[] = new int[2];
                 if (displayContent.isDimming()) {
                     anim[0] = anim[1] = 0;
@@ -3135,6 +3074,19 @@
         }
     }
 
+    // If this is true we have updated our desired orientation, but not yet
+    // changed the real orientation our applied our screen rotation animation.
+    // For example, because a previous screen rotation was in progress.
+    boolean rotationNeedsUpdateLocked() {
+        int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
+        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
+                mLastOrientation, rotation);
+        if (mRotation == rotation && mAltOrientation == altOrientation) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public int[] setNewConfiguration(Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3147,13 +3099,7 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
-            boolean configChanged = mCurConfiguration.diff(config) != 0;
-            if (!configChanged) {
-                return null;
-            }
-            prepareFreezingAllTaskBounds();
-            mCurConfiguration = new Configuration(config);
-            return onConfigurationChanged();
+            return mRoot.setGlobalConfigurationIfNeeded(config);
         }
     }
 
@@ -3167,42 +3113,6 @@
         }
     }
 
-    private void prepareFreezingAllTaskBounds() {
-        for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
-            ArrayList<TaskStack> stacks = mDisplayContents.valueAt(i).getStacks();
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final TaskStack stack = stacks.get(stackNdx);
-                stack.prepareFreezingTaskBounds();
-            }
-        }
-
-    }
-    private int[] onConfigurationChanged() {
-        mPolicy.onConfigurationChanged();
-
-        final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
-        if (!mReconfigureOnConfigurationChanged.contains(defaultDisplayContent)) {
-            // The default display size information is heavily dependent on the resources in the
-            // current configuration, so we need to reconfigure it everytime the configuration
-            // changes. See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
-            mReconfigureOnConfigurationChanged.add(defaultDisplayContent);
-        }
-        for (int i = mReconfigureOnConfigurationChanged.size() - 1; i >= 0; i--) {
-            reconfigureDisplayLocked(mReconfigureOnConfigurationChanged.remove(i));
-        }
-
-        defaultDisplayContent.getDockedDividerController().onConfigurationChanged();
-        mChangedStackList.clear();
-        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
-            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
-            if (stack.onConfigurationChanged()) {
-                mChangedStackList.add(stack.mStackId);
-            }
-        }
-        return mChangedStackList.isEmpty() ?
-                null : ArrayUtils.convertToIntArray(mChangedStackList);
-    }
-
     @Override
     public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3211,13 +3121,13 @@
         }
 
         synchronized(mWindowMap) {
-            AppWindowToken atoken = findAppWindowToken(token.asBinder());
+            final AppWindowToken atoken = findAppWindowToken(token.asBinder());
             if (atoken == null) {
                 Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
                 return;
             }
 
-            atoken.requestedOrientation = requestedOrientation;
+            atoken.setOrientation(requestedOrientation);
         }
     }
 
@@ -3229,7 +3139,7 @@
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
 
-            return wtoken.requestedOrientation;
+            return wtoken.getOrientation();
         }
     }
 
@@ -3545,9 +3455,9 @@
 
     public void setAppFullscreen(IBinder token, boolean toOpaque) {
         synchronized (mWindowMap) {
-            AppWindowToken atoken = findAppWindowToken(token);
+            final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken != null) {
-                atoken.appFullscreen = toOpaque;
+                atoken.setFillsParent(toOpaque);
                 setWindowOpaqueLocked(token, toOpaque);
                 mWindowPlacerLocked.requestTraversal();
             }
@@ -3580,7 +3490,7 @@
     }
 
     @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped) {
+    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "notifyAppResumed()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3593,7 +3503,7 @@
                 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
                 return;
             }
-            wtoken.notifyAppResumed(wasStopped);
+            wtoken.notifyAppResumed(wasStopped, allowSavedSurface);
         }
     }
 
@@ -3645,7 +3555,7 @@
                 // If the app is dead while it was visible, we kept its dead window on screen.
                 // Now that the app is going invisible, we can remove it. It will be restarted
                 // if made visible again.
-                wtoken.removeAllDeadWindows();
+                wtoken.removeDeadWindows();
                 wtoken.setVisibleBeforeClientHidden();
             } else if (visible) {
                 if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
@@ -3711,8 +3621,7 @@
                 }
                 if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
                     // We're launchingBehind, add the launching activity to mOpeningApps.
-                    final WindowState win =
-                            findFocusedWindowLocked(getDefaultDisplayContentLocked());
+                    final WindowState win = getDefaultDisplayContentLocked().findFocusedWindow();
                     if (win != null) {
                         final AppWindowToken focusedToken = win.mAppToken;
                         if (focusedToken != null) {
@@ -3823,7 +3732,7 @@
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
-                    wtoken.removeAppFromTaskLocked();
+                    wtoken.removeIfPossible();
                 }
 
                 wtoken.removed = true;
@@ -3879,44 +3788,14 @@
         mH.sendMessage(m);
     }
 
-    void dumpAppTokensLocked() {
-        final int numStacks = mStackIdToStack.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
-            Slog.v(TAG_WM, "  Stack #" + stack.mStackId + " tasks from bottom to top:");
-            final ArrayList<Task> tasks = stack.getTasks();
-            final int numTasks = tasks.size();
-            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                Slog.v(TAG_WM, "    Task #" + task.mTaskId + " activities from bottom to top:");
-                AppTokenList tokens = task.mAppTokens;
-                final int numTokens = tokens.size();
-                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                    Slog.v(TAG_WM, "      activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token);
-                }
-            }
-        }
-    }
-
-    void dumpWindowsLocked() {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            Slog.v(TAG_WM, " Display #" + displayContent.getDisplayId());
-            final WindowList windows = displayContent.getWindowList();
-            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                Slog.v(TAG_WM, "  #" + winNdx + ": " + windows.get(winNdx));
-            }
-        }
-    }
-
-    void moveStackWindowsLocked(DisplayContent displayContent) {
+    /** Rebuilds the input display's window list and does a relayout if something changed. */
+    private void rebuildAppWindowsAndLayoutIfNeededLocked(DisplayContent displayContent) {
         final WindowList windows = displayContent.getWindowList();
         mTmpWindows.addAll(windows);
 
-        rebuildAppWindowListLocked(displayContent);
+        displayContent.rebuildAppWindowList();
 
-        // Set displayContent.layoutNeeded if window order changed.
+        // Set displayContent.mLayoutNeeded if window order changed.
         final int tmpSize = mTmpWindows.size();
         final int winSize = windows.size();
         int tmpNdx = 0, winNdx = 0;
@@ -3934,13 +3813,13 @@
 
             if (tmp != win) {
                 // Window order changed.
-                displayContent.layoutNeeded = true;
+                displayContent.setLayoutNeeded();
                 break;
             }
         }
         if (tmpNdx != winNdx) {
             // One list was different from the other.
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
         }
         mTmpWindows.clear();
 
@@ -3952,7 +3831,6 @@
         mInputMonitor.setUpdateInputWindowsNeededLw();
         mWindowPlacerLocked.performSurfacePlacement();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
-        //dump();
     }
 
     public void moveTaskToTop(int taskId) {
@@ -3979,7 +3857,7 @@
                 if (mAppTransition.isTransitionSet()) {
                     task.setSendingToBottom(false);
                 }
-                moveStackWindowsLocked(displayContent);
+                rebuildAppWindowsAndLayoutIfNeededLocked(displayContent);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4001,7 +3879,7 @@
                 if (mAppTransition.isTransitionSet()) {
                     task.setSendingToBottom(true);
                 }
-                moveStackWindowsLocked(stack.getDisplayContent());
+                rebuildAppWindowsAndLayoutIfNeededLocked(stack.getDisplayContent());
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4010,7 +3888,7 @@
 
     boolean isStackVisibleLocked(int stackId) {
         final TaskStack stack = mStackIdToStack.get(stackId);
-        return (stack != null && stack.isVisibleLocked());
+        return (stack != null && stack.isVisible());
     }
 
     public void setDockedStackCreateState(int mode, Rect bounds) {
@@ -4036,69 +3914,18 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
-                final DisplayContent displayContent = mDisplayContents.get(displayId);
-                boolean attachedToDisplay = false;
-                if (displayContent != null) {
-                    TaskStack stack = mStackIdToStack.get(stackId);
-                    if (stack == null) {
-                        if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
-
-                        stack = displayContent.getStackById(stackId);
-                        if (stack != null) {
-                            // It's already attached to the display. Detach and re-attach
-                            // because onTop might change, and be sure to clear mDeferDetach!
-                            displayContent.detachStack(stack);
-                            stack.mDeferDetach = false;
-                            attachedToDisplay = true;
-                        } else {
-                            stack = new TaskStack(this, stackId);
-                        }
-
-                        mStackIdToStack.put(stackId, stack);
-                        if (stackId == DOCKED_STACK_ID) {
-                            getDefaultDisplayContentLocked().mDividerControllerLocked
-                                    .notifyDockedStackExistsChanged(true);
-                        }
-                    }
-                    if (!attachedToDisplay) {
-                        stack.attachDisplayContent(displayContent);
-                    }
-                    displayContent.attachStack(stack, onTop);
-                    if (stack.getRawFullscreen()) {
-                        return null;
-                    }
-                    Rect bounds = new Rect();
-                    stack.getRawBounds(bounds);
-                    return bounds;
-                }
+                return mRoot.addStackToDisplay(stackId, displayId, onTop);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
-        return null;
-    }
-
-    void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
-        displayContent.detachStack(stack);
-        stack.detachDisplay();
-        if (stack.mStackId == DOCKED_STACK_ID) {
-            getDefaultDisplayContentLocked().mDividerControllerLocked
-                    .notifyDockedStackExistsChanged(false);
-        }
     }
 
     public void detachStack(int stackId) {
         synchronized (mWindowMap) {
-            TaskStack stack = mStackIdToStack.get(stackId);
+            final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack != null) {
-                final DisplayContent displayContent = stack.getDisplayContent();
-                if (displayContent != null) {
-                    if (stack.isAnimating()) {
-                        stack.mDeferDetach = true;
-                        return;
-                    }
-                    detachStackLocked(displayContent, stack);
-                }
+                stack.removeIfPossible();
             }
         }
     }
@@ -4116,7 +3943,7 @@
                 if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId);
                 return;
             }
-            task.removeLocked();
+            task.removeIfPossible();
         }
     }
 
@@ -4140,23 +3967,6 @@
         }
     }
 
-    public void addTask(int taskId, int stackId, boolean toTop) {
-        synchronized (mWindowMap) {
-            if (DEBUG_STACK) Slog.i(TAG_WM, "addTask: adding taskId=" + taskId
-                    + " to " + (toTop ? "top" : "bottom"));
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM, "addTask: could not find taskId=" + taskId);
-                return;
-            }
-            TaskStack stack = mStackIdToStack.get(stackId);
-            stack.addTask(task, toTop);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.layoutNeeded = true;
-            mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
         synchronized (mWindowMap) {
             if (DEBUG_STACK) Slog.i(TAG_WM, "moveTaskToStack: moving taskId=" + taskId
@@ -4173,7 +3983,7 @@
             }
             task.moveTaskToStack(stack, toTop);
             final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
             mWindowPlacerLocked.performSurfacePlacement();
         }
     }
@@ -4201,6 +4011,11 @@
         }
     }
 
+    @Override
+    public void overridePlayingAppAnimationsLw(Animation a) {
+        getDefaultDisplayContentLocked().overridePlayingAppAnimations(a);
+    }
+
     /**
      * Re-sizes a stack and its containing tasks.
      * @param stackId Id of stack to resize.
@@ -4219,8 +4034,8 @@
                         + " not found.");
             }
             if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
-                    && stack.isVisibleLocked()) {
-                stack.getDisplayContent().layoutNeeded = true;
+                    && stack.isVisible()) {
+                stack.getDisplayContent().setLayoutNeeded();
                 mWindowPlacerLocked.performSurfacePlacement();
             }
             return stack.getRawFullscreen();
@@ -4257,7 +4072,7 @@
             }
             task.positionTaskInStack(stack, position, bounds, config);
             final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
             mWindowPlacerLocked.performSurfacePlacement();
         }
     }
@@ -4267,7 +4082,7 @@
      * Returns a {@link Configuration} object that contains configurations settings
      * that should be overridden due to the operation.
      */
-    public void resizeTask(int taskId, Rect bounds, Configuration configuration,
+    public void resizeTask(int taskId, Rect bounds, Configuration overrideConfig,
             boolean relayout, boolean forced) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -4276,8 +4091,8 @@
                         + " not found.");
             }
 
-            if (task.resizeLocked(bounds, configuration, forced) && relayout) {
-                task.getDisplayContent().layoutNeeded = true;
+            if (task.resizeLocked(bounds, overrideConfig, forced) && relayout) {
+                task.getDisplayContent().setLayoutNeeded();
                 mWindowPlacerLocked.performSurfacePlacement();
             }
         }
@@ -4554,20 +4369,7 @@
     @Override
     public void closeSystemDialogs(String reason) {
         synchronized(mWindowMap) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                final int numWindows = windows.size();
-                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                    final WindowState w = windows.get(winNdx);
-                    if (w.mHasSurface) {
-                        try {
-                            w.mClient.closeSystemDialogs(reason);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-            }
+            mRoot.closeSystemDialogs(reason);
         }
     }
 
@@ -4756,12 +4558,7 @@
             mPolicy.enableKeyguard(true);
 
             // Hide windows that should not be seen by the new user.
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                displayContent.switchUserStacks();
-                rebuildAppWindowListLocked(displayContent);
-            }
+            mRoot.switchUser();
             mWindowPlacerLocked.performSurfacePlacement();
 
             // Notify whether the docked stack exists for the current user
@@ -4780,22 +4577,13 @@
         }
     }
 
-    /**
-     * Returns whether there is a docked task for the current user.
-     */
+    /** Returns whether there is a docked task for the current user. */
     boolean hasDockedTasksForUser(int userId) {
         final TaskStack stack = mStackIdToStack.get(DOCKED_STACK_ID);
         if (stack == null) {
             return false;
         }
-
-        final ArrayList<Task> tasks = stack.getTasks();
-        boolean hasUserTask = false;
-        for (int i = tasks.size() - 1; i >= 0 && !hasUserTask; i--) {
-            final Task task = tasks.get(i);
-            hasUserTask = (task.mUserId == userId);
-        }
-        return hasUserTask;
+        return stack.hasTaskForUser(userId);
     }
 
     /* Called by WindowState */
@@ -4824,7 +4612,7 @@
             hideBootMessagesLocked();
             // If the screen still doesn't come up after 30 seconds, give
             // up and turn it on.
-            mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000);
+            mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);
         }
 
         mPolicy.systemBooted();
@@ -4890,7 +4678,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;
@@ -5088,7 +4877,7 @@
 
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                     ">>> OPEN TRANSACTION showCircularMask(visible=" + visible + ")");
-            SurfaceControl.openTransaction();
+            openSurfaceTransaction();
             try {
                 if (visible) {
                     // TODO(multi-display): support multiple displays
@@ -5111,7 +4900,7 @@
                     mCircularDisplayMask = null;
                 }
             } finally {
-                SurfaceControl.closeTransaction();
+                closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                         "<<< CLOSE TRANSACTION showCircularMask(visible=" + visible + ")");
             }
@@ -5123,7 +4912,7 @@
 
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                     ">>> OPEN TRANSACTION showEmulatorDisplayOverlay");
-            SurfaceControl.openTransaction();
+            openSurfaceTransaction();
             try {
                 if (mEmulatorDisplayOverlay == null) {
                     mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(
@@ -5136,7 +4925,7 @@
                 }
                 mEmulatorDisplayOverlay.setVisibility(true);
             } finally {
-                SurfaceControl.closeTransaction();
+                closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                         "<<< CLOSE TRANSACTION showEmulatorDisplayOverlay");
             }
@@ -5154,30 +4943,16 @@
     private void showStrictModeViolation(int arg, int pid) {
         final boolean on = arg != 0;
         synchronized(mWindowMap) {
-            // Ignoring requests to enable the red border from clients
-            // which aren't on screen.  (e.g. Broadcast Receivers in
-            // the background..)
-            if (on) {
-                boolean isVisible = false;
-                final int numDisplays = mDisplayContents.size();
-                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                    final int numWindows = windows.size();
-                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                        final WindowState ws = windows.get(winNdx);
-                        if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
-                            isVisible = true;
-                            break;
-                        }
-                    }
-                }
-                if (!isVisible) {
-                    return;
-                }
+            // Ignoring requests to enable the red border from clients which aren't on screen.
+            // (e.g. Broadcast Receivers in the background..)
+            if (on && !mRoot.canShowStrictModeViolation(pid)) {
+                return;
             }
 
             if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM,
                     ">>> OPEN TRANSACTION showStrictModeViolation");
+            // TODO: Modify this to use the surface trace once it is not going crazy.
+            // b/31532461
             SurfaceControl.openTransaction();
             try {
                 // TODO(multi-display): support multiple displays
@@ -5306,7 +5081,7 @@
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
         synchronized(mWindowMap) {
-            displayContent = getDisplayContentLocked(displayId);
+            displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent == null) {
                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
                         + ": returning null. No Display for displayId=" + displayId);
@@ -5675,7 +5450,7 @@
         synchronized(mWindowMap) {
             changed = updateRotationUncheckedLocked(false);
             if (!changed || forceRelayout) {
-                getDefaultDisplayContentLocked().layoutNeeded = true;
+                getDefaultDisplayContentLocked().setLayoutNeeded();
                 mWindowPlacerLocked.performSurfacePlacement();
             }
         }
@@ -5758,7 +5533,7 @@
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
-        displayContent.layoutNeeded = true;
+        displayContent.setLayoutNeeded();
         final int[] anim = new int[2];
         if (displayContent.isDimming()) {
             anim[0] = anim[1] = 0;
@@ -5811,14 +5586,14 @@
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
         // By updating the Display info here it will be available to
         // computeScreenConfigurationLocked later.
-        updateDisplayAndOrientationLocked(mCurConfiguration.uiMode);
+        updateDisplayAndOrientationLocked(mRoot.getConfiguration().uiMode);
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!inTransaction) {
             if (SHOW_TRANSACTIONS) {
                 Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
             }
-            SurfaceControl.openTransaction();
+            openSurfaceTransaction();
         }
         try {
             // NOTE: We disable the rotation in the emulator because
@@ -5843,7 +5618,7 @@
             mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
         } finally {
             if (!inTransaction) {
-                SurfaceControl.closeTransaction();
+                closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) {
                     Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
                 }
@@ -5859,7 +5634,7 @@
             if (w.mHasSurface && !rotateSeamlessly) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
-                mWindowPlacerLocked.mOrientationChangeComplete = false;
+                mRoot.mOrientationChangeComplete = false;
                 w.mLastFreezeDuration = 0;
             }
         }
@@ -6096,13 +5871,12 @@
     }
 
     /**
-     * Lists all availble windows in the system. The listing is written in the
-     * specified Socket's output stream with the following syntax:
-     * windowHashCodeInHexadecimal windowName
-     * Each line of the ouput represents a different window.
+     * Lists all available windows in the system. The listing is written in the specified Socket's
+     * output stream with the following syntax: windowHashCodeInHexadecimal windowName
+     * Each line of the output represents a different window.
      *
      * @param client The remote client to send the listing to.
-     * @return False if an error occured, true otherwise.
+     * @return false if an error occurred, true otherwise.
      */
     boolean viewServerListWindows(Socket client) {
         if (isSystemSecure()) {
@@ -6111,14 +5885,9 @@
 
         boolean result = true;
 
-        WindowList windows = new WindowList();
+        final WindowList windows = new WindowList();
         synchronized (mWindowMap) {
-            //noinspection unchecked
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                windows.addAll(displayContent.getWindowList());
-            }
+            mRoot.getWindows(windows);
         }
 
         BufferedWriter out = null;
@@ -6345,25 +6114,13 @@
         }
 
         synchronized (mWindowMap) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                final int numWindows = windows.size();
-                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                    final WindowState w = windows.get(winNdx);
-                    if (System.identityHashCode(w) == hashCode) {
-                        return w;
-                    }
-                }
-            }
+            return mRoot.findWindow(hashCode);
         }
-
-        return null;
     }
 
-    /*
-     * Instruct the Activity Manager to fetch the current configuration and broadcast
-     * that to config-changed listeners if appropriate.
+    /**
+     * Instruct the Activity Manager to fetch new configurations, update global configuration
+     * and broadcast changes to config-changed listeners if appropriate.
      */
     void sendNewConfiguration() {
         try {
@@ -6680,7 +6437,7 @@
     private void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
         int taskId = -1;
         synchronized (mWindowMap) {
-            final Task task = displayContent.findTaskForControlPoint(x, y);
+            final Task task = displayContent.findTaskForResizePoint(x, y);
             if (task != null) {
                 if (!startPositioningLocked(
                         task.getTopVisibleAppMainWindow(), true /*resize*/, x, y)) {
@@ -6759,51 +6516,6 @@
         }
     }
 
-    void adjustForImeIfNeeded(final DisplayContent displayContent) {
-        final WindowState imeWin = mInputMethodWindow;
-        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
-                && !displayContent.mDividerControllerLocked.isImeHideRequested();
-        final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
-        final TaskStack imeTargetStack = getImeFocusStackLocked();
-        final int imeDockSide = (dockVisible && imeTargetStack != null) ?
-                imeTargetStack.getDockSide() : DOCKED_INVALID;
-        final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
-        final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
-        final boolean dockMinimized = displayContent.mDividerControllerLocked.isMinimizedDock();
-        final int imeHeight = mPolicy.getInputMethodWindowVisibleHeightLw();
-        final boolean imeHeightChanged = imeVisible &&
-                imeHeight != displayContent.mDividerControllerLocked.getImeHeightAdjustedFor();
-
-        // The divider could be adjusted for IME position, or be thinner than usual,
-        // or both. There are three possible cases:
-        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
-        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
-        // - If IME is not visible, divider is not moved and is normal width.
-
-        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
-            final ArrayList<TaskStack> stacks = displayContent.getStacks();
-            for (int i = stacks.size() - 1; i >= 0; --i) {
-                final TaskStack stack = stacks.get(i);
-                final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
-                if (stack.isVisibleLocked() && (imeOnBottom || isDockedOnBottom)) {
-                    stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
-                } else {
-                    stack.resetAdjustedForIme(false);
-                }
-            }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(
-                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
-        } else {
-            final ArrayList<TaskStack> stacks = displayContent.getStacks();
-            for (int i = stacks.size() - 1; i >= 0; --i) {
-                final TaskStack stack = stacks.get(i);
-                stack.resetAdjustedForIme(!dockVisible);
-            }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(
-                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
-        }
-    }
-
     // -------------------------------------------------------------
     // Drag and drop
     // -------------------------------------------------------------
@@ -7061,7 +6773,7 @@
 
     private void displayReady(int displayId) {
         synchronized(mWindowMap) {
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent != null) {
                 mAnimator.addDisplayLocked(displayId);
                 displayContent.initializeDisplayBaseInfo();
@@ -7137,7 +6849,7 @@
         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
         public static final int UPDATE_ANIMATION_SCALE = 51;
-        public static final int WINDOW_REMOVE_TIMEOUT = 52;
+        public static final int WINDOW_HIDE_TIMEOUT = 52;
         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
@@ -7240,8 +6952,8 @@
 
                     View view = null;
                     try {
-                        final Configuration overrideConfig = wtoken != null && wtoken.mTask != null
-                                ? wtoken.mTask.mOverrideConfig : null;
+                        final Configuration overrideConfig =
+                                wtoken != null ? wtoken.getMergedOverrideConfiguration() : null;
                         view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme,
                             sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo,
                             sd.windowFlags, overrideConfig);
@@ -7486,20 +7198,8 @@
                     synchronized (mWindowMap) {
                         Slog.w(TAG_WM, "App freeze timeout expired.");
                         mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
-                        final int numStacks = mStackIdToStack.size();
-                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
-                            final ArrayList<Task> tasks = stack.getTasks();
-                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                                    AppWindowToken tok = tokens.get(tokenNdx);
-                                    if (tok.mAppAnimator.freezingScreen) {
-                                        Slog.w(TAG_WM, "Force clearing freeze: " + tok);
-                                        tok.stopFreezingScreen(true, true);
-                                    }
-                                }
-                            }
+                        for (int i = mAppFreezeListeners.size() - 1; i >=0 ; --i) {
+                            mAppFreezeListeners.get(i).onAppFreezeTimeout();
                         }
                     }
                     break;
@@ -7718,7 +7418,7 @@
                     synchronized (mWindowMap) {
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
                         displayContent.getDockedDividerController().reevaluateVisibility(false);
-                        adjustForImeIfNeeded(displayContent);
+                        displayContent.adjustForImeIfNeeded();
                     }
                 }
                 break;
@@ -7741,11 +7441,11 @@
                 break;
                 case WINDOW_REPLACEMENT_TIMEOUT: {
                     synchronized (mWindowMap) {
-                        for (int i = mReplacingWindowTimeouts.size() - 1; i >= 0; i--) {
-                            final AppWindowToken token = mReplacingWindowTimeouts.get(i);
-                            token.clearTimedoutReplacesLocked();
+                        for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
+                            final AppWindowToken token = mWindowReplacementTimeouts.get(i);
+                            token.onWindowReplacementTimeout();
                         }
-                        mReplacingWindowTimeouts.clear();
+                        mWindowReplacementTimeouts.clear();
                     }
                 }
                 case NOTIFY_APP_TRANSITION_STARTING: {
@@ -7764,7 +7464,7 @@
                     mAmInternal.notifyStartingWindowDrawn();
                 }
                 break;
-                case WINDOW_REMOVE_TIMEOUT: {
+                case WINDOW_HIDE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized(mWindowMap) {
                         // TODO: This is all about fixing b/21693547
@@ -7775,8 +7475,11 @@
                         // running under debugger) to crash (b/29105388). The windows will
                         // eventually be removed when the client process finishes.
                         // The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
-                        // and prevent the symptoms of b/21693547.
+                        // and prevent the symptoms of b/21693547. Since apps don't
+                        // support windows being removed under them we hide the window
+                        // and it will be removed when the app dies.
                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
+                        window.hidePermanentlyLw();
                         window.setDisplayLayoutNeeded();
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
@@ -7870,7 +7573,7 @@
                             && imFocus.mAppToken != null) {
                         // The client has definitely started, so it really should
                         // have a window in this app token.  Let's look for it.
-                        final WindowState w = imFocus.mAppToken.getFirstWindow(imFocus);
+                        final WindowState w = imFocus.mAppToken.getFirstNonStartingWindow();
                         if (w != null) {
                             if (DEBUG_INPUT_METHOD) Slog.i(TAG_WM,
                                     "Switching to real app window: " + w);
@@ -7911,7 +7614,7 @@
     @Override
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mInitialDisplayWidth;
                 size.y = displayContent.mInitialDisplayHeight;
@@ -7922,7 +7625,7 @@
     @Override
     public void getBaseDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mBaseDisplayWidth;
                 size.y = displayContent.mBaseDisplayHeight;
@@ -7949,7 +7652,7 @@
                 final int MIN_WIDTH = 200;
                 final int MIN_HEIGHT = 200;
                 final int MAX_SCALE = 2;
-                final DisplayContent displayContent = getDisplayContentLocked(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
                 if (displayContent != null) {
                     width = Math.min(Math.max(width, MIN_WIDTH),
                             displayContent.mInitialDisplayWidth * MAX_SCALE);
@@ -7979,7 +7682,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = getDisplayContentLocked(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
                 if (displayContent != null) {
                     if (mode < 0 || mode > 1) {
                         mode = 0;
@@ -8062,7 +7765,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = getDisplayContentLocked(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
                 if (displayContent != null) {
                     setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
                             displayContent.mInitialDisplayHeight);
@@ -8078,7 +7781,7 @@
     @Override
     public int getInitialDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mInitialDisplayDensity;
             }
@@ -8089,7 +7792,7 @@
     @Override
     public int getBaseDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mBaseDisplayDensity;
             }
@@ -8098,7 +7801,7 @@
     }
 
     @Override
-    public void setForcedDisplayDensity(int displayId, int density) {
+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                 PackageManager.PERMISSION_GRANTED) {
@@ -8108,16 +7811,20 @@
         if (displayId != Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("Can only set the default display");
         }
+
+        final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
+                null);
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = getDisplayContentLocked(displayId);
-                if (displayContent != null) {
+                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                if (displayContent != null && mCurrentUserId == targetUserId) {
                     setForcedDisplayDensityLocked(displayContent, density);
-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                            Settings.Secure.DISPLAY_DENSITY_FORCED,
-                            Integer.toString(density), mCurrentUserId);
                 }
+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        Settings.Secure.DISPLAY_DENSITY_FORCED,
+                        Integer.toString(density), targetUserId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -8125,7 +7832,7 @@
     }
 
     @Override
-    public void clearForcedDisplayDensity(int displayId) {
+    public void clearForcedDisplayDensityForUser(int displayId, int userId) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                 PackageManager.PERMISSION_GRANTED) {
@@ -8135,16 +7842,20 @@
         if (displayId != Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("Can only set the default display");
         }
+
+        final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
+                null);
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = getDisplayContentLocked(displayId);
-                if (displayContent != null) {
+                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                if (displayContent != null && mCurrentUserId == callingUserId) {
                     setForcedDisplayDensityLocked(displayContent,
                             displayContent.mInitialDisplayDensity);
-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                            Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
                 }
+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        Settings.Secure.DISPLAY_DENSITY_FORCED, "", callingUserId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -8183,34 +7894,29 @@
         reconfigureDisplayLocked(displayContent);
     }
 
-    // displayContent must not be null
-    private void reconfigureDisplayLocked(DisplayContent displayContent) {
-        // TODO: Multidisplay: for now only use with default display.
+    void reconfigureDisplayLocked(@NonNull DisplayContent displayContent) {
         if (!mDisplayReady) {
             return;
         }
         configureDisplayPolicyLocked(displayContent);
-        displayContent.layoutNeeded = true;
+        displayContent.setLayoutNeeded();
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
-        mTempConfiguration.setToDefaults();
-        mTempConfiguration.updateFrom(mCurConfiguration);
+        final Configuration globalConfig = mRoot.getConfiguration();
+        mTempConfiguration.setTo(globalConfig);
         computeScreenConfigurationLocked(mTempConfiguration);
-        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
+        configChanged |= globalConfig.diff(mTempConfiguration) != 0;
 
         if (configChanged) {
             mWaitingForConfig = true;
             startFreezingDisplayLocked(false, 0, 0);
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-            if (!mReconfigureOnConfigurationChanged.contains(displayContent)) {
-                mReconfigureOnConfigurationChanged.add(displayContent);
-            }
         }
 
         mWindowPlacerLocked.performSurfacePlacement();
     }
 
-    private void configureDisplayPolicyLocked(DisplayContent displayContent) {
+    void configureDisplayPolicyLocked(DisplayContent displayContent) {
         mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
                 displayContent.mBaseDisplayWidth,
                 displayContent.mBaseDisplayHeight,
@@ -8233,7 +7939,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                DisplayContent displayContent = getDisplayContentLocked(displayId);
+                DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
                 if (displayContent != null) {
                     setOverscanLocked(displayContent, left, top, right, bottom);
                 }
@@ -8292,102 +7998,6 @@
         return win;
     }
 
-    final void rebuildAppWindowListLocked() {
-        rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
-    }
-
-    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
-        final WindowList windows = displayContent.getWindowList();
-        int NW = windows.size();
-        int i;
-        int lastBelow = -1;
-        int numRemoved = 0;
-
-        if (mRebuildTmp.length < NW) {
-            mRebuildTmp = new WindowState[NW+10];
-        }
-
-        // First remove all existing app windows.
-        i=0;
-        while (i < NW) {
-            WindowState w = windows.get(i);
-            if (w.mAppToken != null) {
-                WindowState win = windows.remove(i);
-                win.mRebuilding = true;
-                mRebuildTmp[numRemoved] = win;
-                mWindowsChanged = true;
-                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win);
-                NW--;
-                numRemoved++;
-                continue;
-            } else if (lastBelow == i-1) {
-                if (w.mAttrs.type == TYPE_WALLPAPER) {
-                    lastBelow = i;
-                }
-            }
-            i++;
-        }
-
-        // Keep whatever windows were below the app windows still below, by skipping them.
-        lastBelow++;
-        i = lastBelow;
-
-        // First add all of the exiting app tokens...  these are no longer in the main app list,
-        // but still have windows shown. We put them in the back because now that the animation is
-        // over we no longer will care about them.
-        final ArrayList<TaskStack> stacks = displayContent.getStacks();
-        final int numStacks = stacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
-            int NT = exitingAppTokens.size();
-            for (int j = 0; j < NT; j++) {
-                i = exitingAppTokens.get(j).reAddAppWindows(displayContent, i);
-            }
-        }
-
-        // And add in the still active app tokens in Z order.
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
-            final int numTasks = tasks.size();
-            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                final int numTokens = tokens.size();
-                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (wtoken.mIsExiting && !wtoken.waitingForReplacement()) {
-                        continue;
-                    }
-                    i = wtoken.reAddAppWindows(displayContent, i);
-                }
-            }
-        }
-
-        i -= lastBelow;
-        if (i != numRemoved) {
-            displayContent.layoutNeeded = true;
-            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed "
-                    + numRemoved + " windows but added " + i + " rebuildAppWindowListLocked() "
-                    + " callers=" + Debug.getCallers(10));
-            for (i = 0; i < numRemoved; i++) {
-                WindowState ws = mRebuildTmp[i];
-                if (ws.mRebuilding) {
-                    StringWriter sw = new StringWriter();
-                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
-                    ws.dump(pw, "", true);
-                    pw.flush();
-                    Slog.w(TAG_WM, "This window was lost: " + ws);
-                    Slog.w(TAG_WM, sw.toString());
-                    ws.mWinAnimator.destroySurfaceLocked();
-                }
-            }
-            Slog.w(TAG_WM, "Current app token list:");
-            dumpAppTokensLocked();
-            Slog.w(TAG_WM, "Final window list:");
-            dumpWindowsLocked();
-        }
-        Arrays.fill(mRebuildTmp, null);
-    }
-
     void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
@@ -8396,7 +8006,7 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
-            mWindowPlacerLocked.mOrientationChangeComplete = false;
+            mRoot.mOrientationChangeComplete = false;
             if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
                 mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
@@ -8424,139 +8034,20 @@
 
         mWallpaperControllerLocked.hideDeferredWallpapersIfNeeded();
 
-        // Restore window app tokens to the ActivityManager views
-        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    tokens.get(tokenNdx).sendingToBottom = false;
-                }
-            }
-        }
-        rebuildAppWindowListLocked();
+        getDefaultDisplayContentLocked().onAppTransitionDone();
 
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG_WM,
                 "Wallpaper layer changed: assigning layers + relayout");
         moveInputMethodWindowsIfNeededLocked(true);
-        mWindowPlacerLocked.mWallpaperMayChange = true;
-        // Since the window list has been rebuilt, focus might
-        // have to be recomputed since the actual order of windows
-        // might have changed again.
+        mRoot.mWallpaperMayChange = true;
+        // Since the window list has been rebuilt, focus might have to be recomputed since the
+        // actual order of windows might have changed again.
         mFocusMayChange = true;
 
         return changes;
     }
 
-    void updateResizingWindows(final WindowState w) {
-        final WindowStateAnimator winAnimator = w.mWinAnimator;
-        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq && !w.isGoneForLayoutLw()) {
-            final Task task = w.getTask();
-            // In the case of stack bound animations, the window frames
-            // will update (unlike other animations which just modifiy
-            // various transformation properties). We don't want to
-            // notify the client of frame changes in this case. Not only
-            // is it a lot of churn, but the frame may not correspond
-            // to the surface size or the onscreen area at various
-            // phases in the animation, and the client will become
-            // sad and confused.
-            if (task != null && task.mStack.getBoundsAnimating()) {
-                return;
-            }
-            w.setReportResizeHints();
-            boolean configChanged = w.isConfigChanged();
-            if (DEBUG_CONFIGURATION && configChanged) {
-                Slog.v(TAG_WM, "Win " + w + " config changed: "
-                        + mCurConfiguration);
-            }
-            final boolean dragResizingChanged = w.isDragResizeChanged()
-                    && !w.isDragResizingChangeReported();
-
-            if (localLOGV) Slog.v(TAG_WM, "Resizing " + w
-                    + ": configChanged=" + configChanged
-                    + " dragResizingChanged=" + dragResizingChanged
-                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
-
-            // We update mLastFrame always rather than in the conditional with the
-            // last inset variables, because mFrameSizeChanged only tracks the
-            // width and height changing.
-            w.mLastFrame.set(w.mFrame);
-
-            if (w.mContentInsetsChanged
-                    || w.mVisibleInsetsChanged
-                    || winAnimator.mSurfaceResized
-                    || w.mOutsetsChanged
-                    || w.mFrameSizeChanged
-                    || configChanged
-                    || dragResizingChanged
-                    || !w.isResizedWhileNotDragResizingReported()) {
-                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
-                    Slog.v(TAG_WM, "Resize reasons for w=" + w + ": "
-                            + " contentInsetsChanged=" + w.mContentInsetsChanged
-                            + " " + w.mContentInsets.toShortString()
-                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
-                            + " " + w.mVisibleInsets.toShortString()
-                            + " stableInsetsChanged=" + w.mStableInsetsChanged
-                            + " " + w.mStableInsets.toShortString()
-                            + " outsetsChanged=" + w.mOutsetsChanged
-                            + " " + w.mOutsets.toShortString()
-                            + " surfaceResized=" + winAnimator.mSurfaceResized
-                            + " configChanged=" + configChanged
-                            + " dragResizingChanged=" + dragResizingChanged
-                            + " resizedWhileNotDragResizingReported="
-                            + w.isResizedWhileNotDragResizingReported());
-                }
-
-                // If it's a dead window left on screen, and the configuration changed,
-                // there is nothing we can do about it. Remove the window now.
-                if (w.mAppToken != null && w.mAppDied) {
-                    w.mAppToken.removeAllDeadWindows();
-                    return;
-                }
-
-                w.mLastOverscanInsets.set(w.mOverscanInsets);
-                w.mLastContentInsets.set(w.mContentInsets);
-                w.mLastVisibleInsets.set(w.mVisibleInsets);
-                w.mLastStableInsets.set(w.mStableInsets);
-                w.mLastOutsets.set(w.mOutsets);
-                makeWindowFreezingScreenIfNeededLocked(w);
-                // If the orientation is changing, or we're starting or ending
-                // a drag resizing action, then we need to hold off on unfreezing
-                // the display until this window has been redrawn; to do that,
-                // we need to go through the process of getting informed by the
-                // application when it has finished drawing.
-                if (w.mOrientationChanging || dragResizingChanged
-                        || w.isResizedWhileNotDragResizing()) {
-                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
-                        Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
-                                + ", mDrawState=DRAW_PENDING in " + w
-                                + ", surfaceController " + winAnimator.mSurfaceController);
-                    }
-                    winAnimator.mDrawState = DRAW_PENDING;
-                    if (w.mAppToken != null) {
-                        w.mAppToken.clearAllDrawn();
-                    }
-                }
-                if (!mResizingWindows.contains(w)) {
-                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Resizing window " + w);
-                    mResizingWindows.add(w);
-                }
-            } else if (w.mOrientationChanging) {
-                if (w.isDrawnLw()) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                            "Orientation not waiting for draw in "
-                            + w + ", surfaceController " + winAnimator.mSurfaceController);
-                    w.mOrientationChanging = false;
-                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
-                            - mDisplayFreezeTime);
-                }
-            }
-        }
-    }
-
     void checkDrawnWindowsLocked() {
         if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
             return;
@@ -8596,20 +8087,20 @@
         if (hold != state) {
             if (hold) {
                 if (DEBUG_KEEP_SCREEN_ON) {
-                    Slog.d(TAG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to " +
-                            mWindowPlacerLocked.mHoldScreenWindow);
+                    Slog.d(TAG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to "
+                            + mRoot.mHoldScreenWindow);
                 }
-                mLastWakeLockHoldingWindow = mWindowPlacerLocked.mHoldScreenWindow;
+                mLastWakeLockHoldingWindow = mRoot.mHoldScreenWindow;
                 mLastWakeLockObscuringWindow = null;
                 mHoldingScreenWakeLock.acquire();
                 mPolicy.keepScreenOnStartedLw();
             } else {
                 if (DEBUG_KEEP_SCREEN_ON) {
-                    Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by " +
-                            mWindowPlacerLocked.mObsuringWindow);
+                    Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by "
+                            + mRoot.mObsuringWindow);
                 }
                 mLastWakeLockHoldingWindow = null;
-                mLastWakeLockObscuringWindow = mWindowPlacerLocked.mObsuringWindow;
+                mLastWakeLockObscuringWindow = mRoot.mObsuringWindow;
                 mPolicy.keepScreenOnStoppedLw();
                 mHoldingScreenWakeLock.release();
             }
@@ -8630,17 +8121,6 @@
         }
     }
 
-    boolean needsLayout() {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            if (displayContent.layoutNeeded) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** If a window that has an animation specifying a colored background and the current wallpaper
      * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
      * suddenly disappear. */
@@ -8655,108 +8135,8 @@
         return winAnimator.mAnimLayer;
     }
 
-    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
-                                           boolean secure) {
-        final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
-        boolean leakedSurface = false;
-        boolean killedApps = false;
-
-        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
-                winAnimator.mSession.mPid, operation);
-
-        final long callingIdentity = Binder.clearCallingIdentity();
-        try {
-            // There was some problem...   first, do a sanity check of the window list to make sure
-            // we haven't left any dangling surfaces around.
-
-            Slog.i(TAG_WM, "Out of memory for surface!  Looking for leaks...");
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                final int numWindows = windows.size();
-                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                    final WindowState ws = windows.get(winNdx);
-                    final WindowStateAnimator wsa = ws.mWinAnimator;
-                    if (wsa.mSurfaceController == null) {
-                        continue;
-                    }
-                    if (!mSessions.contains(wsa.mSession)) {
-                        Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
-                                + ws + " surface=" + wsa.mSurfaceController
-                                + " token=" + ws.mToken
-                                + " pid=" + ws.mSession.mPid
-                                + " uid=" + ws.mSession.mUid);
-                        wsa.destroySurface();
-                        mForceRemoves.add(ws);
-                        leakedSurface = true;
-                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
-                        Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
-                                + ws + " surface=" + wsa.mSurfaceController
-                                + " token=" + ws.mAppToken
-                                + " saved=" + ws.hasSavedSurface());
-                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
-                        wsa.destroySurface();
-                        leakedSurface = true;
-                    }
-                }
-            }
-
-            if (!leakedSurface) {
-                Slog.w(TAG_WM, "No leaked surfaces; killing applicatons!");
-                SparseIntArray pidCandidates = new SparseIntArray();
-                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-                    final int numWindows = windows.size();
-                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                        final WindowState ws = windows.get(winNdx);
-                        if (mForceRemoves.contains(ws)) {
-                            continue;
-                        }
-                        WindowStateAnimator wsa = ws.mWinAnimator;
-                        if (wsa.mSurfaceController != null) {
-                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
-                        }
-                    }
-                    if (pidCandidates.size() > 0) {
-                        int[] pids = new int[pidCandidates.size()];
-                        for (int i=0; i<pids.length; i++) {
-                            pids[i] = pidCandidates.keyAt(i);
-                        }
-                        try {
-                            if (mActivityManager.killPids(pids, "Free memory", secure)) {
-                                killedApps = true;
-                            }
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-            }
-
-            if (leakedSurface || killedApps) {
-                // We managed to reclaim some memory, so get rid of the trouble
-                // surface and ask the app to request another one.
-                Slog.w(TAG_WM, "Looks like we have reclaimed some memory, clearing surface for retry.");
-                if (surfaceController != null) {
-                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
-                            "RECOVER DESTROY", false);
-                    winAnimator.destroySurface();
-                    scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
-                }
-
-                try {
-                    winAnimator.mWin.mClient.dispatchGetNewSurface();
-                } catch (RemoteException e) {
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(callingIdentity);
-        }
-
-        return leakedSurface || killedApps;
-    }
-
     boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
-        WindowState newFocus = computeFocusedWindowLocked();
+        WindowState newFocus = mRoot.computeFocusedWindow();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
             // This check makes sure that we don't already have the focus
@@ -8769,8 +8149,8 @@
                     mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
                             && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
             if (imWindowChanged) {
-                displayContent.layoutNeeded = true;
-                newFocus = computeFocusedWindowLocked();
+                displayContent.setLayoutNeeded();
+                newFocus = mRoot.computeFocusedWindow();
             }
 
             if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG_WM, "Changing focus from " +
@@ -8796,7 +8176,7 @@
 
             if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                 // The change in focus caused us to need to do a layout.  Okay.
-                displayContent.layoutNeeded = true;
+                displayContent.setLayoutNeeded();
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
                             updateInputWindows);
@@ -8809,7 +8189,13 @@
                 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
             }
 
-            adjustForImeIfNeeded(displayContent);
+            displayContent.adjustForImeIfNeeded();
+
+            // We may need to schedule some toast windows to be removed. The
+            // toasts for an app that does not have input focus are removed
+            // within a timeout to prevent apps to redress other apps' UI.
+            getDefaultDisplayContentLocked().scheduleToastWindowsTimeoutIfNeededLocked(
+                        oldFocus, newFocus);
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             return true;
@@ -8817,79 +8203,6 @@
         return false;
     }
 
-    private WindowState computeFocusedWindowLocked() {
-        final int displayCount = mDisplayContents.size();
-        for (int i = 0; i < displayCount; i++) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(i);
-            WindowState win = findFocusedWindowLocked(displayContent);
-            if (win != null) {
-                return win;
-            }
-        }
-        return null;
-    }
-
-    WindowState findFocusedWindowLocked(DisplayContent displayContent) {
-        final WindowList windows = displayContent.getWindowList();
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-
-            if (localLOGV || DEBUG_FOCUS) Slog.v(
-                TAG_WM, "Looking for focus: " + i
-                + " = " + win
-                + ", flags=" + win.mAttrs.flags
-                + ", canReceive=" + win.canReceiveKeys());
-
-            if (!win.canReceiveKeys()) {
-                continue;
-            }
-
-            AppWindowToken wtoken = win.mAppToken;
-
-            // If this window's application has been removed, just skip it.
-            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
-                if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
-                        + (wtoken.removed ? "removed" : "sendingToBottom"));
-                continue;
-            }
-
-            // Descend through all of the app tokens and find the first that either matches
-            // win.mAppToken (return win) or mFocusedApp (return null).
-            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
-                    mFocusedApp != null) {
-                ArrayList<Task> tasks = displayContent.getTasks();
-                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                    int tokenNdx = tokens.size() - 1;
-                    for ( ; tokenNdx >= 0; --tokenNdx) {
-                        final AppWindowToken token = tokens.get(tokenNdx);
-                        if (wtoken == token) {
-                            break;
-                        }
-                        if (mFocusedApp == token && token.windowsAreFocusable()) {
-                            // Whoops, we are below the focused app whose windows are focusable...
-                            // No focus for you!!!
-                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
-                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
-                            return null;
-                        }
-                    }
-                    if (tokenNdx >= 0) {
-                        // Early exit from loop, must have found the matching token.
-                        break;
-                    }
-                }
-            }
-
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + i +
-                        " = " + win);
-            return win;
-        }
-
-        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
-        return null;
-    }
-
     void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
         if (mDisplayFrozen) {
             return;
@@ -8953,7 +8266,7 @@
             // TODO(multidisplay): rotation on main screen only.
             displayContent.updateDisplayInfo();
             screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
-                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
+                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure, this);
             mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
         }
     }
@@ -9091,6 +8404,7 @@
             if (line != null) {
                 String[] toks = line.split("%");
                 if (toks != null && toks.length > 0) {
+                    // TODO(multi-display): Show watermarks on secondary displays.
                     mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
                             mRealDisplayMetrics, mFxSession, toks);
                 }
@@ -9113,6 +8427,32 @@
     }
 
     @Override
+    public void setRecentsVisibility(boolean visible) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold permission "
+                    + android.Manifest.permission.STATUS_BAR);
+        }
+
+        synchronized (mWindowMap) {
+            mPolicy.setRecentsVisibilityLw(visible);
+        }
+    }
+
+    @Override
+    public void setTvPipVisibility(boolean visible) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold permission "
+                    + android.Manifest.permission.STATUS_BAR);
+        }
+
+        synchronized (mWindowMap) {
+            mPolicy.setTvPipVisibilityLw(visible);
+        }
+    }
+
+    @Override
     public void statusBarVisibilityChanged(int visibility) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -9397,19 +8737,6 @@
         }
     }
 
-    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
-        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
-        if (mDisplayReady) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                displayContent.dump("  ", pw);
-            }
-        } else {
-            pw.println("  NO DISPLAY");
-        }
-    }
-
     void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
         pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
@@ -9418,18 +8745,8 @@
 
     void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
-            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                final WindowState w = windowList.get(winNdx);
-                if (windows == null || windows.contains(w)) {
-                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
-                            pw.print(w); pw.println(":");
-                    w.dump(pw, "    ", dumpAll || windows != null);
-                }
-            }
-        }
+        mRoot.dumpWindowsNoHeader(pw, dumpAll, windows);
+
         if (mInputMethodDialogs.size() > 0) {
             pw.println();
             pw.println("  Input method dialogs:");
@@ -9532,7 +8849,7 @@
             }
         }
         pw.println();
-        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
+        pw.print("  mGlobalConfiguration="); pw.println(mRoot.getConfiguration());
         pw.print("  mHasPermanentDpad="); pw.println(mHasPermanentDpad);
         pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
         if (mLastFocus != mCurrentFocus) {
@@ -9572,16 +8889,9 @@
             mLayersController.dump(pw, "  ");
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
-            if (needsLayout()) {
-                pw.print("  layoutNeeded on displays=");
-                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                    if (displayContent.layoutNeeded) {
-                        pw.print(displayContent.getDisplayId());
-                    }
-                }
-                pw.println();
-            }
+
+            mRoot.dumpLayoutNeededDisplayIds(pw);
+
             pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" windows="); pw.print(mWindowsFreezingScreen);
@@ -9603,54 +8913,21 @@
         }
     }
 
-    boolean dumpWindows(PrintWriter pw, String name, String[] args,
-            int opti, boolean dumpAll) {
+    boolean dumpWindows(PrintWriter pw, String name, String[] args, int opti, boolean dumpAll) {
         WindowList windows = new WindowList();
         if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) {
             final boolean appsOnly = name.contains("apps");
             final boolean visibleOnly = name.contains("visible");
             synchronized(mWindowMap) {
                 if (appsOnly) {
-                    dumpDisplayContentsLocked(pw, true);
+                    mRoot.dumpDisplayContents(pw);
                 }
 
-                final int numDisplays = mDisplayContents.size();
-                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final WindowList windowList =
-                            mDisplayContents.valueAt(displayNdx).getWindowList();
-                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                        final WindowState w = windowList.get(winNdx);
-                        if ((!visibleOnly || w.mWinAnimator.getShown())
-                                && (!appsOnly || w.mAppToken != null)) {
-                            windows.add(w);
-                        }
-                    }
-                }
+                mRoot.getWindows(windows, visibleOnly, appsOnly);
             }
         } else {
-            int objectId = 0;
-            // See if this is an object ID.
-            try {
-                objectId = Integer.parseInt(name, 16);
-                name = null;
-            } catch (RuntimeException e) {
-            }
             synchronized(mWindowMap) {
-                final int numDisplays = mDisplayContents.size();
-                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                    final WindowList windowList =
-                            mDisplayContents.valueAt(displayNdx).getWindowList();
-                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
-                        final WindowState w = windowList.get(winNdx);
-                        if (name != null) {
-                            if (w.mAttrs.getTitle().toString().contains(name)) {
-                                windows.add(w);
-                            }
-                        } else if (System.identityHashCode(w) == objectId) {
-                            windows.add(w);
-                        }
-                    }
-                }
+                mRoot.getWindowsByName(windows, name);
             }
         }
 
@@ -9700,7 +8977,7 @@
         dumpWindowsNoHeaderLocked(pw, true, null);
         pw.println();
         pw.println("Last ANR continued");
-        dumpDisplayContentsLocked(pw, true);
+        mRoot.dumpDisplayContents(pw);
         pw.close();
         mLastANRState = sw.toString();
 
@@ -9785,7 +9062,7 @@
                 return;
             } else if ("displays".equals(cmd) || "d".equals(cmd)) {
                 synchronized(mWindowMap) {
-                    dumpDisplayContentsLocked(pw, true);
+                    mRoot.dumpDisplayContents(pw);
                 }
                 return;
             } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
@@ -9803,6 +9080,13 @@
                     dumpWindowsLocked(pw, true, null);
                 }
                 return;
+            } else if ("containers".equals(cmd)) {
+                synchronized(mWindowMap) {
+                    StringBuilder output = new StringBuilder();
+                    mRoot.dumpChildrenNames(output, " ");
+                    pw.println(output.toString());
+                }
+                return;
             } else {
                 // Dumping a single name?
                 if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
@@ -9845,7 +9129,7 @@
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
-            dumpDisplayContentsLocked(pw, dumpAll);
+            mRoot.dumpDisplayContents(pw);
             pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
@@ -9865,61 +9149,17 @@
         synchronized (mWindowMap) { }
     }
 
-    private DisplayContent newDisplayContentLocked(final Display display) {
-        DisplayContent displayContent = new DisplayContent(display, this);
-        final int displayId = display.getDisplayId();
-        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
-        mDisplayContents.put(displayId, displayContent);
-
-        DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final Rect rect = new Rect();
-        mDisplaySettings.getOverscanLocked(displayInfo.name, displayInfo.uniqueId, rect);
-        displayInfo.overscanLeft = rect.left;
-        displayInfo.overscanTop = rect.top;
-        displayInfo.overscanRight = rect.right;
-        displayInfo.overscanBottom = rect.bottom;
-        if (mDisplayManagerInternal != null) {
-            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(displayId, displayInfo);
-            configureDisplayPolicyLocked(displayContent);
-
-            // TODO: Create an input channel for each display with touch capability.
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                displayContent.mTapDetector = new TaskTapPointerEventListener(this, displayContent);
-                registerPointerEventListener(displayContent.mTapDetector);
-                registerPointerEventListener(mMousePositionTracker);
-            }
-        }
-
-        return displayContent;
-    }
-
+    // TODO: All the display method below should probably be moved into the RootWindowContainer...
     public void createDisplayContentLocked(final Display display) {
         if (display == null) {
             throw new IllegalArgumentException("getDisplayContent: display must not be null");
         }
-        getDisplayContentLocked(display.getDisplayId());
-    }
-
-    /**
-     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
-     * there is a Display for the displayId.
-     * @param displayId The display the caller is interested in.
-     * @return The DisplayContent associated with displayId or null if there is no Display for it.
-     */
-    public DisplayContent getDisplayContentLocked(final int displayId) {
-        DisplayContent displayContent = mDisplayContents.get(displayId);
-        if (displayContent == null) {
-            final Display display = mDisplayManager.getDisplay(displayId);
-            if (display != null) {
-                displayContent = newDisplayContentLocked(display);
-            }
-        }
-        return displayContent;
+        mRoot.getDisplayContentOrCreate(display.getDisplayId());
     }
 
     // There is an inherent assumption that this will never return null.
     public DisplayContent getDefaultDisplayContentLocked() {
-        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
+        return mRoot.getDisplayContentOrCreate(Display.DEFAULT_DISPLAY);
     }
 
     public WindowList getDefaultWindowListLocked() {
@@ -9932,20 +9172,11 @@
 
     /**
      * Return the list of WindowStates associated on the passed display.
-     * @param display The screen to return windows from.
-     * @return The list of WindowStates on the screen, or null if the there is no screen.
-     */
-    public WindowList getWindowListLocked(final Display display) {
-        return getWindowListLocked(display.getDisplayId());
-    }
-
-    /**
-     * Return the list of WindowStates associated on the passed display.
      * @param displayId The screen to return windows from.
      * @return The list of WindowStates on the screen, or null if the there is no screen.
      */
-    public WindowList getWindowListLocked(final int displayId) {
-        final DisplayContent displayContent = getDisplayContentLocked(displayId);
+    WindowList getWindowListLocked(final int displayId) {
+        final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
         return displayContent != null ? displayContent.getWindowList() : null;
     }
 
@@ -9969,19 +9200,9 @@
     }
 
     private void handleDisplayRemovedLocked(int displayId) {
-        final DisplayContent displayContent = getDisplayContentLocked(displayId);
+        final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
         if (displayContent != null) {
-            if (displayContent.isAnimating()) {
-                displayContent.mDeferredRemoval = true;
-                return;
-            }
-            if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + displayContent);
-            mDisplayContents.delete(displayId);
-            displayContent.close();
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                unregisterPointerEventListener(displayContent.mTapDetector);
-                unregisterPointerEventListener(mMousePositionTracker);
-            }
+            displayContent.removeIfPossible();
         }
         mAnimator.removeDisplayLocked(displayId);
         mWindowPlacerLocked.requestTraversal();
@@ -9992,7 +9213,7 @@
     }
 
     private void handleDisplayChangedLocked(int displayId) {
-        final DisplayContent displayContent = getDisplayContentLocked(displayId);
+        final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
         if (displayContent != null) {
             displayContent.updateDisplayInfo();
         }
@@ -10009,16 +9230,15 @@
      * a window.
      * @param token Application token for which the activity will be relaunched.
      */
-    public void setReplacingWindow(IBinder token, boolean animate) {
-        AppWindowToken appWindowToken = null;
+    public void setWillReplaceWindow(IBinder token, boolean animate) {
         synchronized (mWindowMap) {
-            appWindowToken = findAppWindowToken(token);
-            if (appWindowToken == null || !appWindowToken.isVisible()) {
+            final AppWindowToken appWindowToken = findAppWindowToken(token);
+            if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
                 Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
                         + token);
                 return;
             }
-            appWindowToken.setReplacingWindows(animate);
+            appWindowToken.setWillReplaceWindows(animate);
         }
     }
 
@@ -10032,23 +9252,24 @@
      *                     reused rather than replaced).
      *
      */
-    public void setReplacingWindows(IBinder token, boolean childrenOnly) {
-        AppWindowToken appWindowToken = null;
+    // TODO: The s at the end of the method name is the only difference with the name of the method
+    // above. We should combine them or find better names.
+    public void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
         synchronized (mWindowMap) {
-            appWindowToken = findAppWindowToken(token);
-            if (appWindowToken == null || !appWindowToken.isVisible()) {
+            final AppWindowToken appWindowToken = findAppWindowToken(token);
+            if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
                 Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
                         + token);
                 return;
             }
 
             if (childrenOnly) {
-                appWindowToken.setReplacingChildren();
+                appWindowToken.setWillReplaceChildWindows();
             } else {
-                appWindowToken.setReplacingWindows(false /* animate */);
+                appWindowToken.setWillReplaceWindows(false /* animate */);
             }
 
-            scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
+            scheduleClearWillReplaceWindows(token, true /* replacing */);
         }
     }
 
@@ -10061,26 +9282,25 @@
      * @param token Application token for the activity whose window might be replaced.
      * @param replacing Whether the window is being replaced or not.
      */
-    public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
-        AppWindowToken appWindowToken = null;
+    public void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) {
         synchronized (mWindowMap) {
-            appWindowToken = findAppWindowToken(token);
+            final AppWindowToken appWindowToken = findAppWindowToken(token);
             if (appWindowToken == null) {
                 Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
                         + token);
                 return;
             }
             if (replacing) {
-                scheduleReplacingWindowTimeouts(appWindowToken);
+                scheduleWindowReplacementTimeouts(appWindowToken);
             } else {
-                appWindowToken.resetReplacingWindows();
+                appWindowToken.clearWillReplaceWindows();
             }
         }
     }
 
-    void scheduleReplacingWindowTimeouts(AppWindowToken appWindowToken) {
-        if (!mReplacingWindowTimeouts.contains(appWindowToken)) {
-            mReplacingWindowTimeouts.add(appWindowToken);
+    void scheduleWindowReplacementTimeouts(AppWindowToken appWindowToken) {
+        if (!mWindowReplacementTimeouts.contains(appWindowToken)) {
+            mWindowReplacementTimeouts.add(appWindowToken);
         }
         mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
         mH.sendEmptyMessageDelayed(
@@ -10249,7 +9469,7 @@
         }
     }
 
-    private MousePositionTracker mMousePositionTracker = new MousePositionTracker();
+    MousePositionTracker mMousePositionTracker = new MousePositionTracker();
 
     private static class MousePositionTracker implements PointerEventListener {
         private boolean mLatestEventWasMouse;
@@ -10509,7 +9729,7 @@
         public void removeWindowToken(IBinder token, boolean removeWindows) {
             synchronized(mWindowMap) {
                 if (removeWindows) {
-                    WindowToken wtoken = mTokenMap.remove(token);
+                    final WindowToken wtoken = mTokenMap.remove(token);
                     if (wtoken != null) {
                         wtoken.removeAllWindows();
                     }
@@ -10588,4 +9808,15 @@
             }
         }
     }
+
+    void registerAppFreezeListener(AppFreezeListener listener) {
+        if (!mAppFreezeListeners.contains(listener)) {
+            mAppFreezeListeners.add(listener);
+        }
+    }
+
+    void unregisterAppFreezeListener(AppFreezeListener listener) {
+        mAppFreezeListeners.remove(listener);
+    }
+
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c83c083..435b1d2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -87,17 +87,20 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 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;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
 import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
 import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
@@ -116,6 +119,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -125,8 +129,10 @@
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.localLOGV;
 import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
 
@@ -137,10 +143,8 @@
     }
 }
 
-/**
- * A window in the window manager.
- */
-class WindowState extends WindowContainer implements WindowManagerPolicy.WindowState {
+/** A window in the window manager. */
+class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
 
     // The minimal size of a window within the usable area of the freeform stack.
@@ -183,9 +187,20 @@
     boolean mEnforceSizeCompat;
     int mViewVisibility;
     int mSystemUiVisibility;
+    /**
+     * The visibility of the window based on policy like {@link WindowManagerPolicy}.
+     * Normally set by calling {@link #showLw} and {@link #hideLw}.
+     */
     boolean mPolicyVisibility = true;
+    /**
+     * What {@link #mPolicyVisibility} should be set to after a transition animation.
+     * For example, {@link #mPolicyVisibility} might true during an exit animation to hide it and
+     * then set to the value of {@link #mPolicyVisibilityAfterAnim} which is false after the exit
+     * animation is done.
+     */
     boolean mPolicyVisibilityAfterAnim = true;
     boolean mAppOpVisibility = true;
+    boolean mPermanentlyHidden; // the window should never be shown again
     boolean mAppFreezing;
     boolean mHidden;    // Used to determine if to show child windows.
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
@@ -211,14 +226,12 @@
 
     int mLayoutSeq = -1;
 
-    private final Configuration mTmpConfig = new Configuration();
-    // Represents the changes from our override configuration applied
-    // to the global configuration. This is the only form of configuration
-    // which is suitable for delivery to the client.
-    private Configuration mMergedConfiguration = new Configuration();
-    // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
-    // Used only on {@link #TYPE_KEYGUARD}.
-    private boolean mConfigHasChanged;
+    /**
+     * Used to store last reported to client configuration and check if we have newer available.
+     * We'll send configuration to client only if it is different from the last applied one and
+     * client won't perform unnecessary updates.
+     */
+    private final Configuration mLastReportedConfiguration = new Configuration();
 
     /**
      * Actual position of the surface shown on-screen (may be modified by animation). These are
@@ -485,7 +498,7 @@
     boolean mAnimateReplacingWindow = false;
     // If not null, the window that will be used to replace the old one. This is being set when
     // the window is added and unset when this window reports its first draw.
-    WindowState mReplacingWindow = null;
+    WindowState mReplacementWindow = null;
     // For the new window in the replacement transition, if we have
     // requested to replace without animation, then we should
     // make sure we also don't apply an enter animation for
@@ -530,13 +543,15 @@
      */
     boolean mSeamlesslyRotated = false;
 
+    private static final Region sEmptyRegion = new Region();
+
     /**
      * Compares to window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
      */
-    private static final Comparator<WindowContainer> sWindowSubLayerComparator = (w1, w2) -> {
-        final int layer1 = ((WindowState)w1).mSubLayer;
-        final int layer2 = ((WindowState)w2).mSubLayer;
+    private static final Comparator<WindowState> sWindowSubLayerComparator = (w1, w2) -> {
+        final int layer1 = w1.mSubLayer;
+        final int layer2 = w2.mSubLayer;
         if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
             // We insert the child window into the list ordered by the sub-layer.
             // For same sub-layers, the negative one should go below others; the positive one should
@@ -598,7 +613,7 @@
         }
         mDeathRecipient = deathRecipient;
 
-        if ((mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW)) {
+        if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
             // The multiplier here is to reserve space for multiple
             // windows in the same type layer.
             mBaseLayer = mPolicy.windowTypeToLayerLw(parentWindow.mAttrs.type)
@@ -1066,6 +1081,112 @@
                 || mOutsetsChanged || mFrameSizeChanged;
     }
 
+    /**
+     * Adds the window to the resizing list if any of the parameters we use to track the window
+     * dimensions or insets have changed.
+     */
+    void updateResizingWindowIfNeeded() {
+        final WindowStateAnimator winAnimator = mWinAnimator;
+        if (!mHasSurface || mService.mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+            return;
+        }
+
+        final Task task = getTask();
+        // In the case of stack bound animations, the window frames will update (unlike other
+        // animations which just modify various transformation properties). We don't want to
+        // notify the client of frame changes in this case. Not only is it a lot of churn, but
+        // the frame may not correspond to the surface size or the onscreen area at various
+        // phases in the animation, and the client will become sad and confused.
+        if (task != null && task.mStack.getBoundsAnimating()) {
+            return;
+        }
+
+        setReportResizeHints();
+        boolean configChanged = isConfigChanged();
+        if (DEBUG_CONFIGURATION && configChanged) {
+            Slog.v(TAG_WM, "Win " + this + " config changed: " + getConfiguration());
+        }
+
+        final boolean dragResizingChanged = isDragResizeChanged()
+                && !isDragResizingChangeReported();
+
+        if (localLOGV) Slog.v(TAG_WM, "Resizing " + this + ": configChanged=" + configChanged
+                + " dragResizingChanged=" + dragResizingChanged + " last=" + mLastFrame
+                + " frame=" + mFrame);
+
+        // We update mLastFrame always rather than in the conditional with the last inset
+        // variables, because mFrameSizeChanged only tracks the width and height changing.
+        mLastFrame.set(mFrame);
+
+        if (mContentInsetsChanged
+                || mVisibleInsetsChanged
+                || winAnimator.mSurfaceResized
+                || mOutsetsChanged
+                || mFrameSizeChanged
+                || configChanged
+                || dragResizingChanged
+                || !isResizedWhileNotDragResizingReported()) {
+            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
+                Slog.v(TAG_WM, "Resize reasons for w=" + this + ": "
+                        + " contentInsetsChanged=" + mContentInsetsChanged
+                        + " " + mContentInsets.toShortString()
+                        + " visibleInsetsChanged=" + mVisibleInsetsChanged
+                        + " " + mVisibleInsets.toShortString()
+                        + " stableInsetsChanged=" + mStableInsetsChanged
+                        + " " + mStableInsets.toShortString()
+                        + " outsetsChanged=" + mOutsetsChanged
+                        + " " + mOutsets.toShortString()
+                        + " surfaceResized=" + winAnimator.mSurfaceResized
+                        + " configChanged=" + configChanged
+                        + " dragResizingChanged=" + dragResizingChanged
+                        + " resizedWhileNotDragResizingReported="
+                        + isResizedWhileNotDragResizingReported());
+            }
+
+            // If it's a dead window left on screen, and the configuration changed, there is nothing
+            // we can do about it. Remove the window now.
+            if (mAppToken != null && mAppDied) {
+                mAppToken.removeDeadWindows();
+                return;
+            }
+
+            mLastOverscanInsets.set(mOverscanInsets);
+            mLastContentInsets.set(mContentInsets);
+            mLastVisibleInsets.set(mVisibleInsets);
+            mLastStableInsets.set(mStableInsets);
+            mLastOutsets.set(mOutsets);
+            mService.makeWindowFreezingScreenIfNeededLocked(this);
+
+            // If the orientation is changing, or we're starting or ending a drag resizing action,
+            // then we need to hold off on unfreezing the display until this window has been
+            // redrawn; to do that, we need to go through the process of getting informed by the
+            // application when it has finished drawing.
+            if (mOrientationChanging || dragResizingChanged || isResizedWhileNotDragResizing()) {
+                if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
+                    Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
+                            + ", mDrawState=DRAW_PENDING in " + this
+                            + ", surfaceController " + winAnimator.mSurfaceController);
+                }
+                winAnimator.mDrawState = DRAW_PENDING;
+                if (mAppToken != null) {
+                    mAppToken.clearAllDrawn();
+                }
+            }
+            if (!mService.mResizingWindows.contains(this)) {
+                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this);
+                mService.mResizingWindows.add(this);
+            }
+        } else if (mOrientationChanging) {
+            if (isDrawnLw()) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in "
+                        + this + ", surfaceController " + winAnimator.mSurfaceController);
+                mOrientationChanging = false;
+                mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                        - mService.mDisplayFreezeTime);
+            }
+        }
+    }
+
     public DisplayContent getDisplayContent() {
         if (mAppToken == null || mNotOnAppsDisplay) {
             return mDisplayContent;
@@ -1164,6 +1285,45 @@
         }
     }
 
+    @Override
+    boolean hasContentToDisplay() {
+        // If we're animating with a saved surface, we're already visible.
+        // Return true so that the alpha doesn't get cleared.
+        if (!mAppFreezing && isDrawnLw()
+                && (mViewVisibility == View.VISIBLE || isAnimatingWithSavedSurface()
+                || (mWinAnimator.isAnimationSet() && !mService.mAppTransition.isTransitionSet()))) {
+            return true;
+        }
+
+        return super.hasContentToDisplay();
+    }
+
+    @Override
+    boolean isVisible() {
+        // TODO: The check for hiddenRequested is commented out below, because the window can still
+        // be visible on screen when the flag is true. We would like the isVisible() method to
+        // return an answer closer to if the window is truly visible (can't be an exact answer
+        // without checking the surface state), so comment out the check for now so we can test to
+        // see what problem it causes.
+        // If it doesn't cause any issues, then we can remove just before we lock down the current
+        // release (O) and also consolidate this method with #isVisibleUnchecked() and possibly
+        // other methods like isVisibleNow().
+        // If it does cause problems, then we can look if there are other ways to solve the problem.
+        // If there isn't then uncomment and document here why it is needed.
+        if (/*(mAppToken == null || !mAppToken.hiddenRequested) && */isVisibleUnchecked()
+            // TODO: The window isn't considered visible when the token is hidden, however
+            // uncommenting the check below breaks the visual transition from an app to the launcher
+            // if the home buttons is pressed. Need to investigate an fix that issue before
+            // uncommenting.
+            /* && !mToken.hidden*/) {
+            // Is this window visible?  It is not visible if there is no surface, or we are in the
+            // process of running an exit animation that will remove the surface, or its app token
+            // has been hidden.
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Does the minimal check for visibility. Callers generally want to use one of the public
      * methods as they perform additional checks on the app token.
@@ -1174,13 +1334,9 @@
                 && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
     }
 
-    /**
-     * Is this window visible?  It is not visible if there is no surface, or we are in the process
-     * of running an exit animation that will remove the surface, or its app token has been hidden.
-     */
     @Override
     public boolean isVisibleLw() {
-        return (mAppToken == null || !mAppToken.hiddenRequested) && isVisibleUnchecked();
+        return isVisible();
     }
 
     /**
@@ -1206,7 +1362,8 @@
      * Is this window visible, ignoring its app token? It is not visible if there is no surface,
      * or we are in the process of running an exit animation that will remove the surface.
      */
-    public boolean isWinVisibleLw() {
+    // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this?
+    boolean isWinVisibleLw() {
         return (mAppToken == null || !mAppToken.hiddenRequested || mAppToken.mAppAnimator.animating)
                 && isVisibleUnchecked();
     }
@@ -1255,7 +1412,7 @@
      * Like isOnScreen(), but ignores any force hiding of the window due
      * to the keyguard.
      */
-    boolean isOnScreenIgnoringKeyguard() {
+    private boolean isOnScreenIgnoringKeyguard() {
         if (!mHasSurface || mDestroying) {
             return false;
         }
@@ -1280,7 +1437,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;
     }
 
@@ -1382,15 +1540,14 @@
     @Override
     public boolean isDrawnLw() {
         return mHasSurface && !mDestroying &&
-                (mWinAnimator.mDrawState == READY_TO_SHOW
-                || mWinAnimator.mDrawState == HAS_DRAWN);
+                (mWinAnimator.mDrawState == READY_TO_SHOW || mWinAnimator.mDrawState == HAS_DRAWN);
     }
 
     /**
      * Return true if the window is opaque and fully drawn.  This indicates
      * it may obscure windows behind it.
      */
-    boolean isOpaqueDrawn() {
+    private boolean isOpaqueDrawn() {
         // When there is keyguard, wallpaper could be placed over the secure app
         // window but invisible. We need to check wallpaper visibility explicitly
         // to determine if it's occluding apps.
@@ -1400,20 +1557,179 @@
                 && (mAppToken == null || mAppToken.mAppAnimator.animation == null);
     }
 
+    @Override
+    void onMovedByResize() {
+        if (DEBUG_RESIZE) Slog.d(TAG, "onMovedByResize: Moving " + this);
+        mMovedByResize = true;
+        super.onMovedByResize();
+    }
+
+    boolean onAppVisibilityChanged(boolean visible, boolean runningAppAnimation) {
+        boolean changed = false;
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            changed |= c.onAppVisibilityChanged(visible, runningAppAnimation);
+        }
+
+        if (mAttrs.type == TYPE_APPLICATION_STARTING) {
+            // Starting window that's exiting will be removed when the animation finishes.
+            // Mark all relevant flags for that onExitAnimationDone will proceed all the way
+            // to actually remove it.
+            if (!visible && isVisibleNow() && mAppToken.mAppAnimator.isAnimating()) {
+                mAnimatingExit = true;
+                mRemoveOnExit = true;
+                mWindowRemovalAllowed = true;
+            }
+            return changed;
+        }
+
+        if (visible != isVisibleNow()) {
+            if (!runningAppAnimation) {
+                final AccessibilityController accessibilityController =
+                        mService.mAccessibilityController;
+                final int winTransit = visible ? TRANSIT_ENTER : TRANSIT_EXIT;
+                mWinAnimator.applyAnimationLocked(winTransit, visible);
+                //TODO (multidisplay): Magnification is supported only for the default
+                if (accessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+                    accessibilityController.onWindowTransitionLocked(this, winTransit);
+                }
+            }
+            changed = true;
+            setDisplayLayoutNeeded();
+        }
+
+        return changed;
+    }
+
+    boolean onSetAppExiting() {
+        final DisplayContent displayContent = getDisplayContent();
+        boolean changed = false;
+
+        if (isVisibleNow()) {
+            mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
+            //TODO (multidisplay): Magnification is supported only for the default
+            if (mService.mAccessibilityController != null && isDefaultDisplay()) {
+                mService.mAccessibilityController.onWindowTransitionLocked(this, TRANSIT_EXIT);
+            }
+            changed = true;
+            if (displayContent != null) {
+                displayContent.setLayoutNeeded();
+            }
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            changed |= c.onSetAppExiting();
+        }
+
+        return changed;
+    }
+
+    @Override
+    void onResize() {
+        // Some windows won't go through the resizing process, if they don't have a surface, so
+        // destroy all saved surfaces here.
+        destroySavedSurface();
+
+        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
+        if (mHasSurface && !resizingWindows.contains(this)) {
+            if (DEBUG_RESIZE) Slog.d(TAG, "onResize: Resizing " + this);
+            resizingWindows.add(this);
+
+            // If we are not drag resizing, force recreating of a new surface so updating
+            // the content and positioning that surface will be in sync.
+            //
+            // 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 still like to manipulate
+            // their frame to update crop, etc...
+            //
+            // Anyway we don't need to synchronize position and content updates for these
+            // windows since they aren't at the base layer and could be moved around anyway.
+            if (!computeDragResizing() && mAttrs.type == TYPE_BASE_APPLICATION &&
+                    !getTask().mStack.getBoundsAnimating() && !isGoneForLayoutLw() &&
+                    !getTask().inPinnedWorkspace()) {
+                setResizedWhileNotDragResizing(true);
+            }
+        }
+        if (isGoneForLayoutLw()) {
+            mResizedWhileGone = true;
+        }
+
+        super.onResize();
+    }
+
+    void onUnfreezeBounds() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.onUnfreezeBounds();
+        }
+
+        if (!mHasSurface) {
+            return;
+        }
+
+        mLayoutNeeded = true;
+        setDisplayLayoutNeeded();
+        if (!mService.mResizingWindows.contains(this)) {
+            mService.mResizingWindows.add(this);
+        }
+    }
+
+    /**
+     * If the window has moved due to its containing content frame changing, then notify the
+     * listeners and optionally animate it. Simply checking a change of position is not enough,
+     * because being move due to dock divider is not a trigger for animation.
+     */
+    void handleWindowMovedIfNeeded() {
+        if (!hasMoved()) {
+            return;
+        }
+
+        // Frame has moved, containing content frame has also moved, and we're not currently
+        // animating... let's do something.
+        final int left = mFrame.left;
+        final int top = mFrame.top;
+        final Task task = getTask();
+        final boolean adjustedForMinimizedDockOrIme = task != null
+                && (task.mStack.isAdjustedForMinimizedDockedStack()
+                || task.mStack.isAdjustedForIme());
+        if (mService.okToDisplay()
+                && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
+                && !isDragResizing() && !adjustedForMinimizedDockOrIme
+                && (task == null || getTask().mStack.hasMovementAnimations())
+                && !mWinAnimator.mLastHidden) {
+            mWinAnimator.setMoveAnimation(left, top);
+        }
+
+        //TODO (multidisplay): Accessibility supported only for the default display.
+        if (mService.mAccessibilityController != null
+                && getDisplayContent().getDisplayId() == Display.DEFAULT_DISPLAY) {
+            mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+        }
+
+        try {
+            mClient.moved(left, top);
+        } catch (RemoteException e) {
+        }
+        mMovedByResize = false;
+    }
+
     /**
      * Return whether this window has moved. (Only makes
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
-    boolean hasMoved() {
+    private boolean hasMoved() {
         return mHasSurface && (mContentChanged || mMovedByResize)
-                && !mAnimatingExit && mService.okToDisplay()
+                && !mAnimatingExit
                 && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
                 && (!mIsChildWindow || !getParentWindow().hasMoved());
     }
 
     boolean isObscuringFullscreen(final DisplayInfo displayInfo) {
         Task task = getTask();
-        if (task != null && task.mStack != null && !task.mStack.isFullscreen()) {
+        if (task != null && task.mStack != null && !task.mStack.fillsParent()) {
             return false;
         }
         if (!isOpaqueDrawn() || !isFrameFullscreen(displayInfo)) {
@@ -1427,21 +1743,9 @@
                 && mFrame.right >= displayInfo.appWidth && mFrame.bottom >= displayInfo.appHeight;
     }
 
+    /** Returns true if last applied config was not yet requested by client. */
     boolean isConfigChanged() {
-        getMergedConfig(mTmpConfig);
-
-        // If the merged configuration is still empty, it means that we haven't issues the
-        // configuration to the client yet and we need to return true so the configuration updates.
-        boolean configChanged = mMergedConfiguration.equals(Configuration.EMPTY)
-                || mTmpConfig.diff(mMergedConfiguration) != 0;
-
-        if ((mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-            // Retain configuration changed status until resetConfiguration called.
-            mConfigHasChanged |= configChanged;
-            configChanged = mConfigHasChanged;
-        }
-
-        return configChanged;
+        return !mLastReportedConfiguration.equals(getConfiguration());
     }
 
     boolean isAdjustedForMinimizedDock() {
@@ -1449,18 +1753,50 @@
                 && mAppToken.mTask.mStack.isAdjustedForMinimizedDock();
     }
 
+    void onWindowReplacementTimeout() {
+        if (mWillReplaceWindow) {
+            // Since the window already timed out, remove it immediately now.
+            // Use WindowState#removeImmediately() instead of WindowState#removeIfPossible(), as the latter
+            // delays removal on certain conditions, which will leave the stale window in the
+            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
+            //
+            // Also removes child windows.
+            removeImmediately();
+        } else {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final WindowState c = mChildren.get(i);
+                c.onWindowReplacementTimeout();
+            }
+        }
+    }
+
     @Override
-    void remove() {
-        super.remove();
+    void forceWindowsScaleableInTransaction(boolean force) {
+        if (mWinAnimator != null && mWinAnimator.hasSurface()) {
+            mWinAnimator.mSurfaceController.forceScaleableInTransaction(force);
+        }
+
+        super.forceWindowsScaleableInTransaction(force);
+    }
+
+    @Override
+    void removeImmediately() {
+        super.removeImmediately();
 
         if (mRemoved) {
             // Nothing to do.
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "WS.remove: " + this + " Already removed...");
+            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                    "WS.removeImmediately: " + this + " Already removed...");
             return;
         }
 
         mRemoved = true;
 
+        mWillReplaceWindow = false;
+        if (mReplacementWindow != null) {
+            mReplacementWindow.mSkipEnterAnimationForSeamlessReplacement = false;
+        }
+
         if (mService.mInputMethodTarget == this) {
             mService.moveInputMethodWindowsIfNeededLocked(false);
         }
@@ -1487,11 +1823,13 @@
         mService.postWindowRemoveCleanupLocked(this);
     }
 
+    @Override
     void removeIfPossible() {
+        super.removeIfPossible();
         removeIfPossible(false /*keepVisibleDeadWindow*/);
     }
 
-    void removeIfPossible(boolean keepVisibleDeadWindow) {
+    private void removeIfPossible(boolean keepVisibleDeadWindow) {
         mWindowRemovalAllowed = true;
         if (DEBUG_ADD_REMOVE) Slog.v(TAG,
                 "removeIfPossible: " + this + " callers=" + Debug.getCallers(5));
@@ -1596,7 +1934,7 @@
             final boolean isAnimating =
                     mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
             final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
-                    && mAppToken.getWindowsCount() == 1;
+                    && mAppToken.isLastWindow(this);
             // We delay the removal of a window if it has a showing surface that can be used to run
             // exit animation and it is marked as exiting.
             // Also, If isn't the an animating starting window that is the last window in the app.
@@ -1616,7 +1954,7 @@
             }
         }
 
-        remove();
+        removeImmediately();
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && mService.updateOrientationFromAppTokensLocked(false)) {
@@ -1688,6 +2026,11 @@
      */
     void notifyMovedInStack() {
         mJustMovedInStack = true;
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.notifyMovedInStack();
+        }
     }
 
     /**
@@ -1704,6 +2047,11 @@
      */
     void resetJustMovedInStack() {
         mJustMovedInStack = false;
+
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            c.resetJustMovedInStack();
+        }
     }
 
     private final class DeadWindowEventReceiver extends InputEventReceiver {
@@ -1724,7 +2072,7 @@
         if (mInputChannel != null) {
             throw new IllegalStateException("Window already has an input channel.");
         }
-        String name = makeInputChannelName();
+        String name = getName();
         InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
         mInputChannel = inputChannels[0];
         mClientChannel = inputChannels[1];
@@ -1787,6 +2135,23 @@
         return getStack();
     }
 
+    /** Returns true if the replacement window was removed. */
+    boolean removeReplacedWindowIfNeeded(WindowState replacement) {
+        if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) {
+            replacement.mSkipEnterAnimationForSeamlessReplacement = false;
+            removeReplacedWindow();
+            return true;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            if (c.removeReplacedWindowIfNeeded(replacement)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void removeReplacedWindow() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + this);
         if (isDimming()) {
@@ -1795,15 +2160,34 @@
         mWillReplaceWindow = false;
         mAnimateReplacingWindow = false;
         mReplacingRemoveRequested = false;
-        mReplacingWindow = null;
+        mReplacementWindow = null;
         if (mAnimatingExit || !mAnimateReplacingWindow) {
-            remove();
+            removeImmediately();
         }
     }
 
+    boolean setReplacementWindowIfNeeded(WindowState replacementCandidate) {
+        boolean replacementSet = false;
+
+        if (mWillReplaceWindow && mReplacementWindow == null
+                && getWindowTag().toString().equals(replacementCandidate.getWindowTag().toString())) {
+
+            mReplacementWindow = replacementCandidate;
+            replacementCandidate.mSkipEnterAnimationForSeamlessReplacement = !mAnimateReplacingWindow;
+            replacementSet = true;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            replacementSet |= c.setReplacementWindowIfNeeded(replacementCandidate);
+        }
+
+        return replacementSet;
+    }
+
     void setDisplayLayoutNeeded() {
         if (mDisplayContent != null) {
-            mDisplayContent.layoutNeeded = true;
+            mDisplayContent.setLayoutNeeded();
         }
     }
 
@@ -1896,10 +2280,10 @@
             mTurnOnScreen = true;
         }
         if (isConfigChanged()) {
-            final Configuration newConfig = updateConfiguration();
+            outConfig.setTo(getConfiguration());
             if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
-                    + newConfig);
-            outConfig.setTo(newConfig);
+                    + outConfig);
+            mLastReportedConfiguration.setTo(outConfig);
         }
     }
 
@@ -2017,6 +2401,11 @@
             // Being hidden due to app op request.
             return false;
         }
+        if (mPermanentlyHidden) {
+            // Permanently hidden until the app exists as apps aren't prepared
+            // to handle their windows being removed from under them.
+            return false;
+        }
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             // Already showing.
             return false;
@@ -2056,8 +2445,7 @@
                 doAnimation = false;
             }
         }
-        boolean current = doAnimation ? mPolicyVisibilityAfterAnim
-                : mPolicyVisibility;
+        boolean current = doAnimation ? mPolicyVisibilityAfterAnim : mPolicyVisibility;
         if (!current) {
             // Already hiding.
             return false;
@@ -2068,11 +2456,9 @@
                 doAnimation = false;
             }
         }
-        if (doAnimation) {
-            mPolicyVisibilityAfterAnim = false;
-        } else {
+        mPolicyVisibilityAfterAnim = false;
+        if (!doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this);
-            mPolicyVisibilityAfterAnim = false;
             mPolicyVisibility = false;
             // Window is no longer visible -- make sure if we were waiting
             // for it to be displayed before enabling the display, that
@@ -2107,6 +2493,13 @@
         }
     }
 
+    public void hidePermanentlyLw() {
+        if (!mPermanentlyHidden) {
+            mPermanentlyHidden = true;
+            hideLw(true, true);
+        }
+    }
+
     public void pokeDrawLockLw(long timeout) {
         if (isVisibleOrAdding()) {
             if (mDrawLock == null) {
@@ -2144,24 +2537,133 @@
         return mAnimatingWithSavedSurface;
     }
 
+    @Override
+    boolean isAnimating() {
+        if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
+            return true;
+        }
+        return super.isAnimating();
+    }
+
     boolean isAnimatingInvisibleWithSavedSurface() {
-        return mAnimatingWithSavedSurface
-                && (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed);
+        if (mAnimatingWithSavedSurface
+                && (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed)) {
+            return true;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            if (c.isAnimatingInvisibleWithSavedSurface()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void stopUsingSavedSurface() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.stopUsingSavedSurface();
+        }
+
+        if (!isAnimatingInvisibleWithSavedSurface()) {
+            return;
+        }
+
+        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, "stopUsingSavedSurface: " + this);
+        clearAnimatingWithSavedSurface();
+        mDestroying = true;
+        mWinAnimator.hide("stopUsingSavedSurface");
+        mService.mWallpaperControllerLocked.hideWallpapers(this);
+    }
+
+    void markSavedSurfaceExiting() {
+        if (isAnimatingInvisibleWithSavedSurface()) {
+            mAnimatingExit = true;
+            mWinAnimator.mAnimating = true;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.markSavedSurfaceExiting();
+        }
+    }
+
+    void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
+        animators.add(mWinAnimator);
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.addWinAnimatorToList(animators);
+        }
+    }
+
+    void sendAppVisibilityToClients() {
+        super.sendAppVisibilityToClients();
+
+        final boolean clientHidden = mAppToken.clientHidden;
+        if (mAttrs.type == TYPE_APPLICATION_STARTING && clientHidden) {
+            // Don't hide the starting window.
+            return;
+        }
+
+        try {
+            if (DEBUG_VISIBILITY) Slog.v(TAG,
+                    "Setting visibility of " + this + ": " + (!clientHidden));
+            mClient.dispatchAppVisibility(!clientHidden);
+        } catch (RemoteException e) {
+        }
     }
 
     public void setVisibleBeforeClientHidden() {
         mWasVisibleBeforeClientHidden |=
                 (mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface);
+
+        super.setVisibleBeforeClientHidden();
     }
 
-    public void clearVisibleBeforeClientHidden() {
+    public void clearWasVisibleBeforeClientHidden() {
         mWasVisibleBeforeClientHidden = false;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.clearWasVisibleBeforeClientHidden();
+        }
     }
 
     public boolean wasVisibleBeforeClientHidden() {
         return mWasVisibleBeforeClientHidden;
     }
 
+    void onStartFreezingScreen() {
+        mAppFreezing = true;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.onStartFreezingScreen();
+        }
+    }
+
+    boolean onStopFreezingScreen() {
+        boolean unfrozeWindows = false;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            unfrozeWindows |= c.onStopFreezingScreen();
+        }
+
+        if (!mAppFreezing) {
+            return unfrozeWindows;
+        }
+
+        mAppFreezing = false;
+
+        if (mHasSurface && !mOrientationChanging
+                && mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
+            mOrientationChanging = true;
+            mService.mRoot.mOrientationChangeComplete = false;
+        }
+        mLastFreezeDuration = 0;
+        setDisplayLayoutNeeded();
+        return true;
+    }
+
     private boolean shouldSaveSurface() {
         if (mWinAnimator.mSurfaceController == null) {
             // Don't bother if the surface controller is gone for any reason.
@@ -2210,7 +2712,38 @@
         return mAppToken.shouldSaveSurface();
     }
 
-    static final Region sEmptyRegion = new Region();
+    boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
+        boolean destroyedSomething = false;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            destroyedSomething |= c.destroySurface(cleanupOnResume, appStopped);
+        }
+
+        if (appStopped || mWindowRemovalAllowed || cleanupOnResume) {
+
+            mWinAnimator.destroyPreservedSurfaceLocked();
+
+            if (mDestroying) {
+                if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this
+                        + " destroySurfaces: appStopped=" + appStopped
+                        + " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
+                        + " win.mRemoveOnExit=" + mRemoveOnExit);
+
+                if (!cleanupOnResume || mRemoveOnExit) {
+                    destroyOrSaveSurface();
+                }
+                if (mRemoveOnExit) {
+                    removeImmediately();
+                }
+                if (cleanupOnResume) {
+                    requestUpdateWallpaperIfNeeded();
+                }
+                mDestroying = false;
+                destroyedSomething = true;
+            }
+        }
+        return destroyedSomething;
+    }
 
     void destroyOrSaveSurface() {
         mSurfaceSaved = shouldSaveSurface();
@@ -2241,29 +2774,65 @@
     }
 
     void destroySavedSurface() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.destroySavedSurface();
+        }
+
         if (mSurfaceSaved) {
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                Slog.v(TAG, "Destroying saved surface: " + this);
-            }
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "Destroying saved surface: " + this);
             mWinAnimator.destroySurfaceLocked();
             mSurfaceSaved = false;
         }
         mWasVisibleBeforeClientHidden = false;
     }
 
-    void restoreSavedSurface() {
-        if (!mSurfaceSaved) {
-            return;
+    /** Returns -1 if there are no interesting windows or number of interesting windows not drawn.*/
+    int restoreSavedSurfaceForInterestingWindow() {
+        int interestingNotDrawn = -1;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            final int childInterestingNotDrawn = c.restoreSavedSurfaceForInterestingWindow();
+            if (childInterestingNotDrawn != -1) {
+                if (interestingNotDrawn == -1) {
+                    interestingNotDrawn = childInterestingNotDrawn;
+                } else {
+                    interestingNotDrawn += childInterestingNotDrawn;
+                }
+            }
         }
 
-        // Sometimes we save surfaces due to layout invisible
-        // directly after rotation occurs. However this means
-        // the surface was never laid out in the new orientation.
-        // We can only restore to the last rotation we were
-        // laid out as visible in.
+        if (mAttrs.type == TYPE_APPLICATION_STARTING
+                || mAppDied || !wasVisibleBeforeClientHidden()
+                || (mAppToken.mAppAnimator.freezingScreen && mAppFreezing)) {
+            // Window isn't interesting...
+            return interestingNotDrawn;
+        }
+
+        restoreSavedSurface();
+
+        if (!isDrawnLw()) {
+            if (interestingNotDrawn == -1) {
+                interestingNotDrawn = 1;
+            } else {
+                interestingNotDrawn++;
+            }
+        }
+        return interestingNotDrawn;
+    }
+
+    /** Returns true if the saved surface was restored. */
+    boolean restoreSavedSurface() {
+        if (!mSurfaceSaved) {
+            return false;
+        }
+
+        // Sometimes we save surfaces due to layout invisible directly after rotation occurs.
+        // However this means the surface was never laid out in the new orientation.
+        // We can only restore to the last rotation we were laid out as visible in.
         if (mLastVisibleLayoutRotation != mService.mRotation) {
             destroySavedSurface();
-            return;
+            return false;
         }
         mSurfaceSaved = false;
 
@@ -2272,6 +2841,8 @@
             mWinAnimator.mDrawState = READY_TO_SHOW;
             mAnimatingWithSavedSurface = true;
 
+            requestUpdateWallpaperIfNeeded();
+
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 Slog.v(TAG, "Restoring saved surface: " + this);
             }
@@ -2281,10 +2852,23 @@
             // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
             Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
         }
+
+        return true;
     }
 
     boolean canRestoreSurface() {
-        return mWasVisibleBeforeClientHidden && mSurfaceSaved;
+        if (mWasVisibleBeforeClientHidden && mSurfaceSaved) {
+            return true;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            if (c.canRestoreSurface()) {
+                return true;
+            }
+        }
+
+        return false;
     }
 
     boolean hasSavedSurface() {
@@ -2398,6 +2982,8 @@
         region.op(mTmpRect, Region.Op.INTERSECT);
     }
 
+    // TODO: This is one reason why WindowList are bad...prime candidate for removal once we
+    // figure-out a good way to replace WindowList with WindowContainer hierarchy.
     WindowList getWindowList() {
         final DisplayContent displayContent = getDisplayContent();
         return displayContent == null ? null : displayContent.getWindowList();
@@ -2429,36 +3015,15 @@
         }
     }
 
-    /**
-     * Update our current configurations, based on task configuration.
-     *
-     * @return A configuration suitable for sending to the client.
-     */
-    private Configuration updateConfiguration() {
-        final boolean configChanged = isConfigChanged();
-        getMergedConfig(mMergedConfiguration);
-        mConfigHasChanged = false;
-        if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
-            Slog.i(TAG, "Sending new config to window " + this + ": " +
-                    " / mergedConfig=" + mMergedConfiguration);
-        }
-        return mMergedConfiguration;
-    }
-
-    private void getMergedConfig(Configuration outConfig) {
+    @Override
+    public Configuration getConfiguration() {
         if (mAppToken != null && mAppToken.mFrozenMergedConfig.size() > 0) {
-            outConfig.setTo(mAppToken.mFrozenMergedConfig.peek());
-            return;
+            return mAppToken.mFrozenMergedConfig.peek();
         }
-        final Task task = getTask();
-        final Configuration overrideConfig = task != null
-                ? task.mOverrideConfig
-                : Configuration.EMPTY;
-        final Configuration serviceConfig = mService.mCurConfiguration;
-        outConfig.setTo(serviceConfig);
-        if (overrideConfig != Configuration.EMPTY) {
-            outConfig.updateFrom(overrideConfig);
-        }
+
+        // TODO: Remove when all windows' hierarchies will start from same root.
+        return mAppToken != null
+                ? super.getConfiguration() : getDisplayContent().getConfiguration();
     }
 
     void reportResized() {
@@ -2466,7 +3031,13 @@
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
-            final Configuration newConfig = isConfigChanged() ? updateConfiguration() : null;
+            final Configuration newConfig;
+            if (isConfigChanged()) {
+                newConfig = new Configuration(getConfiguration());
+                mLastReportedConfiguration.setTo(newConfig);
+            } else {
+                newConfig = null;
+            }
             if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
                 Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
 
@@ -2597,6 +3168,14 @@
         return mDragResizing != computeDragResizing();
     }
 
+    @Override
+    void setWaitingForDrawnIfResizingChanged() {
+        if (isDragResizeChanged()) {
+            mService.mWaitingForDrawn.add(this);
+        }
+        super.setWaitingForDrawnIfResizingChanged();
+    }
+
     /**
      * @return Whether we reported a drag resize change to the application or not already.
      */
@@ -2607,8 +3186,10 @@
     /**
      * Resets the state whether we reported a drag resize change to the app.
      */
+    @Override
     void resetDragResizingChangeReported() {
         mDragResizingChangeReported = false;
+        super.resetDragResizingChangeReported();
     }
 
     /**
@@ -2747,7 +3328,7 @@
             pw.println(Integer.toHexString(mSystemUiVisibility));
         }
         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
-                || isParentWindowHidden()) {
+                || isParentWindowHidden()|| mPermanentlyHidden) {
             pw.print(prefix); pw.print("mPolicyVisibility=");
                     pw.print(mPolicyVisibility);
                     pw.print(" mPolicyVisibilityAfterAnim=");
@@ -2755,6 +3336,7 @@
                     pw.print(" mAppOpVisibility=");
                     pw.print(mAppOpVisibility);
                     pw.print(" parentHidden="); pw.println(isParentWindowHidden());
+                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
@@ -2777,7 +3359,9 @@
                 getTouchableRegion(region);
                 pw.print(prefix); pw.print("touchable region="); pw.println(region);
             }
-            pw.print(prefix); pw.print("mMergedConfiguration="); pw.println(mMergedConfiguration);
+            pw.print(prefix); pw.print("mFullConfiguration="); pw.println(getConfiguration());
+            pw.print(prefix); pw.print("mLastReportedConfiguration=");
+                    pw.println(mLastReportedConfiguration);
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
@@ -2873,7 +3457,8 @@
         }
     }
 
-    String makeInputChannelName() {
+    @Override
+    String getName() {
         return Integer.toHexString(System.identityHashCode(this))
             + " " + getWindowTag();
     }
@@ -3005,7 +3590,8 @@
     WindowState getBottomChild() {
         // Child windows are z-ordered based on sub-layer using {@link #sWindowSubLayerComparator}
         // and the child with the lowest z-order will be at the head of the list.
-        return (WindowState) mChildren.peekFirst();
+        WindowState c = mChildren.peekFirst();
+        return c == null ? null : c;
     }
 
     boolean layoutInParentFrame() {
@@ -3034,7 +3620,12 @@
         return (parent == null) ? false : parent.mHidden;
     }
 
-    void setReplacing(boolean animate) {
+    void setWillReplaceWindow(boolean animate) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            c.setWillReplaceWindow(animate);
+        }
+
         if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
                 || mAttrs.type == TYPE_APPLICATION_STARTING) {
             // We don't set replacing on starting windows since they are added by window manager and
@@ -3043,22 +3634,46 @@
         }
 
         mWillReplaceWindow = true;
-        mReplacingWindow = null;
+        mReplacementWindow = null;
         mAnimateReplacingWindow = animate;
     }
 
-    void resetReplacing() {
+    void clearWillReplaceWindow() {
         mWillReplaceWindow = false;
-        mReplacingWindow = null;
+        mReplacementWindow = null;
         mAnimateReplacingWindow = false;
+
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            c.clearWillReplaceWindow();
+        }
+    }
+
+    boolean waitingForReplacement() {
+        if (mWillReplaceWindow) {
+            return true;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            if (c.waitingForReplacement()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     void requestUpdateWallpaperIfNeeded() {
         if (mDisplayContent != null && (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
             mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-            mDisplayContent.layoutNeeded = true;
+            mDisplayContent.setLayoutNeeded();
             mService.mWindowPlacerLocked.requestTraversal();
         }
+
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            c.requestUpdateWallpaperIfNeeded();
+        }
     }
 
     float translateToWindowX(float x) {
@@ -3081,7 +3696,7 @@
         final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
         if (dimLayerUser != null && mDisplayContent != null) {
             mDisplayContent.mDimLayerController.applyDim(dimLayerUser,
-                    mReplacingWindow.mWinAnimator,
+                    mReplacementWindow.mWinAnimator,
                     (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? true : false);
         }
     }
@@ -3090,12 +3705,37 @@
     // 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;
+    }
+
+    void setWillReplaceChildWindows() {
+        if (shouldBeReplacedWithChildren()) {
+            setWillReplaceWindow(false /* animate */);
+        }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            c.setWillReplaceChildWindows();
+        }
+    }
+
+    WindowState getReplacingWindow() {
+        if (mAnimatingExit && mWillReplaceWindow && mAnimateReplacingWindow) {
+            return this;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState c = mChildren.get(i);
+            final WindowState replacing = c.getReplacingWindow();
+            if (replacing != null) {
+                return replacing;
+            }
+        }
+        return null;
     }
 
     public int getRotationAnimationHint() {
@@ -3137,14 +3777,14 @@
             final DisplayContent displayContent = getDisplayContent();
 
             for (int i = mChildren.size() - 1; i >= 0; --i) {
-                final WindowState c = (WindowState) mChildren.get(i);
+                final WindowState c = mChildren.get(i);
                 if (c.mWinAnimator.mSurfaceController != null) {
                     c.performShowLocked();
                     // It hadn't been shown, which means layout not performed on it, so now we
                     // want to make sure to do a layout.  If called from within the transaction
                     // loop, this will cause it to restart with a new layout.
                     if (displayContent != null) {
-                        displayContent.layoutNeeded = true;
+                        displayContent.setLayoutNeeded();
                     }
                 }
             }
@@ -3199,20 +3839,47 @@
                 windowInfo.childTokens = new ArrayList(childCount);
             }
             for (int j = 0; j < childCount; j++) {
-                final WindowState child = (WindowState) mChildren.get(j);
+                final WindowState child = mChildren.get(j);
                 windowInfo.childTokens.add(child.mClient.asBinder());
             }
         }
         return windowInfo;
     }
 
-    void adjustAnimLayer(int adj) {
-        mWinAnimator.mAnimLayer = mLayer + adj;
-        if (DEBUG_LAYERS) Slog.v(TAG_WM, "win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
+    int getHighestAnimLayer() {
+        int highest = mWinAnimator.mAnimLayer;
         for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowState childWindow = (WindowState) mChildren.get(i);
-            childWindow.adjustAnimLayer(adj);
+            final WindowState c = mChildren.get(i);
+            final int childLayer = c.getHighestAnimLayer();
+            if (childLayer > highest) {
+                highest = childLayer;
+            }
         }
+        return highest;
+    }
+
+    int adjustAnimLayer(int adj) {
+        int highestAnimLayer = mWinAnimator.mAnimLayer = mLayer + adj;
+        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG_WM,
+                "adjustAnimLayer win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState childWindow = mChildren.get(i);
+            childWindow.adjustAnimLayer(adj);
+            if (childWindow.mWinAnimator.mAnimLayer > highestAnimLayer) {
+                highestAnimLayer = childWindow.mWinAnimator.mAnimLayer;
+            }
+        }
+        return highestAnimLayer;
+    }
+
+    @Override
+    int rebuildWindowList(DisplayContent dc, int addIndex) {
+        final DisplayContent winDisplayContent = getDisplayContent();
+        if (winDisplayContent == dc || winDisplayContent == null) {
+            mDisplayContent = dc;
+            return reAddWindow(addIndex);
+        }
+        return addIndex;
     }
 
     // TODO: come-up with a better name for this method that represents what it does.
@@ -3225,7 +3892,7 @@
         final int childCount = mChildren.size();
         boolean winAdded = false;
         for (int j = 0; j < childCount; j++) {
-            final WindowState child = (WindowState) mChildren.get(j);
+            final WindowState child = mChildren.get(j);
             if (!winAdded && child.mSubLayer >= 0) {
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM,
                         "Re-adding child window at " + index + ": " + child);
@@ -3263,7 +3930,7 @@
         int childCount = mChildren.size();
         while (childCount > 0) {
             childCount--;
-            final WindowState cw = (WindowState) mChildren.get(childCount);
+            final WindowState cw = mChildren.get(childCount);
             int cpos = windows.indexOf(cw);
             if (cpos >= 0) {
                 if (cpos < interestingPos) interestingPos--;
@@ -3275,6 +3942,19 @@
         return interestingPos;
     }
 
+    boolean isWindowAnimationSet() {
+        if (mWinAnimator.isWindowAnimationSet()) {
+            return true;
+        }
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            if (c.isWindowAnimationSet()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void onExitAnimationDone() {
         if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
                 + ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
@@ -3283,9 +3963,9 @@
         if (!mChildren.isEmpty()) {
             // Copying to a different list as multiple children can be removed.
             // TODO: Not sure if we really need to copy this into a different list.
-            final LinkedList childWindows = new LinkedList(mChildren);
+            final LinkedList<WindowState> childWindows = new LinkedList(mChildren);
             for (int i = childWindows.size() - 1; i >= 0; i--) {
-                ((WindowState)childWindows.get(i)).onExitAnimationDone();
+                childWindows.get(i).onExitAnimationDone();
             }
         }
 
@@ -3346,11 +4026,54 @@
         mService.mWallpaperControllerLocked.hideWallpapers(this);
     }
 
+    boolean clearAnimatingFlags() {
+        boolean didSomething = false;
+        // We don't want to clear it out for windows that get replaced, because the
+        // animation depends on the flag to remove the replaced window.
+        //
+        // We also don't clear the mAnimatingExit flag for windows which have the
+        // mRemoveOnExit flag. This indicates an explicit remove request has been issued
+        // by the client. We should let animation proceed and not clear this flag or
+        // they won't eventually be removed by WindowStateAnimator#finishExit.
+        if (!mWillReplaceWindow && !mRemoveOnExit) {
+            // Clear mAnimating flag together with mAnimatingExit. When animation
+            // changes from exiting to entering, we need to clear this flag until the
+            // new animation gets applied, so that isAnimationStarting() becomes true
+            // until then.
+            // Otherwise applySurfaceChangesTransaction will fail to skip surface
+            // placement for this window during this period, one or more frame will
+            // show up with wrong position or scale.
+            if (mAnimatingExit) {
+                mAnimatingExit = false;
+                didSomething = true;
+            }
+            if (mWinAnimator.mAnimating) {
+                mWinAnimator.mAnimating = false;
+                didSomething = true;
+            }
+            if (mDestroying) {
+                mDestroying = false;
+                mService.mDestroySurface.remove(this);
+                didSomething = true;
+            }
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            didSomething |= (mChildren.get(i)).clearAnimatingFlags();
+        }
+
+        return didSomething;
+    }
+
     public boolean isRtl() {
-        return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        return getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
     }
 
     void hideWallpaperWindow(boolean wasDeferred, String reason) {
+        for (int j = mChildren.size() - 1; j >= 0; --j) {
+            final WindowState c = mChildren.get(j);
+            c.hideWallpaperWindow(wasDeferred, reason);
+        }
         if (!mWinAnimator.mLastHidden || wasDeferred) {
             mWinAnimator.hide(reason);
             dispatchWallpaperVisibility(false);
@@ -3383,57 +4106,69 @@
         }
     }
 
-    /** Places this window after the input window in the window list. */
-    void addWindowToListAfter(WindowState pos) {
-        final WindowList windows = pos.getWindowList();
-        final int i = windows.indexOf(pos);
-        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                "Adding window " + this + " at " + (i+1) + " of " + windows.size()
-                + " (after " + pos + ")");
-        windows.add(i+1, this);
-        mService.mWindowsChanged = true;
-    }
-
-    /** Places this window before the input window in the window list. */
-    void addWindowToListBefore(WindowState pos) {
-        final WindowList windows = pos.getWindowList();
-        int i = windows.indexOf(pos);
-        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                "Adding window " + this + " at " + i + " of " + windows.size()
-                + " (before " + pos + ")");
-        if (i < 0) {
-            Slog.w(TAG_WM, "addWindowToListBefore: Unable to find " + pos + " in " + windows);
-            i = 0;
+    boolean hasVisibleNotDrawnWallpaper() {
+        if (mWallpaperVisible && !isDrawnLw()) {
+            return true;
         }
-        windows.add(i, this);
-        mService.mWindowsChanged = true;
+        for (int j = mChildren.size() - 1; j >= 0; --j) {
+            final WindowState c = mChildren.get(j);
+            if (c.hasVisibleNotDrawnWallpaper()) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    /** Adds this non-app window to the window list. */
-    void addNonAppWindowToList() {
-        final WindowList windows = getWindowList();
+    void updateReportedVisibility(UpdateReportedVisibilityResults results) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState c = mChildren.get(i);
+            c.updateReportedVisibility(results);
+        }
 
-        // Figure out where window should go, based on layer.
-        int i;
-        for (i = windows.size() - 1; i >= 0; i--) {
-            final WindowState otherWin = windows.get(i);
-            if (otherWin.getBaseType() != TYPE_WALLPAPER && otherWin.mBaseLayer <= mBaseLayer) {
-                // Wallpaper wanders through the window list, for example to position itself
-                // directly behind keyguard. Because of this it will break the ordering based on
-                // WindowState.mBaseLayer. There might windows with higher mBaseLayer behind it and
-                // we don't want the new window to appear above them. An example of this is adding
-                // of the docked stack divider. Consider a scenario with the following ordering (top
-                // to bottom): keyguard, wallpaper, assist preview, apps. We want the dock divider
-                // to land below the assist preview, so the dock divider must ignore the wallpaper,
-                // with which it shares the base layer.
-                break;
+        if (mAppFreezing || mViewVisibility != View.VISIBLE
+                || mAttrs.type == TYPE_APPLICATION_STARTING
+                || mDestroying) {
+            return;
+        }
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
+                    + ", isAnimationSet=" + mWinAnimator.isAnimationSet());
+            if (!isDrawnLw()) {
+                Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
+                        + " pv=" + mPolicyVisibility
+                        + " mDrawState=" + mWinAnimator.mDrawState
+                        + " ph=" + isParentWindowHidden()
+                        + " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
+                        + " a=" + mWinAnimator.mAnimating);
             }
         }
 
-        i++;
-        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                "Free window: Adding window " + this + " at " + i + " of " + windows.size());
-        windows.add(i, this);
-        mService.mWindowsChanged = true;
+        results.numInteresting++;
+        if (isDrawnLw()) {
+            results.numDrawn++;
+            if (!mWinAnimator.isAnimationSet()) {
+                results.numVisible++;
+            }
+            results.nowGone = false;
+        } else if (mWinAnimator.isAnimationSet()) {
+            results.nowGone = false;
+        }
+    }
+
+    // TODO: Hack to work around the number of states AppWindowToken needs to access without having
+    // access to its windows children. Need to investigate re-writing
+    // {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
+    static final class UpdateReportedVisibilityResults {
+        int numInteresting;
+        int numVisible;
+        int numDrawn;
+        boolean nowGone = true;
+
+        void reset() {
+            numInteresting = 0;
+            numVisible = 0;
+            numDrawn = 0;
+            nowGone = true;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index dfee8de..dc83ac0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -70,6 +70,7 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
+import java.io.FileDescriptor;
 
 /**
  * Keep track of animations and surface operations for a single WindowState.
@@ -225,8 +226,6 @@
     int mAttrType;
 
     static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-    long mDeferTransactionUntilFrame = -1;
-    long mDeferTransactionTime = -1;
 
     boolean mForceScaleUntilResize;
 
@@ -483,7 +482,7 @@
             // Upon completion of a not-visible to visible status bar animation a relayout is
             // required.
             if (displayContent != null) {
-                displayContent.layoutNeeded = true;
+                displayContent.setLayoutNeeded();
             }
         }
 
@@ -597,10 +596,9 @@
 
     WindowSurfaceController createSurfaceLocked() {
         final WindowState w = mWin;
-        if (w.hasSavedSurface()) {
+        if (w.restoreSavedSurface()) {
             if (DEBUG_ANIM) Slog.i(TAG,
                     "createSurface: " + this + ": called when we had a saved surface");
-            w.restoreSavedSurface();
             return mSurfaceController;
         }
 
@@ -687,7 +685,7 @@
             }
         } catch (OutOfResourcesException e) {
             Slog.w(TAG, "OutOfResourcesException creating surface");
-            mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
+            mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true);
             mDrawState = NO_SURFACE;
             return null;
         } catch (Exception e) {
@@ -968,7 +966,7 @@
             mDtDy = tmpFloats[Matrix.MSCALE_Y];
             float x = tmpFloats[Matrix.MTRANS_X];
             float y = tmpFloats[Matrix.MTRANS_Y];
-            mWin.mShownPosition.set((int) x, (int) y);
+            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             // Now set the alpha...  but because our current hardware
             // can't do alpha transformation on a non-opaque surface,
@@ -1022,7 +1020,7 @@
                     + " screen=" + (screenAnimation ?
                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
             return;
-        } else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) {
+        } else if (mIsWallpaper && mService.mRoot.mWallpaperActionPending) {
             return;
         } else if (mWin.isDragResizeChanged()) {
             // This window is awaiting a relayout because user just started (or ended)
@@ -1061,7 +1059,7 @@
             mDtDy = tmpFloats[Matrix.MSCALE_Y];
             float x = tmpFloats[Matrix.MTRANS_X];
             float y = tmpFloats[Matrix.MTRANS_Y];
-            mWin.mShownPosition.set((int) x, (int) y);
+            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             mShownAlpha = mAlpha;
         } else {
@@ -1583,7 +1581,7 @@
 
         try {
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
             mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
                     mWin.mFrame.top + top, false);
             calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
@@ -1592,7 +1590,7 @@
             Slog.w(TAG, "Error positioning surface of " + mWin
                     + " pos=(" + left + "," + top + ")", e);
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setWallpaperOffset");
         }
@@ -1752,7 +1750,7 @@
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
 
         if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
-            mService.adjustForImeIfNeeded(mWin.mDisplayContent);
+            mWin.mDisplayContent.adjustForImeIfNeeded();
             if (isEntrance) {
                 mWin.setDisplayLayoutNeeded();
                 mService.mWindowPlacerLocked.requestTraversal();
@@ -1852,7 +1850,7 @@
     }
 
     void reclaimSomeSurfaceMemory(String operation, boolean secure) {
-        mService.reclaimSomeSurfaceMemoryLocked(this, operation, secure);
+        mService.mRoot.reclaimSomeSurfaceMemory(this, operation, secure);
     }
 
     boolean getShown() {
@@ -1890,35 +1888,10 @@
         if (!mWin.isChildWindow()) {
             return;
         }
-        mDeferTransactionUntilFrame = frameNumber;
-        mDeferTransactionTime = System.currentTimeMillis();
         mSurfaceController.deferTransactionUntil(
                 mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
     }
 
-    // Defer the current transaction to the frame number of the last saved transaction.
-    // We do this to avoid shooting through an unsynchronized transaction while something is
-    // pending. This is generally fine, as either we will get in on the synchronization,
-    // or SurfaceFlinger will see that the frame has already occured. The only
-    // potential problem is in frame number resets so we reset things with a timeout
-    // every so often to be careful.
-    void deferToPendingTransaction() {
-        if (mDeferTransactionUntilFrame < 0) {
-            return;
-        }
-        final WindowState parentWindow = mWin.getParentWindow();
-        long time = System.currentTimeMillis();
-        if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
-            mDeferTransactionTime = -1;
-            mDeferTransactionUntilFrame = -1;
-        } else if (parentWindow != null &&
-                parentWindow.mWinAnimator.hasSurface()) {
-            mSurfaceController.deferTransactionUntil(
-                    mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(),
-                    mDeferTransactionUntilFrame);
-        }
-    }
-
     /**
      * Sometimes we need to synchronize the first frame of animation with some external event.
      * To achieve this, we prolong the start of the animation and keep producing the first frame of
@@ -2034,4 +2007,20 @@
                     DtDy * w.mVScale, false);
         }
     }
+
+    void enableSurfaceTrace(FileDescriptor fd) {
+        if (mSurfaceController != null) {
+            mSurfaceController.installRemoteTrace(fd);
+        }
+    }
+
+    void disableSurfaceTrace() {
+        if (mSurfaceController != null) {
+            try {
+                mSurfaceController.removeRemoteTrace();
+            } catch (ClassCastException e) {
+                Slog.e(TAG, "Disable surface trace for " + this + " but its not enabled");
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c77e572..368484a 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -41,6 +41,7 @@
 
 import android.util.Slog;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -70,6 +71,8 @@
     private boolean mHiddenForOtherReasons = true;
     private final String title;
 
+    private final WindowManagerService mService;
+
     public WindowSurfaceController(SurfaceSession s,
             String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
         mAnimator = animator;
@@ -79,6 +82,8 @@
 
         title = name;
 
+        mService = animator.mService;
+
         // For opaque child windows placed under parent windows,
         // we use a special SurfaceControl which mirrors commands
         // to a black-out layer placed one Z-layer below the surface.
@@ -95,10 +100,24 @@
             mSurfaceControl = new SurfaceControl(
                     s, name, w, h, format, flags);
         }
+
+        if (mService.mRoot.mSurfaceTraceEnabled) {
+            mSurfaceControl = new RemoteSurfaceTrace(
+                    mService.mRoot.mSurfaceTraceFd.getFileDescriptor(),
+                    mSurfaceControl, animator.mWin);
+        }
+    }
+
+    void installRemoteTrace(FileDescriptor fd) {
+        mSurfaceControl = new RemoteSurfaceTrace(fd, mSurfaceControl, mAnimator.mWin);
+    }
+
+    void removeRemoteTrace() {
+        mSurfaceControl = new SurfaceControl(mSurfaceControl);
     }
 
 
-    void logSurface(String msg, RuntimeException where) {
+    private void logSurface(String msg, RuntimeException where) {
         String str = "  SURFACE " + msg + ": " + title;
         if (where != null) {
             Slog.i(TAG, str, where);
@@ -127,7 +146,7 @@
     }
 
     void setPositionAndLayer(float left, float top, int layerStack, int layer) {
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
             mSurfaceX = left;
             mSurfaceY = top;
@@ -146,16 +165,16 @@
                 mAnimator.reclaimSomeSurfaceMemory("create-init", true);
             }
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setPositionAndLayer");
         }
     }
 
     void destroyInTransaction() {
-        //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
-        //        }
+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+            Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
+        }
         try {
             if (mSurfaceControl != null) {
                 mSurfaceControl.destroy();
@@ -230,11 +249,11 @@
 
     void setLayer(int layer) {
         if (mSurfaceControl != null) {
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
             try {
                 mSurfaceControl.setLayer(layer);
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
             }
         }
     }
@@ -338,11 +357,11 @@
             return;
         }
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
             mSurfaceControl.setTransparentRegionHint(region);
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setTransparentRegion");
         }
@@ -356,11 +375,11 @@
             return;
         }
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaqueLocked");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
             mSurfaceControl.setOpaque(isOpaque);
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaqueLocked");
         }
     }
@@ -373,11 +392,11 @@
             return;
         }
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setSecureLocked");
-        SurfaceControl.openTransaction();
+        mService.openSurfaceTransaction();
         try {
             mSurfaceControl.setSecure(isSecure);
         } finally {
-            SurfaceControl.closeTransaction();
+            mService.closeSurfaceTransaction();
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setSecureLocked");
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4c9211a..668e1b4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1,66 +1,37 @@
+
 package com.android.server.wm;
 
 import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_STARTING_WINDOW;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.DO_TRAVERSAL;
-import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
-import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
-import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
-import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
-import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
 
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.Trace;
-import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.view.Display;
@@ -99,46 +70,12 @@
     static final int SET_TURN_ON_SCREEN                 = 1 << 4;
     static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
 
-    boolean mWallpaperMayChange = false;
-    boolean mOrientationChangeComplete = true;
-    boolean mWallpaperActionPending = false;
-
-    private boolean mWallpaperForceHidingChanged = false;
-    private Object mLastWindowFreezeSource = null;
-    private Session mHoldScreen = null;
-    private boolean mObscured = false;
-    private boolean mSyswin = false;
-    private float mScreenBrightness = -1;
-    private float mButtonBrightness = -1;
-    private long mUserActivityTimeout = -1;
-    private boolean mUpdateRotation = false;
     private final Rect mTmpStartRect = new Rect();
     private final Rect mTmpContentRect = new Rect();
 
-    // Set to true when the display contains content to show the user.
-    // When false, the display manager may choose to mirror or blank the display.
-    private boolean mDisplayHasContent = false;
-
-    // Only set while traversing the default display based on its content.
-    // Affects the behavior of mirroring on secondary displays.
-    private boolean mObscureApplicationContentOnSecondaryDisplays = false;
-
-    private float mPreferredRefreshRate = 0;
-
-    private int mPreferredModeId = 0;
-
     private boolean mTraversalScheduled;
     private int mDeferDepth = 0;
 
-    private boolean mSustainedPerformanceModeEnabled = false;
-    private boolean mSustainedPerformanceModeCurrent = false;
-
-    // Following variables are for debugging screen wakelock only.
-    // Last window that requires screen wakelock
-    WindowState mHoldScreenWindow = null;
-    // Last window that obscures all windows below
-    WindowState mObsuringWindow = null;
-
     private static final class LayerAndToken {
         public int layer;
         public AppWindowToken token;
@@ -180,7 +117,7 @@
             mService.mH.removeMessages(DO_TRAVERSAL);
             loopCount--;
         } while (mTraversalScheduled && loopCount > 0);
-        mWallpaperActionPending = false;
+        mService.mRoot.mWallpaperActionPending = false;
     }
 
     private void performSurfacePlacementLoop() {
@@ -215,7 +152,7 @@
             while (!mService.mForceRemoves.isEmpty()) {
                 final WindowState ws = mService.mForceRemoves.remove(0);
                 Slog.i(TAG, "Force removing: " + ws);
-                ws.remove();
+                ws.removeImmediately();
             }
             Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
             Object tmp = new Object();
@@ -228,11 +165,11 @@
         }
 
         try {
-            performSurfacePlacementInner(recoveringMemory);
+            mService.mRoot.performSurfacePlacement(recoveringMemory);
 
             mInLayout = false;
 
-            if (mService.needsLayout()) {
+            if (mService.mRoot.isLayoutNeeded()) {
                 if (++mLayoutRepeatCount < 6) {
                     requestTraversal();
                 } else {
@@ -262,638 +199,16 @@
         }
     }
 
-    // "Something has changed!  Let's make it correct now."
-    private void performSurfacePlacementInner(boolean recoveringMemory) {
-        if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
-                + Debug.getCallers(3));
-
-        int i;
-        boolean updateInputWindowsNeeded = false;
-
-        if (mService.mFocusMayChange) {
-            mService.mFocusMayChange = false;
-            updateInputWindowsNeeded = mService.updateFocusedWindowLocked(
-                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
-        }
-
-        // Initialize state of exiting tokens.
-        final int numDisplays = mService.mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
-                displayContent.mExitingTokens.get(i).hasVisible = false;
-            }
-        }
-
-        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                exitingAppTokens.get(tokenNdx).hasVisible = false;
-            }
-        }
-
-        mHoldScreen = null;
-        mHoldScreenWindow = null;
-        mObsuringWindow = null;
-        mScreenBrightness = -1;
-        mButtonBrightness = -1;
-        mUserActivityTimeout = -1;
-        mObscureApplicationContentOnSecondaryDisplays = false;
-        mSustainedPerformanceModeCurrent = false;
-        mService.mTransactionSequence++;
-
-        final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
-        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
-        final int defaultDw = defaultInfo.logicalWidth;
-        final int defaultDh = defaultInfo.logicalHeight;
-
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
-        SurfaceControl.openTransaction();
-        try {
-            applySurfaceChangesTransaction(recoveringMemory, numDisplays, defaultDw, defaultDh);
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
-        }
-
-        final WindowList defaultWindows = defaultDisplay.getWindowList();
-
-        // If we are ready to perform an app transition, check through
-        // all of the app tokens to be shown and see if they are ready
-        // to go.
-        if (mService.mAppTransition.isReady()) {
-            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
-            if (DEBUG_LAYOUT_REPEATS)
-                debugLayoutRepeats("after handleAppTransitionReadyLocked",
-                        defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (!mService.mAnimator.mAppWindowAnimating && mService.mAppTransition.isRunning()) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            defaultDisplay.pendingLayoutChanges |=
-                    mService.handleAnimatingStoppedAndTransitionLocked();
-            if (DEBUG_LAYOUT_REPEATS)
-                debugLayoutRepeats("after handleAnimStopAndXitionLock",
-                        defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
-                && !mService.mAppTransition.isReady()) {
-            // At this point, there was a window with a wallpaper that
-            // was force hiding other windows behind it, but now it
-            // is going away.  This may be simple -- just animate
-            // away the wallpaper and its window -- or it may be
-            // hard -- the wallpaper now needs to be shown behind
-            // something that was hidden.
-            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS)
-                debugLayoutRepeats("after animateAwayWallpaperLocked",
-                        defaultDisplay.pendingLayoutChanges);
-        }
-        mWallpaperForceHidingChanged = false;
-
-        if (mWallpaperMayChange) {
-            if (DEBUG_WALLPAPER_LIGHT)
-                Slog.v(TAG, "Wallpaper may change!  Adjusting");
-            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mService.mFocusMayChange) {
-            mService.mFocusMayChange = false;
-            if (mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                    false /*updateInputWindows*/)) {
-                updateInputWindowsNeeded = true;
-                defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
-            }
-        }
-
-        if (mService.needsLayout()) {
-            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        for (i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
-            WindowState win = mService.mResizingWindows.get(i);
-            if (win.mAppFreezing) {
-                // Don't remove this window until rotation has completed.
-                continue;
-            }
-            // Discard the saved surface if window size is changed, it can't be reused.
-            if (win.mAppToken != null) {
-                win.mAppToken.destroySavedSurfaces();
-            }
-            win.reportResized();
-            mService.mResizingWindows.remove(i);
-        }
-
-        if (DEBUG_ORIENTATION && mService.mDisplayFrozen) Slog.v(TAG,
-                "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete);
-        if (mOrientationChangeComplete) {
-            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
-                mService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
-                mService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
-            }
-            mService.stopFreezingDisplayLocked();
-        }
-
-        // Destroy the surface of any windows that are no longer visible.
-        boolean wallpaperDestroyed = false;
-        i = mService.mDestroySurface.size();
-        if (i > 0) {
-            do {
-                i--;
-                WindowState win = mService.mDestroySurface.get(i);
-                win.mDestroying = false;
-                if (mService.mInputMethodWindow == win) {
-                    mService.mInputMethodWindow = null;
-                }
-                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
-                    wallpaperDestroyed = true;
-                }
-                win.destroyOrSaveSurface();
-            } while (i > 0);
-            mService.mDestroySurface.clear();
-        }
-
-        // Time to remove any exiting tokens?
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
-            for (i = exitingTokens.size() - 1; i >= 0; i--) {
-                WindowToken token = exitingTokens.get(i);
-                if (!token.hasVisible) {
-                    exitingTokens.remove(i);
-                    if (token.windowType == TYPE_WALLPAPER) {
-                        mWallpaperControllerLocked.removeWallpaperToken(token);
-                    }
-                }
-            }
-        }
-
-        // Time to remove any exiting applications?
-        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
-                AppWindowToken token = exitingAppTokens.get(i);
-                if (!token.hasVisible && !mService.mClosingApps.contains(token) &&
-                        (!token.mIsExiting || token.isEmpty())) {
-                    // Make sure there is no animation running on this token,
-                    // so any windows associated with it will be removed as
-                    // soon as their animations are complete
-                    token.mAppAnimator.clearAnimation();
-                    token.mAppAnimator.animating = false;
-                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                            "performLayout: App token exiting now removed" + token);
-                    token.removeAppFromTaskLocked();
-                }
-            }
-        }
-
-        if (wallpaperDestroyed) {
-            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-            defaultDisplay.layoutNeeded = true;
-        }
-
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            if (displayContent.pendingLayoutChanges != 0) {
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Finally update all input windows now that the window changes have stabilized.
-        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
-
-        mService.setHoldScreenLocked(mHoldScreen);
-        if (!mService.mDisplayFrozen) {
-            if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
-                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mScreenBrightness));
-            }
-            if (mButtonBrightness < 0
-                    || mButtonBrightness > 1.0f) {
-                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mButtonBrightness));
-            }
-            mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
-                    mUserActivityTimeout);
-        }
-
-        if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
-            mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
-            mService.mPowerManagerInternal.powerHint(
-                    mService.mPowerManagerInternal.POWER_HINT_SUSTAINED_PERFORMANCE_MODE,
-                    (mSustainedPerformanceModeEnabled ? 1 : 0));
-        }
-
-        if (mService.mTurnOnScreen) {
-            if (mService.mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
-                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
-                        "android.server.wm:TURN_ON");
-            }
-            mService.mTurnOnScreen = false;
-        }
-
-        if (mUpdateRotation) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
-            if (mService.updateRotationUncheckedLocked(false)) {
-                mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
-            } else {
-                mUpdateRotation = false;
-            }
-        }
-
-        if (mService.mWaitingForDrawnCallback != null ||
-                (mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
-                        !mUpdateRotation)) {
-            mService.checkDrawnWindowsLocked();
-        }
-
-        final int N = mService.mPendingRemove.size();
-        if (N > 0) {
-            if (mService.mPendingRemoveTmp.length < N) {
-                mService.mPendingRemoveTmp = new WindowState[N+10];
-            }
-            mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
-            mService.mPendingRemove.clear();
-            DisplayContentList displayList = new DisplayContentList();
-            for (i = 0; i < N; i++) {
-                final WindowState w = mService.mPendingRemoveTmp[i];
-                w.remove();
-                final DisplayContent displayContent = w.getDisplayContent();
-                if (displayContent != null && !displayList.contains(displayContent)) {
-                    displayList.add(displayContent);
-                }
-            }
-
-            for (DisplayContent displayContent : displayList) {
-                mService.mLayersController.assignLayersLocked(displayContent.getWindowList());
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Remove all deferred displays stacks, tasks, and activities.
-        for (int displayNdx = mService.mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
-            mService.mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
-        }
-
-        if (updateInputWindowsNeeded) {
-            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-        mService.setFocusTaskRegionLocked();
-
-        // Check to see if we are now in a state where the screen should
-        // be enabled, because the window obscured flags have changed.
-        mService.enableScreenIfNeededLocked();
-
-        mService.scheduleAnimationLocked();
-        mService.mWindowPlacerLocked.destroyPendingSurfaces();
-
-        if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
-                "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
-    }
-
-    private void applySurfaceChangesTransaction(boolean recoveringMemory, int numDisplays,
-            int defaultDw, int defaultDh) {
-        if (mService.mWatermark != null) {
-            mService.mWatermark.positionSurface(defaultDw, defaultDh);
-        }
-        if (mService.mStrictModeFlash != null) {
-            mService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
-        }
-        if (mService.mCircularDisplayMask != null) {
-            mService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
-                    mService.mRotation);
-        }
-        if (mService.mEmulatorDisplayOverlay != null) {
-            mService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
-                    mService.mRotation);
-        }
-
-        boolean focusDisplayed = false;
-
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
-            boolean updateAllDrawn = false;
-            WindowList windows = displayContent.getWindowList();
-            DisplayInfo displayInfo = displayContent.getDisplayInfo();
-            final int displayId = displayContent.getDisplayId();
-            final int dw = displayInfo.logicalWidth;
-            final int dh = displayInfo.logicalHeight;
-            final int innerDw = displayInfo.appWidth;
-            final int innerDh = displayInfo.appHeight;
-            final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-
-            // Reset for each display.
-            mDisplayHasContent = false;
-            mPreferredRefreshRate = 0;
-            mPreferredModeId = 0;
-
-            int repeats = 0;
-            do {
-                repeats++;
-                if (repeats > 6) {
-                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
-                    displayContent.layoutNeeded = false;
-                    break;
-                }
-
-                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
-                        "On entry to LockedInner", displayContent.pendingLayoutChanges);
-
-                if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                        mWallpaperControllerLocked.adjustWallpaperWindows()) {
-                    mService.mLayersController.assignLayersLocked(windows);
-                    displayContent.layoutNeeded = true;
-                }
-
-                if (isDefaultDisplay
-                        && (displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                    if (mService.updateOrientationFromAppTokensLocked(true)) {
-                        displayContent.layoutNeeded = true;
-                        mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
-                    }
-                }
-
-                if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
-                    displayContent.layoutNeeded = true;
-                }
-
-                // FIRST LOOP: Perform a layout, if needed.
-                if (repeats < LAYOUT_REPEAT_THRESHOLD) {
-                    performLayoutLockedInner(displayContent, repeats == 1,
-                            false /* updateInputWindows */);
-                } else {
-                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
-                }
-
-                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
-                // it is animating.
-                displayContent.pendingLayoutChanges = 0;
-
-                if (isDefaultDisplay) {
-                    mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
-                    for (int i = windows.size() - 1; i >= 0; i--) {
-                        WindowState w = windows.get(i);
-                        if (w.mHasSurface) {
-                            mService.mPolicy.applyPostLayoutPolicyLw(
-                                    w, w.mAttrs, w.getParentWindow());
-                        }
-                    }
-                    displayContent.pendingLayoutChanges |=
-                            mService.mPolicy.finishPostLayoutPolicyLw();
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishPostLayoutPolicyLw",
-                            displayContent.pendingLayoutChanges);
-                }
-            } while (displayContent.pendingLayoutChanges != 0);
-
-            mObscured = false;
-            mSyswin = false;
-            displayContent.resetDimming();
-
-            // Only used if default window
-            final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty();
-
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                WindowState w = windows.get(i);
-                final Task task = w.getTask();
-                final boolean obscuredChanged = w.mObscured != mObscured;
-
-                // Update effect.
-                w.mObscured = mObscured;
-                if (!mObscured) {
-                    handleNotObscuredLocked(w, displayInfo);
-                }
-
-                w.applyDimLayerIfNeeded();
-
-                if (isDefaultDisplay && obscuredChanged
-                        && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) {
-                    // This is the wallpaper target and its obscured state
-                    // changed... make sure the current wallaper's visibility
-                    // has been updated accordingly.
-                    mWallpaperControllerLocked.updateWallpaperVisibility();
-                }
-
-                final WindowStateAnimator winAnimator = w.mWinAnimator;
-
-                // If the window has moved due to its containing content frame changing, then
-                // notify the listeners and optionally animate it. Simply checking a change of
-                // position is not enough, because being move due to dock divider is not a trigger
-                // for animation.
-                if (w.hasMoved()) {
-                    // Frame has moved, containing content frame has also moved, and we're not
-                    // currently animating... let's do something.
-                    final int left = w.mFrame.left;
-                    final int top = w.mFrame.top;
-                    final boolean adjustedForMinimizedDockOrIme = task != null
-                                && (task.mStack.isAdjustedForMinimizedDockedStack()
-                                    || task.mStack.isAdjustedForIme());
-                    if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
-                            && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
-                            && (task == null || w.getTask().mStack.hasMovementAnimations())
-                            && !w.mWinAnimator.mLastHidden) {
-                        winAnimator.setMoveAnimation(left, top);
-                    }
-
-                    //TODO (multidisplay): Accessibility supported only for the default display.
-                    if (mService.mAccessibilityController != null
-                            && displayId == Display.DEFAULT_DISPLAY) {
-                        mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
-                    }
-
-                    try {
-                        w.mClient.moved(left, top);
-                    } catch (RemoteException e) {
-                    }
-                    w.mMovedByResize = false;
-                }
-
-                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-                w.mContentChanged = false;
-
-                // Moved from updateWindowsAndWallpaperLocked().
-                if (w.mHasSurface) {
-                    // If we have recently synchronized a previous transaction for this
-                    // window ensure we don't push through an unsynchronized one now.
-                    winAnimator.deferToPendingTransaction();
-
-                    // Take care of the window being ready to display.
-                    final boolean committed = winAnimator.commitFinishDrawingLocked();
-                    if (isDefaultDisplay && committed) {
-                        if (w.mAttrs.type == TYPE_DREAM) {
-                            // HACK: When a dream is shown, it may at that
-                            // point hide the lock screen.  So we need to
-                            // redo the layout to let the phone window manager
-                            // make this happen.
-                            displayContent.pendingLayoutChanges |=
-                                    FINISH_LAYOUT_REDO_LAYOUT;
-                            if (DEBUG_LAYOUT_REPEATS) {
-                                debugLayoutRepeats("dream and commitFinishDrawingLocked true",
-                                        displayContent.pendingLayoutChanges);
-                            }
-                        }
-                        if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
-                            if (DEBUG_WALLPAPER_LIGHT)
-                                Slog.v(TAG, "First draw done in potential wallpaper target " + w);
-                            mWallpaperMayChange = true;
-                            displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                            if (DEBUG_LAYOUT_REPEATS) {
-                                debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true",
-                                        displayContent.pendingLayoutChanges);
-                            }
-                        }
-                    }
-                    if (!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) {
-                        // Updates the shown frame before we set up the surface. This is needed
-                        // because the resizing could change the top-left position (in addition to
-                        // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
-                        // position the surface.
-                        //
-                        // If an animation is being started, we can't call this method because the
-                        // animation hasn't processed its initial transformation yet, but in general
-                        // we do want to update the position if the window is animating.
-                        winAnimator.computeShownFrameLocked();
-                    }
-                    winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
-                }
-
-                final AppWindowToken atoken = w.mAppToken;
-                if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
-                    Slog.d(TAG, "updateWindows: starting " + w
-                            + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
-                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
-                }
-                if (atoken != null && (!atoken.allDrawn || !atoken.allDrawnExcludingSaved
-                        || atoken.mAppAnimator.freezingScreen)) {
-                    if (atoken.lastTransactionSequence != mService.mTransactionSequence) {
-                        atoken.lastTransactionSequence = mService.mTransactionSequence;
-                        atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                        atoken.numInterestingWindowsExcludingSaved = 0;
-                        atoken.numDrawnWindowsExclusingSaved = 0;
-                        atoken.startingDisplayed = false;
-                    }
-                    if (!atoken.allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
-                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                            Slog.v(TAG, "Eval win " + w + ": isDrawn="
-                                    + w.isDrawnLw()
-                                    + ", isAnimationSet=" + winAnimator.isAnimationSet());
-                            if (!w.isDrawnLw()) {
-                                Slog.v(TAG, "Not displayed: s="
-                                        + winAnimator.mSurfaceController
-                                        + " pv=" + w.mPolicyVisibility
-                                        + " mDrawState=" + winAnimator.drawStateToString()
-                                        + " ph=" + w.isParentWindowHidden()
-                                        + " th=" + atoken.hiddenRequested
-                                        + " a=" + winAnimator.mAnimating);
-                            }
-                        }
-                        if (w != atoken.startingWindow) {
-                            if (w.isInteresting()) {
-                                atoken.numInterestingWindows++;
-                                if (w.isDrawnLw()) {
-                                    atoken.numDrawnWindows++;
-                                    if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
-                                        Slog.v(TAG, "tokenMayBeDrawn: " + atoken
-                                                + " w=" + w + " numInteresting="
-                                                + atoken.numInterestingWindows
-                                                + " freezingScreen="
-                                                + atoken.mAppAnimator.freezingScreen
-                                                + " mAppFreezing=" + w.mAppFreezing);
-                                    updateAllDrawn = true;
-                                }
-                            }
-                        } else if (w.isDrawnLw()) {
-                            mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
-                            atoken.startingDisplayed = true;
-                        }
-                    }
-                    if (!atoken.allDrawnExcludingSaved
-                            && w.mightAffectAllDrawn(true /* visibleOnly */)) {
-                        if (w != atoken.startingWindow && w.isInteresting()) {
-                            atoken.numInterestingWindowsExcludingSaved++;
-                            if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
-                                atoken.numDrawnWindowsExclusingSaved++;
-                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
-                                    Slog.v(TAG, "tokenMayBeDrawnExcludingSaved: " + atoken
-                                            + " w=" + w + " numInteresting="
-                                            + atoken.numInterestingWindowsExcludingSaved
-                                            + " freezingScreen="
-                                            + atoken.mAppAnimator.freezingScreen
-                                            + " mAppFreezing=" + w.mAppFreezing);
-                                updateAllDrawn = true;
-                            }
-                        }
-                    }
-                }
-
-                if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus
-                        && w.isDisplayedLw()) {
-                    focusDisplayed = true;
-                }
-
-                mService.updateResizingWindows(w);
-            }
-
-            mService.mDisplayManagerInternal.setDisplayProperties(displayId,
-                    mDisplayHasContent,
-                    mPreferredRefreshRate,
-                    mPreferredModeId,
-                    true /* inTraversal, must call performTraversalInTrans... below */);
-
-            mService.getDisplayContentLocked(displayId).stopDimmingIfNeeded();
-
-            if (updateAllDrawn) {
-                updateAllDrawnLocked(displayContent);
-            }
-        }
-
-        if (focusDisplayed) {
-            mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS);
-        }
-
-        // Give the display manager a chance to adjust properties
-        // like display rotation if it needs to.
-        mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
-    }
-
     boolean isInLayout() {
         return mInLayout;
     }
 
     final void performLayoutLockedInner(final DisplayContent displayContent,
             boolean initial, boolean updateInputWindows) {
-        if (!displayContent.layoutNeeded) {
+        if (!displayContent.isLayoutNeeded()) {
             return;
         }
-        displayContent.layoutNeeded = false;
+        displayContent.clearLayoutNeeded();
         WindowList windows = displayContent.getWindowList();
         boolean isDefaultDisplay = displayContent.isDefaultDisplay;
 
@@ -914,12 +229,12 @@
 
         if (DEBUG_LAYOUT) {
             Slog.v(TAG, "-------------------------------------");
-            Slog.v(TAG, "performLayout: needed="
-                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
+            Slog.v(TAG, "performLayout: needed=" + displayContent.isLayoutNeeded()
+                    + " dw=" + dw + " dh=" + dh);
         }
 
         mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation,
-                mService.mCurConfiguration.uiMode);
+                displayContent.getConfiguration().uiMode);
         if (isDefaultDisplay) {
             // Not needed on non-default displays.
             mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
@@ -1068,7 +383,7 @@
      * @param windows List of windows on default display.
      * @return bitmap indicating if another pass through layout must be made.
      */
-    private int handleAppTransitionReadyLocked(WindowList windows) {
+    int handleAppTransitionReadyLocked(WindowList windows) {
         int appsCount = mService.mOpeningApps.size();
         if (!transitionGoodToGo(appsCount)) {
             return 0;
@@ -1085,9 +400,10 @@
 
         mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
 
-        mService.rebuildAppWindowListLocked();
+        final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
+        displayContent.rebuildAppWindowList();
 
-        mWallpaperMayChange = false;
+        mService.mRoot.mWallpaperMayChange = false;
 
         // The top-most window will supply the layout params,
         // and we will determine it below.
@@ -1109,11 +425,10 @@
         }
         // Adjust wallpaper before we pull the lower/upper target, since pending changes
         // (like the clearAnimatingFlags() above) might affect wallpaper target result.
-        final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
         if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
                 mWallpaperControllerLocked.adjustWallpaperWindows()) {
             mService.mLayersController.assignLayersLocked(windows);
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
         }
 
         final WindowState lowerWallpaperTarget =
@@ -1160,7 +475,7 @@
 
             voiceInteraction |= wtoken.voiceInteraction;
 
-            if (wtoken.appFullscreen) {
+            if (wtoken.fillsParent()) {
                 WindowState ws = wtoken.findMainWindow();
                 if (ws != null) {
                     animLp = ws.mAttrs;
@@ -1218,7 +533,7 @@
 
         // This has changed the visibility of windows, so perform
         // a new layout to get them all up-to-date.
-        displayContent.layoutNeeded = true;
+        displayContent.setLayoutNeeded();
 
         // TODO(multidisplay): IMEs are only supported on the default display.
         if (windows == mService.getDefaultWindowListLocked()
@@ -1261,11 +576,11 @@
 
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
-            SurfaceControl.openTransaction();
+            mService.openSurfaceTransaction();
             try {
                 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked());
             } finally {
-                SurfaceControl.closeTransaction();
+                mService.closeSurfaceTransaction();
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                         "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
             }
@@ -1336,8 +651,25 @@
                 "Checking " + appsCount + " opening apps (frozen="
                         + mService.mDisplayFrozen + " timeout="
                         + mService.mAppTransition.isTimeout() + ")...");
+        final ScreenRotationAnimation screenRotationAnimation =
+            mService.mAnimator.getScreenRotationAnimationLocked(
+                    Display.DEFAULT_DISPLAY);
+
         int reason = APP_TRANSITION_TIMEOUT;
         if (!mService.mAppTransition.isTimeout()) {
+            // Imagine the case where we are changing orientation due to an app transition, but a previous
+            // orientation change is still in progress. We won't process the orientation change
+            // for our transition because we need to wait for the rotation animation to finish.
+            // If we start the app transition at this point, we will interrupt it halfway with a new rotation
+            // animation after the old one finally finishes. It's better to defer the
+            // app transition.
+            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
+                    mService.rotationNeedsUpdateLocked()) {
+                if (DEBUG_APP_TRANSITIONS) {
+                    Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
+                }
+                return false;
+            }
             for (int i = 0; i < appsCount; i++) {
                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -1352,7 +684,7 @@
                 }
 
                 final boolean drawnBeforeRestoring = wtoken.allDrawn;
-                wtoken.restoreSavedSurfaces();
+                wtoken.restoreSavedSurfaceForInterestingWindows();
 
                 if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
                     return false;
@@ -1441,142 +773,10 @@
         return transit;
     }
 
-    /**
-     * @param w WindowState this method is applied to.
-     * @param dispInfo info of the display that the window's obscuring state is checked against.
-     */
-    private void handleNotObscuredLocked(final WindowState w, final DisplayInfo dispInfo) {
-        final LayoutParams attrs = w.mAttrs;
-        final int attrFlags = attrs.flags;
-        final boolean canBeSeen = w.isDisplayedLw();
-        final int privateflags = attrs.privateFlags;
-
-        if (canBeSeen && w.isObscuringFullscreen(dispInfo)) {
-            // This window completely covers everything behind it,
-            // so we want to leave all of them as undimmed (for
-            // performance reasons).
-            if (!mObscured) {
-                mObsuringWindow = w;
-            }
-
-            mObscured = true;
-        }
-
-        if (w.mHasSurface && canBeSeen) {
-            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
-                mHoldScreen = w.mSession;
-                mHoldScreenWindow = w;
-            } else if (DEBUG_KEEP_SCREEN_ON && w == mService.mLastWakeLockHoldingWindow) {
-                Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked: " + w + " was holding "
-                        + "screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by"
-                        + Debug.getCallers(10));
-            }
-            if (!mSyswin && w.mAttrs.screenBrightness >= 0
-                    && mScreenBrightness < 0) {
-                mScreenBrightness = w.mAttrs.screenBrightness;
-            }
-            if (!mSyswin && w.mAttrs.buttonBrightness >= 0
-                    && mButtonBrightness < 0) {
-                mButtonBrightness = w.mAttrs.buttonBrightness;
-            }
-            if (!mSyswin && w.mAttrs.userActivityTimeout >= 0
-                    && mUserActivityTimeout < 0) {
-                mUserActivityTimeout = w.mAttrs.userActivityTimeout;
-            }
-
-            final int type = attrs.type;
-            if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
-                    || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                mSyswin = true;
-            }
-
-            // This function assumes that the contents of the default display are
-            // processed first before secondary displays.
-            final DisplayContent displayContent = w.getDisplayContent();
-            if (displayContent != null && displayContent.isDefaultDisplay) {
-                // While a dream or keyguard is showing, obscure ordinary application
-                // content on secondary displays (by forcibly enabling mirroring unless
-                // there is other content we want to show) but still allow opaque
-                // keyguard dialogs to be shown.
-                if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    mObscureApplicationContentOnSecondaryDisplays = true;
-                }
-                mDisplayHasContent = true;
-            } else if (displayContent != null &&
-                    (!mObscureApplicationContentOnSecondaryDisplays
-                            || (mObscured && type == TYPE_KEYGUARD_DIALOG))) {
-                // Allow full screen keyguard presentation dialogs to be seen.
-                mDisplayHasContent = true;
-            }
-            if (mPreferredRefreshRate == 0
-                    && w.mAttrs.preferredRefreshRate != 0) {
-                mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
-            }
-            if (mPreferredModeId == 0
-                    && w.mAttrs.preferredDisplayModeId != 0) {
-                mPreferredModeId = w.mAttrs.preferredDisplayModeId;
-            }
-            if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
-                mSustainedPerformanceModeCurrent = true;
-            }
-        }
-    }
-
-    private void updateAllDrawnLocked(DisplayContent displayContent) {
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        ArrayList<TaskStack> stacks = displayContent.getStacks();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (!wtoken.allDrawn) {
-                        int numInteresting = wtoken.numInterestingWindows;
-                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                            if (DEBUG_VISIBILITY)
-                                Slog.v(TAG, "allDrawn: " + wtoken
-                                    + " interesting=" + numInteresting
-                                    + " drawn=" + wtoken.numDrawnWindows);
-                            wtoken.allDrawn = true;
-                            // Force an additional layout pass where WindowStateAnimator#
-                            // commitFinishDrawingLocked() will call performShowLocked().
-                            displayContent.layoutNeeded = true;
-                            mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN,
-                                    wtoken.token).sendToTarget();
-                        }
-                    }
-                    if (!wtoken.allDrawnExcludingSaved) {
-                        int numInteresting = wtoken.numInterestingWindowsExcludingSaved;
-                        if (numInteresting > 0
-                                && wtoken.numDrawnWindowsExclusingSaved >= numInteresting) {
-                            if (DEBUG_VISIBILITY)
-                                Slog.v(TAG, "allDrawnExcludingSaved: " + wtoken
-                                    + " interesting=" + numInteresting
-                                    + " drawn=" + wtoken.numDrawnWindowsExclusingSaved);
-                            wtoken.allDrawnExcludingSaved = true;
-                            displayContent.layoutNeeded = true;
-                            if (wtoken.isAnimatingInvisibleWithSavedSurface()
-                                    && !mService.mFinishedEarlyAnim.contains(wtoken)) {
-                                mService.mFinishedEarlyAnim.add(wtoken);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private static int toBrightnessOverride(float value) {
-        return (int)(value * PowerManager.BRIGHTNESS_ON);
-    }
-
     private void processApplicationsAnimatingInPlace(int transit) {
         if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
             // Find the focused window
-            final WindowState win = mService.findFocusedWindowLocked(
-                    mService.getDefaultDisplayContentLocked());
+            final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow();
             if (win != null) {
                 final AppWindowToken wtoken = win.mAppToken;
                 final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
@@ -1641,13 +841,14 @@
                 Rect appRect = win != null ? win.getContentFrameLw() :
                         new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
                 Rect insets = win != null ? win.mContentInsets : null;
+                final Configuration displayConfig = displayContent.getConfiguration();
                 // For the new aspect-scaled transition, we want it to always show
                 // above the animating opening/closing window, and we want to
                 // synchronize its thumbnail surface with the surface for the
                 // open/close animation (only on the way down)
                 anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
-                        insets, thumbnailHeader, taskId, mService.mCurConfiguration.uiMode,
-                        mService.mCurConfiguration.orientation);
+                        insets, thumbnailHeader, taskId, displayConfig.uiMode,
+                        displayConfig.orientation);
                 openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
                 openingAppAnimator.deferThumbnailDestruction =
                         !mService.mAppTransition.isNextThumbnailTransitionScaleUp();
@@ -1669,41 +870,6 @@
         }
     }
 
-    boolean copyAnimToLayoutParamsLocked() {
-        boolean doRequest = false;
-
-        final int bulkUpdateParams = mService.mAnimator.mBulkUpdateParams;
-        if ((bulkUpdateParams & SET_UPDATE_ROTATION) != 0) {
-            mUpdateRotation = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & SET_WALLPAPER_MAY_CHANGE) != 0) {
-            mWallpaperMayChange = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
-            mWallpaperForceHidingChanged = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
-            mOrientationChangeComplete = false;
-        } else {
-            mOrientationChangeComplete = true;
-            mLastWindowFreezeSource = mService.mAnimator.mLastWindowFreezeSource;
-            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                doRequest = true;
-            }
-        }
-        if ((bulkUpdateParams & SET_TURN_ON_SCREEN) != 0) {
-            mService.mTurnOnScreen = true;
-        }
-        if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
-            mWallpaperActionPending = true;
-        }
-
-        return doRequest;
-    }
-
     void requestTraversal() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
@@ -1731,8 +897,8 @@
     }
 
     public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("mTraversalScheduled="); pw.println(mTraversalScheduled);
-        pw.print(prefix); pw.print("mHoldScreenWindow="); pw.println(mHoldScreenWindow);
-        pw.print(prefix); pw.print("mObsuringWindow="); pw.println(mObsuringWindow);
+        pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
+        pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
+        pw.println(prefix + "mObsuringWindow=" + mService.mRoot.mObsuringWindow);
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 00e71f2..177652c 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,26 +16,20 @@
 
 package com.android.server.wm;
 
-import android.annotation.CallSuper;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.IWindow;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -43,12 +37,11 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 
 /**
- * Container of a set of related windows in the window manager.  Often this
- * is an AppWindowToken, which is the handle for an Activity that it uses
- * to display windows.  For nested windows, there is a WindowToken created for
- * the parent window to manage its children.
+ * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
+ * which is the handle for an Activity that it uses to display windows. For nested windows, there is
+ * a WindowToken created for the parent window to manage its children.
  */
-class WindowToken {
+class WindowToken extends WindowContainer<WindowState> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM;
 
     // The window manager!
@@ -67,9 +60,6 @@
     // For printing.
     String stringName;
 
-    // All of the windows associated with this token.
-    protected final WindowList windows = new WindowList();
-
     // Is key dispatching paused for this token?
     boolean paused = false;
 
@@ -96,18 +86,14 @@
     }
 
     void removeAllWindows() {
-        for (int winNdx = windows.size() - 1; winNdx >= 0;
-                // WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
-                // allAppWindows if the window to be removed has child windows. It also may not
-                // remove any windows from allAppWindows at all if win is exiting and currently
-                // animating away. This ensures that winNdx is monotonically decreasing and never
-                // beyond allAppWindows bounds.
-                winNdx = Math.min(winNdx - 1, windows.size() - 1)) {
-            WindowState win = windows.get(winNdx);
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState win = mChildren.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, "removeAllWindows: removing win=" + win);
             win.removeIfPossible();
+            if (mChildren.contains(win)) {
+                removeChild(win);
+            }
         }
-        windows.clear();
     }
 
     void setExiting() {
@@ -115,30 +101,20 @@
             return;
         }
 
-        boolean delayed = false;
-        final int count = windows.size();
+        final int count = mChildren.size();
         boolean changed = false;
+        boolean delayed = false;
         DisplayContent displayContent = null;
 
         for (int i = 0; i < count; i++) {
-            final WindowState win = windows.get(i);
-            displayContent = win.getDisplayContent();
-
+            final WindowState win = mChildren.get(i);
             if (win.mWinAnimator.isAnimationSet()) {
                 delayed = true;
+                // TODO: This is technically wrong as a token can have windows on multi-displays
+                // currently. That will change moving forward though.
+                displayContent = win.getDisplayContent();
             }
-
-            if (win.isVisibleNow()) {
-                win.mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-                //TODO (multidisplay): Magnification is supported only for the default
-                if (mService.mAccessibilityController != null && win.isDefaultDisplay()) {
-                    mService.mAccessibilityController.onWindowTransitionLocked(win, TRANSIT_EXIT);
-                }
-                changed = true;
-                if (displayContent != null) {
-                    displayContent.layoutNeeded = true;
-                }
-            }
+            changed |= win.onSetAppExiting();
         }
 
         hidden = true;
@@ -155,14 +131,11 @@
 
     int adjustAnimLayer(int adj) {
         int highestAnimLayer = -1;
-        for (int j = windows.size() - 1; j >= 0; j--) {
-            final WindowState w = windows.get(j);
-            w.adjustAnimLayer(adj);
-            final int animLayer = w.mWinAnimator.mAnimLayer;
-            if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
-                    "adjustAnimLayer win " + w + " anim layer: " + animLayer);
-            if (animLayer > highestAnimLayer) {
-                highestAnimLayer = animLayer;
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final WindowState w = mChildren.get(j);
+            final int winHighestAnimLayer = w.adjustAnimLayer(adj);
+            if (winHighestAnimLayer > highestAnimLayer) {
+                highestAnimLayer = winHighestAnimLayer;
             }
             if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
                 mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
@@ -171,11 +144,11 @@
         return highestAnimLayer;
     }
 
-    private WindowState getTopWindow() {
-        if (windows.isEmpty()) {
+    WindowState getTopWindow() {
+        if (mChildren.isEmpty()) {
             return null;
         }
-        return windows.get(windows.size() - 1);
+        return (WindowState) mChildren.get(mChildren.size() - 1).getTop();
     }
 
     /**
@@ -183,9 +156,9 @@
      * @param target The window to search for.
      * @return The index of win in windows or of the window that is an ancestor of win.
      */
-    private int getWindowIndex(WindowState target) {
-        for (int i = windows.size() - 1; i >= 0; --i) {
-            final WindowState w = windows.get(i);
+    int getWindowIndex(WindowState target) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowState w = mChildren.get(i);
             if (w == target || w.hasChild(target)) {
                 return i;
             }
@@ -193,336 +166,60 @@
         return -1;
     }
 
-    /**
-     * Return the list of Windows in this token on the given Display.
-     * @param displayContent The display we are interested in.
-     * @return List of windows from token that are on displayContent.
-     */
-    protected WindowList getTokenWindowsOnDisplay(DisplayContent displayContent) {
-        final WindowList windowList = new WindowList();
-        final int count = windows.size();
-        for (int i = 0; i < count; i++) {
-            final WindowState win = windows.get(i);
-            if (win.getDisplayContent() == displayContent) {
-                windowList.add(win);
-            }
-        }
-        return windowList;
-    }
-
-    private void addChildWindow(final WindowState win) {
-        final DisplayContent displayContent = win.getDisplayContent();
-        if (displayContent == null) {
-            return;
-        }
-        final WindowState parentWindow = win.getParentWindow();
-
-        WindowList windowsOnSameDisplay = getTokenWindowsOnDisplay(displayContent);
-
-        // Figure out this window's ordering relative to the parent window.
-        final int wCount = windowsOnSameDisplay.size();
-        final int sublayer = win.mSubLayer;
-        int largestSublayer = Integer.MIN_VALUE;
-        WindowState windowWithLargestSublayer = null;
-        int i;
-        for (i = 0; i < wCount; i++) {
-            WindowState w = windowsOnSameDisplay.get(i);
-            final int wSublayer = w.mSubLayer;
-            if (wSublayer >= largestSublayer) {
-                largestSublayer = wSublayer;
-                windowWithLargestSublayer = w;
-            }
-            if (sublayer < 0) {
-                // For negative sublayers, we go below all windows in the same sublayer.
-                if (wSublayer >= sublayer) {
-                    if (!windows.contains(win)) {
-                        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
-                        windows.add(i, win);
-                    }
-                    win.addWindowToListBefore(wSublayer >= 0 ? parentWindow : w);
-                    break;
-                }
-            } else {
-                // For positive sublayers, we go above all windows in the same sublayer.
-                if (wSublayer > sublayer) {
-                    if (!windows.contains(win)) {
-                        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
-                        windows.add(i, win);
-                    }
-                    win.addWindowToListBefore(w);
-                    break;
-                }
-            }
-        }
-        if (i >= wCount) {
-            if (!windows.contains(win)) {
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
-                windows.add(win);
-            }
-            if (sublayer < 0) {
-                win.addWindowToListBefore(parentWindow);
-            } else {
-                win.addWindowToListAfter(
-                        largestSublayer >= 0 ? windowWithLargestSublayer : parentWindow);
-            }
-        }
-    }
-
     void addWindow(final WindowState win) {
         if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
 
+        final DisplayContent dc = win.getDisplayContent();
         if (!win.isChildWindow()) {
             int tokenWindowsPos = 0;
-            if (asAppWindowToken() != null) {
-                tokenWindowsPos = addAppWindow(win);
-            } else {
-                win.addNonAppWindowToList();
-            }
-            if (!windows.contains(win)) {
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
-                windows.add(tokenWindowsPos, win);
-            }
-        } else {
-            addChildWindow(win);
-        }
-    }
-
-    private int addAppWindow(final WindowState win) {
-        final DisplayContent displayContent = win.getDisplayContent();
-        if (displayContent == null) {
-            // It doesn't matter this display is going away.
-            return 0;
-        }
-        final IWindow client = win.mClient;
-
-        final WindowList windows = displayContent.getWindowList();
-        WindowList tokenWindowList = getTokenWindowsOnDisplay(displayContent);
-        int tokenWindowsPos = 0;
-        if (!tokenWindowList.isEmpty()) {
-            return addAppWindowExisting(win, windows, tokenWindowList);
-        }
-
-        // No windows from this token on this display
-        if (mService.localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window "
-                + client.asBinder() + " (token=" + this + ")");
-
-        // Figure out where the window should go, based on the order of applications.
-        WindowState pos = null;
-
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        int taskNdx;
-        int tokenNdx = -1;
-        for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            for (tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                final AppWindowToken t = tokens.get(tokenNdx);
-                if (t == this) {
-                    --tokenNdx;
-                    if (tokenNdx < 0) {
-                        --taskNdx;
-                        if (taskNdx >= 0) {
-                            tokenNdx = tasks.get(taskNdx).mAppTokens.size() - 1;
-                        }
-                    }
-                    break;
-                }
-
-                // We haven't reached the token yet; if this token is not going to the bottom and
-                // has windows on this display, we can use it as an anchor for when we do reach the
-                // token.
-                tokenWindowList = getTokenWindowsOnDisplay(displayContent);
-                if (!t.sendingToBottom && tokenWindowList.size() > 0) {
-                    pos = tokenWindowList.get(0);
-                }
-            }
-            if (tokenNdx >= 0) {
-                // early exit
-                break;
-            }
-        }
-
-        // We now know the index into the apps. If we found an app window above, that gives us the
-        // position; else we need to look some more.
-        if (pos != null) {
-            // Move behind any windows attached to this one.
-            final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
-            if (atoken != null) {
-                tokenWindowList = atoken.getTokenWindowsOnDisplay(displayContent);
-                final int NC = tokenWindowList.size();
-                if (NC > 0) {
-                    WindowState bottom = tokenWindowList.get(0);
-                    if (bottom.mSubLayer < 0) {
-                        pos = bottom;
-                    }
-                }
-            }
-            win.addWindowToListBefore(pos);
-            return tokenWindowsPos;
-        }
-
-        // Continue looking down until we find the first token that has windows on this display.
-        for ( ; taskNdx >= 0; --taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            for ( ; tokenNdx >= 0; --tokenNdx) {
-                final AppWindowToken t = tokens.get(tokenNdx);
-                tokenWindowList = t.getTokenWindowsOnDisplay(displayContent);
-                final int NW = tokenWindowList.size();
-                if (NW > 0) {
-                    pos = tokenWindowList.get(NW-1);
-                    break;
-                }
-            }
-            if (tokenNdx >= 0) {
-                // found
-                break;
-            }
-        }
-
-        if (pos != null) {
-            // Move in front of any windows attached to this one.
-            final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
-            if (atoken != null) {
-                final WindowState top = atoken.getTopWindow();
-                if (top != null && top.mSubLayer >= 0) {
-                    pos = top;
-                }
-            }
-            win.addWindowToListAfter(pos);
-            return tokenWindowsPos;
-        }
-
-        // Just search for the start of this layer.
-        final int myLayer = win.mBaseLayer;
-        int i;
-        for (i = windows.size() - 1; i >= 0; --i) {
-            WindowState w = windows.get(i);
-            // Dock divider shares the base layer with application windows, but we want to always
-            // keep it above the application windows. The sharing of the base layer is intended
-            // for window animations, which need to be above the dock divider for the duration
-            // of the animation.
-            if (w.mBaseLayer <= myLayer && w.mAttrs.type != TYPE_DOCK_DIVIDER) {
-                break;
-            }
-        }
-        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                "Based on layer: Adding window " + win + " at " + (i + 1) + " of "
-                        + windows.size());
-        windows.add(i + 1, win);
-        mService.mWindowsChanged = true;
-        return tokenWindowsPos;
-    }
-
-    private int addAppWindowExisting(
-            WindowState win, WindowList windowList, WindowList tokenWindowList) {
-
-        int tokenWindowsPos;
-        // If this application has existing windows, we simply place the new window on top of
-        // them... but keep the starting window on top.
-        if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
-            // Base windows go behind everything else.
-            final WindowState lowestWindow = tokenWindowList.get(0);
-            win.addWindowToListBefore(lowestWindow);
-            tokenWindowsPos = getWindowIndex(lowestWindow);
-        } else {
-            final AppWindowToken atoken = win.mAppToken;
-            final int windowListPos = tokenWindowList.size();
-            final WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
-            if (atoken != null && lastWindow == atoken.startingWindow) {
-                win.addWindowToListBefore(lastWindow);
-                tokenWindowsPos = getWindowIndex(lastWindow);
-            } else {
-                int newIdx = findIdxBasedOnAppTokens(win);
-                // There is a window above this one associated with the same apptoken note that the
-                // window could be a floating window that was created later or a window at the top
-                // of the list of windows associated with this token.
-                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                        "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
-                                + windowList.size());
-                windowList.add(newIdx + 1, win);
-                if (newIdx < 0) {
-                    // No window from token found on win's display.
-                    tokenWindowsPos = 0;
+            if (dc != null) {
+                if (asAppWindowToken() != null) {
+                    tokenWindowsPos = dc.addAppWindowToWindowList(win);
                 } else {
-                    tokenWindowsPos = getWindowIndex(windowList.get(newIdx)) + 1;
+                    dc.addNonAppWindowToWindowList(win);
                 }
-                mService.mWindowsChanged = true;
             }
+            if (!mChildren.contains(win)) {
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
+                addChild(win, tokenWindowsPos);
+            }
+        } else if (dc != null) {
+            dc.addChildWindowToWindowList(win);
         }
-        return tokenWindowsPos;
     }
 
-    int reAddAppWindows(DisplayContent displayContent, int index) {
-        final int count = windows.size();
+    /** Return the first window in the token window list that isn't a starting window or null. */
+    WindowState getFirstNonStartingWindow() {
+        final int count = mChildren.size();
+        // We only care about parent windows so no need to loop through child windows.
         for (int i = 0; i < count; i++) {
-            final WindowState win = windows.get(i);
-            if (win.isChildWindow()) {
-                // The WindowState.reAddWindow below already takes care of re-adding the
-                // child windows for any parent window in this token. This is a side effect of
-                // ensuring child windows are in the same WindowToken as their parent window.
-                //
-                // TODO: Can be removed once WindowToken no longer contains child windows. i.e it is
-                // using WindowContainer which uses the hierarchy to access child windows through
-                // their parent window.
-                continue;
-            }
-            final DisplayContent winDisplayContent = win.getDisplayContent();
-            if (winDisplayContent == displayContent || winDisplayContent == null) {
-                win.mDisplayContent = displayContent;
-                index = win.reAddWindow(index);
-            }
-        }
-        return index;
-    }
-
-    /**
-     * This method finds out the index of a window that has the same app token as win. used for z
-     * ordering the windows in mWindows
-     */
-    private int findIdxBasedOnAppTokens(WindowState win) {
-        WindowList windows = win.getWindowList();
-        for(int j = windows.size() - 1; j >= 0; j--) {
-            WindowState wentry = windows.get(j);
-            if(wentry.mAppToken == win.mAppToken) {
-                return j;
-            }
-        }
-        return -1;
-    }
-
-    /** Return the first window in the token window list that isn't the exclude window or null. */
-    WindowState getFirstWindow(WindowState exclude) {
-        for (int i = 0; i < windows.size(); i++) {
-            WindowState w = windows.get(i);
-            if (w != exclude) {
+            final WindowState w = mChildren.get(i);
+            if (w.mAttrs.type != TYPE_APPLICATION_STARTING) {
                 return w;
             }
         }
         return null;
     }
 
-    @CallSuper
-    void removeWindow(WindowState win) {
-        windows.remove(win);
-    }
-
     /** Returns true if the token windows list is empty. */
     boolean isEmpty() {
-        return windows.isEmpty();
+        return mChildren.isEmpty();
     }
 
     WindowState getReplacingWindow() {
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-            if (win.mAnimatingExit && win.mWillReplaceWindow && win.mAnimateReplacingWindow) {
-                return win;
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState win = mChildren.get(i);
+            final WindowState replacing = win.getReplacingWindow();
+            if (replacing != null) {
+                return replacing;
             }
         }
         return null;
     }
 
     void hideWallpaperToken(boolean wasDeferred, String reason) {
-        for (int j = windows.size() - 1; j >= 0; j--) {
-            final WindowState wallpaper = windows.get(j);
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final WindowState wallpaper = mChildren.get(j);
             wallpaper.hideWallpaperWindow(wasDeferred, reason);
         }
         hidden = true;
@@ -530,8 +227,8 @@
 
     void sendWindowWallpaperCommand(
             String action, int x, int y, int z, Bundle extras, boolean sync) {
-        for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            WindowState wallpaper = windows.get(wallpaperNdx);
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
             try {
                 wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync);
                 // We only want to be synchronous with one wallpaper.
@@ -543,8 +240,8 @@
 
     void updateWallpaperOffset(int dw, int dh, boolean sync) {
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
-        for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            WindowState wallpaper = windows.get(wallpaperNdx);
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
             if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
                 final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
                 winAnimator.computeShownFrameLocked();
@@ -560,12 +257,12 @@
         if (hidden == visible) {
             hidden = !visible;
             // Need to do a layout to ensure the wallpaper now has the correct size.
-            displayContent.layoutNeeded = true;
+            displayContent.setLayoutNeeded();
         }
 
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
-        for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            WindowState wallpaper = windows.get(wallpaperNdx);
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
             if (visible) {
                 wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
             }
@@ -583,12 +280,12 @@
                     "Wallpaper token " + token + " hidden=" + !visible);
             hidden = !visible;
             // Need to do a layout to ensure the wallpaper now has the correct size.
-            mService.getDefaultDisplayContentLocked().layoutNeeded = true;
+            mService.getDefaultDisplayContentLocked().setLayoutNeeded();
         }
 
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
-        for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = windows.get(wallpaperNdx);
+        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+            final WindowState wallpaper = mChildren.get(wallpaperNdx);
 
             if (visible) {
                 wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, false);
@@ -623,15 +320,16 @@
             }
 
             // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
-            // layer. For keyguard over wallpaper put the wallpaper under the keyguard unless
-            // the keyguard is still animating in.
+            // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
+            // is currently on screen, i.e. not hidden by policy.
             int insertionIndex = 0;
             if (visible && wallpaperTarget != null) {
                 final int type = wallpaperTarget.mAttrs.type;
                 final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
                 if (((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || type == TYPE_KEYGUARD_SCRIM)
                         && !mService.isKeyguardAnimatingIn()) {
-                    insertionIndex = windowList.indexOf(wallpaperTarget);
+                    insertionIndex = Math.min(windowList.indexOf(wallpaperTarget),
+                            findLowestWindowOnScreen(windowList));
                 }
             }
             if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
@@ -646,10 +344,25 @@
         return changed;
     }
 
+    /**
+     * @return The index in {@param windows} of the lowest window that is currently on screen and
+     *         not hidden by the policy.
+     */
+    private int findLowestWindowOnScreen(WindowList windowList) {
+        final int size = windowList.size();
+        for (int index = 0; index < size; index++) {
+            final WindowState win = windowList.get(index);
+            if (win.isOnScreen()) {
+                return index;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
     boolean hasVisibleNotDrawnWallpaper() {
-        for (int j = windows.size() - 1; j >= 0; --j) {
-            final WindowState wallpaper = windows.get(j);
-            if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
+        for (int j = mChildren.size() - 1; j >= 0; --j) {
+            final WindowState wallpaper = mChildren.get(j);
+            if (wallpaper.hasVisibleNotDrawnWallpaper()) {
                 return true;
             }
         }
@@ -657,14 +370,15 @@
     }
 
     int getHighestAnimLayer() {
-        int layer = -1;
-        for (int j = 0; j < windows.size(); j++) {
-            final WindowState win = windows.get(j);
-            if (win.mWinAnimator.mAnimLayer > layer) {
-                layer = win.mWinAnimator.mAnimLayer;
+        int highest = -1;
+        for (int j = 0; j < mChildren.size(); j++) {
+            final WindowState w = mChildren.get(j);
+            final int wLayer = w.getHighestAnimLayer();
+            if (wLayer > highest) {
+                highest = wLayer;
             }
         }
-        return layer;
+        return highest;
     }
 
     AppWindowToken asAppWindowToken() {
@@ -674,7 +388,7 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("windows="); pw.println(windows);
+        pw.print(prefix); pw.print("windows="); pw.println(mChildren);
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
                 pw.print(" hidden="); pw.print(hidden);
                 pw.print(" hasVisible="); pw.println(hasVisible);
@@ -695,4 +409,9 @@
         }
         return stringName;
     }
+
+    @Override
+    String getName() {
+        return toString();
+    }
 }
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index a502c3a..9459517 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -4,16 +4,9 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 
-ifneq ($(ENABLE_CPUSETS),)
-ifneq ($(ENABLE_SCHED_BOOST),)
-LOCAL_CFLAGS += -DUSE_SCHED_BOOST
-endif
-endif
-
 LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
@@ -45,8 +38,6 @@
     frameworks/base/libs/hwui \
     frameworks/base/core/jni \
     frameworks/native/services \
-    libcore/include \
-    libcore/include/libsuspend \
     system/security/keystore/include \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 8f6f613..3a0273d 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -39,39 +39,26 @@
 #include <linux/ioctl.h>
 #include <linux/rtc.h>
 
+#include <array>
 #include <memory>
 
-//--------------------------------------------------------------------------
-// The android_alarm.h header has been deleted from the kernel headers.
-// Add only the parts still needed, this should be deleted in the future.
-#include <linux/ioctl.h>
-
-enum android_alarm_type {
-  ANDROID_ALARM_RTC_WAKEUP,
-  ANDROID_ALARM_RTC,
-  ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
-  ANDROID_ALARM_ELAPSED_REALTIME,
-  ANDROID_ALARM_SYSTEMTIME,
-  ANDROID_ALARM_TYPE_COUNT,
-};
-
-enum android_alarm_return_flags {
-  ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
-  ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
-  ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK = 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
-  ANDROID_ALARM_ELAPSED_REALTIME_MASK = 1U << ANDROID_ALARM_ELAPSED_REALTIME,
-  ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
-  ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
-};
-
-#define ALARM_IOW(c,type,size) _IOW('a', (c) | ((type) << 4), size)
-#define ANDROID_ALARM_WAIT _IO('a', 1)
-#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
-#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
-//--------------------------------------------------------------------------
-
 namespace android {
 
+static constexpr int ANDROID_ALARM_TIME_CHANGE_MASK = 1 << 16;
+
+/**
+ * The AlarmManager alarm constants:
+ *
+ *   RTC_WAKEUP
+ *   RTC
+ *   REALTIME_WAKEUP
+ *   REALTIME
+ *   SYSTEMTIME (only defined in old alarm driver header, possibly unused?)
+ *
+ * We also need an extra CLOCK_REALTIME fd which exists specifically to be
+ * canceled on RTC changes.
+ */
+static const size_t ANDROID_ALARM_TYPE_COUNT = 5;
 static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
 static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
     CLOCK_REALTIME_ALARM,
@@ -81,98 +68,39 @@
     CLOCK_MONOTONIC,
     CLOCK_REALTIME,
 };
-/* to match the legacy alarm driver implementation, we need an extra
-   CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
+
+typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
 
 class AlarmImpl
 {
 public:
-    AlarmImpl(int *fds, size_t n_fds);
-    virtual ~AlarmImpl();
-
-    virtual int set(int type, struct timespec *ts) = 0;
-    virtual int setTime(struct timeval *tv) = 0;
-    virtual int waitForAlarm() = 0;
-
-protected:
-    int *fds;
-    size_t n_fds;
-};
-
-class AlarmImplAlarmDriver : public AlarmImpl
-{
-public:
-    explicit AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
-
-    int set(int type, struct timespec *ts);
-    int setTime(struct timeval *tv);
-    int waitForAlarm();
-};
-
-class AlarmImplTimerFd : public AlarmImpl
-{
-public:
-    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
-        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
-    ~AlarmImplTimerFd();
+    AlarmImpl(const TimerFds &fds, int epollfd, int rtc_id) :
+        fds{fds}, epollfd{epollfd}, rtc_id{rtc_id} { }
+    ~AlarmImpl();
 
     int set(int type, struct timespec *ts);
     int setTime(struct timeval *tv);
     int waitForAlarm();
 
 private:
-    int epollfd;
-    int rtc_id;
+    const TimerFds fds;
+    const int epollfd;
+    const int rtc_id;
 };
 
-AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
-        n_fds(n_fds)
-{
-    memcpy(fds, fds_, n_fds * sizeof(fds[0]));
-}
-
 AlarmImpl::~AlarmImpl()
 {
-    for (size_t i = 0; i < n_fds; i++) {
-        close(fds[i]);
+    for (auto fd : fds) {
+        epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
+        close(fd);
     }
-    delete [] fds;
-}
 
-int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
-{
-    return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
-}
-
-int AlarmImplAlarmDriver::setTime(struct timeval *tv)
-{
-    struct timespec ts;
-    int res;
-
-    ts.tv_sec = tv->tv_sec;
-    ts.tv_nsec = tv->tv_usec * 1000;
-    res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts);
-    if (res < 0)
-        ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
-    return res;
-}
-
-int AlarmImplAlarmDriver::waitForAlarm()
-{
-    return ioctl(fds[0], ANDROID_ALARM_WAIT);
-}
-
-AlarmImplTimerFd::~AlarmImplTimerFd()
-{
-    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
-        epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL);
-    }
     close(epollfd);
 }
 
-int AlarmImplTimerFd::set(int type, struct timespec *ts)
+int AlarmImpl::set(int type, struct timespec *ts)
 {
-    if (type > ANDROID_ALARM_TYPE_COUNT) {
+    if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
         errno = EINVAL;
         return -1;
     }
@@ -190,7 +118,7 @@
     return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
 }
 
-int AlarmImplTimerFd::setTime(struct timeval *tv)
+int AlarmImpl::setTime(struct timeval *tv)
 {
     struct rtc_time rtc;
     struct tm tm, *gmtime_res;
@@ -241,7 +169,7 @@
     return res;
 }
 
-int AlarmImplTimerFd::waitForAlarm()
+int AlarmImpl::waitForAlarm()
 {
     epoll_event events[N_ANDROID_TIMERFDS];
 
@@ -311,25 +239,12 @@
     return 0;
 }
 
-static jlong init_alarm_driver()
-{
-    int fd = open("/dev/alarm", O_RDWR);
-    if (fd < 0) {
-        ALOGV("opening alarm driver failed: %s", strerror(errno));
-        return 0;
-    }
-
-    AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
-    return reinterpret_cast<jlong>(ret);
-}
-
 static const char rtc_sysfs[] = "/sys/class/rtc";
 
 static bool rtc_is_hctosys(unsigned int rtc_id)
 {
     android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
             rtc_sysfs, rtc_id);
-
     FILE *file = fopen(hctosys_path.string(), "re");
     if (!file) {
         ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
@@ -383,23 +298,48 @@
     return -1;
 }
 
-static jlong init_timerfd()
+static void log_timerfd_create_error(clockid_t id)
+{
+    if (errno == EINVAL) {
+        switch (id) {
+        case CLOCK_REALTIME_ALARM:
+        case CLOCK_BOOTTIME_ALARM:
+            ALOGE("kernel missing required commits:");
+            ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6cffe00f7d4e24679eae6b7aae4caaf915288256");
+            ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=11ffa9d6065f344a9bd769a2452f26f2f671e5f8");
+            LOG_ALWAYS_FATAL("kernel does not support timerfd_create() with alarm timers");
+            break;
+
+        case CLOCK_BOOTTIME:
+            ALOGE("kernel missing required commit:");
+            ALOGE("https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=4a2378a943f09907fb1ae35c15de917f60289c14");
+            LOG_ALWAYS_FATAL("kernel does not support timerfd_create(CLOCK_BOOTTIME)");
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    ALOGE("timerfd_create(%u) failed: %s", id, strerror(errno));
+}
+
+static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
 {
     int epollfd;
-    int fds[N_ANDROID_TIMERFDS];
+    TimerFds fds;
 
-    epollfd = epoll_create(N_ANDROID_TIMERFDS);
+    epollfd = epoll_create(fds.size());
     if (epollfd < 0) {
-        ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
+        ALOGE("epoll_create(%zu) failed: %s", fds.size(),
                 strerror(errno));
         return 0;
     }
 
-    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
+    for (size_t i = 0; i < fds.size(); i++) {
         fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
         if (fds[i] < 0) {
-            ALOGV("timerfd_create(%u) failed: %s",  android_alarm_to_clockid[i],
-                    strerror(errno));
+            log_timerfd_create_error(android_alarm_to_clockid[i]);
             close(epollfd);
             for (size_t j = 0; j < i; j++) {
                 close(fds[j]);
@@ -408,16 +348,16 @@
         }
     }
 
-    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());
+    AlarmImpl *ret = new AlarmImpl(fds, epollfd, wall_clock_rtc());
 
-    for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
+    for (size_t i = 0; i < fds.size(); i++) {
         epoll_event event;
         event.events = EPOLLIN | EPOLLWAKEUP;
         event.data.u32 = i;
 
         int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event);
         if (err < 0) {
-            ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
+            ALOGE("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno));
             delete ret;
             return 0;
         }
@@ -431,7 +371,7 @@
     int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
             TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
     if (err < 0) {
-        ALOGV("timerfd_settime() failed: %s", strerror(errno));
+        ALOGE("timerfd_settime() failed: %s", strerror(errno));
         delete ret;
         return 0;
     }
@@ -439,16 +379,6 @@
     return reinterpret_cast<jlong>(ret);
 }
 
-static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
-{
-    jlong ret = init_alarm_driver();
-    if (ret) {
-        return ret;
-    }
-
-    return init_timerfd();
-}
-
 static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData)
 {
     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
deleted file mode 100644
index 50e4502..0000000
--- a/services/core/jni/com_android_server_am_ActivityManagerService.cpp
+++ /dev/null
@@ -1,150 +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.
- */
-
-#define LOG_TAG "ActivityManagerService"
-//#define LOG_NDEBUG 0
-
-#include <android_runtime/AndroidRuntime.h>
-#include <jni.h>
-
-#include <ScopedLocalRef.h>
-#include <ScopedPrimitiveArray.h>
-
-#include <cutils/log.h>
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <semaphore.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-namespace android
-{
-
-    // migrate from foreground to foreground_boost
-    static jint migrateToBoost(JNIEnv *env, jobject _this)
-    {
-#ifdef USE_SCHED_BOOST
-        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
-        FILE* fg_cpuset_file = NULL;
-        int   boost_cpuset_fd = 0;
-        if (!access("/dev/cpuset/tasks", F_OK)) {
-            fg_cpuset_file = fopen("/dev/cpuset/foreground/tasks", "r+");
-            if (ferror(fg_cpuset_file)) {
-                return 0;
-            }
-            boost_cpuset_fd = open("/dev/cpuset/foreground/boost/tasks", O_WRONLY);
-            if (boost_cpuset_fd < 0) {
-                fclose(fg_cpuset_file);
-                return 0;
-            }
-
-        }
-        if (!fg_cpuset_file || !boost_cpuset_fd) {
-            fclose(fg_cpuset_file);
-            close(boost_cpuset_fd);
-            return 0;
-        }
-        char buf[17];
-        while (fgets(buf, 16, fg_cpuset_file)) {
-            int i = 0;
-            for (; i < 16; i++) {
-                if (buf[i] == '\n') {
-                    buf[i] = 0;
-                    break;
-                }
-            }
-            if (write(boost_cpuset_fd, buf, i) < 0) {
-                // ignore error
-            }
-            if (feof(fg_cpuset_file))
-                break;
-        }
-        fclose(fg_cpuset_file);
-        close(boost_cpuset_fd);
-#endif
-        return 0;
-    }
-
-    // migrate from foreground_boost to foreground
-    static jint migrateFromBoost(JNIEnv *env, jobject _this)
-    {
-#ifdef USE_SCHED_BOOST
-        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
-        int   fg_cpuset_fd = 0;
-        FILE* boost_cpuset_file = NULL;
-        if (!access("/dev/cpuset/tasks", F_OK)) {
-            boost_cpuset_file = fopen("/dev/cpuset/foreground/boost/tasks", "r+");
-            if (ferror(boost_cpuset_file)) {
-                return 0;
-            }
-            fg_cpuset_fd = open("/dev/cpuset/foreground/tasks", O_WRONLY);
-            if (fg_cpuset_fd < 0) {
-                fclose(boost_cpuset_file);
-                return 0;
-            }
-
-        }
-        if (!boost_cpuset_file || !fg_cpuset_fd) {
-            fclose(boost_cpuset_file);
-            close(fg_cpuset_fd);
-            return 0;
-        }
-        char buf[17];
-        while (fgets(buf, 16, boost_cpuset_file)) {
-            //ALOGE("Appending FD %s to fg", buf);
-            int i = 0;
-            for (; i < 16; i++) {
-                if (buf[i] == '\n') {
-                    buf[i] = 0;
-                    break;
-                }
-            }
-            if (write(fg_cpuset_fd, buf, i) < 0) {
-                //ALOGE("Appending FD %s to fg ERROR", buf);
-                // handle error?
-            }
-            if (feof(boost_cpuset_file))
-                break;
-        }
-
-        close(fg_cpuset_fd);
-        fclose(boost_cpuset_file);
-
-#endif
-        return 0;
-
-    }
-
-
-    static JNINativeMethod method_table[] = {
-        { "nativeMigrateToBoost",   "()I", (void*)migrateToBoost },
-        { "nativeMigrateFromBoost", "()I", (void*)migrateFromBoost },
-    };
-
-    int register_android_server_ActivityManagerService(JNIEnv *env)
-    {
-        return jniRegisterNativeMethods(env, "com/android/server/am/ActivityManagerService",
-                                        method_table, NELEM(method_table));
-    }
-
-}
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h
index 62c8570..e6f25cc 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.h
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.h
@@ -26,7 +26,7 @@
 
 class NativeInputApplicationHandle : public InputApplicationHandle {
 public:
-    NativeInputApplicationHandle(jweak objWeak);
+    explicit NativeInputApplicationHandle(jweak objWeak);
     virtual ~NativeInputApplicationHandle();
 
     jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index d3341e5..327019d 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -20,7 +20,6 @@
 #include "utils/misc.h"
 
 namespace android {
-int register_android_server_ActivityManagerService(JNIEnv* env);
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_AssetAtlasService(JNIEnv* env);
 int register_android_server_BatteryStatsService(JNIEnv* env);
@@ -61,7 +60,6 @@
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
 
-    register_android_server_ActivityManagerService(env);
     register_android_server_PowerManagerService(env);
     register_android_server_SerialService(env);
     register_android_server_InputApplicationHandle(env);
@@ -88,6 +86,5 @@
     register_android_server_Watchdog(env);
     register_android_server_HardwarePropertiesManagerService(env);
 
-
     return JNI_VERSION_1_4;
 }
diff --git a/services/core/proto/ipconnectivity.proto b/services/core/proto/ipconnectivity.proto
new file mode 100644
index 0000000..e0d7f09
--- /dev/null
+++ b/services/core/proto/ipconnectivity.proto
@@ -0,0 +1,274 @@
+// LINT: LEGACY_NAMES
+syntax = "proto2";
+
+package clearcut.connectivity;
+
+option java_package = "com.android.server.connectivity.metrics";
+option java_outer_classname = "IpConnectivityLogClass";
+
+// NetworkId represents the id given by the system to a physical network on the
+// Android device. It is used to relates events to each other for devices with
+// multiple networks (WiFi, 4G, ...).
+message NetworkId {
+  // Every network gets assigned a network_id on creation based on order of
+  // creation. Thus network_id N is assigned to the network created directly
+  // after network N-1. Thus there is no PII involved here. Zero means no
+  // network. The value 0 is never assigned to a network.
+  optional int32 network_id = 1;
+};
+
+// Logs changes in the system default network. Changes can be 1) acquiring a
+// default network with no previous default, 2) a switch of the system default
+// network to a new default network, 3) a loss of the system default network.
+// This message is associated to android.net.metrics.DefaultNetworkEvent.
+message DefaultNetworkEvent {
+  // A value of 0 means this is a loss of the system default network.
+  optional NetworkId network_id = 1;
+
+  // A value of 0 means there was no previous default network.
+  optional NetworkId previous_network_id = 2;
+
+  // Whether the network supports IPv4, IPv6, or both.
+  enum IPSupport {
+    NONE = 0;
+    IPV4 = 1;
+    IPV6 = 2;
+    DUAL = 3;
+  };
+
+  // Best available information about IP support of the previous network when
+  // disconnecting or switching to a new default network.
+  optional IPSupport previous_network_ip_support = 3;
+
+  // The transport types of the new default network, represented by
+  // TRANSPORT_* constants as defined in NetworkCapabilities.
+  repeated int32 transport_types = 4;
+};
+
+// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
+// This message is associated to android.net.metrics.IpReachabilityEvent.
+message IpReachabilityEvent {
+  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
+  optional string if_name = 1;
+
+  // The event type code of the probe, represented by constants defined in
+  // android.net.metrics.IpReachabilityEvent.
+  optional int32 event_type = 2;
+};
+
+// Logs NetworkMonitor and ConnectivityService events related to the state of
+// a network: connection, evaluation, validation, lingering, and disconnection.
+// This message is associated to android.net.metrics.NetworkEvent.
+message NetworkEvent {
+  // The id of the network on which this event happened.
+  optional NetworkId network_id = 1;
+
+  // The type of network event, represented by NETWORK_* constants defined in
+  // android.net.metrics.NetworkEvent.
+  optional int32 event_type = 2;
+
+  // Only valid after finishing evaluating a network for Internet connectivity.
+  // The time it took for this evaluation to complete.
+  optional int32 latency_ms = 3;
+}
+
+// Logs individual captive portal probing events that are performed when
+// evaluating or reevaluating networks for Internet connectivity.
+// This message is associated to android.net.metrics.ValidationProbeEvent.
+message ValidationProbeEvent {
+  // The id of the network for which the probe was sent.
+  optional NetworkId network_id = 1;
+
+  // The time it took for that probe to complete or time out.
+  optional int32 latency_ms = 2;
+
+  // The type of portal probe, represented by PROBE_* constants defined in
+  // android.net.metrics.ValidationProbeEvent.
+  optional int32 probe_type = 3;
+
+  // The http code result of the probe test.
+  optional int32 probe_result = 4;
+}
+
+// Logs DNS lookup latencies. Repeated fields must have the same length.
+// This message is associated to android.net.metrics.DnsEvent.
+message DNSLookupBatch {
+  // The id of the network on which the DNS lookups took place.
+  optional NetworkId network_id = 1;
+
+  // The types of the DNS lookups, as defined in android.net.metrics.DnsEvent.
+  repeated int32 event_types = 2;
+
+  // The return values of the DNS resolver for each DNS lookups.
+  repeated int32 return_codes = 3;
+
+  // The time it took for each DNS lookups to complete.
+  repeated int32 latencies_ms = 4;
+};
+
+// Represents a DHCP event on a single interface, which can be a DHCPClient
+// state transition or a response packet parsing error.
+// This message is associated to android.net.metrics.DhcpClientEvent and
+// android.net.metrics.DhcpErrorEvent.
+message DHCPEvent {
+  // The interface name (wlan, rmnet, lo, ...) on which the event happened.
+  optional string if_name = 1;
+
+  oneof value {
+    // The name of a state in the DhcpClient state machine, represented by
+    // the inner classes of android.net.dhcp.DhcpClient.
+    string state_transition = 2;
+
+    // The error code of a DHCP error, represented by constants defined in
+    // android.net.metrics.DhcpErrorEvent.
+    int32 error_code = 3;
+  }
+
+  // Lifetime duration in milliseconds of a DhcpClient state, or transition
+  // time in milliseconds between specific pairs of DhcpClient's states.
+  // Only populated when state_transition is populated.
+  optional int32 duration_ms = 4;
+}
+
+// Represents the generation of an Android Packet Filter program.
+message ApfProgramEvent {
+  // Lifetime of the program in seconds.
+  optional int64 lifetime = 1;
+
+  // Number of RAs filtered by the APF program.
+  optional int32 filtered_ras = 2;
+
+  // Total number of RAs to filter currently tracked by ApfFilter. Can be more
+  // than filtered_ras if all available program size was exhausted.
+  optional int32 current_ras = 3;
+
+  // Length of the APF program in bytes.
+  optional int32 program_length = 4;
+
+  // True if the APF program is dropping multicast and broadcast traffic.
+  optional bool drop_multicast = 5;
+
+  // True if the interface on which APF runs has an IPv4 address.
+  optional bool has_ipv4_addr = 6;
+}
+
+// Represents Router Advertisement listening statistics for an interface with
+// Android Packet Filter enabled.
+message ApfStatistics {
+  // The time interval in milliseconds these stastistics cover.
+  optional int64 duration_ms = 1;
+
+  // The total number of received RAs.
+  optional int32 received_ras = 2;
+
+  // The total number of received RAs that matched a known RA.
+  optional int32 matching_ras = 3;
+
+  // The total number of received RAs ignored due to the MAX_RAS limit.
+  optional int32 dropped_ras = 5;
+
+  // The total number of received RAs with an effective lifetime of 0 seconds.
+  // Effective lifetime for APF is the minimum of all lifetimes in a RA.
+  optional int32 zero_lifetime_ras = 6;
+
+  // The total number of received RAs that could not be parsed.
+  optional int32 parse_errors = 7;
+
+  // The total number of APF program updates triggered by an RA reception.
+  optional int32 program_updates = 8;
+
+  // The maximum APF program size in byte advertised by hardware.
+  optional int32 max_program_size = 9;
+}
+
+// Represents the reception of a Router Advertisement packet for an interface
+// with Android Packet Filter enabled.
+message RaEvent {
+  // All lifetime values are expressed in seconds. The default value for an
+  // option lifetime that was not present in the RA option list is -1.
+  // The lifetime of an option (e.g., the Prefix Information Option) is the
+  // minimum lifetime of all such options in the packet.
+
+  // The value of the router lifetime in the RA packet.
+  optional int64 router_lifetime = 1;
+
+  // Prefix valid lifetime from the prefix information option.
+  optional int64 prefix_valid_lifetime = 2;
+
+  // Prefix preferred lifetime from the prefix information option.
+  optional int64 prefix_preferred_lifetime = 3;
+
+  // Route info lifetime.
+  optional int64 route_info_lifetime = 4;
+
+  // Recursive DNS server lifetime.
+  optional int64 rdnss_lifetime = 5;
+
+  // DNS search list lifetime.
+  optional int64 dnssl_lifetime = 6;
+}
+
+// Represents an IP provisioning event in IpManager and how long the
+// provisioning action took.
+// This message is associated to android.net.metrics.IpManagerEvent.
+message IpProvisioningEvent {
+  // The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
+  optional string if_name = 1;
+
+  // The code of the IP provisioning event, represented by constants defined in
+  // android.net.metrics.IpManagerEvent.
+  optional int32 event_type = 2;
+
+  // The duration of the provisioning action that resulted in this event.
+  optional int32 latency_ms = 3;
+}
+
+// Represents one of the IP connectivity event defined in this file.
+// Next tag: 12
+message IpConnectivityEvent {
+  // Time in ms when the event was recorded.
+  optional int64 time_ms = 1;
+
+  // Event type.
+  oneof event {
+
+    // An event about the system default network.
+    DefaultNetworkEvent default_network_event = 2;
+
+    // An IP reachability probe event.
+    IpReachabilityEvent ip_reachability_event = 3;
+
+    // A network lifecycle event.
+    NetworkEvent network_event = 4;
+
+    // A batch of DNS lookups.
+    DNSLookupBatch dns_lookup_batch = 5;
+
+    // A DHCP client event or DHCP receive error.
+    DHCPEvent dhcp_event = 6;
+
+    // An IP provisioning event.
+    IpProvisioningEvent ip_provisioning_event = 7;
+
+    // A network validation probe event.
+    ValidationProbeEvent validation_probe_event = 8;
+
+    // An Android Packet Filter program event.
+    ApfProgramEvent apf_program_event = 9;
+
+    // An Android Packet Filter statistics event.
+    ApfStatistics apf_statistics = 10;
+
+    // An RA packet reception event.
+    RaEvent ra_event = 11;
+  };
+};
+
+// The information about IP connectivity events.
+message IpConnectivityLog {
+  // An array of IP connectivity events.
+  repeated IpConnectivityEvent events = 1;
+
+  // The number of events that had to be dropped due to a full buffer.
+  optional int32 dropped_events = 2;
+};
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 46ce398..0c57179 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -29,6 +29,7 @@
 
 import android.Manifest.permission;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -227,6 +228,7 @@
 
     /**
      *  System property whose value is either "true" or "false", indicating whether
+     *  device owner is present.
      */
     private static final String PROPERTY_DEVICE_OWNER_PRESENT = "ro.device_owner";
 
@@ -307,6 +309,12 @@
 
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
+    /**
+     * Minimum timeout in milliseconds after which unlocking with weak auth times out,
+     * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+     */
+    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
+
     final Context mContext;
     final Injector mInjector;
     final IPackageManager mIPackageManager;
@@ -488,6 +496,12 @@
                     }
                 });
             }
+            // STOPSHIP: Remove this code once all dogfood devices are fixed. See b/31754835
+            if (Intent.ACTION_BOOT_COMPLETED.equals(action) && !mOwners.hasDeviceOwner()
+                    && !isBackupServiceEnabledInternal()) {
+                setBackupServiceEnabledInternal(true);
+                Slog.w(LOG_TAG, "Fix backup for device that is not in Device Owner mode.");
+            }
             if (Intent.ACTION_USER_UNLOCKED.equals(action)
                     || Intent.ACTION_USER_STARTED.equals(action)
                     || KeyChain.ACTION_TRUST_STORE_CHANGED.equals(action)) {
@@ -495,9 +509,9 @@
                 new MonitoringCertNotificationTask().execute(userId);
             }
             if (Intent.ACTION_USER_ADDED.equals(action)) {
-                disableSecurityLoggingIfNotCompliant();
+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                disableSecurityLoggingIfNotCompliant();
+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
                 removeUserData(userHandle);
             } else if (Intent.ACTION_USER_STARTED.equals(action)) {
                 synchronized (DevicePolicyManagerService.this) {
@@ -523,6 +537,7 @@
 
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
+        private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
         private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id";
         private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search";
@@ -547,6 +562,7 @@
         private static final String TAG_PERMITTED_IMES = "permitted-imes";
         private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
         private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
+        private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout";
         private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
         private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
         private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
@@ -601,6 +617,8 @@
         static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
         long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
 
+        long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+
         static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
         int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
 
@@ -615,6 +633,7 @@
         int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
 
         boolean encryptionRequested = false;
+        boolean testOnlyAdmin = false;
         boolean disableCamera = false;
         boolean disableCallerId = false;
         boolean disableContactsSearch = false;
@@ -749,6 +768,11 @@
                 out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
                 out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
             }
+            if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
+                out.startTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
+                out.attribute(null, ATTR_VALUE, Long.toString(strongAuthUnlockTimeout));
+                out.endTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT);
+            }
             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
                 out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
                 out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
@@ -784,6 +808,11 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
                 out.endTag(null, TAG_ENCRYPTION_REQUESTED);
             }
+            if (testOnlyAdmin) {
+                out.startTag(null, TAG_TEST_ONLY_ADMIN);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(testOnlyAdmin));
+                out.endTag(null, TAG_TEST_ONLY_ADMIN);
+            }
             if (disableCamera) {
                 out.startTag(null, TAG_DISABLE_CAMERA);
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
@@ -958,6 +987,9 @@
                 } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                     maximumTimeToUnlock = Long.parseLong(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
+                    strongAuthUnlockTimeout = Long.parseLong(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
                     maximumFailedPasswordsForWipe = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
@@ -979,6 +1011,9 @@
                 } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
                     encryptionRequested = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) {
+                    testOnlyAdmin = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_DISABLE_CAMERA.equals(tag)) {
                     disableCamera = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
@@ -1177,6 +1212,8 @@
 
         void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("uid="); pw.println(getUid());
+            pw.print(prefix); pw.print("testOnlyAdmin=");
+            pw.println(testOnlyAdmin);
             pw.print(prefix); pw.println("policies:");
             ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
             if (pols != null) {
@@ -1204,6 +1241,8 @@
                     pw.println(minimumPasswordNonLetter);
             pw.print(prefix); pw.print("maximumTimeToUnlock=");
                     pw.println(maximumTimeToUnlock);
+            pw.print(prefix); pw.print("strongAuthUnlockTimeout=");
+                    pw.println(strongAuthUnlockTimeout);
             pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
                     pw.println(maximumFailedPasswordsForWipe);
             pw.print(prefix); pw.print("specifiesGlobalProxy=");
@@ -1392,6 +1431,10 @@
             return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
         }
 
+        boolean isBuildDebuggable() {
+            return Build.IS_DEBUGGABLE;
+        }
+
         LockPatternUtils newLockPatternUtils() {
             return new LockPatternUtils(mContext);
         }
@@ -1694,7 +1737,7 @@
             if (mOwners.hasDeviceOwner()) {
                 mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
                 Slog.i(LOG_TAG, "Set ro.device_owner property to true");
-                disableSecurityLoggingIfNotCompliant();
+                disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
                 if (mInjector.securityLogGetLoggingEnabledProperty()) {
                     mSecurityLogMonitor.start();
                 }
@@ -2823,8 +2866,9 @@
         synchronized (this) {
             long ident = mInjector.binderClearCallingIdentity();
             try {
-                if (!refreshing
-                        && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
+                final ActiveAdmin existingAdmin
+                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
+                if (!refreshing && existingAdmin != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
                 if (policy.mRemovingAdmins.contains(adminReceiver)) {
@@ -2832,6 +2876,9 @@
                             "Trying to set an admin which is being removed");
                 }
                 ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
+                newAdmin.testOnlyAdmin =
+                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin
+                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);
                 policy.mAdminMap.put(adminReceiver, newAdmin);
                 int replaceIndex = -1;
                 final int N = policy.mAdminList.size();
@@ -2943,23 +2990,13 @@
         enforceShell("forceRemoveActiveAdmin");
         long ident = mInjector.binderClearCallingIdentity();
         try {
-            final ApplicationInfo ai;
-            try {
-                ai = mIPackageManager.getApplicationInfo(adminReceiver.getPackageName(),
-                        0, userHandle);
-            } catch (RemoteException e) {
-                throw new IllegalStateException(e);
-            }
-            if (ai == null) {
-                throw new IllegalStateException("Couldn't find package to remove admin "
-                        + adminReceiver.getPackageName() + " " + userHandle);
-            }
-            if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
-                throw new SecurityException("Attempt to remove non-test admin " + adminReceiver
-                        + adminReceiver + " " + userHandle);
-            }
-            // If admin is a device or profile owner tidy that up first.
             synchronized (this)  {
+                if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
+                    throw new SecurityException("Attempt to remove non-test admin "
+                            + adminReceiver + " " + userHandle);
+                }
+
+                // If admin is a device or profile owner tidy that up first.
                 if (isDeviceOwner(adminReceiver, userHandle)) {
                     clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
                 }
@@ -2971,11 +3008,47 @@
             }
             // Remove the admin skipping sending the broadcast.
             removeAdminArtifacts(adminReceiver, userHandle);
+            Slog.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
+    /**
+     * Return if a given package has testOnly="true", in which case we'll relax certain rules
+     * for CTS.
+     *
+     * DO NOT use this method except in {@link #setActiveAdmin}.  Use {@link #isAdminTestOnlyLocked}
+     * to check wehter an active admin is test-only or not.
+     *
+     * The system allows this flag to be changed when an app is updated, which is not good
+     * for us.  So we persist the flag in {@link ActiveAdmin} when an admin is first installed,
+     * and used the persisted version in actual checks. (See b/31382361 and b/28928996)
+     */
+    private boolean isPackageTestOnly(String packageName, int userHandle) {
+        final ApplicationInfo ai;
+        try {
+            ai = mIPackageManager.getApplicationInfo(packageName,
+                    (PackageManager.MATCH_DIRECT_BOOT_AWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e);
+        }
+        if (ai == null) {
+            throw new IllegalStateException("Couldn't find package: "
+                    + packageName + " on user " + userHandle);
+        }
+        return (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
+    }
+
+    /**
+     * See {@link #isPackageTestOnly}.
+     */
+    private boolean isAdminTestOnlyLocked(ComponentName who, int userHandle) {
+        final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+        return (admin != null) && admin.testOnlyAdmin;
+    }
+
     private void enforceShell(String method) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
@@ -4175,6 +4248,60 @@
     }
 
     @Override
+    public void setRequiredStrongAuthTimeout(ComponentName who, long timeoutMs,
+            boolean parent) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkArgument(timeoutMs >= MINIMUM_STRONG_AUTH_TIMEOUT_MS,
+                "Timeout must not be lower than the minimum strong auth timeout.");
+        Preconditions.checkArgument(timeoutMs <= DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS,
+                "Timeout must not be higher than the default strong auth timeout.");
+
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
+            if (ap.strongAuthUnlockTimeout != timeoutMs) {
+                ap.strongAuthUnlockTimeout = timeoutMs;
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    /**
+     * Return a single admin's strong auth unlock timeout or minimum value (strictest) of all
+     * admins if who is null.
+     * Returns default timeout if not configured.
+     */
+    @Override
+    public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
+        if (!mHasFeature) {
+            return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+        }
+        enforceFullCrossUsersPermission(userId);
+        synchronized (this) {
+            if (who != null) {
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
+                return admin != null ? Math.max(admin.strongAuthUnlockTimeout,
+                        MINIMUM_STRONG_AUTH_TIMEOUT_MS)
+                        : DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+            }
+
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId, parent);
+
+            long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+            for (int i = 0; i < admins.size(); i++) {
+                strongAuthUnlockTimeout = Math.min(admins.get(i).strongAuthUnlockTimeout,
+                        strongAuthUnlockTimeout);
+            }
+            return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+        }
+    }
+
+    @Override
     public void lockNow(boolean parent) {
         if (!mHasFeature) {
             return;
@@ -4514,7 +4641,7 @@
      * not installed and therefore not available.
      *
      * @throws SecurityException if the caller is not a profile or device owner.
-     * @throws UnsupportedException if the package does not support being set as always-on.
+     * @throws UnsupportedOperationException if the package does not support being set as always-on.
      */
     @Override
     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
@@ -4558,14 +4685,14 @@
         }
     }
 
-    private void wipeDataLocked(boolean wipeExtRequested, String reason) {
+    private void wipeDataLocked(boolean wipeExtRequested, String reason, boolean force) {
         if (wipeExtRequested) {
             StorageManager sm = (StorageManager) mContext.getSystemService(
                     Context.STORAGE_SERVICE);
             sm.wipeAdoptableDisks();
         }
         try {
-            RecoverySystem.rebootWipeUserData(mContext, reason);
+            RecoverySystem.rebootWipeUserData(mContext, false /* shutdown */, reason, force);
         } catch (IOException | SecurityException e) {
             Slog.w(LOG_TAG, "Failed requesting data wipe", e);
         }
@@ -4600,17 +4727,35 @@
                     }
                 }
                 boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
+                // If the admin is the only one who has set the restriction: force wipe, even if
+                // {@link UserManager.DISALLOW_FACTORY_RESET} is set. Reason is that the admin
+                // could remove this user restriction anyway.
+                boolean force = (userHandle == UserHandle.USER_SYSTEM)
+                        && isAdminOnlyOneWhoSetRestriction(admin,
+                                UserManager.DISALLOW_FACTORY_RESET, UserHandle.USER_SYSTEM);
                 wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
-                        "DevicePolicyManager.wipeData() from " + source);
+                        "DevicePolicyManager.wipeData() from " + source, force);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
 
-    private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle, String reason) {
+    private boolean isAdminOnlyOneWhoSetRestriction(ActiveAdmin admin, String userRestriction,
+            int userId) {
+        int source = mUserManager.getUserRestrictionSource(userRestriction, UserHandle.of(userId));
+        if (isDeviceOwner(admin.info.getComponent(), userId)) {
+            return source == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
+        } else if (isProfileOwner(admin.info.getComponent(), userId)) {
+            return source == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+        }
+        return false;
+    }
+
+    private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle,
+            String reason, boolean force) {
         if (userHandle == UserHandle.USER_SYSTEM) {
-            wipeDataLocked(wipeExtRequested, reason);
+            wipeDataLocked(wipeExtRequested, reason, force);
         } else {
             mHandler.post(new Runnable() {
                 @Override
@@ -4786,7 +4931,7 @@
             if (wipeData) {
                 // Call without holding lock.
                 wipeDeviceOrUserLocked(false, identifier,
-                        "reportFailedPasswordAttempt()");
+                        "reportFailedPasswordAttempt()", false);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -5710,7 +5855,7 @@
                     + " for device owner");
         }
         synchronized (this) {
-            enforceCanSetDeviceOwnerLocked(userId);
+            enforceCanSetDeviceOwnerLocked(admin, userId);
             if (getActiveAdminUncheckedLocked(admin, userId) == null
                     || getUserData(userId).mRemovingAdmins.contains(admin)) {
                 throw new IllegalArgumentException("Not active admin: " + admin);
@@ -5742,6 +5887,7 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
+            Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
             return true;
         }
     }
@@ -5860,9 +6006,12 @@
             try {
                 clearDeviceOwnerLocked(admin, deviceOwnerUserId);
                 removeActiveAdminLocked(deviceOwnerComponent, deviceOwnerUserId);
+                Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(deviceOwnerUserId));
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
+            Slog.i(LOG_TAG, "Device owner removed: " + deviceOwnerComponent);
         }
     }
 
@@ -5878,7 +6027,7 @@
         mOwners.clearDeviceOwner();
         mOwners.writeDeviceOwner();
         updateDeviceOwnerLocked();
-        disableSecurityLoggingIfNotCompliant();
+        disableDeviceOwnerManagedSingleUserFeaturesIfNeeded();
         try {
             if (mInjector.getIBackupManager() != null) {
                 // Reactivate backup service.
@@ -5900,7 +6049,7 @@
                     + " not installed for userId:" + userHandle);
         }
         synchronized (this) {
-            enforceCanSetProfileOwnerLocked(userHandle);
+            enforceCanSetProfileOwnerLocked(who, userHandle);
 
             if (getActiveAdminUncheckedLocked(who, userHandle) == null
                     || getUserData(userHandle).mRemovingAdmins.contains(who)) {
@@ -5909,6 +6058,7 @@
 
             mOwners.setProfileOwner(who, ownerName, userHandle);
             mOwners.writeProfileOwner(userHandle);
+            Slog.i(LOG_TAG, "Profile owner set: " + who + " on user " + userHandle);
             return true;
         }
     }
@@ -5933,6 +6083,7 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
+            Slog.i(LOG_TAG, "Profile owner " + who + " removed from user " + userId);
         }
     }
 
@@ -6215,9 +6366,9 @@
      * The profile owner can only be set before the user setup phase has completed,
      * except for:
      * - SYSTEM_UID
-     * - adb if there are not accounts.
+     * - adb if there are no accounts. (But see {@link #hasIncompatibleAccountsLocked})
      */
-    private void enforceCanSetProfileOwnerLocked(int userHandle) {
+    private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle) {
         UserInfo info = getUserInfo(userHandle);
         if (info == null) {
             // User doesn't exist.
@@ -6237,8 +6388,8 @@
         }
         int callingUid = mInjector.binderGetCallingUid();
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
-            if (hasUserSetupCompleted(userHandle) &&
-                    AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
+            if (hasUserSetupCompleted(userHandle)
+                    && hasIncompatibleAccountsLocked(userHandle, owner)) {
                 throw new IllegalStateException("Not allowed to set the profile owner because "
                         + "there are already some accounts on the profile");
             }
@@ -6255,14 +6406,14 @@
      * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
      * permission.
      */
-    private void enforceCanSetDeviceOwnerLocked(int userId) {
+    private void enforceCanSetDeviceOwnerLocked(@Nullable ComponentName owner, int userId) {
         int callingUid = mInjector.binderGetCallingUid();
         boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
         if (!isAdb) {
             enforceCanManageProfileAndDeviceOwners();
         }
 
-        final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
+        final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb);
         switch (code) {
             case CODE_OK:
                 return;
@@ -8530,8 +8681,8 @@
      * The device owner can only be set before the setup phase of the primary user has completed,
      * except for adb command if no accounts or additional users are present on the device.
      */
-    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
-            int deviceOwnerUserId, boolean isAdb) {
+    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked(
+            @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) {
         if (mOwners.hasDeviceOwner()) {
             return CODE_HAS_DEVICE_OWNER;
         }
@@ -8548,7 +8699,7 @@
                     if (mUserManager.getUserCount() > 1) {
                         return CODE_NONSYSTEM_USER_EXISTS;
                     }
-                    if (AccountManager.get(mContext).getAccounts().length > 0) {
+                    if (hasIncompatibleAccountsLocked(UserHandle.USER_SYSTEM, owner)) {
                         return CODE_ACCOUNTS_NOT_EMPTY;
                     }
                 } else {
@@ -8574,7 +8725,10 @@
     }
 
     private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
-        return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
+        synchronized (this) {
+            return CODE_OK == checkSetDeviceOwnerPreConditionLocked(
+                    /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false);
+        }
     }
 
     private boolean hasFeatureManagedUsers() {
@@ -8906,10 +9060,14 @@
         return false;
     }
 
-    private synchronized void disableSecurityLoggingIfNotCompliant() {
+    private synchronized void disableDeviceOwnerManagedSingleUserFeaturesIfNeeded() {
         if (!isDeviceOwnerManagedSingleUserDevice()) {
             mInjector.securityLogSetLoggingEnabledProperty(false);
             Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
+            if (mOwners.hasDeviceOwner()) {
+                setBackupServiceEnabledInternal(false);
+                Slog.w(LOG_TAG, "Backup is off as it's a managed device that has more that one user.");
+            }
         }
     }
 
@@ -8978,6 +9136,14 @@
                 android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
     }
 
+    private void enforceCallerSystemUserHandle() {
+        final int callingUid = mInjector.binderGetCallingUid();
+        final int userId = UserHandle.getUserId(callingUid);
+        if (userId != UserHandle.USER_SYSTEM) {
+            throw new SecurityException("Caller has to be in user 0");
+        }
+    }
+
     @Override
     public boolean isUninstallInQueue(final String packageName) {
         enforceCanManageDeviceAdmin();
@@ -9107,6 +9273,8 @@
             saveSettingsLocked(userHandle);
             updateMaximumTimeToLockLocked(userHandle);
             policy.mRemovingAdmins.remove(adminReceiver);
+
+            Slog.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
         }
         // The removed admin might have disabled camera, so update user
         // restrictions.
@@ -9131,4 +9299,151 @@
             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();
+        enforceCallerSystemUserHandle();
+        // no effect if it's called from user build
+        if (!mInjector.isBuildDebuggable()) {
+            return;
+        }
+        final int userId = UserHandle.USER_SYSTEM;
+        boolean isUserCompleted = mInjector.settingsSecureGetIntForUser(
+                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0;
+        DevicePolicyData policy = getUserData(userId);
+        policy.mUserSetupComplete = isUserCompleted;
+        synchronized (this) {
+            saveSettingsLocked(userId);
+        }
+    }
+
+    @Override
+    public void setBackupServiceEnabled(ComponentName admin, boolean enabled) {
+        Preconditions.checkNotNull(admin);
+        if (!mHasFeature) {
+            return;
+        }
+        ensureDeviceOwnerManagingSingleUser(admin);
+        setBackupServiceEnabledInternal(enabled);
+    }
+
+    private synchronized void setBackupServiceEnabledInternal(boolean enabled) {
+        long ident = mInjector.binderClearCallingIdentity();
+        try {
+            IBackupManager ibm = mInjector.getIBackupManager();
+            if (ibm != null) {
+                ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, enabled);
+            }
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                "Failed " + (enabled ? "" : "de") + "activating backup service.", e);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public boolean isBackupServiceEnabled(ComponentName admin) {
+        Preconditions.checkNotNull(admin);
+        if (!mHasFeature) {
+            return true;
+        }
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            return isBackupServiceEnabledInternal();
+        }
+    }
+    private boolean isBackupServiceEnabledInternal() {
+        try {
+            IBackupManager ibm = mInjector.getIBackupManager();
+            return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed requesting backup service state.", e);
+        }
+    }
+
+    /**
+     * Return true if a given user has any accounts that'll prevent installing a device or profile
+     * owner {@code owner}.
+     * - If the user has no accounts, then return false.
+     * - Otherwise, if the owner is unknown (== null), or is not test-only, then return true.
+     * - Otherwise, if there's any account that does not have ..._ALLOWED, or does have
+     *   ..._DISALLOWED, return true.
+     * - Otherwise return false.
+     */
+    private boolean hasIncompatibleAccountsLocked(int userId, @Nullable ComponentName owner) {
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            final AccountManager am = AccountManager.get(mContext);
+            final Account accounts[] = am.getAccountsAsUser(userId);
+            if (accounts.length == 0) {
+                return false;
+            }
+            final String[] feature_allow =
+                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
+            final String[] feature_disallow =
+                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
+
+            // Even if we find incompatible accounts along the way, we still check all accounts
+            // for logging.
+            boolean compatible = true;
+            for (Account account : accounts) {
+                if (hasAccountFeatures(am, account, feature_disallow)) {
+                    Log.e(LOG_TAG, account + " has " + feature_disallow[0]);
+                    compatible = false;
+                }
+                if (!hasAccountFeatures(am, account, feature_allow)) {
+                    Log.e(LOG_TAG, account + " doesn't have " + feature_allow[0]);
+                    compatible = false;
+                }
+            }
+            if (compatible) {
+                Log.w(LOG_TAG, "All accounts are compatible");
+            } else {
+                Log.e(LOG_TAG, "Found incompatible accounts");
+            }
+
+            // Then check if the owner is test-only.
+            String log;
+            if (owner == null) {
+                // Owner is unknown.  Suppose it's not test-only
+                compatible = false;
+                log = "Only test-only device/profile owner can be installed with accounts";
+            } else if (isAdminTestOnlyLocked(owner, userId)) {
+                if (compatible) {
+                    log = "Installing test-only owner " + owner;
+                } else {
+                    log = "Can't install test-only owner " + owner + " with incompatible accounts";
+                }
+            } else {
+                compatible = false;
+                log = "Can't install non test-only owner " + owner + " with accounts";
+            }
+            if (compatible) {
+                Log.w(LOG_TAG, log);
+            } else {
+                Log.e(LOG_TAG, log);
+            }
+            return !compatible;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
+        try {
+            return am.hasFeatures(account, features, null, null).getResult();
+        } catch (Exception e) {
+            Log.w(LOG_TAG, "Failed to get account feature", e);
+            return false;
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 548f831..769b5ee 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -32,7 +31,6 @@
 import android.os.Environment;
 import android.os.FactoryTest;
 import android.os.FileUtils;
-import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -47,6 +45,7 @@
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.WindowManager;
 
@@ -55,17 +54,20 @@
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.internal.os.ZygoteInit;
+import com.android.internal.policy.EmergencyAffordanceManager;
 import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
+import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MetricsLoggerService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.display.NightDisplayService;
 import com.android.server.dreams.DreamManagerService;
+import com.android.server.emergency.EmergencyAffordanceService;
 import com.android.server.fingerprint.FingerprintService;
 import com.android.server.hdmi.HdmiControlService;
 import com.android.server.input.InputManagerService;
@@ -78,6 +80,7 @@
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
+import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
@@ -91,6 +94,7 @@
 import com.android.server.power.ShutdownThread;
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.retaildemo.RetailDemoModeService;
+import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.soundtrigger.SoundTriggerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
@@ -106,6 +110,8 @@
 
 import dalvik.system.VMRuntime;
 
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.io.File;
 import java.io.IOException;
 import java.util.Locale;
@@ -115,6 +121,12 @@
 public final class SystemServer {
     private static final String TAG = "SystemServer";
 
+    private static final boolean LOG_BOOT_TIME = true;
+    // Debug boot time for every step if it's non-user build.
+    private static final boolean DEBUG_BOOT_TIME = LOG_BOOT_TIME && !"user".equals(Build.TYPE);
+    private static final String TAG_BOOT_TIME = "SystemServerTiming";
+    private static final Deque<Pair<String, Long>> START_TIMES = new ArrayDeque<>();
+
     private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
     private static final String ENCRYPTED_STATE = "1";
 
@@ -226,7 +238,7 @@
 
     private void run() {
         try {
-            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
+            traceBeginAndSlog("InitBeforeStartServices");
             // If a device's clock is before 1970 (before 0), a lot of
             // APIs crash dealing with negative numbers, notably
             // java.io.File#setLastModified, so instead we fake it and
@@ -323,12 +335,12 @@
             mSystemServiceManager = new SystemServiceManager(mSystemContext);
             LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
         } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();  // InitBeforeStartServices
         }
 
         // Start services.
         try {
-            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
+            traceBeginAndSlog("StartServices");
             startBootstrapServices();
             startCoreServices();
             startOtherServices();
@@ -337,7 +349,7 @@
             Slog.e("System", "************ Failure starting system services", ex);
             throw ex;
         } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
         }
 
         // For debug builds, log event loop stalls to dropbox for analysis.
@@ -413,35 +425,53 @@
         // Wait for installd to finish starting up so that it has a chance to
         // create critical directories such as /data/user with the appropriate
         // permissions.  We need this to complete before we initialize other services.
+        traceBeginAndSlog("StartInstaller");
         Installer installer = mSystemServiceManager.startService(Installer.class);
+        traceEnd();
+
+        // In some cases after launching an app we need to access device identifiers,
+        // therefore register the device identifier policy before the activity manager.
+        traceBeginAndSlog("DeviceIdentifiersPolicyService");
+        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
+        traceEnd();
 
         // Activity manager runs the show.
+        traceBeginAndSlog("StartActivityManager");
         mActivityManagerService = mSystemServiceManager.startService(
                 ActivityManagerService.Lifecycle.class).getService();
         mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
         mActivityManagerService.setInstaller(installer);
+        traceEnd();
 
         // Power manager needs to be started early because other services need it.
         // Native daemons may be watching for it to be registered so it must be ready
         // to handle incoming binder calls immediately (including being able to verify
         // the permissions for those calls).
+        traceBeginAndSlog("StartPowerManager");
         mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
+        traceEnd();
 
         // Now that the power manager has been started, let the activity manager
         // initialize power management features.
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitPowerManagement");
+        traceBeginAndSlog("InitPowerManagement");
         mActivityManagerService.initPowerManagement();
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         // Manages LEDs and display backlight so we need it to bring up the display.
+        traceBeginAndSlog("StartLightsService");
         mSystemServiceManager.startService(LightsService.class);
+        traceEnd();
 
         // Display manager is needed to provide display metrics before package manager
         // starts up.
+        traceBeginAndSlog("StartDisplayManager");
         mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
+        traceEnd();
 
         // We need the default display before we can initialize the package manager.
+        traceBeginAndSlog("WaitForDisplay");
         mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+        traceEnd();
 
         // Only run "core" apps if we're encrypting the device.
         String cryptState = SystemProperties.get("vold.decrypt");
@@ -459,7 +489,7 @@
                 mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
         mFirstBoot = mPackageManagerService.isFirstBoot();
         mPackageManager = mSystemContext.getPackageManager();
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
         // A/B artifacts after boot, before anything else might touch/need them.
@@ -474,40 +504,57 @@
                 } catch (Throwable e) {
                     reportWtf("starting OtaDexOptService", e);
                 } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                    traceEnd();
                 }
             }
         }
 
         traceBeginAndSlog("StartUserManagerService");
         mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         // Initialize attribute cache used to cache resources from packages.
+        traceBeginAndSlog("InitAttributerCache");
         AttributeCache.init(mSystemContext);
+        traceEnd();
 
         // Set up the Application instance for the system process and get started.
+        traceBeginAndSlog("SetSystemProcess");
         mActivityManagerService.setSystemProcess();
+        traceEnd();
 
         // The sensor service needs access to package manager service, app ops
         // service, and permissions service, therefore we start it after them.
+        traceBeginAndSlog("StartSensorService");
         startSensorService();
+        traceEnd();
     }
 
     /**
      * Starts some essential services that are not tangled up in the bootstrap process.
      */
     private void startCoreServices() {
+        // Records errors and logs, for example wtf()
+        traceBeginAndSlog("StartDropBoxManager");
+        mSystemServiceManager.startService(DropBoxManagerService.class);
+        traceEnd();
+
+        traceBeginAndSlog("StartBatteryService");
         // Tracks the battery level.  Requires LightService.
         mSystemServiceManager.startService(BatteryService.class);
+        traceEnd();
 
         // Tracks application usage stats.
+        traceBeginAndSlog("StartUsageService");
         mSystemServiceManager.startService(UsageStatsService.class);
         mActivityManagerService.setUsageStatsManager(
                 LocalServices.getService(UsageStatsManagerInternal.class));
+        traceEnd();
 
         // Tracks whether the updatable WebView is in a ready state and watches for update installs.
+        traceBeginAndSlog("StartWebViewUpdateService");
         mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
+        traceEnd();
     }
 
     /**
@@ -549,70 +596,91 @@
                 false);
         boolean disableTrustManager = SystemProperties.getBoolean("config.disable_trustmanager",
                 false);
-        boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices", false);
+        boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices",
+                false);
         boolean disableSamplingProfiler = SystemProperties.getBoolean("config.disable_samplingprof",
                 false);
+        boolean disableConsumerIr = SystemProperties.getBoolean("config.disable_consumerir", false);
+        boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false);
+        boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
+                false);
+
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
         try {
             Slog.i(TAG, "Reading configuration...");
+            traceBeginAndSlog("ReadingSystemConfig");
             SystemConfig.getInstance();
+            traceEnd();
+
+            traceBeginAndSlog("StartKeyAttestationApplicationIdProviderService");
+            ServiceManager.addService("sec_key_att_app_id_provider",
+                    new KeyAttestationApplicationIdProviderService(context));
+            traceEnd();
 
             traceBeginAndSlog("StartSchedulingPolicyService");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
+            traceBeginAndSlog("StartTelecomLoaderService");
             mSystemServiceManager.startService(TelecomLoaderService.class);
+            traceEnd();
 
             traceBeginAndSlog("StartTelephonyRegistry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("StartEntropyMixer");
             mEntropyMixer = new EntropyMixer(context);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             mContentResolver = context.getContentResolver();
 
-            Slog.i(TAG, "Camera Service");
-            mSystemServiceManager.startService(CameraService.class);
+            if (!disableCameraService) {
+                Slog.i(TAG, "Camera Service");
+                traceBeginAndSlog("StartCameraService");
+                mSystemServiceManager.startService(CameraService.class);
+                traceEnd();
+            }
 
             // The AccountManager must come before the ContentService
             traceBeginAndSlog("StartAccountManagerService");
             mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("StartContentService");
             mSystemServiceManager.startService(CONTENT_SERVICE_CLASS);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("InstallSystemProviders");
             mActivityManagerService.installSystemProviders();
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("StartVibratorService");
             vibrator = new VibratorService(context);
             ServiceManager.addService("vibrator", vibrator);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
-            traceBeginAndSlog("StartConsumerIrService");
-            consumerIr = new ConsumerIrService(context);
-            ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            if (!disableConsumerIr) {
+                traceBeginAndSlog("StartConsumerIrService");
+                consumerIr = new ConsumerIrService(context);
+                ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
+                traceEnd();
+            }
 
             traceBeginAndSlog("StartAlarmManagerService");
             mSystemServiceManager.startService(AlarmManagerService.class);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("InitWatchdog");
             final Watchdog watchdog = Watchdog.getInstance();
             watchdog.init(context, mActivityManagerService);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("StartInputManagerService");
             inputManager = new InputManagerService(context);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             traceBeginAndSlog("StartWindowManagerService");
             wm = WindowManagerService.main(context, inputManager,
@@ -620,19 +688,25 @@
                     !mFirstBoot, mOnlyCore, new PhoneWindowManager());
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
-            traceBeginAndSlog("StartVrManagerService");
-            mSystemServiceManager.startService(VrManagerService.class);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            if (!disableVrManager) {
+                traceBeginAndSlog("StartVrManagerService");
+                mSystemServiceManager.startService(VrManagerService.class);
+                traceEnd();
+            }
 
             mActivityManagerService.setWindowManager(wm);
 
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
+            traceBeginAndSlog("StartInputManager");
             inputManager.start();
+            traceEnd();
 
             // TODO: Use service dependencies instead.
+            traceBeginAndSlog("DisplayManagerWindowManagerAndInputReady");
             mDisplayManagerService.windowManagerAndInputReady();
+            traceEnd();
 
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
@@ -647,16 +721,22 @@
             } else if (disableBluetooth) {
                 Slog.i(TAG, "Bluetooth Service disabled by config");
             } else {
+                traceBeginAndSlog("StartBluetoothService");
                 mSystemServiceManager.startService(BluetoothService.class);
+                traceEnd();
             }
 
             traceBeginAndSlog("ConnectivityMetricsLoggerService");
             mSystemServiceManager.startService(MetricsLoggerService.class);
+            traceEnd();
+
+            traceBeginAndSlog("IpConnectivityMetrics");
+            mSystemServiceManager.startService(IpConnectivityMetrics.class);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             traceBeginAndSlog("PinnerService");
             mSystemServiceManager.startService(PinnerService.class);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
@@ -672,7 +752,9 @@
 
         // Bring up services needed for UI.
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+            traceBeginAndSlog("StartInputMethodManagerLifecycle");
             mSystemServiceManager.startService(InputMethodManagerService.Lifecycle.class);
+            traceEnd();
 
             traceBeginAndSlog("StartAccessibilityManagerService");
             try {
@@ -681,18 +763,21 @@
             } catch (Throwable e) {
                 reportWtf("starting Accessibility Manager", e);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
         }
 
+        traceBeginAndSlog("MakeDisplayReady");
         try {
             wm.displayReady();
         } catch (Throwable e) {
             reportWtf("making display ready", e);
         }
+        traceEnd();
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             if (!disableStorage &&
                 !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+                traceBeginAndSlog("StartMountService");
                 try {
                     /*
                      * NotificationManagerService is dependant on MountService,
@@ -704,30 +789,33 @@
                 } catch (Throwable e) {
                     reportWtf("starting Mount Service", e);
                 }
+                traceEnd();
             }
         }
 
         // We start this here so that we update our configuration to set watch or television
         // as appropriate.
+        traceBeginAndSlog("StartUiModeManager");
         mSystemServiceManager.startService(UiModeManagerService.class);
+        traceEnd();
 
         if (!mOnlyCore) {
-            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "UpdatePackagesIfNeeded");
+            traceBeginAndSlog("UpdatePackagesIfNeeded");
             try {
                 mPackageManagerService.updatePackagesIfNeeded();
             } catch (Throwable e) {
                 reportWtf("update packages", e);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
         }
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformFstrimIfNeeded");
+        traceBeginAndSlog("PerformFstrimIfNeeded");
         try {
             mPackageManagerService.performFstrimIfNeeded();
         } catch (Throwable e) {
             reportWtf("performing fstrim", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             if (!disableNonCoreServices) {
@@ -739,17 +827,23 @@
                 } catch (Throwable e) {
                     reportWtf("starting LockSettingsService service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
+                    traceBeginAndSlog("StartPersistentDataBlock");
                     mSystemServiceManager.startService(PersistentDataBlockService.class);
+                    traceEnd();
                 }
 
+                traceBeginAndSlog("StartDeviceIdleController");
                 mSystemServiceManager.startService(DeviceIdleController.class);
+                traceEnd();
 
                 // Always start the Device Policy Manager, so that the API is compatible with
                 // API8.
+                traceBeginAndSlog("StartDevicePolicyManager");
                 mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+                traceEnd();
             }
 
             if (!disableSystemUI) {
@@ -760,18 +854,13 @@
                 } catch (Throwable e) {
                     reportWtf("starting StatusBarManagerService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartClipboardService");
-                try {
-                    ServiceManager.addService(Context.CLIPBOARD_SERVICE,
-                            new ClipboardService(context));
-                } catch (Throwable e) {
-                    reportWtf("starting Clipboard Service", e);
-                }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                mSystemServiceManager.startService(ClipboardService.class);
+                traceEnd();
             }
 
             if (!disableNetwork) {
@@ -782,11 +871,13 @@
                 } catch (Throwable e) {
                     reportWtf("starting NetworkManagement Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices && !disableTextServices) {
+                traceBeginAndSlog("StartTextServicesManager");
                 mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
+                traceEnd();
             }
 
             if (!disableNetwork) {
@@ -797,7 +888,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting Network Score Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 traceBeginAndSlog("StartNetworkStatsService");
                 try {
@@ -806,7 +897,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting NetworkStats Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 traceBeginAndSlog("StartNetworkPolicyManagerService");
                 try {
@@ -816,29 +907,41 @@
                 } catch (Throwable e) {
                     reportWtf("starting NetworkPolicy Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)) {
+                    traceBeginAndSlog("StartWifiNan");
                     mSystemServiceManager.startService(WIFI_NAN_SERVICE_CLASS);
+                    traceEnd();
                 } else {
                     Slog.i(TAG, "No Wi-Fi NAN Service (NAN support Not Present)");
                 }
 
                 if (context.getPackageManager().hasSystemFeature(
                         PackageManager.FEATURE_WIFI_DIRECT)) {
+                    traceBeginAndSlog("StartWifiP2P");
                     mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+                    traceEnd();
                 }
+                traceBeginAndSlog("StartWifi");
                 mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+                traceEnd();
+                traceBeginAndSlog("StartWifiScanning");
                 mSystemServiceManager.startService(
                             "com.android.server.wifi.scanner.WifiScanningService");
+                traceEnd();
 
                 if (!disableRtt) {
+                    traceBeginAndSlog("StartWifiRtt");
                     mSystemServiceManager.startService("com.android.server.wifi.RttService");
+                    traceEnd();
                 }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
+                    traceBeginAndSlog("StartEthernet");
                     mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
+                    traceEnd();
                 }
 
                 traceBeginAndSlog("StartConnectivityService");
@@ -851,7 +954,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting Connectivity Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 traceBeginAndSlog("StartNsdService");
                 try {
@@ -861,7 +964,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting Service Discovery Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices) {
@@ -872,11 +975,13 @@
                 } catch (Throwable e) {
                     reportWtf("starting UpdateLockService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartRecoverSystemService");
                 mSystemServiceManager.startService(RecoverySystemService.class);
+                traceEnd();
             }
 
             /*
@@ -885,20 +990,24 @@
              * first before continuing.
              */
             if (mountService != null && !mOnlyCore) {
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WaitForAsecScan");
+                traceBeginAndSlog("WaitForAsecScan");
                 try {
                     mountService.waitForAsecScan();
                 } catch (RemoteException ignored) {
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
+            traceBeginAndSlog("StartNotificationManager");
             mSystemServiceManager.startService(NotificationManagerService.class);
             notification = INotificationManager.Stub.asInterface(
                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
             networkPolicy.bindNotificationManager(notification);
+            traceEnd();
 
+            traceBeginAndSlog("StartDeviceMonitor");
             mSystemServiceManager.startService(DeviceStorageMonitorService.class);
+            traceEnd();
 
             if (!disableLocation) {
                 traceBeginAndSlog("StartLocationManagerService");
@@ -908,7 +1017,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting Location Manager", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 traceBeginAndSlog("StartCountryDetectorService");
                 try {
@@ -917,7 +1026,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting Country Detector", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices && !disableSearchManager) {
@@ -927,27 +1036,29 @@
                 } catch (Throwable e) {
                     reportWtf("starting Search Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
-            mSystemServiceManager.startService(DropBoxManagerService.class);
-
             if (!disableNonCoreServices && context.getResources().getBoolean(
                         R.bool.config_enableWallpaperService)) {
                 traceBeginAndSlog("StartWallpaperManagerService");
                 mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             traceBeginAndSlog("StartAudioService");
             mSystemServiceManager.startService(AudioService.Lifecycle.class);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartDockObserver");
                 mSystemServiceManager.startService(DockObserver.class);
+                traceEnd();
 
                 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                    traceBeginAndSlog("StartThermalObserver");
                     mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
+                    traceEnd();
                 }
             }
 
@@ -959,21 +1070,23 @@
             } catch (Throwable e) {
                 reportWtf("starting WiredAccessoryManager", e);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             if (!disableNonCoreServices) {
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
                     // Start MIDI Manager service
+                    traceBeginAndSlog("StartMidiManager");
                     mSystemServiceManager.startService(MIDI_SERVICE_CLASS);
+                    traceEnd();
                 }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
                         || mPackageManager.hasSystemFeature(
                                 PackageManager.FEATURE_USB_ACCESSORY)) {
                     // Manage USB host and device support
-                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartUsbService");
+                    traceBeginAndSlog("StartUsbService");
                     mSystemServiceManager.startService(USB_SERVICE_CLASS);
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                    traceEnd();
                 }
 
                 if (!disableSerial) {
@@ -985,11 +1098,10 @@
                     } catch (Throwable e) {
                         Slog.e(TAG, "Failure starting SerialService", e);
                     }
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                    traceEnd();
                 }
 
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
-                        "StartHardwarePropertiesManagerService");
+                traceBeginAndSlog("StartHardwarePropertiesManagerService");
                 try {
                     hardwarePropertiesService = new HardwarePropertiesManagerService(context);
                     ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
@@ -997,43 +1109,65 @@
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
+            traceBeginAndSlog("StartTwilightService");
             mSystemServiceManager.startService(TwilightService.class);
+            traceEnd();
 
             if (NightDisplayController.isAvailable(context)) {
+                traceBeginAndSlog("StartNightDisplay");
                 mSystemServiceManager.startService(NightDisplayService.class);
+                traceEnd();
             }
 
+            traceBeginAndSlog("StartJobScheduler");
             mSystemServiceManager.startService(JobSchedulerService.class);
+            traceEnd();
 
+            traceBeginAndSlog("StartSoundTrigger");
             mSystemServiceManager.startService(SoundTriggerService.class);
+            traceEnd();
 
             if (!disableNonCoreServices) {
                 if (!disableTrustManager) {
+                    traceBeginAndSlog("StartTrustManager");
                     mSystemServiceManager.startService(TrustManagerService.class);
+                    traceEnd();
                 }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+                    traceBeginAndSlog("StartBackupManager");
                     mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
+                    traceEnd();
                 }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
                     || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
+                    traceBeginAndSlog("StartAppWidgerService");
                     mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
+                    traceEnd();
                 }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
+                    traceBeginAndSlog("StartVoiceRecognitionManager");
                     mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+                    traceEnd();
                 }
 
                 if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
-                    Slog.i(TAG, "Gesture Launcher Service");
+                    traceBeginAndSlog("StartGestureLauncher");
                     mSystemServiceManager.startService(GestureLauncherService.class);
+                    traceEnd();
                 }
+                traceBeginAndSlog("StartSensorNotification");
                 mSystemServiceManager.startService(SensorNotificationService.class);
+                traceEnd();
+
+                traceBeginAndSlog("StartContextHubSystemService");
                 mSystemServiceManager.startService(ContextHubSystemService.class);
+                traceEnd();
             }
 
             traceBeginAndSlog("StartDiskStatsService");
@@ -1042,7 +1176,7 @@
             } catch (Throwable e) {
                 reportWtf("starting DiskStats Service", e);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             if (!disableSamplingProfiler) {
                 traceBeginAndSlog("StartSamplingProfilerService");
@@ -1056,7 +1190,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting SamplingProfiler Service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNetwork && !disableNetworkTime) {
@@ -1067,7 +1201,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting NetworkTimeUpdate service", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             traceBeginAndSlog("StartCommonTimeManagementService");
@@ -1077,7 +1211,7 @@
             } catch (Throwable e) {
                 reportWtf("starting CommonTimeManagementService service", e);
             }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            traceEnd();
 
             if (!disableNetwork) {
                 traceBeginAndSlog("CertBlacklister");
@@ -1086,12 +1220,19 @@
                 } catch (Throwable e) {
                     reportWtf("starting CertBlacklister", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
+            }
+
+            if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
+                // EmergencyMode sevice
+                mSystemServiceManager.startService(EmergencyAffordanceService.class);
             }
 
             if (!disableNonCoreServices) {
                 // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
+                traceBeginAndSlog("StartDreamManager");
                 mSystemServiceManager.startService(DreamManagerService.class);
+                traceEnd();
             }
 
             if (!disableNonCoreServices && ZygoteInit.PRELOAD_RESOURCES) {
@@ -1102,36 +1243,52 @@
                 } catch (Throwable e) {
                     reportWtf("starting AssetAtlasService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("AddGraphicsStatsService");
                 ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
                         new GraphicsStatsService(context));
+                traceEnd();
             }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+                traceBeginAndSlog("StartPrintManager");
                 mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
+                traceEnd();
             }
 
+            traceBeginAndSlog("StartRestrictionManager");
             mSystemServiceManager.startService(RestrictionsManagerService.class);
+            traceEnd();
 
+            traceBeginAndSlog("StartMediaSessionService");
             mSystemServiceManager.startService(MediaSessionService.class);
+            traceEnd();
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
+                traceBeginAndSlog("StartHdmiControlService");
                 mSystemServiceManager.startService(HdmiControlService.class);
+                traceEnd();
             }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)) {
+                traceBeginAndSlog("StartTvInputManager");
                 mSystemServiceManager.startService(TvInputManagerService.class);
+                traceEnd();
             }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
+                traceBeginAndSlog("StartMediaResourceMonitor");
                 mSystemServiceManager.startService(MediaResourceMonitorService.class);
+                traceEnd();
             }
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+                traceBeginAndSlog("StartTvRemoteService");
                 mSystemServiceManager.startService(TvRemoteService.class);
+                traceEnd();
             }
 
             if (!disableNonCoreServices) {
@@ -1142,10 +1299,12 @@
                 } catch (Throwable e) {
                     reportWtf("starting MediaRouterService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+                    traceBeginAndSlog("StartFingerprintSensor");
                     mSystemServiceManager.startService(FingerprintService.class);
+                    traceEnd();
                 }
 
                 traceBeginAndSlog("StartBackgroundDexOptService");
@@ -1154,57 +1313,75 @@
                 } catch (Throwable e) {
                     reportWtf("starting BackgroundDexOptService", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
             }
             // LauncherAppsService uses ShortcutService.
+            traceBeginAndSlog("StartShortcutServiceLifecycle");
             mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
+            traceEnd();
 
+            traceBeginAndSlog("StartLauncherAppsService");
             mSystemServiceManager.startService(LauncherAppsService.class);
+            traceEnd();
         }
 
         if (!disableNonCoreServices && !disableMediaProjection) {
+            traceBeginAndSlog("StartMediaProjectionManager");
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
+            traceEnd();
         }
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            traceBeginAndSlog("StartWearBluetooth");
             mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+            traceEnd();
+
+            traceBeginAndSlog("StartWearWifiMediator");
             mSystemServiceManager.startService(WEAR_WIFI_MEDIATOR_SERVICE_CLASS);
-          if (!disableNonCoreServices) {
-              mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
-          }
+            traceEnd();
+            if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartWearTimeService");
+                mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
+                traceEnd();
+            }
         }
 
         // Before things start rolling, be sure we have decided whether
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
+            traceBeginAndSlog("EnterSafeModeAndDisableJitCompilation");
             mActivityManagerService.enterSafeMode();
             // Disable the JIT for the system_server process
             VMRuntime.getRuntime().disableJitCompilation();
+            traceEnd();
         } else {
             // Enable the JIT for the system_server process
+            traceBeginAndSlog("StartJitCompilation");
             VMRuntime.getRuntime().startJitCompilation();
+            traceEnd();
         }
 
         // MMS service broker
+        traceBeginAndSlog("StartMmsService");
         mmsService = mSystemServiceManager.startService(MmsServiceBroker.class);
+        traceEnd();
 
-        if (Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0 ||
-                UserManager.isDeviceInDemoMode(mSystemContext)) {
-            mSystemServiceManager.startService(RetailDemoModeService.class);
-        }
+        traceBeginAndSlog("StartRetailDemoModeService");
+        mSystemServiceManager.startService(RetailDemoModeService.class);
+        traceEnd();
 
         // It is now time to start up the app processes...
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
+        traceBeginAndSlog("MakeVibratorServiceReady");
         try {
             vibrator.systemReady();
         } catch (Throwable e) {
             reportWtf("making Vibrator Service ready", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeLockSettingsServiceReady");
+        traceBeginAndSlog("MakeLockSettingsServiceReady");
         if (lockSettings != null) {
             try {
                 lockSettings.systemReady();
@@ -1212,20 +1389,24 @@
                 reportWtf("making Lock Settings Service ready", e);
             }
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         // Needed by DevicePolicyManager for initialization
+        traceBeginAndSlog("StartBootPhaseLockSettingsReady");
         mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
+        traceEnd();
 
+        traceBeginAndSlog("StartBootPhaseSystemServicesReady");
         mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+        traceEnd();
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeWindowManagerServiceReady");
+        traceBeginAndSlog("MakeWindowManagerServiceReady");
         try {
             wm.systemReady();
         } catch (Throwable e) {
             reportWtf("making Window Manager Service ready", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         if (safeMode) {
             mActivityManagerService.showSafeModeOverlay();
@@ -1246,32 +1427,31 @@
             systemTheme.rebase();
         }
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePowerManagerServiceReady");
+        traceBeginAndSlog("MakePowerManagerServiceReady");
         try {
             // TODO: use boot phase
             mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         } catch (Throwable e) {
             reportWtf("making Power Manager Service ready", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePackageManagerServiceReady");
+        traceBeginAndSlog("MakePackageManagerServiceReady");
         try {
             mPackageManagerService.systemReady();
         } catch (Throwable e) {
             reportWtf("making Package Manager Service ready", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
-        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeDisplayManagerServiceReady");
+        traceBeginAndSlog("MakeDisplayManagerServiceReady");
         try {
             // TODO: use boot phase and communicate these flags some other way
             mDisplayManagerService.systemReady(safeMode, mOnlyCore);
         } catch (Throwable e) {
             reportWtf("making Display Manager Service ready", e);
         }
-        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        traceEnd();
 
         mSystemServiceManager.setSafeMode(safeMode);
 
@@ -1302,90 +1482,99 @@
                 Slog.i(TAG, "Making services ready");
                 mSystemServiceManager.startBootPhase(
                         SystemService.PHASE_ACTIVITY_MANAGER_READY);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseActivityManagerReady");
+                traceBeginAndSlog("PhaseActivityManagerReady");
 
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartObservingNativeCrashes");
+                traceBeginAndSlog("StartObservingNativeCrashes");
                 try {
                     mActivityManagerService.startObservingNativeCrashes();
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
                 if (!mOnlyCore) {
                     Slog.i(TAG, "WebViewFactory preparation");
-                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
+                    traceBeginAndSlog("WebViewFactoryPreparation");
                     mWebViewUpdateService.prepareWebViewInSystemServer();
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                    traceEnd();
                 }
 
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
+                traceBeginAndSlog("StartSystemUI");
                 try {
                     startSystemUi(context);
                 } catch (Throwable e) {
                     reportWtf("starting System UI", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkScoreReady");
+                traceEnd();
+                traceBeginAndSlog("MakeNetworkScoreReady");
                 try {
                     if (networkScoreF != null) networkScoreF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Score Service ready", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkManagementServiceReady");
+                traceEnd();
+                traceBeginAndSlog("MakeNetworkManagementServiceReady");
                 try {
                     if (networkManagementF != null) networkManagementF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Managment Service ready", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkStatsServiceReady");
+                traceEnd();
+                traceBeginAndSlog("MakeNetworkStatsServiceReady");
                 try {
                     if (networkStatsF != null) networkStatsF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Stats Service ready", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkPolicyServiceReady");
+                traceEnd();
+                traceBeginAndSlog("MakeNetworkPolicyServiceReady");
                 try {
                     if (networkPolicyF != null) networkPolicyF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Policy Service ready", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeConnectivityServiceReady");
+                traceEnd();
+                traceBeginAndSlog("MakeConnectivityServiceReady");
                 try {
                     if (connectivityF != null) connectivityF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Connectivity Service ready", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
 
+                traceBeginAndSlog("StartWatchdog");
                 Watchdog.getInstance().start();
+                traceEnd();
 
                 // It is now okay to let the various system services start their
                 // third party code...
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseThirdPartyAppsCanStart");
+                traceBeginAndSlog("PhaseThirdPartyAppsCanStart");
                 mSystemServiceManager.startBootPhase(
                         SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+                traceEnd();
 
+                traceBeginAndSlog("MakeLocationServiceReady");
                 try {
                     if (locationF != null) locationF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying Location Service running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeCountryDetectionServiceReady");
                 try {
                     if (countryDetectorF != null) countryDetectorF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying CountryDetectorService running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeNetworkTimeUpdateReady");
                 try {
                     if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying NetworkTimeService running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeCommonTimeManagementServiceReady");
                 try {
                     if (commonTimeMgmtServiceF != null) {
                         commonTimeMgmtServiceF.systemRunning();
@@ -1393,40 +1582,53 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying CommonTimeManagementService running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeAtlasServiceReady");
                 try {
                     if (atlasF != null) atlasF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying AssetAtlasService running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeInputManagerServiceReady");
                 try {
                     // TODO(BT) Pass parameter to input manager
                     if (inputManagerF != null) inputManagerF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying InputManagerService running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeTelephonyRegistryReady");
                 try {
                     if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying TelephonyRegistry running", e);
                 }
+                traceEnd();
+                traceBeginAndSlog("MakeMediaRouterServiceReady");
                 try {
                     if (mediaRouterF != null) mediaRouterF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying MediaRouterService running", e);
                 }
-
+                traceEnd();
+                traceBeginAndSlog("MakeMmsServiceReady");
                 try {
                     if (mmsServiceF != null) mmsServiceF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying MmsService running", e);
                 }
+                traceEnd();
 
+                traceBeginAndSlog("MakeNetworkScoreServiceReady");
                 try {
                     if (networkScoreF != null) networkScoreF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying NetworkScoreService running", e);
                 }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                traceEnd();
+
+                traceEnd();  // PhaseActivityManagerReady
             }
         });
     }
@@ -1443,5 +1645,22 @@
     private static void traceBeginAndSlog(String name) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
         Slog.i(TAG, name);
+        if (DEBUG_BOOT_TIME) {
+            START_TIMES.push(Pair.create(name, Long.valueOf(SystemClock.elapsedRealtime())));
+        }
+    }
+
+    private static void traceEnd() {
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        if (!DEBUG_BOOT_TIME) {
+            return;
+        }
+        Pair<String, Long> event = START_TIMES.pollFirst();
+        if (event == null) {
+            Slog.w(TAG, "traceEnd called more times than traceBeginAndSlog");
+            return;
+        }
+        Slog.d(TAG_BOOT_TIME, event.first + " took to complete: "
+                + (SystemClock.elapsedRealtime() - event.second) + "ms");
     }
 }
diff --git a/services/net/Android.mk b/services/net/Android.mk
index 336bc45..408794e 100644
--- a/services/net/Android.mk
+++ b/services/net/Android.mk
@@ -7,4 +7,7 @@
 LOCAL_SRC_FILES += \
     $(call all-java-files-under,java)
 
+LOCAL_AIDL_INCLUDES += \
+    system/netd/server/binder
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 4bb0902..4c75452 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -19,6 +19,7 @@
 import static android.system.OsConstants.*;
 
 import android.os.SystemClock;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
 import android.net.apf.ApfGenerator;
@@ -44,6 +45,7 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.lang.Thread;
+import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
@@ -171,8 +173,8 @@
     private static final int ETH_HEADER_LEN = 14;
     private static final int ETH_DEST_ADDR_OFFSET = 0;
     private static final int ETH_ETHERTYPE_OFFSET = 12;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
+            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
     // Endianness is not an issue for this constant because the APF interpreter always operates in
@@ -181,6 +183,7 @@
     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
     private static final int IPV4_ANY_HOST_ADDRESS = 0;
+    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
 
     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
@@ -188,7 +191,7 @@
     private static final int IPV6_HEADER_LEN = 40;
     // The IPv6 all nodes address ff02::1
     private static final byte[] IPV6_ALL_NODES_ADDRESS =
-            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 
     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
@@ -206,7 +209,7 @@
     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
     private static final short ARP_OPCODE_REQUEST = 1;
     private static final short ARP_OPCODE_REPLY = 2;
-    private static final byte[] ARP_IPV4_HEADER = new byte[]{
+    private static final byte[] ARP_IPV4_HEADER = {
             0, 1, // Hardware type: Ethernet (1)
             8, 0, // Protocol type: IP (0x0800)
             6,    // Hardware size: 6
@@ -229,6 +232,9 @@
     // Our IPv4 address, if we have just one, otherwise null.
     @GuardedBy("this")
     private byte[] mIPv4Address;
+    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
+    @GuardedBy("this")
+    private int mIPv4PrefixLength;
 
     @VisibleForTesting
     ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
@@ -364,26 +370,6 @@
 
         // Can't be static because it's in a non-static inner class.
         // TODO: Make this static once RA is its own class.
-        private int uint8(byte b) {
-            return b & 0xff;
-        }
-
-        private int uint16(short s) {
-            return s & 0xffff;
-        }
-
-        private long uint32(int i) {
-            return i & 0xffffffffL;
-        }
-
-        private long getUint16(ByteBuffer buffer, int position) {
-            return uint16(buffer.getShort(position));
-        }
-
-        private long getUint32(ByteBuffer buffer, int position) {
-            return uint32(buffer.getInt(position));
-        }
-
         private void prefixOptionToString(StringBuffer sb, int offset) {
             String prefix = IPv6AddresstoString(offset + 16);
             int length = uint8(mPacket.get(offset + 2));
@@ -737,39 +723,57 @@
         // Here's a basic summary of what the IPv4 filter program does:
         //
         // if filtering multicast (i.e. multicast lock not held):
-        //   if it's multicast:
-        //     drop
-        //   if it's not broadcast:
+        //   if it's DHCP destined to our MAC:
         //     pass
-        //   if it's not DHCP destined to our MAC:
+        //   if it's L2 broadcast:
+        //     drop
+        //   if it's IPv4 multicast:
+        //     drop
+        //   if it's IPv4 broadcast:
         //     drop
         // pass
 
         if (mMulticastFilter) {
-            // Check for multicast destination address range
+            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
+
+            // Pass DHCP addressed to us.
+            // Check it's UDP.
+            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
+            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
+            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
+            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
+            // Check it's addressed to DHCP client port.
+            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
+            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
+            // Check it's DHCP to our MAC address.
+            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
+            // NOTE: Relies on R1 containing IPv4 header offset.
+            gen.addAddR1();
+            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
+            gen.addJump(gen.PASS_LABEL);
+
+            // Drop all multicasts/broadcasts.
+            gen.defineLabel(skipDhcpv4Filter);
+
+            // If IPv4 destination address is in multicast range, drop.
             gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
             gen.addAnd(0xf0);
             gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
 
-            // Drop all broadcasts besides DHCP addressed to us
-            // If not a broadcast packet, pass
+            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
+            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
+            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
+            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
+                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
+                gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
+            }
+
+            // If L2 broadcast packet, drop.
             gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
             gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
-            // If not UDP, drop
-            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
-            gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL);
-            // If fragment, drop. This matches the BPF filter installed by the DHCP client.
-            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
-            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL);
-            // If not to DHCP client port, drop
-            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
-            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL);
-            // If not DHCP to our MAC address, drop
-            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
-            // NOTE: Relies on R1 containing IPv4 header offset.
-            gen.addAddR1();
-            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL);
+            gen.addJump(gen.DROP_LABEL);
         }
 
         // Otherwise, pass
@@ -1062,26 +1066,32 @@
         }
     }
 
-    // Find the single IPv4 address if there is one, otherwise return null.
-    private static byte[] findIPv4Address(LinkProperties lp) {
-        byte[] ipv4Address = null;
-        for (InetAddress inetAddr : lp.getAddresses()) {
-            byte[] addr = inetAddr.getAddress();
-            if (addr.length != 4) continue;
-            // More than one IPv4 address, abort
-            if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
-            ipv4Address = addr;
+    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
+    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
+        LinkAddress ipv4Address = null;
+        for (LinkAddress address : lp.getLinkAddresses()) {
+            if (!(address.getAddress() instanceof Inet4Address)) {
+                continue;
+            }
+            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
+                // More than one IPv4 address, abort.
+                return null;
+            }
+            ipv4Address = address;
         }
         return ipv4Address;
     }
 
     public synchronized void setLinkProperties(LinkProperties lp) {
         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
-        byte[] ipv4Address = findIPv4Address(lp);
-        // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
-        if (Arrays.equals(ipv4Address, mIPv4Address)) return;
-        // Otherwise update mIPv4Address and install new program.
-        mIPv4Address = ipv4Address;
+        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
+        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
+        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
+        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
+            return;
+        }
+        mIPv4Address = addr;
+        mIPv4PrefixLength = prefix;
         installNewProgramLocked();
     }
 
@@ -1127,4 +1137,38 @@
             pw.decreaseIndent();
         }
     }
+
+    private static int uint8(byte b) {
+        return b & 0xff;
+    }
+
+    private static int uint16(short s) {
+        return s & 0xffff;
+    }
+
+    private static long uint32(int i) {
+        return i & 0xffffffffL;
+    }
+
+    private static long getUint16(ByteBuffer buffer, int position) {
+        return uint16(buffer.getShort(position));
+    }
+
+    private static long getUint32(ByteBuffer buffer, int position) {
+        return uint32(buffer.getInt(position));
+    }
+
+    // TODO: move to android.net.NetworkUtils
+    @VisibleForTesting
+    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
+        return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
+    }
+
+    @VisibleForTesting
+    public static int bytesToInt(byte[] addrBytes) {
+        return (uint8(addrBytes[0]) << 24)
+                + (uint8(addrBytes[1]) << 16)
+                + (uint8(addrBytes[2]) << 8)
+                + (uint8(addrBytes[3]));
+    }
 }
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 654ef18..ee67d95 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -45,6 +45,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.IState;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.net.NetlinkTracker;
@@ -357,6 +358,7 @@
     }
 
     public static final String DUMP_ARG = "ipmanager";
+    public static final String DUMP_ARG_CONFIRM = "confirm";
 
     private static final int CMD_STOP = 1;
     private static final int CMD_START = 2;
@@ -382,6 +384,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;
@@ -394,6 +397,7 @@
     private final WakeupMessage mProvisioningTimeoutAlarm;
     private final WakeupMessage mDhcpActionTimeoutAlarm;
     private final LocalLog mLocalLog;
+    private final MessageHandlingLogger mMsgStateLogger;
     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
 
     private NetworkInterface mNetworkInterface;
@@ -476,10 +480,12 @@
         // Super simple StateMachine.
         addState(mStoppedState);
         addState(mStartedState);
+            addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
         mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+        mMsgStateLogger = new MessageHandlingLogger();
         super.start();
     }
 
@@ -557,6 +563,12 @@
     }
 
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
+            // Execute confirmConfiguration() and take no further action.
+            confirmConfiguration();
+            return;
+        }
+
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
         pw.println("APF dump:");
         pw.increaseIndent();
@@ -570,7 +582,7 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.println("StateMachine dump:");
+        pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
@@ -589,9 +601,9 @@
     @Override
     protected String getLogRecString(Message msg) {
         final String logLine = String.format(
-                "%s/%d %d %d %s",
+                "%s/%d %d %d %s [%s]",
                 mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(),
-                msg.arg1, msg.arg2, Objects.toString(msg.obj));
+                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
 
         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
         mLocalLog.log(richerLogLine);
@@ -599,6 +611,7 @@
             Log.d(mTag, richerLogLine);
         }
 
+        mMsgStateLogger.reset();
         return logLine;
     }
 
@@ -607,7 +620,11 @@
         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
         // and we already log any LinkProperties change that results in an
         // invocation of IpManager.Callback#onLinkPropertiesChange().
-        return (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+        if (!shouldLog) {
+            mMsgStateLogger.reset();
+        }
+        return shouldLog;
     }
 
     private void getNetworkInterface() {
@@ -768,6 +785,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 +961,29 @@
         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) {
@@ -994,6 +1029,8 @@
                 default:
                     return NOT_HANDLED;
             }
+
+            mMsgStateLogger.handled(this, getCurrentState());
             return HANDLED;
         }
     }
@@ -1010,6 +1047,13 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_STOP:
+                    break;
+
+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
+                    clearIPv4Address();
+                    break;
+
                 case DhcpClient.CMD_ON_QUIT:
                     mDhcpClient = null;
                     transitionTo(mStoppedState);
@@ -1018,17 +1062,80 @@
                 default:
                     deferMessage(msg);
             }
+
+            mMsgStateLogger.handled(this, getCurrentState());
             return HANDLED;
         }
     }
 
     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);
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            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 +1144,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 +1171,6 @@
 
         @Override
         public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
             stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
@@ -1167,10 +1267,6 @@
                     break;
                 }
 
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
@@ -1233,7 +1329,29 @@
                 default:
                     return NOT_HANDLED;
             }
+
+            mMsgStateLogger.handled(this, getCurrentState());
             return HANDLED;
         }
     }
+
+    private static class MessageHandlingLogger {
+        public String processedInState;
+        public String receivedInState;
+
+        public void reset() {
+            processedInState = null;
+            receivedInState = null;
+        }
+
+        public void handled(State processedIn, IState receivedIn) {
+            processedInState = processedIn.getClass().getSimpleName();
+            receivedInState = receivedIn.getName();
+        }
+
+        public String toString() {
+            return String.format("rcvd_in=%s, proc_in=%s",
+                                 receivedInState, processedInState);
+        }
+    }
 }
diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
new file mode 100644
index 0000000..153cb50
--- /dev/null
+++ b/services/net/java/android/net/util/NetdService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.net.util;
+
+import android.net.INetd;
+import android.os.ServiceManager;
+import android.util.Log;
+
+
+/**
+ * @hide
+ */
+public class NetdService {
+    private static final String TAG = NetdService.class.getSimpleName();
+    private static final String NETD_SERVICE_NAME = "netd";
+
+    /**
+     * It is the caller's responsibility to check for a null return value
+     * and to handle RemoteException errors from invocations on the returned
+     * interface if, for example, netd dies and is restarted.
+     *
+     * @return an INetd instance or null.
+     */
+    public static INetd getInstance() {
+        final INetd netdInstance = INetd.Stub.asInterface(
+                ServiceManager.getService(NETD_SERVICE_NAME));
+        if (netdInstance == null) {
+            Log.w(TAG, "WARNING: returning null INetd instance.");
+        }
+        return netdInstance;
+    }
+}
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 07cc9c0..07b26e8 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -57,6 +57,9 @@
  * spooler if needed, to make the timed remote calls, to handle
  * remote exceptions, and to bind/unbind to the remote instance as
  * needed.
+ *
+ * The calls might be blocking and need the main thread of to be unblocked to finish. Hence do not
+ * call this while holding any monitors that might need to be acquired the main thread.
  */
 final class RemotePrintSpooler {
 
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 71f8899..65c740f 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -441,12 +441,12 @@
     }
 
     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
+        mSpooler.clearCustomPrinterIconCache();
+
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
             if (mPrinterDiscoverySession == null) {
-                mSpooler.clearCustomPrinterIconCache();
-
                 // If we do not have a session, tell all service to create one.
                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
                     @Override
@@ -738,6 +738,8 @@
 
     @Override
     public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+        mSpooler.onCustomPrinterIconLoaded(printerId, icon);
+
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
@@ -745,7 +747,6 @@
             if (mPrinterDiscoverySession == null) {
                 return;
             }
-            mSpooler.onCustomPrinterIconLoaded(printerId, icon);
             mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
         }
     }
@@ -994,18 +995,21 @@
      * Prune persistent state if a print service was uninstalled
      */
     public void prunePrintServices() {
+        ArrayList<ComponentName> installedComponents;
+
         synchronized (mLock) {
-            ArrayList<ComponentName> installedComponents = getInstalledComponents();
+            installedComponents = getInstalledComponents();
 
             // Remove unnecessary entries from persistent state "disabled services"
             boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
             if (disabledServicesUninstalled) {
                 writeDisabledPrintServicesLocked(mDisabledServices);
             }
-
-            // Remove unnecessary entries from persistent state "approved services"
-            mSpooler.pruneApprovedPrintServices(installedComponents);
         }
+
+        // Remove unnecessary entries from persistent state "approved services"
+        mSpooler.pruneApprovedPrintServices(installedComponents);
+
     }
 
     private void onConfigurationChangedLocked() {
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 6b273210..7c7c299 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;
@@ -44,6 +43,7 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.net.Uri;
+import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -63,6 +63,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 +82,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 +95,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 +109,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();
@@ -130,7 +124,12 @@
     @GuardedBy("mActivityLock")
     long mLastUserActivityTime;
 
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+    private boolean mSafeBootRestrictionInitialState;
+    private int mPackageVerifierEnableInitialState;
+
+    private IntentReceiver mBroadcastReceiver = null;
+
+    private final class IntentReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (!mDeviceInDemoMode) {
@@ -156,12 +155,15 @@
 
         @Override
         public void handleMessage(Message msg) {
+            if (!mDeviceInDemoMode) {
+                return;
+            }
             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 +180,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 +211,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,
@@ -224,11 +227,11 @@
             if (mDeviceDemoModeUri.equals(uri)) {
                 mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
                 if (mDeviceInDemoMode) {
-                    putDeviceInDemoMode();
+                    startDemoMode();
                 } 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();
                     }
                 }
             }
@@ -243,13 +246,14 @@
                         }
                     }
                 });
+                stopDemoMode();
             }
         }
 
         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 +286,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 +315,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 +326,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 +354,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,91 +370,89 @@
         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);
     }
 
     private void registerBroadcastReceiver() {
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(ACTION_RESET_DEMO);
-        getContext().registerReceiver(mBroadcastReceiver, filter);
+        if (mBroadcastReceiver == null) {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            filter.addAction(ACTION_RESET_DEMO);
+            mBroadcastReceiver = new IntentReceiver();
+            getContext().registerReceiver(mBroadcastReceiver, filter);
+        }
+    }
+
+    private void unregisterBroadcastReceiver() {
+        if (mBroadcastReceiver != null) {
+            getContext().unregisterReceiver(mBroadcastReceiver);
+            mBroadcastReceiver = null;
+        }
     }
 
     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());
+    private void startDemoMode() {
+        mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
+        mInjector.initializeWakeLock();
+        if (mCameraIdsWithFlash == null) {
+            mCameraIdsWithFlash = getCameraIdsWithFlash();
         }
-        return mSystemUserConfiguration;
-    }
+        registerBroadcastReceiver();
 
-    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);
+
+        mSafeBootRestrictionInitialState = mInjector.getUserManager().hasUserRestriction(
+                UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM);
+        mPackageVerifierEnableInitialState = Settings.Global.getInt(mInjector.getContentResolver(),
+                Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+    }
+
+    private void stopDemoMode() {
+        mPreloadAppsInstaller = null;
+        mCameraIdsWithFlash = null;
+        mInjector.destroyWakeLock();
+        unregisterBroadcastReceiver();
+
+        mInjector.getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT,
+                mSafeBootRestrictionInitialState, UserHandle.SYSTEM);
+        Settings.Global.putInt(mInjector.getContentResolver(),
+                Settings.Global.PACKAGE_VERIFIER_ENABLE, mPackageVerifierEnableInitialState);
     }
 
     @Override
@@ -476,33 +464,21 @@
                 false);
         mHandlerThread.start();
         mHandler = new MainHandler(mHandlerThread.getLooper());
-        publishLocalService(RetailDemoModeServiceInternal.class, mLocalService);
+        mInjector.publishLocalService(this, mLocalService);
     }
 
     @Override
     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);
-                mCameraIdsWithFlash = getCameraIdsWithFlash();
                 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
                 settingsObserver.register();
                 settingsObserver.refreshTimeoutConstants();
-                registerBroadcastReceiver();
                 break;
             case PHASE_BOOT_COMPLETED:
                 if (UserManager.isDeviceInDemoMode(getContext())) {
                     mDeviceInDemoMode = true;
-                    putDeviceInDemoMode();
+                    startDemoMode();
                 }
                 break;
         }
@@ -516,27 +492,31 @@
         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();
+        if (!mInjector.getWifiManager().isWifiEnabled()) {
+            mInjector.getWifiManager().setWifiEnabled(true);
+        }
         // 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 +550,197 @@
             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 WifiManager mWifiManager;
+        private Configuration mSystemUserConfiguration;
+        private PendingIntent mResetDemoPendingIntent;
+        private PreloadAppsInstaller mPreloadAppsInstaller;
+
+        Injector(Context context) {
+            mContext = context;
+        }
+
+        Context getContext() {
+            return mContext;
+        }
+
+        WifiManager getWifiManager() {
+            if (mWifiManager == null) {
+                mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+            }
+            return mWifiManager;
+        }
+
+        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() {
+            if (mPreloadAppsInstaller == null) {
+                mPreloadAppsInstaller = new PreloadAppsInstaller(getContext());
+            }
+            return mPreloadAppsInstaller;
+        }
+
+        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() {
+            if (mWakeLock == null) {
+                mWakeLock = getPowerManager().newWakeLock(
+                        PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+            }
+        }
+
+        void destroyWakeLock() {
+            mWakeLock = null;
+        }
+
+        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();
+        }
+
+        void publishLocalService(RetailDemoModeService service,
+                RetailDemoModeServiceInternal localService) {
+            service.publishLocalService(RetailDemoModeServiceInternal.class, localService);
+        }
+    }
 }
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index fb8d814..3f5b96e 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -17,11 +17,12 @@
     services.core \
     services.devicepolicy \
     services.net \
+    services.retaildemo \
     services.usage \
-    easymocklib \
     guava \
     android-support-test \
-    mockito-target \
+    mockito-target-minus-junit4 \
+    platform-test-annotations \
     ShortcutManagerTestUtils
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
@@ -47,6 +48,13 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
+# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
+ifeq (true,$(EMMA_INSTRUMENT))
+LOCAL_JACK_FLAGS := --multi-dex native
+endif # EMMA_INSTRUMENT_STATIC
+
+LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
+
 include $(BUILD_PACKAGE)
 
 #########################################################################
@@ -69,6 +77,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
   libbinder \
+  liblog \
   libcutils \
   libnativehelper \
   libnetdaidl
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index b8ace28..514f095 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -43,6 +43,7 @@
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -155,6 +156,9 @@
             </intent-filter>
         </activity-alias>
 
+        <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityA" />
+        <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityB" />
+
     </application>
 
     <instrumentation
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/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml
new file mode 100644
index 0000000..034411e
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-on.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true" >
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml
new file mode 100644
index 0000000..5b1c03c
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="false">
+  <uid-policy uid="10004" policy="1" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml
new file mode 100644
index 0000000..bec2371
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true">
+  <uid-policy uid="10004" policy="1" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml
new file mode 100644
index 0000000..196ca28
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="false">
+  <uid-policy uid="10004" policy="4" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml
new file mode 100644
index 0000000..4b7724c
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10" restrictBackground="true">
+  <uid-policy uid="10004" policy="4" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uids-with-mixed-policies.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uids-with-mixed-policies.xml
new file mode 100644
index 0000000..c4e13e5
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uids-with-mixed-policies.xml
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<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="3" />
+  <uid-policy uid="10023" policy="4" />
+  <uid-policy uid="10042" policy="6" />
+</policy-list>
diff --git a/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java b/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
new file mode 100644
index 0000000..6d42cce
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/ConnectivityMetricsLoggerTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.net;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import java.util.List;
+import junit.framework.TestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ConnectivityMetricsLoggerTest extends TestCase {
+
+    // use same Parcel object everywhere for pointer equality
+    static final Bundle FAKE_EV = new Bundle();
+    static final int FAKE_COMPONENT = 1;
+    static final int FAKE_EVENT = 2;
+
+    @Mock IConnectivityMetricsLogger mService;
+    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
+    ArgumentCaptor<ConnectivityMetricsEvent[]> evArrayCaptor;
+
+    ConnectivityMetricsLogger mLog;
+
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
+        evArrayCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent[].class);
+        mLog = new ConnectivityMetricsLogger(mService);
+    }
+
+    public void testLogEvents() throws Exception {
+        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+
+        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
+        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
+        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
+    }
+
+    public void testLogEventTriggerThrottling() throws Exception {
+        when(mService.logEvent(any())).thenReturn(1234L);
+
+        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+
+        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
+        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+    }
+
+    public void testLogEventFails() throws Exception {
+        when(mService.logEvent(any())).thenReturn(-1L); // Error.
+
+        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+
+        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
+        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+    }
+
+    public void testLogEventWhenThrottling() throws Exception {
+        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
+
+        // No events are logged. The service is only called once
+        // After that, throttling state is maintained locally.
+        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+
+        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
+        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+    }
+
+    public void testLogEventRecoverFromThrottling() throws Exception {
+        final long throttleTimeout = System.currentTimeMillis() + 10;
+        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
+
+        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+        Thread.sleep(100);
+        mLog.logEvent(53, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+
+        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
+        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
+
+        verify(mService, times(1)).logEvents(evArrayCaptor.capture());
+        ConnectivityMetricsEvent[] gotOtherEvents = evArrayCaptor.getAllValues().get(0);
+        assertEquals(ConnectivityMetricsLogger.TAG_SKIPPED_EVENTS, gotOtherEvents[0].eventTag);
+        assertEventsEqual(expectedEvent(53), gotOtherEvents[1]);
+    }
+
+    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
+        verify(mService, times(n)).logEvent(evCaptor.capture());
+        return evCaptor.getAllValues();
+    }
+
+    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
+        return new ConnectivityMetricsEvent((long)timestamp, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
+    }
+
+    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
+    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
+        assertEquals(expected.timestamp, got.timestamp);
+        assertEquals(expected.componentTag, got.componentTag);
+        assertEquals(expected.eventTag, got.eventTag);
+        assertEquals(expected.data, got.data);
+    }
+}
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index bd76118..f7c61d1 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -20,6 +20,9 @@
 
 import com.android.frameworks.servicestests.R;
 
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
 import android.net.apf.ApfCapabilities;
 import android.net.apf.ApfFilter;
 import android.net.apf.ApfGenerator;
@@ -28,8 +31,6 @@
 import android.net.ip.IpManager;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.RaEvent;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.os.ConditionVariable;
 import android.os.Parcelable;
 import android.system.ErrnoException;
@@ -61,7 +62,7 @@
  * Tests for APF program generator and interpreter.
  *
  * Build, install and run with:
- *  runtest frameworks-services -c com.android.server.ApfTest
+ *  runtest frameworks-services -c android.net.apf.ApfTest
  */
 public class ApfTest extends AndroidTestCase {
     private static final int TIMEOUT_MS = 500;
@@ -86,21 +87,45 @@
     private final static boolean DROP_MULTICAST = true;
     private final static boolean ALLOW_MULTICAST = false;
 
+    private static String label(int code) {
+        switch (code) {
+            case PASS: return "PASS";
+            case DROP: return "DROP";
+            default:   return "UNKNOWN";
+        }
+    }
+
+    private static void assertReturnCodesEqual(int expected, int got) {
+        assertEquals(label(expected), label(got));
+    }
+
     private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
-        assertEquals(expected, apfSimulate(program, packet, filterAge));
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge));
+    }
+
+    private void assertVerdict(int expected, byte[] program, byte[] packet) {
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, 0));
     }
 
     private void assertPass(byte[] program, byte[] packet, int filterAge) {
         assertVerdict(PASS, program, packet, filterAge);
     }
 
+    private void assertPass(byte[] program, byte[] packet) {
+        assertVerdict(PASS, program, packet);
+    }
+
     private void assertDrop(byte[] program, byte[] packet, int filterAge) {
         assertVerdict(DROP, program, packet, filterAge);
     }
 
+    private void assertDrop(byte[] program, byte[] packet) {
+        assertVerdict(DROP, program, packet);
+    }
+
     private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
             throws IllegalInstructionException {
-        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
+        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
     }
 
     private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
@@ -516,7 +541,7 @@
         gen = new ApfGenerator();
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
+        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
         assertPass(gen, packet123, 0);
         gen = new ApfGenerator();
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
@@ -524,7 +549,7 @@
         gen = new ApfGenerator();
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
-        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
+        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
         assertDrop(gen, packet12345, 0);
         gen = new ApfGenerator();
         gen.addLoadImmediate(Register.R0, 1);
@@ -575,12 +600,12 @@
     }
 
     private static class TestApfFilter extends ApfFilter {
-        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
+        public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
         private FileDescriptor mWriteSocket;
 
         public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
                 IpConnectivityLog log) throws Exception {
-            super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
+            super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
                     ipManagerCallback, multicastFilter, log);
         }
 
@@ -620,19 +645,21 @@
     private static final int ETH_HEADER_LEN = 14;
     private static final int ETH_DEST_ADDR_OFFSET = 0;
     private static final int ETH_ETHERTYPE_OFFSET = 12;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
-        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
+            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
 
     private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+    private static final byte[] IPV4_BROADCAST_ADDRESS =
+            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
 
     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
     private static final int IPV6_HEADER_LEN = 40;
     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
     // The IPv6 all nodes address ff02::1
     private static final byte[] IPV6_ALL_NODES_ADDRESS =
-            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 
     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
     private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
@@ -670,14 +697,14 @@
     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
 
     private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
-    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
+    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
             0, 1, // Hardware type: Ethernet (1)
             8, 0, // Protocol type: IP (0x0800)
             6,    // Hardware size: 6
             4,    // Protocol size: 4
             0, 1  // Opcode: request (1)
     };
-    private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
+    private static final byte[] ARP_IPV4_REPLY_HEADER = {
             0, 1, // Hardware type: Ethernet (1)
             8, 0, // Protocol type: IP (0x0800)
             6,    // Hardware size: 6
@@ -686,38 +713,63 @@
     };
     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
 
-    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
-    private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
-    private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
+    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
+    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
+    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
+    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
+    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
 
     @LargeTest
     public void testApfFilterIPv4() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+
         ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
+        apfFilter.setLinkProperties(lp);
+
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify empty packet of 100 zero bytes is passed
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array(), 0);
+        assertPass(program, packet.array());
 
         // Verify unicast IPv4 packet is passed
+        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array(), 0);
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
+        assertPass(program, packet.array());
 
-        // Verify broadcast IPv4, not DHCP to us, is dropped
-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
-        assertDrop(program, packet.array(), 0);
+        // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
+        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+
+        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        assertDrop(program, packet.array());
         packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
         packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
         packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+        assertDrop(program, packet.array());
 
         // Verify broadcast IPv4 DHCP to us is passed
-        packet.position(DHCP_CLIENT_MAC_OFFSET);
-        packet.put(TestApfFilter.MOCK_MAC_ADDR);
-        assertPass(program, packet.array(), 0);
+        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
+        assertPass(program, packet.array());
+
+        // Verify unicast IPv4 DHCP to us is passed
+        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
+        assertPass(program, packet.array());
 
         apfFilter.shutdown();
     }
@@ -731,82 +783,108 @@
         // Verify empty IPv6 packet is passed
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array(), 0);
+        assertPass(program, packet.array());
 
         // Verify empty ICMPv6 packet is passed
         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, packet.array(), 0);
+        assertPass(program, packet.array());
 
         // Verify empty ICMPv6 NA packet is passed
         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
-        assertPass(program, packet.array(), 0);
+        assertPass(program, packet.array());
 
         // Verify ICMPv6 NA to ff02::1 is dropped
-        packet.position(IPV6_DEST_ADDR_OFFSET);
-        packet.put(IPV6_ALL_NODES_ADDRESS);
-        assertDrop(program, packet.array(), 0);
+        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
+        assertDrop(program, packet.array());
 
         apfFilter.shutdown();
     }
 
     @LargeTest
     public void testApfFilterMulticast() throws Exception {
+        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
+        final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
+        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
+        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+
         ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
+        apfFilter.setLinkProperties(lp);
+
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Construct IPv4 and IPv6 multicast packets.
         ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
         mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
-        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
+        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
 
         ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
         mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
         mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
-        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
-        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
+        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
 
         // Construct IPv4 broadcast packet.
-        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
-        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
-        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
-        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
+        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
+        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
+        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
+
+        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
+        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
+        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+
+        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
+        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
+        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
+        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
 
         // Verify initially disabled multicast filter is off
-        assertPass(program, bcastv4packet.array(), 0);
-        assertPass(program, mcastv4packet.array(), 0);
-        assertPass(program, mcastv6packet.array(), 0);
+        assertPass(program, mcastv4packet.array());
+        assertPass(program, mcastv6packet.array());
+        assertPass(program, bcastv4packet1.array());
+        assertPass(program, bcastv4packet2.array());
+        assertPass(program, bcastv4unicastl2packet.array());
 
         // Turn on multicast filter and verify it works
         ipManagerCallback.resetApfProgramWait();
         apfFilter.setMulticastFilter(true);
         program = ipManagerCallback.getApfProgram();
-        assertDrop(program, bcastv4packet.array(), 0);
-        assertDrop(program, mcastv4packet.array(), 0);
-        assertDrop(program, mcastv6packet.array(), 0);
+        assertDrop(program, mcastv4packet.array());
+        assertDrop(program, mcastv6packet.array());
+        assertDrop(program, bcastv4packet1.array());
+        assertDrop(program, bcastv4packet2.array());
+        assertDrop(program, bcastv4unicastl2packet.array());
 
         // Turn off multicast filter and verify it's off
         ipManagerCallback.resetApfProgramWait();
         apfFilter.setMulticastFilter(false);
         program = ipManagerCallback.getApfProgram();
-        assertPass(program, bcastv4packet.array(), 0);
-        assertPass(program, mcastv4packet.array(), 0);
-        assertPass(program, mcastv6packet.array(), 0);
+        assertPass(program, mcastv4packet.array());
+        assertPass(program, mcastv6packet.array());
+        assertPass(program, bcastv4packet1.array());
+        assertPass(program, bcastv4packet2.array());
+        assertPass(program, bcastv4unicastl2packet.array());
 
         // Verify it can be initialized to on
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
         apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
+        apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
-        assertDrop(program, bcastv4packet.array(), 0);
-        assertDrop(program, mcastv4packet.array(), 0);
-        assertDrop(program, mcastv6packet.array(), 0);
+        assertDrop(program, mcastv4packet.array());
+        assertDrop(program, mcastv6packet.array());
+        assertDrop(program, bcastv4packet1.array());
+        assertDrop(program, bcastv4unicastl2packet.array());
 
         // Verify that ICMPv6 multicast is not dropped.
         mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, mcastv6packet.array(), 0);
+        assertPass(program, mcastv6packet.array());
 
         apfFilter.shutdown();
     }
@@ -819,17 +897,17 @@
 
     private void verifyArpFilter(byte[] program, int filterResult) {
         // Verify ARP request packet
-        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
-        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
-        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
+        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
+        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
+        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
 
         // Verify unicast ARP reply packet is always accepted.
-        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
-        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
-        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
+        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
+        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
+        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));
 
         // Verify GARP reply packets are always filtered
-        assertDrop(program, garpReply(), 0);
+        assertDrop(program, garpReply());
     }
 
     @LargeTest
@@ -855,34 +933,26 @@
     private static byte[] arpRequestBroadcast(byte[] tip) {
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        packet.position(ETH_DEST_ADDR_OFFSET);
-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
-        packet.position(ARP_HEADER_OFFSET);
-        packet.put(ARP_IPV4_REQUEST_HEADER);
-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
-        packet.put(tip);
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
         return packet.array();
     }
 
     private static byte[] arpReplyUnicast(byte[] tip) {
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        packet.position(ARP_HEADER_OFFSET);
-        packet.put(ARP_IPV4_REPLY_HEADER);
-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
-        packet.put(tip);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
         return packet.array();
     }
 
     private static byte[] garpReply() {
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        packet.position(ETH_DEST_ADDR_OFFSET);
-        packet.put(ETH_BROADCAST_MAC_ADDRESS);
-        packet.position(ARP_HEADER_OFFSET);
-        packet.put(ARP_IPV4_REPLY_HEADER);
-        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
-        packet.put(IPV4_ANY_HOST_ADDR);
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
         return packet.array();
     }
 
@@ -893,22 +963,22 @@
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify new program should drop RA for 1/6th its lifetime
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
         assertDrop(program, packet.array(), lifetime/6);
         assertPass(program, packet.array(), lifetime/6 + 1);
         assertPass(program, packet.array(), lifetime);
 
         // Verify RA checksum is ignored
         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
 
         // Verify other changes to RA make it not match filter
         packet.put(0, (byte)-1);
-        assertPass(program, packet.array(), 0);
+        assertPass(program, packet.array());
         packet.put(0, (byte)0);
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, packet.array());
     }
 
     // Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -973,7 +1043,7 @@
         basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
         basePacket.position(IPV6_DEST_ADDR_OFFSET);
         basePacket.put(IPV6_ALL_NODES_ADDRESS);
-        assertPass(program, basePacket.array(), 0);
+        assertPass(program, basePacket.array());
 
         testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
         verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
@@ -1069,6 +1139,13 @@
         return file.getAbsolutePath();
     }
 
+    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
+        final int original = buffer.position();
+        buffer.position(position);
+        buffer.put(bytes);
+        buffer.position(original);
+    }
+
     /**
      * Call the APF interpreter the run {@code program} on {@code packet} pretending the
      * filter was installed {@code filter_age} seconds ago.
@@ -1089,4 +1166,30 @@
      */
     private native static boolean compareBpfApf(String filter, String pcap_filename,
             byte[] apf_program);
+
+    public void testBytesToInt() {
+        assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
+        assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
+        assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR));
+        assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR));
+        assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR));
+        assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR));
+    }
+
+    public void testBroadcastAddress() throws Exception {
+        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
+        assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
+        assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
+        assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
+
+        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
+        assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
+        assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
+        assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
+    }
+
+    public void assertEqualsIp(String expected, int got) throws Exception {
+        int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress());
+        assertEquals(want, got);
+    }
 }
diff --git a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java b/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
deleted file mode 100644
index 1433f95..0000000
--- a/services/tests/servicestests/src/android/net/metrics/IpConnectivityLogTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.net.ConnectivityMetricsEvent;
-import android.net.IConnectivityMetricsLogger;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.List;
-
-public class IpConnectivityLogTest extends TestCase {
-
-    // use same Parcel object everywhere for pointer equality
-    static final Bundle FAKE_EV = new Bundle();
-
-    @Mock IConnectivityMetricsLogger mService;
-    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
-
-    IpConnectivityLog mLog;
-
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
-        mLog = new IpConnectivityLog(mService);
-    }
-
-    public void testLogEvents() throws Exception {
-        assertTrue(mLog.log(1, FAKE_EV));
-        assertTrue(mLog.log(2, FAKE_EV));
-        assertTrue(mLog.log(3, FAKE_EV));
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
-        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
-    }
-
-    public void testLogEventTriggerThrottling() throws Exception {
-        when(mService.logEvent(any())).thenReturn(1234L);
-
-        assertFalse(mLog.log(1, FAKE_EV));
-    }
-
-    public void testLogEventFails() throws Exception {
-        when(mService.logEvent(any())).thenReturn(-1L); // Error.
-
-        assertFalse(mLog.log(1, FAKE_EV));
-    }
-
-    public void testLogEventWhenThrottling() throws Exception {
-        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
-
-        // No events are logged. The service is only called once
-        // After that, throttling state is maintained locally.
-        assertFalse(mLog.log(1, FAKE_EV));
-        assertFalse(mLog.log(2, FAKE_EV));
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-    }
-
-    public void testLogEventRecoverFromThrottling() throws Exception {
-        final long throttleTimeout = System.currentTimeMillis() + 50;
-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
-
-        assertFalse(mLog.log(1, FAKE_EV));
-        new Thread() {
-            public void run() {
-                busySpinLog();
-            }
-        }.start();
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(2, 200);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
-    }
-
-    public void testLogEventRecoverFromThrottlingWithMultipleCallers() throws Exception {
-        final long throttleTimeout = System.currentTimeMillis() + 50;
-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
-
-        assertFalse(mLog.log(1, FAKE_EV));
-        final int nCallers = 10;
-        for (int i = 0; i < nCallers; i++) {
-            new Thread() {
-                public void run() {
-                    busySpinLog();
-                }
-            }.start();
-        }
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1 + nCallers, 200);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-        for (int i = 0; i < nCallers; i++) {
-            assertEventsEqual(expectedEvent(2), gotEvents.get(1 + i));
-        }
-    }
-
-    void busySpinLog() {
-        final long timeout = 200;
-        final long stop = System.currentTimeMillis() + timeout;
-        try {
-            while (System.currentTimeMillis() < stop) {
-                if (mLog.log(2, FAKE_EV)) {
-                    return;
-                }
-                Thread.sleep(10);
-            }
-        } catch (InterruptedException e) { }
-    }
-
-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
-        verify(mService, times(n)).logEvent(evCaptor.capture());
-        return evCaptor.getAllValues();
-    }
-
-    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
-        verify(mService, timeout(timeoutMs).times(n)).logEvent(evCaptor.capture());
-        return evCaptor.getAllValues();
-    }
-
-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
-        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
-    }
-
-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
-        assertEquals(expected.timestamp, got.timestamp);
-        assertEquals(expected.componentTag, got.componentTag);
-        assertEquals(expected.eventTag, got.eventTag);
-        assertEquals(expected.data, got.data);
-    }
-}
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/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index 13657ab..6b5be58 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -44,7 +44,17 @@
 
     private final List<BroadcastInterceptor> mInterceptors = Lists.newArrayList();
 
-    public class BroadcastInterceptor extends AbstractFuture<Intent> {
+    abstract class FutureIntent extends AbstractFuture<Intent> {
+        public void assertNotReceived()
+                throws InterruptedException, ExecutionException {
+            assertNotReceived(5, TimeUnit.SECONDS);
+        }
+
+        public abstract void assertNotReceived(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException;
+    }
+
+    public class BroadcastInterceptor extends FutureIntent {
         private final BroadcastReceiver mReceiver;
         private final IntentFilter mFilter;
 
@@ -76,17 +86,32 @@
                 throw new RuntimeException(e);
             }
         }
+
+        @Override
+        public void assertNotReceived()
+            throws InterruptedException, ExecutionException {
+            assertNotReceived(5, TimeUnit.SECONDS);
+        }
+
+        public void assertNotReceived(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException {
+            try {
+                final Intent intent = get(timeout, unit);
+                throw new AssertionError("Received intent: " + intent);
+            } catch (TimeoutException e) {
+            }
+        }
     }
 
     public BroadcastInterceptingContext(Context base) {
         super(base);
     }
 
-    public Future<Intent> nextBroadcastIntent(String action) {
+    public FutureIntent nextBroadcastIntent(String action) {
         return nextBroadcastIntent(new IntentFilter(action));
     }
 
-    public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
+    public FutureIntent nextBroadcastIntent(IntentFilter filter) {
         final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
         synchronized (mInterceptors) {
             mInterceptors.add(interceptor);
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 59ccbd9..257341b 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -25,6 +25,7 @@
 
 import static org.mockito.Mockito.mock;
 
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -81,6 +82,7 @@
 
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -137,7 +139,8 @@
 
         @Override
         public Object getSystemService(String name) {
-            if (name == Context.CONNECTIVITY_SERVICE) return mCm;
+            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
+            if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
             return super.getSystemService(name);
         }
 
@@ -593,12 +596,13 @@
 
         @Override
         protected CaptivePortalProbeResult isCaptivePortal() {
-            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl);
+            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
         }
     }
 
     private class WrappedConnectivityService extends ConnectivityService {
         private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+        public boolean configRestrictsAvoidBadWifi;
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
                 INetworkStatsService statsService, INetworkPolicyManager policyManager,
@@ -654,6 +658,11 @@
             return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
         }
 
+        @Override
+        public boolean configRestrictsAvoidBadWifi() {
+            return configRestrictsAvoidBadWifi;
+        }
+
         public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
             return mLastCreatedNetworkMonitor;
         }
@@ -717,6 +726,7 @@
     }
 
     public void tearDown() throws Exception {
+        setMobileDataAlwaysOn(false);
         if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); }
         if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); }
         mCellNetworkAgent = mWiFiNetworkAgent = null;
@@ -1047,7 +1057,8 @@
         NETWORK_CAPABILITIES,
         LINK_PROPERTIES,
         LOSING,
-        LOST
+        LOST,
+        UNAVAILABLE
     }
 
     /**
@@ -1088,6 +1099,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 */);
         }
@@ -1814,6 +1830,85 @@
         mCm.unregisterNetworkCallback(cellNetworkCallback);
     }
 
+    private void setMobileDataAlwaysOn(boolean enable) {
+        ContentResolver cr = mServiceContext.getContentResolver();
+        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
+        mService.updateMobileDataAlwaysOn();
+        mService.waitForIdle();
+    }
+
+    private boolean isForegroundNetwork(MockNetworkAgent network) {
+        NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
+        assertNotNull(nc);
+        return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
+    }
+
+    @SmallTest
+    public void testBackgroundNetworks() throws Exception {
+        // Create a background request. We can't do this ourselves because ConnectivityService
+        // doesn't have an API for it. So just turn on mobile data always on.
+        setMobileDataAlwaysOn(true);
+        final NetworkRequest request = new NetworkRequest.Builder().build();
+        final NetworkRequest fgRequest = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_FOREGROUND).build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        final TestNetworkCallback fgCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+        mCm.registerNetworkCallback(fgRequest, fgCallback);
+
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+
+        // When wifi connects, cell lingers.
+        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
+
+        // When lingering is complete, cell is still there but is now in the background.
+        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS);
+        callback.assertNoCallback();
+        assertFalse(isForegroundNetwork(mCellNetworkAgent));
+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
+
+        // File a cell request and check that cell comes into the foreground.
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        final TestNetworkCallback cellCallback = new TestNetworkCallback();
+        mCm.requestNetwork(cellRequest, cellCallback);
+        cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        callback.assertNoCallback();  // Because the network is already up.
+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
+
+        // Release the request. The network immediately goes into the background, since it was not
+        // lingering.
+        mCm.unregisterNetworkCallback(cellCallback);
+        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        callback.assertNoCallback();
+        assertFalse(isForegroundNetwork(mCellNetworkAgent));
+        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
+
+        // Disconnect wifi and check that cell is foreground again.
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertTrue(isForegroundNetwork(mCellNetworkAgent));
+
+        mCm.unregisterNetworkCallback(callback);
+        mCm.unregisterNetworkCallback(fgCallback);
+    }
+
     @SmallTest
     public void testRequestBenchmark() throws Exception {
         // Benchmarks connecting and switching performance in the presence of a large number of
@@ -1919,8 +2014,7 @@
 
         // Turn on mobile data always on. The factory starts looking again.
         testFactory.expectAddRequests(1);
-        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1);
-        mService.updateMobileDataAlwaysOn();
+        setMobileDataAlwaysOn(true);
         testFactory.waitForNetworkRequests(2);
         assertTrue(testFactory.getMyStartRequested());
 
@@ -1940,8 +2034,7 @@
 
         // Turn off mobile data always on and expect the request to disappear...
         testFactory.expectRemoveRequests(1);
-        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0);
-        mService.updateMobileDataAlwaysOn();
+        setMobileDataAlwaysOn(false);
         testFactory.waitForNetworkRequests(1);
 
         // ...  and cell data to be torn down.
@@ -1953,6 +2046,238 @@
         handlerThread.quit();
     }
 
+    @SmallTest
+    public void testAvoidBadWifiSetting() throws Exception {
+        final ContentResolver cr = mServiceContext.getContentResolver();
+        final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+
+        mService.configRestrictsAvoidBadWifi = false;
+        String[] values = new String[] {null, "0", "1"};
+        for (int i = 0; i < values.length; i++) {
+            Settings.Global.putInt(cr, settingName, 1);
+            mService.updateNetworkAvoidBadWifi();
+            mService.waitForIdle();
+            String msg = String.format("config=false, setting=%s", values[i]);
+            assertTrue(msg, mService.avoidBadWifi());
+            assertFalse(msg, mService.shouldNotifyWifiUnvalidated());
+        }
+
+        mService.configRestrictsAvoidBadWifi = true;
+
+        Settings.Global.putInt(cr, settingName, 0);
+        mService.updateNetworkAvoidBadWifi();
+        mService.waitForIdle();
+        assertFalse(mService.avoidBadWifi());
+        assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+        Settings.Global.putInt(cr, settingName, 1);
+        mService.updateNetworkAvoidBadWifi();
+        mService.waitForIdle();
+        assertTrue(mService.avoidBadWifi());
+        assertFalse(mService.shouldNotifyWifiUnvalidated());
+
+        Settings.Global.putString(cr, settingName, null);
+        mService.updateNetworkAvoidBadWifi();
+        mService.waitForIdle();
+        assertFalse(mService.avoidBadWifi());
+        assertTrue(mService.shouldNotifyWifiUnvalidated());
+    }
+
+    @SmallTest
+    public void testAvoidBadWifi() throws Exception {
+        ContentResolver cr = mServiceContext.getContentResolver();
+
+        // Pretend we're on a carrier that restricts switching away from bad wifi.
+        mService.configRestrictsAvoidBadWifi = true;
+
+        // File a request for cell to ensure it doesn't go down.
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        mCm.requestNetwork(cellRequest, cellNetworkCallback);
+
+        TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+
+        NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI)
+                .addCapability(NET_CAPABILITY_VALIDATED)
+                .build();
+        TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
+
+        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+        mService.updateNetworkAvoidBadWifi();
+
+        // Bring up validated cell.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        Network cellNetwork = mCellNetworkAgent.getNetwork();
+
+        // Bring up validated wifi.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
+
+        // Fail validation on wifi.
+        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mCm.reportNetworkConnectivity(wifiNetwork, false);
+        validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+        // Because avoid bad wifi is off, we don't switch to cellular.
+        defaultCallback.assertNoCallback();
+        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+
+        // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
+        // that we switch back to cell.
+        mService.configRestrictsAvoidBadWifi = false;
+        mService.updateNetworkAvoidBadWifi();
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+        // Switch back to a restrictive carrier.
+        mService.configRestrictsAvoidBadWifi = true;
+        mService.updateNetworkAvoidBadWifi();
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+
+        // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
+        mCm.setAvoidUnvalidated(wifiNetwork);
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+        // Disconnect and reconnect wifi to clear the one-time switch above.
+        mWiFiNetworkAgent.disconnect();
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        wifiNetwork = mWiFiNetworkAgent.getNetwork();
+
+        // Fail validation on wifi and expect the dialog to appear.
+        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mCm.reportNetworkConnectivity(wifiNetwork, false);
+        validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+        // Simulate the user selecting "switch" and checking the don't ask again checkbox.
+        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+        mService.updateNetworkAvoidBadWifi();
+
+        // We now switch to cell.
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+        // Simulate the user turning the cellular fallback setting off and then on.
+        // We switch to wifi and then to cell.
+        Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+        mService.updateNetworkAvoidBadWifi();
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
+        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+        mService.updateNetworkAvoidBadWifi();
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        assertEquals(mCm.getActiveNetwork(), cellNetwork);
+
+        // If cell goes down, we switch to wifi.
+        mCellNetworkAgent.disconnect();
+        defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        validatedWifiCallback.assertNoCallback();
+
+        mCm.unregisterNetworkCallback(cellNetworkCallback);
+        mCm.unregisterNetworkCallback(validatedWifiCallback);
+        mCm.unregisterNetworkCallback(defaultCallback);
+    }
+
+    /**
+     * 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..bd07d8b 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;
@@ -50,9 +52,11 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
@@ -62,15 +66,18 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
+import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkPolicyListener;
 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;
@@ -81,23 +88,31 @@
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 import android.text.format.Time;
 import android.util.Log;
 import android.util.TrustedTime;
 
+import com.android.server.BroadcastInterceptingContext.FutureIntent;
 import com.android.server.net.NetworkPolicyManagerInternal;
 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 +120,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,11 +136,13 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
 /**
  * Tests for {@link NetworkPolicyManagerService}.
  */
 @RunWith(AndroidJUnit4.class)
+@MediumTest
 public class NetworkPolicyManagerServiceTest {
     private static final String TAG = "NetworkPolicyManagerServiceTest";
 
@@ -127,9 +152,21 @@
 
     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;
@@ -137,6 +174,7 @@
     private @Mock IConnectivityManager mConnManager;
     private @Mock INotificationManager mNotifManager;
     private @Mock PackageManager mPackageManager;
+    private @Mock IPackageManager mIpm;
 
     private IUidObserver mUidObserver;
     private INetworkManagementEventObserver mNetworkObserver;
@@ -149,14 +187,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 +235,7 @@
             }
         };
 
-        mPolicyDir = context.getFilesDir();
-        if (mPolicyDir.exists()) {
-            IoUtils.deleteContents(mPolicyDir);
-        }
+        setNetpolicyXml(context);
 
         doAnswer(new Answer<Void>() {
 
@@ -203,7 +248,7 @@
         }).when(mActivityManager).registerUidObserver(any(), anyInt());
 
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
-                mNetworkManager, mTime, mPolicyDir, true);
+                mNetworkManager, mIpm, mTime, mPolicyDir, true);
         mService.bindConnectivityManager(mConnManager);
         mService.bindNotificationManager(mNotifManager);
         mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -238,7 +283,7 @@
         mService.systemReady();
 
         // catch INetworkManagementEventObserver during systemReady()
-        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
+        final ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
               ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetworkManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
@@ -257,21 +302,284 @@
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
     }
 
-    // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they
+    @Test
+    public void testTurnRestrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        assertRestrictBackgroundChangedReceived(futureIntent, null);
+    }
+
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testTurnRestrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(false);
+        assertRestrictBackgroundChangedReceived(futureIntent, null);
+    }
+
+    /**
+     * Adds whitelist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testAddRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        addRestrictBackgroundWhitelist(true);
+    }
+
+    /**
+     * Adds whitelist when restrict background is off - app should not receive an intent.
+     */
+    @Test
+    public void testAddRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        addRestrictBackgroundWhitelist(false);
+    }
+
+    private void addRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
+        // Sanity checks.
+        assertWhitelistUids();
+        assertUidPolicy(UID_A, POLICY_NONE);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt());
+
+        mService.setUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+
+        assertWhitelistUids(UID_A);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+        mPolicyListener.waitAndVerify()
+                .onUidPoliciesChanged(APP_ID_A, POLICY_ALLOW_METERED_BACKGROUND);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Removes whitelist when restrict background is on - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml")
+    public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        removeRestrictBackgroundWhitelist(true);
+    }
+
+    /**
+     * Removes whitelist when restrict background is off - app should not receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-off.xml")
+    public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        removeRestrictBackgroundWhitelist(false);
+    }
+
+    private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
+        // Sanity checks.
+        assertWhitelistUids(UID_A);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt());
+
+        mService.setUidPolicy(UID_A, POLICY_NONE);
+
+        assertWhitelistUids();
+        assertUidPolicy(UID_A, POLICY_NONE);
+        mPolicyListener.waitAndVerify().onUidPoliciesChanged(APP_ID_A, POLICY_NONE);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Adds blacklist when restrict background is on - app should not receive an intent.
+     */
+    @Test
+    @NetPolicyXml("restrict-background-on.xml")
+    public void testAddRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        addRestrictBackgroundBlacklist(false);
+    }
+
+    /**
+     * Adds blacklist when restrict background is off - app should receive an intent.
+     */
+    @Test
+    public void testAddRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        addRestrictBackgroundBlacklist(true);
+    }
+
+    private void addRestrictBackgroundBlacklist(boolean expectIntent) throws Exception {
+        assertUidPolicy(UID_A, POLICY_NONE); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt());
+
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mPolicyListener.waitAndVerify()
+                .onUidPoliciesChanged(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    /**
+     * Removes blacklist when restrict background is on - app should not receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml")
+    public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception {
+        assertRestrictBackgroundOn(); // Sanity check.
+        removeRestrictBackgroundBlacklist(false);
+    }
+
+    /**
+     * Removes blacklist when restrict background is off - app should receive an intent.
+     */
+    @Test
+    @NetPolicyXml("uidA-blacklisted-restrict-background-off.xml")
+    public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception {
+        assertRestrictBackgroundOff(); // Sanity check.
+        removeRestrictBackgroundBlacklist(true);
+    }
+
+    private void removeRestrictBackgroundBlacklist(boolean expectIntent) throws Exception {
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); // Sanity check.
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt());
+
+        mService.setUidPolicy(UID_A, POLICY_NONE);
+
+        assertUidPolicy(UID_A, POLICY_NONE);
+        mPolicyListener.waitAndVerify()
+                .onUidPoliciesChanged(APP_ID_A, POLICY_NONE);
+        if (expectIntent) {
+            assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+        } else {
+            futureIntent.assertNotReceived();
+        }
+    }
+
+    @Test
+    @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml")
+    public void testBlacklistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOn();
+        assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        futureIntent.assertNotReceived();
+    }
+
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml")
+    public void testWhitelistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOn();
+        assertWhitelistUids(UID_A);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        setRestrictBackground(true);
+        futureIntent.assertNotReceived();
+    }
+
+    @Test
+    @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml")
+    public void testWhitelistedAppIsNotifiedWhenBlacklisted() throws Exception {
+        // Sanity checks.
+        assertRestrictBackgroundOn();
+        assertWhitelistUids(UID_A);
+
+        final FutureIntent futureIntent = newRestrictBackgroundChangedFuture();
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        assertRestrictBackgroundChangedReceived(futureIntent, PKG_NAME_A);
+    }
+
+    @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.setUidPolicy(UID_A, POLICY_NONE);
+        assertUidPolicy(UID_A, POLICY_NONE);
+        assertWhitelistUids(UID_B, UID_C);
+
+        // Add whitelist when blacklisted.
+        mService.setUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND);
+        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); // Blacklist prevails.
+        assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2));
+        assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
+    @Test
+    @NetPolicyXml("uids-with-mixed-policies.xml")
+    public void testGetUidsWithPolicy() throws Exception {
+        assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_NONE));
+        assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND),
+                UID_B, UID_D);
+        assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND),
+                UID_E, UID_F);
+        // Legacy (POLICY_ALLOW_BACKGROUND_BATTERY_SAVE)
+        assertContainsInAnyOrder(mService.getUidsWithPolicy(2),
+                UID_C, UID_D, UID_F);
+    }
+
+    // NOTE: testPolicyChangeTriggersListener() is 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...).
     // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
-
-    @Test
-    public void testPolicyChangeTriggersListener() throws Exception {
-        mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean());
-
-        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
-        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
-
-        mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
-    }
-
     @Test
     public void testUidForeground() throws Exception {
         // push all uids into background
@@ -665,6 +973,11 @@
         return futureAnswer;
     }
 
+    private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
+        when(mIpm.checkUidPermission(Manifest.permission.INTERNET, uid)).thenReturn(
+                hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+    }
+
     private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception {
         verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes);
     }
@@ -739,6 +1052,61 @@
                 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.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND), uids);
+    }
+
+    private void assertRestrictBackgroundOn() throws Exception {
+        assertTrue("restrictBackground should be set", mService.getRestrictBackground());
+    }
+
+    private void assertRestrictBackgroundOff() throws Exception {
+        assertFalse("restrictBackground should not be set", mService.getRestrictBackground());
+    }
+
+    private FutureIntent newRestrictBackgroundChangedFuture() {
+        return mServiceContext
+                .nextBroadcastIntent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
+    }
+
+    private void assertRestrictBackgroundChangedReceived(Future<Intent> future,
+            String expectedPackage) throws Exception {
+        final String action = ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
+        final Intent intent = future.get(5, TimeUnit.SECONDS);
+        assertNotNull("Didn't get a " + action + "intent in 5 seconds");
+        assertEquals("Wrong package on " + action + " intent", expectedPackage, intent.getPackage());
+    }
+
+    // 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;
     }
@@ -756,6 +1124,16 @@
         mElapsedRealtime += duration;
     }
 
+    private FutureIntent mRestrictBackgroundChanged;
+
+    private void setRestrictBackground(boolean flag) throws Exception {
+        // Must set expectation, otherwise NMPS will reset value to previous one.
+        when(mNetworkManager.setDataSaverModeEnabled(flag)).thenReturn(true);
+        mService.setRestrictBackground(flag);
+        // Sanity check.
+        assertEquals("restrictBackground not set", flag, mService.getRestrictBackground());
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -810,5 +1188,57 @@
             }
             return verify(listener, atLeastOnce());
         }
+
+        INetworkPolicyListener verifyNotCalled() {
+            return verify(listener, never());
+        }
+
+    }
+
+    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/accessibility/AccessibilityCacheTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
new file mode 100644
index 0000000..9ccf290
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
@@ -0,0 +1,573 @@
+/*
+ * 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.accessibility;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.view.accessibility.AccessibilityCache;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.View;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityCacheTest {
+    private static int WINDOW_ID_1 = 0xBEEF;
+    private static int WINDOW_ID_2 = 0xFACE;
+    private static int SINGLE_VIEW_ID = 0xCAFE;
+    private static int OTHER_VIEW_ID = 0xCAB2;
+    private static int PARENT_VIEW_ID = 0xFED4;
+    private static int CHILD_VIEW_ID = 0xFEED;
+    private static int MOCK_CONNECTION_ID = 1;
+
+    AccessibilityCache mAccessibilityCache;
+    AccessibilityCache.AccessibilityNodeRefresher mAccessibilityNodeRefresher;
+    AtomicInteger numA11yNodeInfosInUse = new AtomicInteger(0);
+    AtomicInteger numA11yWinInfosInUse = new AtomicInteger(0);
+
+    @Before
+    public void setUp() {
+        mAccessibilityNodeRefresher = mock(AccessibilityCache.AccessibilityNodeRefresher.class);
+        when(mAccessibilityNodeRefresher.refreshNode(anyObject(), anyBoolean())).thenReturn(true);
+        mAccessibilityCache = new AccessibilityCache(mAccessibilityNodeRefresher);
+        AccessibilityNodeInfo.setNumInstancesInUseCounter(numA11yNodeInfosInUse);
+        AccessibilityWindowInfo.setNumInstancesInUseCounter(numA11yWinInfosInUse);
+    }
+
+    @After
+    public void tearDown() {
+        // Make sure we're recycling all of our window and node infos
+        mAccessibilityCache.clear();
+        AccessibilityInteractionClient.getInstance().clearCache();
+        assertEquals(0, numA11yWinInfosInUse.get());
+        assertEquals(0, numA11yNodeInfosInUse.get());
+    }
+
+    @Test
+    public void testEmptyCache_returnsNull() {
+        assertNull(mAccessibilityCache.getNode(0, 0));
+        assertNull(mAccessibilityCache.getWindows());
+        assertNull(mAccessibilityCache.getWindow(0));
+    }
+
+    @Test
+    public void testEmptyCache_clearDoesntCrash() {
+        mAccessibilityCache.clear();
+    }
+
+    @Test
+    public void testEmptyCache_a11yEventsHaveNoEffect() {
+        AccessibilityEvent event = AccessibilityEvent.obtain();
+        int[] a11yEventTypes = {
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                AccessibilityEvent.TYPE_VIEW_FOCUSED,
+                AccessibilityEvent.TYPE_VIEW_SELECTED,
+                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED,
+                AccessibilityEvent.TYPE_VIEW_CLICKED,
+                AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED,
+                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
+                AccessibilityEvent.TYPE_VIEW_SCROLLED,
+                AccessibilityEvent.TYPE_WINDOWS_CHANGED,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED};
+        for (int i = 0; i < a11yEventTypes.length; i++) {
+            event.setEventType(a11yEventTypes[i]);
+            mAccessibilityCache.onAccessibilityEvent(event);
+        }
+    }
+
+    @Test
+    public void addThenGetWindow_returnsEquivalentButNotSameWindow() {
+        AccessibilityWindowInfo windowInfo = null, copyOfInfo = null, windowFromCache = null;
+        try {
+            windowInfo = AccessibilityWindowInfo.obtain();
+            windowInfo.setId(WINDOW_ID_1);
+            mAccessibilityCache.addWindow(windowInfo);
+            // Make a copy
+            copyOfInfo = AccessibilityWindowInfo.obtain(windowInfo);
+            windowInfo.setId(WINDOW_ID_2); // Simulate recycling and reusing the original info
+            windowFromCache = mAccessibilityCache.getWindow(WINDOW_ID_1);
+            assertEquals(copyOfInfo, windowFromCache);
+        } finally {
+            windowFromCache.recycle();
+            windowInfo.recycle();
+            copyOfInfo.recycle();
+        }
+    }
+
+    @Test
+    public void addWindowThenClear_noLongerInCache() {
+        putWindowWithIdInCache(WINDOW_ID_1);
+        mAccessibilityCache.clear();
+        assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1));
+    }
+
+    @Test
+    public void addWindowGetOtherId_returnsNull() {
+        putWindowWithIdInCache(WINDOW_ID_1);
+        assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1 + 1));
+    }
+
+    @Test
+    public void addWindowThenGetWindows_returnsNull() {
+        putWindowWithIdInCache(WINDOW_ID_1);
+        assertNull(mAccessibilityCache.getWindows());
+    }
+
+    @Test
+    public void setWindowsThenGetWindows_returnsInDecreasingLayerOrder() {
+        AccessibilityWindowInfo windowInfo1 = null, windowInfo2 = null;
+        AccessibilityWindowInfo window1Out = null, window2Out = null;
+        List<AccessibilityWindowInfo> windowsOut = null;
+        try {
+            windowInfo1 = AccessibilityWindowInfo.obtain();
+            windowInfo1.setId(WINDOW_ID_1);
+            windowInfo1.setLayer(5);
+            windowInfo2 = AccessibilityWindowInfo.obtain();
+            windowInfo2.setId(WINDOW_ID_2);
+            windowInfo2.setLayer(windowInfo1.getLayer() + 1);
+            List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1, windowInfo2);
+            mAccessibilityCache.setWindows(windowsIn);
+
+            windowsOut = mAccessibilityCache.getWindows();
+            window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1);
+            window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2);
+
+            assertEquals(2, windowsOut.size());
+            assertEquals(windowInfo2, windowsOut.get(0));
+            assertEquals(windowInfo1, windowsOut.get(1));
+            assertEquals(windowInfo1, window1Out);
+            assertEquals(windowInfo2, window2Out);
+        } finally {
+            window1Out.recycle();
+            window2Out.recycle();
+            windowInfo1.recycle();
+            windowInfo2.recycle();
+            for (AccessibilityWindowInfo windowInfo : windowsOut) {
+                windowInfo.recycle();
+            }
+        }
+    }
+
+    @Test
+    public void addWindowThenStateChangedEvent_noLongerInCache() {
+        putWindowWithIdInCache(WINDOW_ID_1);
+        mAccessibilityCache.onAccessibilityEvent(
+                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED));
+        assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1));
+    }
+
+    @Test
+    public void addWindowThenWindowsChangedEvent_noLongerInCache() {
+        putWindowWithIdInCache(WINDOW_ID_1);
+        mAccessibilityCache.onAccessibilityEvent(
+                AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOWS_CHANGED));
+        assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1));
+    }
+
+    @Test
+    public void addThenGetNode_returnsEquivalentNode() {
+        AccessibilityNodeInfo nodeInfo, nodeCopy = null, nodeFromCache = null;
+        try {
+            nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+            long id = nodeInfo.getSourceNodeId();
+            nodeCopy = AccessibilityNodeInfo.obtain(nodeInfo);
+            mAccessibilityCache.add(nodeInfo);
+            nodeInfo.recycle();
+            nodeFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id);
+            assertEquals(nodeCopy, nodeFromCache);
+        } finally {
+            nodeFromCache.recycle();
+            nodeCopy.recycle();
+        }
+    }
+
+    @Test
+    public void overwriteThenGetNode_returnsNewNode() {
+        final CharSequence contentDescription1 = "foo";
+        final CharSequence contentDescription2 = "bar";
+        AccessibilityNodeInfo nodeInfo1 = null, nodeInfo2 = null, nodeFromCache = null;
+        try {
+            nodeInfo1 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+            nodeInfo1.setContentDescription(contentDescription1);
+            long id = nodeInfo1.getSourceNodeId();
+            nodeInfo2 = AccessibilityNodeInfo.obtain(nodeInfo1);
+            nodeInfo2.setContentDescription(contentDescription2);
+            mAccessibilityCache.add(nodeInfo1);
+            mAccessibilityCache.add(nodeInfo2);
+            nodeFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id);
+            assertEquals(nodeInfo2, nodeFromCache);
+            assertEquals(contentDescription2, nodeFromCache.getContentDescription());
+        } finally {
+            nodeFromCache.recycle();
+            nodeInfo2.recycle();
+            nodeInfo1.recycle();
+        }
+    }
+
+    @Test
+    public void nodesInDifferentWindowWithSameId_areKeptSeparate() {
+        final CharSequence contentDescription1 = "foo";
+        final CharSequence contentDescription2 = "bar";
+        AccessibilityNodeInfo nodeInfo1 = null, nodeInfo2 = null,
+                node1FromCache = null, node2FromCache = null;
+        try {
+            nodeInfo1 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+            nodeInfo1.setContentDescription(contentDescription1);
+            long id = nodeInfo1.getSourceNodeId();
+            nodeInfo2 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_2);
+            nodeInfo2.setContentDescription(contentDescription2);
+            assertEquals(id, nodeInfo2.getSourceNodeId());
+            mAccessibilityCache.add(nodeInfo1);
+            mAccessibilityCache.add(nodeInfo2);
+            node1FromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id);
+            node2FromCache = mAccessibilityCache.getNode(WINDOW_ID_2, id);
+            assertEquals(nodeInfo1, node1FromCache);
+            assertEquals(nodeInfo2, node2FromCache);
+            assertEquals(nodeInfo1.getContentDescription(), node1FromCache.getContentDescription());
+            assertEquals(nodeInfo2.getContentDescription(), node2FromCache.getContentDescription());
+        } finally {
+            node1FromCache.recycle();
+            node2FromCache.recycle();
+            nodeInfo1.recycle();
+            nodeInfo2.recycle();
+        }
+    }
+
+    @Test
+    public void addNodeThenClear_nodeIsRemoved() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        long id = nodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(nodeInfo);
+        nodeInfo.recycle();
+        mAccessibilityCache.clear();
+        assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, id));
+    }
+
+    @Test
+    public void windowStateChangeAndWindowsChangedEvents_clearsNode() {
+        assertEventTypeClearsNode(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        assertEventTypeClearsNode(AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+    }
+
+    @Test
+    public void subTreeChangeEvent_clearsNodeAndChild() {
+        AccessibilityEvent event = AccessibilityEvent
+                .obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+        event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+
+        try {
+            assertEventClearsParentAndChild(event);
+        } finally {
+            event.recycle();
+        }
+    }
+
+    @Test
+    public void scrollEvent_clearsNodeAndChild() {
+        AccessibilityEvent event = AccessibilityEvent
+                .obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+        event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        try {
+            assertEventClearsParentAndChild(event);
+        } finally {
+            event.recycle();
+        }
+    }
+
+    @Test
+    public void reparentNode_clearsOldParent() {
+        AccessibilityNodeInfo parentNodeInfo = getParentNode();
+        AccessibilityNodeInfo childNodeInfo = getChildNode();
+        long parentId = parentNodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(childNodeInfo);
+
+        childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID + 1, WINDOW_ID_1));
+        mAccessibilityCache.add(childNodeInfo);
+
+        AccessibilityNodeInfo parentFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, parentId);
+        try {
+            assertNull(parentFromCache);
+        } finally {
+            parentNodeInfo.recycle();
+            childNodeInfo.recycle();
+            if (parentFromCache != null) {
+                parentFromCache.recycle();
+            }
+        }
+    }
+
+    @Test
+    public void removeChildFromParent_clearsChild() {
+        AccessibilityNodeInfo parentNodeInfo = getParentNode();
+        AccessibilityNodeInfo childNodeInfo = getChildNode();
+        long childId = childNodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(childNodeInfo);
+
+        AccessibilityNodeInfo parentNodeInfoWithNoChildren =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        mAccessibilityCache.add(parentNodeInfoWithNoChildren);
+
+        AccessibilityNodeInfo childFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, childId);
+        try {
+            assertNull(childFromCache);
+        } finally {
+            parentNodeInfoWithNoChildren.recycle();
+            parentNodeInfo.recycle();
+            childNodeInfo.recycle();
+            if (childFromCache != null) {
+                childFromCache.recycle();
+            }
+        }
+    }
+
+    @Test
+    public void nodeSourceOfA11yFocusEvent_getsRefreshed() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setAccessibilityFocused(false);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+        event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1));
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void nodeWithA11yFocusWhenAnotherNodeGetsFocus_getsRefreshed() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setAccessibilityFocused(true);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+        event.setSource(getMockViewWithA11yAndWindowIds(OTHER_VIEW_ID, WINDOW_ID_1));
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void nodeWithA11yFocusClearsIt_refreshes() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setAccessibilityFocused(true);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+        event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1));
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void nodeSourceOfInputFocusEvent_getsRefreshed() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setFocused(false);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1));
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void nodeWithInputFocusWhenAnotherNodeGetsFocus_getsRefreshed() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        nodeInfo.setFocused(true);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        event.setSource(getMockViewWithA11yAndWindowIds(OTHER_VIEW_ID, WINDOW_ID_1));
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
+    public void nodeEventSaysWasSelected_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_SELECTED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    @Test
+    public void nodeEventSaysHadTextChanged_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    @Test
+    public void nodeEventSaysWasClicked_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_CLICKED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    @Test
+    public void nodeEventSaysHadSelectionChange_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    @Test
+    public void nodeEventSaysHadTextContentChange_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+    }
+
+    @Test
+    public void nodeEventSaysHadContentDescriptionChange_getsRefreshed() {
+        assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
+    }
+
+    private void assertNodeIsRefreshedWithEventType(int eventType, int contentChangeTypes) {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+        event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1));
+        event.setContentChangeTypes(contentChangeTypes);
+        mAccessibilityCache.onAccessibilityEvent(event);
+        event.recycle();
+        try {
+            verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    private void putWindowWithIdInCache(int id) {
+        AccessibilityWindowInfo windowInfo = AccessibilityWindowInfo.obtain();
+        windowInfo.setId(id);
+        mAccessibilityCache.addWindow(windowInfo);
+        windowInfo.recycle();
+    }
+
+    private AccessibilityNodeInfo getNodeWithA11yAndWindowId(int a11yId, int windowId) {
+        AccessibilityNodeInfo node =
+                AccessibilityNodeInfo.obtain(getMockViewWithA11yAndWindowIds(a11yId, windowId));
+        node.setConnectionId(MOCK_CONNECTION_ID);
+        return node;
+    }
+
+    private View getMockViewWithA11yAndWindowIds(int a11yId, int windowId) {
+        View mockView = mock(View.class);
+        when(mockView.getAccessibilityViewId()).thenReturn(a11yId);
+        when(mockView.getAccessibilityWindowId()).thenReturn(windowId);
+        doAnswer(new Answer<AccessibilityNodeInfo>() {
+            public AccessibilityNodeInfo answer(InvocationOnMock invocation) {
+                return AccessibilityNodeInfo.obtain((View) invocation.getMock());
+            }
+        }).when(mockView).createAccessibilityNodeInfo();
+        return mockView;
+    }
+
+    private void assertEventTypeClearsNode(int eventType) {
+        final int nodeId = 0xBEEF;
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(nodeId, WINDOW_ID_1);
+        long id = nodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(nodeInfo);
+        nodeInfo.recycle();
+        mAccessibilityCache.onAccessibilityEvent(AccessibilityEvent.obtain(eventType));
+        assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, id));
+    }
+
+    private AccessibilityNodeInfo getParentNode() {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(CHILD_VIEW_ID, WINDOW_ID_1));
+        return parentNodeInfo;
+    }
+
+    private AccessibilityNodeInfo getChildNode() {
+        AccessibilityNodeInfo childNodeInfo =
+                getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
+        childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        return childNodeInfo;
+    }
+
+    private void assertEventClearsParentAndChild(AccessibilityEvent event) {
+        AccessibilityNodeInfo parentNodeInfo = getParentNode();
+        AccessibilityNodeInfo childNodeInfo = getChildNode();
+        long parentId = parentNodeInfo.getSourceNodeId();
+        long childId = childNodeInfo.getSourceNodeId();
+        mAccessibilityCache.add(parentNodeInfo);
+        mAccessibilityCache.add(childNodeInfo);
+
+        mAccessibilityCache.onAccessibilityEvent(event);
+        parentNodeInfo.recycle();
+        childNodeInfo.recycle();
+
+        AccessibilityNodeInfo parentFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, parentId);
+        AccessibilityNodeInfo childFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, childId);
+        try {
+            assertNull(parentFromCache);
+            assertNull(childFromCache);
+        } finally {
+            if (parentFromCache != null) {
+                parentFromCache.recycle();
+            }
+            if (childFromCache != null) {
+                childFromCache.recycle();
+            }
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index a247056..9c241d7 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -16,14 +16,17 @@
 
 package com.android.server.accounts;
 
+import static android.database.sqlite.SQLiteDatabase.deleteDatabase;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
 import android.app.AppOpsManager;
-import android.app.Notification;
+import android.app.INotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -37,11 +40,11 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 import android.test.mock.MockContext;
-import android.test.mock.MockPackageManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
@@ -52,28 +55,38 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class AccountManagerServiceTest extends AndroidTestCase {
     private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
 
-    static final String PREN_DB = "pren.db";
-    static final String DE_DB = "de.db";
-    static final String CE_DB = "ce.db";
+    private static final String PREN_DB = "pren.db";
+    private static final String DE_DB = "de.db";
+    private static final String CE_DB = "ce.db";
     private AccountManagerService mAms;
+    private TestInjector mTestInjector;
 
     @Override
     protected void setUp() throws Exception {
         Context realTestContext = getContext();
-        Context mockContext = new MyMockContext(realTestContext);
+        MyMockContext mockContext = new MyMockContext(realTestContext);
         setContext(mockContext);
-        mAms = createAccountManagerService(mockContext, realTestContext);
+        mTestInjector = new TestInjector(realTestContext, mockContext);
+        mAms = new AccountManagerService(mTestInjector);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
-        SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
-        SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
+        // Let async logging tasks finish, otherwise they may crash due to db being removed
+        CountDownLatch cdl = new CountDownLatch(1);
+        mAms.mHandler.post(() -> {
+            deleteDatabase(new File(mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM)));
+            deleteDatabase(new File(mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM)));
+            deleteDatabase(new File(mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
+            cdl.countDown();
+        });
+        cdl.await(1, TimeUnit.SECONDS);
         super.tearDown();
     }
 
@@ -226,7 +239,7 @@
 
         Context originalContext = ((MyMockContext)getContext()).mTestContext;
         // create a separate instance of AMS. It initially assumes that user0 is locked
-        AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext);
+        AccountManagerService ams2 = new AccountManagerService(mTestInjector);
 
         // Verify that account can be removed when user is locked
         ams2.removeAccountInternal(a1);
@@ -235,7 +248,7 @@
         assertEquals("Only a2 should be returned", a2, accounts[0]);
 
         // Verify that CE db file is unchanged and still has 2 accounts
-        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM);
         int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
         assertEquals("CE database should still have 2 accounts", 2, accountsNumber);
 
@@ -250,7 +263,7 @@
 
     @SmallTest
     public void testPreNDatabaseMigration() throws Exception {
-        String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
+        String preNDatabaseName = mTestInjector.getPreNDatabaseName(UserHandle.USER_SYSTEM);
         Context originalContext = ((MyMockContext) getContext()).mTestContext;
         PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName);
         // Assert that database was created with 1 account
@@ -271,8 +284,8 @@
                 new File(preNDatabaseName).exists());
 
         // Verify that ce/de files are present
-        String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM);
-        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        String deDatabaseName = mTestInjector.getDeDatabaseName(UserHandle.USER_SYSTEM);
+        String ceDatabaseName = mTestInjector.getCeDatabaseName(UserHandle.USER_SYSTEM);
         assertTrue("DE database file should be created at " + deDatabaseName,
                 new File(deDatabaseName).exists());
         assertTrue("CE database file should be created at " + ceDatabaseName,
@@ -287,12 +300,6 @@
         }
     }
 
-    private AccountManagerService createAccountManagerService(Context mockContext,
-            Context realContext) {
-        return new MyAccountManagerService(mockContext,
-                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
-    }
-
     private void unlockSystemUser() {
         mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
     }
@@ -344,6 +351,10 @@
         @Override
         public void invalidateCache(int userId) {
         }
+
+        @Override
+        public void updateServices(int userId) {
+        }
     }
 
     static class MyMockContext extends MockContext {
@@ -357,6 +368,8 @@
             this.mAppOpsManager = mock(AppOpsManager.class);
             this.mUserManager = mock(UserManager.class);
             this.mPackageManager = mock(PackageManager.class);
+            when(mPackageManager.checkSignatures(anyInt(), anyInt()))
+                    .thenReturn(PackageManager.SIGNATURE_MATCH);
             final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
             when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
         }
@@ -372,6 +385,11 @@
         }
 
         @Override
+        public String getPackageName() {
+            return mTestContext.getPackageName();
+        }
+
+        @Override
         public Object getSystemService(String name) {
             if (Context.APP_OPS_SERVICE.equals(name)) {
                 return mAppOpsManager;
@@ -418,42 +436,45 @@
         }
     }
 
-    static class MyMockPackageManager extends MockPackageManager {
-        @Override
-        public int checkSignatures(final int uid1, final int uid2) {
-            return PackageManager.SIGNATURE_MATCH;
-        }
-    }
-
-    static class MyAccountManagerService extends AccountManagerService {
-        private Context mRealTestContext;
-        MyAccountManagerService(Context context, PackageManager packageManager,
-                IAccountAuthenticatorCache authenticatorCache, Context realTestContext) {
-            super(context, packageManager, authenticatorCache);
-            this.mRealTestContext = realTestContext;
+    static class TestInjector extends AccountManagerService.Injector {
+        private Context mRealContext;
+        TestInjector(Context realContext, MyMockContext mockContext) {
+            super(mockContext);
+            mRealContext = realContext;
         }
 
         @Override
-        protected void installNotification(final int notificationId, final Notification n, UserHandle user) {
+        Looper getMessageHandlerLooper() {
+            return Looper.getMainLooper();
         }
 
         @Override
-        protected void cancelNotification(final int id, UserHandle user) {
+        void addLocalService(AccountManagerInternal service) {
+        }
+
+        @Override
+        IAccountAuthenticatorCache getAccountAuthenticatorCache() {
+            return new MockAccountAuthenticatorCache();
         }
 
         @Override
         protected String getCeDatabaseName(int userId) {
-            return new File(mRealTestContext.getCacheDir(), CE_DB).getPath();
+            return new File(mRealContext.getCacheDir(), CE_DB).getPath();
         }
 
         @Override
         protected String getDeDatabaseName(int userId) {
-            return new File(mRealTestContext.getCacheDir(), DE_DB).getPath();
+            return new File(mRealContext.getCacheDir(), DE_DB).getPath();
         }
 
         @Override
         String getPreNDatabaseName(int userId) {
-            return new File(mRealTestContext.getCacheDir(), PREN_DB).getPath();
+            return new File(mRealContext.getCacheDir(), PREN_DB).getPath();
+        }
+
+        @Override
+        INotificationManager getNotificationManager() {
+            return mock(INotificationManager.class);
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
new file mode 100644
index 0000000..5b565a7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -0,0 +1,341 @@
+
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link AccountsDb}.
+ * <p>Run with:<pre>
+ * m FrameworksServicesTests &&
+ * adb install \
+ * -r out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ * adb shell am instrument -e class com.android.server.accounts.AccountsDbTest \
+ * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AccountsDbTest {
+    private static final String PREN_DB = "pren.db";
+    private static final String DE_DB = "de.db";
+    private static final String CE_DB = "ce.db";
+
+    private AccountsDb mAccountsDb;
+    private File preNDb;
+    private File deDb;
+    private File ceDb;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        preNDb = new File(context.getCacheDir(), PREN_DB);
+        ceDb = new File(context.getCacheDir(), CE_DB);
+        deDb = new File(context.getCacheDir(), DE_DB);
+        deleteDbFiles();
+        mAccountsDb = AccountsDb.create(context, 0, preNDb, deDb);
+    }
+
+    @After
+    public void tearDown() {
+        deleteDbFiles();
+    }
+
+    private void deleteDbFiles() {
+        AccountsDb.deleteDbFileWarnIfFailed(preNDb);
+        AccountsDb.deleteDbFileWarnIfFailed(ceDb);
+        AccountsDb.deleteDbFileWarnIfFailed(deDb);
+    }
+
+    @Test
+    public void testCeNotAvailableInitially() {
+        Account account = new Account("name", "example.com");
+        long id = mAccountsDb.insertCeAccount(account, "");
+        assertEquals("Insert into CE should fail until CE database is attached", -1, id);
+    }
+
+    @Test
+    public void testDeAccountInsertFindDelete() {
+        Account account = new Account("name", "example.com");
+        long accId = 1;
+        mAccountsDb.insertDeAccount(account, accId);
+        long actualId = mAccountsDb.findDeAccountId(account);
+        assertEquals(accId, actualId);
+        // Delete and verify that account no longer exists
+        mAccountsDb.deleteDeAccount(accId);
+        actualId = mAccountsDb.findDeAccountId(account);
+        assertEquals(-1, actualId);
+    }
+
+    @Test
+    public void testCeAccountInsertFindDelete() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        long actualId = mAccountsDb.findCeAccountId(account);
+        assertEquals(accId, actualId);
+        // Delete and verify that account no longer exists
+        mAccountsDb.deleteCeAccount(accId);
+        actualId = mAccountsDb.findCeAccountId(account);
+        assertEquals(-1, actualId);
+    }
+
+    @Test
+    public void testAuthTokenInsertFindDelete() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+        long authTokenId = mAccountsDb.insertAuthToken(accId, "type", "token");
+        Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+        assertEquals(1, authTokensByAccount.size());
+        try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "token")) {
+            assertTrue(cursor.moveToNext());
+        }
+        try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "nosuchtoken")) {
+            assertFalse(cursor.moveToNext());
+        }
+        mAccountsDb.deleteAuthToken(String.valueOf(authTokenId));
+        // Verify that token no longer exists
+        authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+        assertEquals(0, authTokensByAccount.size());
+    }
+
+    @Test
+    public void testAuthTokenDeletes() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        // 1st account
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+        mAccountsDb.insertAuthToken(accId, "type", "token");
+        mAccountsDb.insertAuthToken(accId, "type2", "token2");
+        // 2nd account
+        Account account2 = new Account("name", "example2.com");
+        long accId2 = mAccountsDb.insertCeAccount(account2, "password");
+        mAccountsDb.insertDeAccount(account2, accId);
+        mAccountsDb.insertAuthToken(accId2, "type", "token");
+
+        mAccountsDb.deleteAuthTokensByAccountId(accId2);
+        Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account2);
+        assertEquals(0, authTokensByAccount.size());
+        // Authtokens from account 1 are still there
+        authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+        assertEquals(2, authTokensByAccount.size());
+
+        // Delete authtokens from account 1 and verify
+        mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type");
+        authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+        assertEquals(1, authTokensByAccount.size());
+        mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type2");
+        authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+        assertEquals(0, authTokensByAccount.size());
+    }
+
+    @Test
+    public void testExtrasInsertFindDelete() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+        String extraKey = "extra_key";
+        String extraValue = "extra_value";
+        long extraId = mAccountsDb.insertExtra(accId, extraKey, extraValue);
+        // Test find methods
+        long actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey);
+        assertEquals(extraId, actualExtraId);
+        Map<String, String> extras = mAccountsDb.findUserExtrasForAccount(account);
+        assertEquals(1, extras.size());
+        assertEquals(extraValue, extras.get(extraKey));
+        // Test update
+        String newExtraValue = "extra_value2";
+        mAccountsDb.updateExtra(extraId, newExtraValue);
+        String newValue = mAccountsDb.findUserExtrasForAccount(account).get(extraKey);
+        assertEquals(newExtraValue, newValue);
+
+        // Delete account and verify that extras cascade removed
+        mAccountsDb.deleteCeAccount(accId);
+        actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey);
+        assertEquals(-1, actualExtraId);
+    }
+
+    @Test
+    public void testGrantsInsertFindDelete() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+        int testUid = 100500;
+        long grantId = mAccountsDb.insertGrant(accId, "tokenType", testUid);
+        assertTrue(grantId > 0);
+        List<Integer> allUidGrants = mAccountsDb.findAllUidGrants();
+        List<Integer> expectedUids = Arrays.asList(testUid);
+        assertEquals(expectedUids, allUidGrants);
+
+        long matchingGrantsCount = mAccountsDb.findMatchingGrantsCount(
+                testUid, "tokenType", account);
+        assertEquals(1, matchingGrantsCount);
+        // Test nonexistent type
+        matchingGrantsCount = mAccountsDb.findMatchingGrantsCount(
+                testUid, "noSuchType", account);
+        assertEquals(0, matchingGrantsCount);
+
+        matchingGrantsCount = mAccountsDb.findMatchingGrantsCountAnyToken(testUid, account);
+        assertEquals(1, matchingGrantsCount);
+
+        List<Pair<String, Integer>> allAccountGrants = mAccountsDb.findAllAccountGrants();
+        assertEquals(1, allAccountGrants.size());
+        assertEquals(account.name, allAccountGrants.get(0).first);
+        assertEquals(testUid, (int)allAccountGrants.get(0).second);
+
+        mAccountsDb.deleteGrantsByUid(testUid);
+        allUidGrants = mAccountsDb.findAllUidGrants();
+        assertTrue("Test grants should be removed", allUidGrants.isEmpty());
+    }
+
+    @Test
+    public void testSharedAccountsInsertFindDelete() {
+        Account account = new Account("name", "example.com");
+        long accId = 0;
+        mAccountsDb.insertDeAccount(account, accId);
+        long sharedAccId = mAccountsDb.insertSharedAccount(account);
+        long foundSharedAccountId = mAccountsDb.findSharedAccountId(account);
+        assertEquals(sharedAccId, foundSharedAccountId);
+        List<Account> sharedAccounts = mAccountsDb.getSharedAccounts();
+        List<Account> expectedList = Arrays.asList(account);
+        assertEquals(expectedList, sharedAccounts);
+
+        // Delete and verify
+        mAccountsDb.deleteSharedAccount(account);
+        foundSharedAccountId = mAccountsDb.findSharedAccountId(account);
+        assertEquals(-1, foundSharedAccountId);
+    }
+
+    @Test
+    public void testMetaInsertFindDelete() {
+        int testUid = 100500;
+        String authenticatorType = "authType";
+        mAccountsDb.insertOrReplaceMetaAuthTypeAndUid(authenticatorType, testUid);
+        Map<String, Integer> metaAuthUid = mAccountsDb.findMetaAuthUid();
+        assertEquals(1, metaAuthUid.size());
+        assertEquals(testUid, (int)metaAuthUid.get(authenticatorType));
+
+        // Delete and verify
+        boolean deleteResult = mAccountsDb.deleteMetaByAuthTypeAndUid(authenticatorType, testUid);
+        assertTrue(deleteResult);
+        metaAuthUid = mAccountsDb.findMetaAuthUid();
+        assertEquals(0, metaAuthUid.size());
+    }
+
+    @Test
+    public void testUpdateDeAccountLastAuthenticatedTime() {
+        Account account = new Account("name", "example.com");
+        long accId = 1;
+        mAccountsDb.insertDeAccount(account, accId);
+        long now = System.currentTimeMillis();
+        mAccountsDb.updateAccountLastAuthenticatedTime(account);
+        long time = mAccountsDb.findAccountLastAuthenticatedTime(account);
+        assertTrue("LastAuthenticatedTime should be current", time >= now);
+    }
+
+    @Test
+    public void testRenameAccount() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+        mAccountsDb.renameDeAccount(accId, "newName", "name");
+        Account newAccount = mAccountsDb.findAllDeAccounts().get(accId);
+        assertEquals("newName", newAccount.name);
+
+        String prevName = mAccountsDb.findDeAccountPreviousName(newAccount);
+        assertEquals("name", prevName);
+        mAccountsDb.renameCeAccount(accId, "newName");
+        long foundAccId = mAccountsDb.findCeAccountId(account);
+        assertEquals("Account shouldn't be found under the old name", -1, foundAccId);
+        foundAccId = mAccountsDb.findCeAccountId(newAccount);
+        assertEquals(accId, foundAccId);
+    }
+
+    @Test
+    public void testUpdateCeAccountPassword() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        String newPassword = "newPassword";
+        mAccountsDb.updateCeAccountPassword(accId, newPassword);
+        String actualPassword = mAccountsDb
+                .findAccountPasswordByNameAndType(account.name, account.type);
+        assertEquals(newPassword, actualPassword);
+    }
+
+    @Test
+    public void testFindCeAccountsNotInDe() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        Account account = new Account("name", "example.com");
+        long accId = mAccountsDb.insertCeAccount(account, "password");
+        mAccountsDb.insertDeAccount(account, accId);
+
+        Account accountNotInDe = new Account("name2", "example.com");
+        mAccountsDb.insertCeAccount(accountNotInDe, "password");
+
+        List<Account> ceAccounts = mAccountsDb.findCeAccountsNotInDe();
+        List<Account> expectedList = Arrays.asList(accountNotInDe);
+        assertEquals(expectedList, ceAccounts);
+    }
+
+    @Test
+    public void testCrossDbTransactions() {
+        mAccountsDb.attachCeDatabase(ceDb);
+        mAccountsDb.beginTransaction();
+        Account account = new Account("name", "example.com");
+        long accId;
+        accId = mAccountsDb.insertCeAccount(account, "password");
+        accId = mAccountsDb.insertDeAccount(account, accId);
+        long actualId = mAccountsDb.findCeAccountId(account);
+        assertEquals(accId, actualId);
+        actualId = mAccountsDb.findDeAccountId(account);
+        assertEquals(accId, actualId);
+        mAccountsDb.endTransaction();
+        // Verify that records were removed
+        actualId = mAccountsDb.findCeAccountId(account);
+        assertEquals(-1, actualId);
+        actualId = mAccountsDb.findDeAccountId(account);
+        assertEquals(-1, actualId);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index e440a0d..984a484 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -62,7 +62,7 @@
         for (int i = 0; i < 100; i++) {
             taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
         }
-        mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
+        mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
         SparseBooleanArray newTaskIdsOnFile = mTaskPersister
                 .loadPersistedTaskIdsForUser(testUserId);
         assertTrue("TaskIds written differ from TaskIds read back from file",
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
new file mode 100644
index 0000000..b47d17e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.am;
+
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.ITaskStackListener;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TaskStackChangedListenerTest extends ITaskStackListener.Stub {
+
+    private IActivityManager mService;
+
+    private static final Object sLock = new Object();
+    @GuardedBy("sLock")
+    private static boolean sTaskStackChangedCalled;
+    private static boolean sActivityBResumed;
+
+    @Before
+    public void setUp() throws Exception {
+        mService = ActivityManagerNative.getDefault();
+        mService.registerTaskStackListener(this);
+    }
+
+    @Test
+    public void testTaskStackChanged_afterFinish() throws Exception {
+        Context ctx = InstrumentationRegistry.getContext();
+        ctx.startActivity(new Intent(ctx, ActivityA.class));
+        UiDevice.getInstance(getInstrumentation()).waitForIdle();
+        synchronized (sLock) {
+            Assert.assertTrue(sTaskStackChangedCalled);
+        }
+        Assert.assertTrue(sActivityBResumed);
+    }
+
+    @Override
+    public void onTaskStackChanged() throws RemoteException {
+        synchronized (sLock) {
+            sTaskStackChangedCalled = true;
+        }
+    }
+
+    @Override
+    public void onActivityPinned() throws RemoteException {
+    }
+
+    @Override
+    public void onPinnedActivityRestartAttempt() throws RemoteException {
+    }
+
+    @Override
+    public void onPinnedStackAnimationEnded() throws RemoteException {
+    }
+
+    @Override
+    public void onActivityForcedResizable(String packageName, int taskId) throws RemoteException {
+    }
+
+    @Override
+    public void onActivityDismissingDockedStack() throws RemoteException {
+    }
+
+    public static class ActivityA extends Activity {
+
+        private boolean mActivityBLaunched = false;
+
+        @Override
+        protected void onPostResume() {
+            super.onPostResume();
+            if (mActivityBLaunched) {
+                return;
+            }
+            mActivityBLaunched = true;
+            finish();
+            startActivity(new Intent(this, ActivityB.class));
+        }
+    }
+
+    public static class ActivityB extends Activity {
+
+        @Override
+        protected void onPostResume() {
+            super.onPostResume();
+            synchronized (sLock) {
+                sTaskStackChangedCalled = false;
+            }
+            sActivityBResumed = true;
+            finish();
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
deleted file mode 100644
index 033b2c9..0000000
--- a/services/tests/servicestests/src/com/android/server/connectivity/DnsEventListenerServiceTest.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.metrics.DnsEvent;
-import android.net.metrics.IDnsEventListener;
-import android.net.metrics.IpConnectivityLog;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.OptionalInt;
-import java.util.stream.IntStream;
-
-public class DnsEventListenerServiceTest extends TestCase {
-
-    // TODO: read from DnsEventListenerService after this constant is read from system property
-    static final int BATCH_SIZE = 100;
-    static final int EVENT_TYPE = IDnsEventListener.EVENT_GETADDRINFO;
-    // TODO: read from IDnsEventListener
-    static final int RETURN_CODE = 1;
-
-    static final byte[] EVENT_TYPES  = new byte[BATCH_SIZE];
-    static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
-    static final int[] LATENCIES     = new int[BATCH_SIZE];
-    static {
-        for (int i = 0; i < BATCH_SIZE; i++) {
-            EVENT_TYPES[i] = EVENT_TYPE;
-            RETURN_CODES[i] = RETURN_CODE;
-            LATENCIES[i] = i;
-        }
-    }
-
-    DnsEventListenerService mDnsService;
-
-    @Mock ConnectivityManager mCm;
-    @Mock IpConnectivityLog mLog;
-    ArgumentCaptor<NetworkCallback> mCallbackCaptor;
-    ArgumentCaptor<DnsEvent> mEvCaptor;
-
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
-        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
-        mDnsService = new DnsEventListenerService(mCm, mLog);
-
-        verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
-    }
-
-    public void testOneBatch() throws Exception {
-        log(105, LATENCIES);
-        log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
-
-        verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
-
-        log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
-
-        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
-        verifyLoggedEvents(
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    public void testSeveralBatches() throws Exception {
-        log(105, LATENCIES);
-        log(106, LATENCIES);
-        log(105, LATENCIES);
-        log(107, LATENCIES);
-
-        verifyLoggedEvents(
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    public void testBatchAndNetworkLost() throws Exception {
-        byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
-        byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
-        int[] latencies = Arrays.copyOf(LATENCIES, 20);
-
-        log(105, LATENCIES);
-        log(105, latencies);
-        mCallbackCaptor.getValue().onLost(new Network(105));
-        log(105, LATENCIES);
-
-        verifyLoggedEvents(
-            new DnsEvent(105, eventTypes, returnCodes, latencies),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    public void testConcurrentBatchesAndDumps() throws Exception {
-        final long stop = System.currentTimeMillis() + 100;
-        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
-        new Thread() {
-            public void run() {
-                while (System.currentTimeMillis() < stop) {
-                    mDnsService.dump(pw);
-                }
-            }
-        }.start();
-
-        logAsync(105, LATENCIES);
-        logAsync(106, LATENCIES);
-        logAsync(107, LATENCIES);
-
-        verifyLoggedEvents(500,
-            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
-            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
-    }
-
-    public void testConcurrentBatchesAndNetworkLoss() throws Exception {
-        logAsync(105, LATENCIES);
-        Thread.sleep(10L);
-        // call onLost() asynchronously to logAsync's onDnsEvent() calls.
-        mCallbackCaptor.getValue().onLost(new Network(105));
-
-        // do not verify unpredictable batch
-        verify(mLog, timeout(500).times(1)).log(any());
-    }
-
-    void log(int netId, int[] latencies) {
-        for (int l : latencies) {
-            mDnsService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
-        }
-    }
-
-    void logAsync(int netId, int[] latencies) {
-        new Thread() {
-            public void run() {
-                log(netId, latencies);
-            }
-        }.start();
-    }
-
-    void verifyLoggedEvents(DnsEvent... expected) {
-        verifyLoggedEvents(0, expected);
-    }
-
-    void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
-        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
-        for (DnsEvent got : mEvCaptor.getAllValues()) {
-            OptionalInt index = IntStream.range(0, expectedEvents.length)
-                    .filter(i -> eventsEqual(expectedEvents[i], got))
-                    .findFirst();
-            // Don't match same expected event more than once.
-            index.ifPresent(i -> expectedEvents[i] = null);
-            assertTrue(index.isPresent());
-        }
-    }
-
-    /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
-    static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
-        return (expected == got) || ((expected != null) && (got != null)
-                && (expected.netId == got.netId)
-                && Arrays.equals(expected.eventTypes, got.eventTypes)
-                && Arrays.equals(expected.returnCodes, got.returnCodes)
-                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
new file mode 100644
index 0000000..aed3635
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.net.ConnectivityMetricsEvent;
+import android.net.metrics.ApfProgramEvent;
+import android.net.metrics.ApfStats;
+import android.net.metrics.DefaultNetworkEvent;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.DhcpErrorEvent;
+import android.net.metrics.DnsEvent;
+import android.net.metrics.IpManagerEvent;
+import android.net.metrics.IpReachabilityEvent;
+import android.net.metrics.NetworkEvent;
+import android.net.metrics.RaEvent;
+import android.net.metrics.ValidationProbeEvent;
+import com.google.protobuf.nano.MessageNano;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.MetricsTestUtil.aBool;
+import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
+import static com.android.server.connectivity.MetricsTestUtil.aLong;
+import static com.android.server.connectivity.MetricsTestUtil.aString;
+import static com.android.server.connectivity.MetricsTestUtil.aType;
+import static com.android.server.connectivity.MetricsTestUtil.anInt;
+import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
+import static com.android.server.connectivity.MetricsTestUtil.b;
+import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
+import static com.android.server.connectivity.MetricsTestUtil.ipEv;
+
+public class IpConnectivityEventBuilderTest extends TestCase {
+
+    public void testDefaultNetworkEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(DefaultNetworkEvent.class),
+                anInt(102),
+                anIntArray(1, 2, 3),
+                anInt(101),
+                aBool(true),
+                aBool(false));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  default_network_event <",
+                "    network_id <",
+                "      network_id: 102",
+                "    >",
+                "    previous_network_id <",
+                "      network_id: 101",
+                "    >",
+                "    previous_network_ip_support: 1",
+                "    transport_types: 1",
+                "    transport_types: 2",
+                "    transport_types: 3",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testDhcpClientEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(DhcpClientEvent.class),
+                aString("wlan0"),
+                aString("SomeState"),
+                anInt(192));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  dhcp_event <",
+                "    duration_ms: 192",
+                "    error_code: 0",
+                "    if_name: \"wlan0\"",
+                "    state_transition: \"SomeState\"",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testDhcpErrorEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(DhcpErrorEvent.class),
+                aString("wlan0"),
+                anInt(DhcpErrorEvent.L4_NOT_UDP));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  dhcp_event <",
+                "    duration_ms: 0",
+                "    error_code: 50397184",
+                "    if_name: \"wlan0\"",
+                "    state_transition: \"\"",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testDnsEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(DnsEvent.class),
+                anInt(101),
+                aByteArray(b(1), b(1), b(2), b(1), b(1), b(1), b(2), b(2)),
+                aByteArray(b(0), b(0), b(22), b(3), b(1), b(0), b(200), b(178)),
+                anIntArray(3456, 267, 1230, 45, 2111, 450, 638, 1300));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  dns_lookup_batch <",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 2",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 1",
+                "    event_types: 2",
+                "    event_types: 2",
+                "    latencies_ms: 3456",
+                "    latencies_ms: 267",
+                "    latencies_ms: 1230",
+                "    latencies_ms: 45",
+                "    latencies_ms: 2111",
+                "    latencies_ms: 450",
+                "    latencies_ms: 638",
+                "    latencies_ms: 1300",
+                "    network_id <",
+                "      network_id: 101",
+                "    >",
+                "    return_codes: 0",
+                "    return_codes: 0",
+                "    return_codes: 22",
+                "    return_codes: 3",
+                "    return_codes: 1",
+                "    return_codes: 0",
+                "    return_codes: 200",
+                "    return_codes: 178",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testIpManagerEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(IpManagerEvent.class),
+                aString("wlan0"),
+                anInt(IpManagerEvent.PROVISIONING_OK),
+                aLong(5678));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  ip_provisioning_event <",
+                "    event_type: 1",
+                "    if_name: \"wlan0\"",
+                "    latency_ms: 5678",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testIpReachabilityEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(IpReachabilityEvent.class),
+                aString("wlan0"),
+                anInt(IpReachabilityEvent.NUD_FAILED));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"wlan0\"",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testNetworkEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(NetworkEvent.class),
+                anInt(100),
+                anInt(5),
+                aLong(20410));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  network_event <",
+                "    event_type: 5",
+                "    latency_ms: 20410",
+                "    network_id <",
+                "      network_id: 100",
+                "    >",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testValidationProbeEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(ValidationProbeEvent.class),
+                anInt(120),
+                aLong(40730),
+                anInt(ValidationProbeEvent.PROBE_HTTP),
+                anInt(204));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  time_ms: 1",
+                "  validation_probe_event <",
+                "    latency_ms: 40730",
+                "    network_id <",
+                "      network_id: 120",
+                "    >",
+                "    probe_result: 204",
+                "    probe_type: 1",
+                "  >",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testApfProgramEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(ApfProgramEvent.class),
+                aLong(200),
+                anInt(7),
+                anInt(9),
+                anInt(2048),
+                anInt(3));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  apf_program_event <",
+                "    current_ras: 9",
+                "    drop_multicast: true",
+                "    filtered_ras: 7",
+                "    has_ipv4_addr: true",
+                "    lifetime: 200",
+                "    program_length: 2048",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testApfStatsSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(ApfStats.class),
+                aLong(45000),
+                anInt(10),
+                anInt(2),
+                anInt(2),
+                anInt(1),
+                anInt(2),
+                anInt(4),
+                anInt(2048));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  apf_statistics <",
+                "    dropped_ras: 2",
+                "    duration_ms: 45000",
+                "    matching_ras: 2",
+                "    max_program_size: 2048",
+                "    parse_errors: 2",
+                "    program_updates: 4",
+                "    received_ras: 10",
+                "    zero_lifetime_ras: 1",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    public void testRaEventSerialization() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(RaEvent.class),
+                aLong(2000),
+                aLong(400),
+                aLong(300),
+                aLong(-1),
+                aLong(1000),
+                aLong(-1));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  ra_event <",
+                "    dnssl_lifetime: -1",
+                "    prefix_preferred_lifetime: 300",
+                "    prefix_valid_lifetime: 400",
+                "    rdnss_lifetime: 1000",
+                "    route_info_lifetime: -1",
+                "    router_lifetime: 2000",
+                "  >",
+                "  time_ms: 1",
+                ">");
+
+        verifySerialization(want, ev);
+    }
+
+    static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
+        try {
+            byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
+            IpConnectivityLog log = new IpConnectivityLog();
+            MessageNano.mergeFrom(log, got);
+            assertEquals(want, log.toString());
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+
+    static String joinLines(String ... elems) {
+        StringBuilder b = new StringBuilder();
+        for (String s : elems) {
+            b.append(s);
+            b.append("\n");
+        }
+        return b.toString();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
new file mode 100644
index 0000000..3fc89b9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -0,0 +1,269 @@
+/*
+ * 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.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.metrics.ApfStats;
+import android.net.metrics.DefaultNetworkEvent;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpManagerEvent;
+import android.net.metrics.IpReachabilityEvent;
+import android.net.metrics.RaEvent;
+import android.net.metrics.ValidationProbeEvent;
+import android.os.Parcelable;
+import android.util.Base64;
+import com.android.server.connectivity.metrics.IpConnectivityLogClass;
+import com.google.protobuf.nano.MessageNano;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import junit.framework.TestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+public class IpConnectivityMetricsTest extends TestCase {
+    static final IpReachabilityEvent FAKE_EV =
+            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
+
+    @Mock Context mCtx;
+    @Mock IIpConnectivityMetrics mMockService;
+
+    IpConnectivityMetrics mService;
+
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mService = new IpConnectivityMetrics(mCtx);
+    }
+
+    public void testLoggingEvents() throws Exception {
+        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+        assertTrue(logger.log(1, FAKE_EV));
+        assertTrue(logger.log(2, FAKE_EV));
+        assertTrue(logger.log(3, FAKE_EV));
+
+        List<ConnectivityMetricsEvent> got = verifyEvents(3);
+        assertEventsEqual(expectedEvent(1), got.get(0));
+        assertEventsEqual(expectedEvent(2), got.get(1));
+        assertEventsEqual(expectedEvent(3), got.get(2));
+    }
+
+    public void testLoggingEventsWithMultipleCallers() throws Exception {
+        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+        final int nCallers = 10;
+        final int nEvents = 10;
+        for (int n = 0; n < nCallers; n++) {
+            final int i = n;
+            new Thread() {
+                public void run() {
+                    for (int j = 0; j < nEvents; j++) {
+                        assertTrue(logger.log(i * 100 + j, FAKE_EV));
+                    }
+                }
+            }.start();
+        }
+
+        List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
+        Collections.sort(got, EVENT_COMPARATOR);
+        Iterator<ConnectivityMetricsEvent> iter = got.iterator();
+        for (int i = 0; i < nCallers; i++) {
+            for (int j = 0; j < nEvents; j++) {
+                int expectedTimestamp = i * 100 + j;
+                assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
+            }
+        }
+    }
+
+    public void testBufferFlushing() {
+        String output1 = getdump("flush");
+        assertEquals("", output1);
+
+        new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
+        String output2 = getdump("flush");
+        assertFalse("".equals(output2));
+
+        String output3 = getdump("flush");
+        assertEquals("", output3);
+    }
+
+    public void testEndToEndLogging() {
+        IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
+
+        Parcelable[] events = {
+            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
+            new DhcpClientEvent("wlan0", "SomeState", 192),
+            new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
+            new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
+            new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
+            new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
+            new RaEvent(2000, 400, 300, -1, 1000, -1)
+        };
+
+        for (int i = 0; i < events.length; i++) {
+            logger.log(100 * (i + 1), events[i]);
+        }
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"wlan0\"",
+                "  >",
+                "  time_ms: 100",
+                ">",
+                "events <",
+                "  dhcp_event <",
+                "    duration_ms: 192",
+                "    error_code: 0",
+                "    if_name: \"wlan0\"",
+                "    state_transition: \"SomeState\"",
+                "  >",
+                "  time_ms: 200",
+                ">",
+                "events <",
+                "  default_network_event <",
+                "    network_id <",
+                "      network_id: 102",
+                "    >",
+                "    previous_network_id <",
+                "      network_id: 101",
+                "    >",
+                "    previous_network_ip_support: 1",
+                "    transport_types: 1",
+                "    transport_types: 2",
+                "    transport_types: 3",
+                "  >",
+                "  time_ms: 300",
+                ">",
+                "events <",
+                "  ip_provisioning_event <",
+                "    event_type: 1",
+                "    if_name: \"wlan0\"",
+                "    latency_ms: 5678",
+                "  >",
+                "  time_ms: 400",
+                ">",
+                "events <",
+                "  time_ms: 500",
+                "  validation_probe_event <",
+                "    latency_ms: 40730",
+                "    network_id <",
+                "      network_id: 120",
+                "    >",
+                "    probe_result: 204",
+                "    probe_type: 1",
+                "  >",
+                ">",
+                "events <",
+                "  apf_statistics <",
+                "    dropped_ras: 2",
+                "    duration_ms: 45000",
+                "    matching_ras: 2",
+                "    max_program_size: 2048",
+                "    parse_errors: 2",
+                "    program_updates: 4",
+                "    received_ras: 10",
+                "    zero_lifetime_ras: 1",
+                "  >",
+                "  time_ms: 600",
+                ">",
+                "events <",
+                "  ra_event <",
+                "    dnssl_lifetime: -1",
+                "    prefix_preferred_lifetime: 300",
+                "    prefix_valid_lifetime: 400",
+                "    rdnss_lifetime: 1000",
+                "    route_info_lifetime: -1",
+                "    router_lifetime: 2000",
+                "  >",
+                "  time_ms: 700",
+                ">");
+
+        verifySerialization(want, getdump("flush"));
+    }
+
+    String getdump(String ... command) {
+        StringWriter buffer = new StringWriter();
+        PrintWriter writer = new PrintWriter(buffer);
+        mService.impl.dump(null, writer, command);
+        return buffer.toString();
+    }
+
+    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
+        ArgumentCaptor<ConnectivityMetricsEvent> captor =
+                ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
+        verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
+        return captor.getAllValues();
+    }
+
+    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
+        return verifyEvents(n, 10);
+    }
+
+    static void verifySerialization(String want, String output) {
+        try {
+            byte[] got = Base64.decode(output, Base64.DEFAULT);
+            IpConnectivityLogClass.IpConnectivityLog log =
+                    new IpConnectivityLogClass.IpConnectivityLog();
+            MessageNano.mergeFrom(log, got);
+            assertEquals(want, log.toString());
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+
+    static String joinLines(String ... elems) {
+        StringBuilder b = new StringBuilder();
+        for (String s : elems) {
+            b.append(s).append("\n");
+        }
+        return b.toString();
+    }
+
+    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
+        return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
+    }
+
+    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
+    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
+        assertEquals(expected.timestamp, got.timestamp);
+        assertEquals(expected.componentTag, got.componentTag);
+        assertEquals(expected.eventTag, got.eventTag);
+        assertEquals(expected.data, got.data);
+    }
+
+    static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
+        new Comparator<ConnectivityMetricsEvent>() {
+            @Override
+            public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
+                return (int) (ev1.timestamp - ev2.timestamp);
+            }
+        };
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
new file mode 100644
index 0000000..bce5787e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/LingerMonitorTest.java
@@ -0,0 +1,349 @@
+/*
+ * 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.PendingIntent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkMisc;
+import android.text.format.DateUtils;
+import com.android.internal.R;
+import com.android.server.ConnectivityService;
+import com.android.server.connectivity.NetworkNotificationManager;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import junit.framework.TestCase;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+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.Mockito.reset;
+
+public class LingerMonitorTest extends TestCase {
+    static final String CELLULAR = "CELLULAR";
+    static final String WIFI     = "WIFI";
+
+    static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS;
+    static final long HIGH_RATE_LIMIT = 0;
+
+    static final int LOW_DAILY_LIMIT = 2;
+    static final int HIGH_DAILY_LIMIT = 1000;
+
+    LingerMonitor mMonitor;
+
+    @Mock ConnectivityService mConnService;
+    @Mock Context mCtx;
+    @Mock NetworkMisc mMisc;
+    @Mock NetworkNotificationManager mNotifier;
+    @Mock Resources mResources;
+
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mCtx.getResources()).thenReturn(mResources);
+        when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
+        when(mConnService.createNetworkMonitor(any(), any(), any(), any())).thenReturn(null);
+
+        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
+    }
+
+    public void testTransitions() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        NetworkAgentInfo nai1 = wifiNai(100);
+        NetworkAgentInfo nai2 = cellNai(101);
+
+        assertTrue(mMonitor.isNotificationEnabled(nai1, nai2));
+        assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
+    }
+
+    public void testNotificationOnLinger() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNotification(from, to);
+    }
+
+    public void testToastOnLinger() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyToast(from, to);
+    }
+
+    public void testNotificationClearedAfterDisconnect() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNotification(from, to);
+
+        mMonitor.noteDisconnect(to);
+        verify(mNotifier, times(1)).clearNotification(100);
+    }
+
+    public void testNotificationClearedAfterSwitchingBack() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNotification(from, to);
+
+        mMonitor.noteLingerDefaultNetwork(to, from);
+        verify(mNotifier, times(1)).clearNotification(100);
+    }
+
+    public void testUniqueToast() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyToast(from, to);
+
+        mMonitor.noteLingerDefaultNetwork(to, from);
+        verify(mNotifier, times(1)).clearNotification(100);
+
+        reset(mNotifier);
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    public void testMultipleNotifications() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo wifi1 = wifiNai(100);
+        NetworkAgentInfo wifi2 = wifiNai(101);
+        NetworkAgentInfo cell = cellNai(102);
+
+        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
+        verifyNotification(wifi1, cell);
+
+        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
+        verify(mNotifier, times(1)).clearNotification(100);
+
+        reset(mNotifier);
+        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
+        verifyNotification(wifi2, cell);
+    }
+
+    public void testRateLimiting() throws InterruptedException {
+        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
+
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo wifi1 = wifiNai(100);
+        NetworkAgentInfo wifi2 = wifiNai(101);
+        NetworkAgentInfo wifi3 = wifiNai(102);
+        NetworkAgentInfo cell = cellNai(103);
+
+        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
+        verifyNotification(wifi1, cell);
+        reset(mNotifier);
+
+        Thread.sleep(50);
+        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
+        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
+        verifyNoNotifications();
+
+        Thread.sleep(50);
+        mMonitor.noteLingerDefaultNetwork(cell, wifi3);
+        mMonitor.noteLingerDefaultNetwork(wifi3, cell);
+        verifyNoNotifications();
+    }
+
+    public void testDailyLimiting() throws InterruptedException {
+        mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
+
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo wifi1 = wifiNai(100);
+        NetworkAgentInfo wifi2 = wifiNai(101);
+        NetworkAgentInfo wifi3 = wifiNai(102);
+        NetworkAgentInfo cell = cellNai(103);
+
+        mMonitor.noteLingerDefaultNetwork(wifi1, cell);
+        verifyNotification(wifi1, cell);
+        reset(mNotifier);
+
+        Thread.sleep(50);
+        mMonitor.noteLingerDefaultNetwork(cell, wifi2);
+        mMonitor.noteLingerDefaultNetwork(wifi2, cell);
+        verifyNotification(wifi2, cell);
+        reset(mNotifier);
+
+        Thread.sleep(50);
+        mMonitor.noteLingerDefaultNetwork(cell, wifi3);
+        mMonitor.noteLingerDefaultNetwork(wifi3, cell);
+        verifyNoNotifications();
+    }
+
+    public void testUniqueNotification() {
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNotification(from, to);
+
+        mMonitor.noteLingerDefaultNetwork(to, from);
+        verify(mNotifier, times(1)).clearNotification(100);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNotification(from, to);
+    }
+
+    public void testIgnoreNeverValidatedNetworks() {
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+        from.everValidated = false;
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    public void testIgnoreCurrentlyValidatedNetworks() {
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+        from.lastValidated = true;
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    public void testNoNotificationType() {
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        setNotificationSwitch();
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    public void testNoTransitionToNotify() {
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
+        setNotificationSwitch(transition(WIFI, CELLULAR));
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    public void testDifferentTransitionToNotify() {
+        setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
+        setNotificationSwitch(transition(CELLULAR, WIFI));
+        NetworkAgentInfo from = wifiNai(100);
+        NetworkAgentInfo to = cellNai(101);
+
+        mMonitor.noteLingerDefaultNetwork(from, to);
+        verifyNoNotifications();
+    }
+
+    void setNotificationSwitch(String... transitions) {
+        when(mResources.getStringArray(R.array.config_networkNotifySwitches))
+                .thenReturn(transitions);
+    }
+
+    String transition(String from, String to) {
+        return from + "-" + to;
+    }
+
+    void setNotificationType(int type) {
+        when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type);
+    }
+
+    void verifyNoToast() {
+        verify(mNotifier, never()).showToast(any(), any());
+    }
+
+    void verifyNoNotification() {
+        verify(mNotifier, never())
+                .showNotification(anyInt(), any(), any(), any(), any(), anyBoolean());
+    }
+
+    void verifyNoNotifications() {
+        verifyNoToast();
+        verifyNoNotification();
+    }
+
+    void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) {
+        verifyNoNotification();
+        verify(mNotifier, times(1)).showToast(from, to);
+    }
+
+    void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) {
+        verifyNoToast();
+        verify(mNotifier, times(1)).showNotification(eq(from.network.netId),
+                eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true));
+    }
+
+    NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName) {
+        NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, "");
+        NetworkCapabilities caps = new NetworkCapabilities();
+        caps.addCapability(0);
+        caps.addTransportType(transport);
+        NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
+                caps, 50, mCtx, null, mMisc, null, mConnService);
+        nai.everValidated = true;
+        return nai;
+    }
+
+    NetworkAgentInfo wifiNai(int netId) {
+        return nai(netId, NetworkCapabilities.TRANSPORT_WIFI,
+                ConnectivityManager.TYPE_WIFI, WIFI);
+    }
+
+    NetworkAgentInfo cellNai(int netId) {
+        return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR,
+                ConnectivityManager.TYPE_MOBILE, CELLULAR);
+    }
+
+    public static class TestableLingerMonitor extends LingerMonitor {
+        public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) {
+            super(c, n, l, r);
+        }
+        @Override protected PendingIntent createNotificationIntent() {
+            return null;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java b/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
new file mode 100644
index 0000000..e201012
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/MetricsTestUtil.java
@@ -0,0 +1,120 @@
+/*
+ * 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.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+abstract public class MetricsTestUtil {
+    private MetricsTestUtil() {
+    }
+
+    static ConnectivityMetricsEvent ipEv(Parcelable p) {
+        return ev(ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY, p);
+    }
+
+    static ConnectivityMetricsEvent telephonyEv() {
+        return ev(ConnectivityMetricsLogger.COMPONENT_TAG_TELEPHONY, new Bundle());
+    }
+
+    static ConnectivityMetricsEvent ev(int tag, Parcelable p) {
+        return new ConnectivityMetricsEvent(1L, tag, 0, p);
+    }
+
+    // Utiliy interface for describing the content of a Parcel. This relies on
+    // the implementation defails of Parcelable and on the fact that the fully
+    // qualified Parcelable class names are written as string in the Parcels.
+    interface ParcelField {
+        void write(Parcel p);
+    }
+
+    static ConnectivityMetricsEvent describeIpEvent(ParcelField... fs) {
+        Parcel p = Parcel.obtain();
+        for (ParcelField f : fs) {
+            f.write(p);
+        }
+        p.setDataPosition(0);
+        return ipEv(p.readParcelable(ClassLoader.getSystemClassLoader()));
+    }
+
+    static ParcelField aType(Class<?> c) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeString(c.getName());
+            }
+        };
+    }
+
+    static ParcelField aBool(boolean b) {
+        return aByte((byte) (b ? 1 : 0));
+    }
+
+    static ParcelField aByte(byte b) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeByte(b);
+            }
+        };
+    }
+
+    static ParcelField anInt(int i) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeInt(i);
+            }
+        };
+    }
+
+    static ParcelField aLong(long l) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeLong(l);
+            }
+        };
+    }
+
+    static ParcelField aString(String s) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeString(s);
+            }
+        };
+    }
+
+    static ParcelField aByteArray(byte... ary) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeByteArray(ary);
+            }
+        };
+    }
+
+    static ParcelField anIntArray(int... ary) {
+        return new ParcelField() {
+            public void write(Parcel p) {
+                p.writeIntArray(ary);
+            }
+        };
+    }
+
+    static byte b(int i) {
+        return (byte) i;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
new file mode 100644
index 0000000..63d5d9fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.metrics.DnsEvent;
+import android.net.metrics.INetdEventListener;
+import android.net.metrics.IpConnectivityLog;
+
+import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.IntStream;
+
+public class NetdEventListenerServiceTest extends TestCase {
+
+    // TODO: read from NetdEventListenerService after this constant is read from system property
+    static final int BATCH_SIZE = 100;
+    static final int EVENT_TYPE = INetdEventListener.EVENT_GETADDRINFO;
+    // TODO: read from INetdEventListener
+    static final int RETURN_CODE = 1;
+
+    static final byte[] EVENT_TYPES  = new byte[BATCH_SIZE];
+    static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
+    static final int[] LATENCIES     = new int[BATCH_SIZE];
+    static {
+        for (int i = 0; i < BATCH_SIZE; i++) {
+            EVENT_TYPES[i] = EVENT_TYPE;
+            RETURN_CODES[i] = RETURN_CODE;
+            LATENCIES[i] = i;
+        }
+    }
+
+    NetdEventListenerService mNetdEventListenerService;
+
+    @Mock ConnectivityManager mCm;
+    @Mock IpConnectivityLog mLog;
+    ArgumentCaptor<NetworkCallback> mCallbackCaptor;
+    ArgumentCaptor<DnsEvent> mEvCaptor;
+
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
+        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
+        mNetdEventListenerService = new NetdEventListenerService(mCm, mLog);
+
+        verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
+    }
+
+    public void testOneBatch() throws Exception {
+        log(105, LATENCIES);
+        log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
+
+        verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+
+        log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
+
+        mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
+        verifyLoggedEvents(
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
+    }
+
+    public void testSeveralBatches() throws Exception {
+        log(105, LATENCIES);
+        log(106, LATENCIES);
+        log(105, LATENCIES);
+        log(107, LATENCIES);
+
+        verifyLoggedEvents(
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
+    }
+
+    public void testBatchAndNetworkLost() throws Exception {
+        byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
+        byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
+        int[] latencies = Arrays.copyOf(LATENCIES, 20);
+
+        log(105, LATENCIES);
+        log(105, latencies);
+        mCallbackCaptor.getValue().onLost(new Network(105));
+        log(105, LATENCIES);
+
+        verifyLoggedEvents(
+            new DnsEvent(105, eventTypes, returnCodes, latencies),
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+    }
+
+    public void testConcurrentBatchesAndDumps() throws Exception {
+        final long stop = System.currentTimeMillis() + 100;
+        final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
+        new Thread() {
+            public void run() {
+                while (System.currentTimeMillis() < stop) {
+                    mNetdEventListenerService.dump(pw);
+                }
+            }
+        }.start();
+
+        logAsync(105, LATENCIES);
+        logAsync(106, LATENCIES);
+        logAsync(107, LATENCIES);
+
+        verifyLoggedEvents(500,
+            new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
+            new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
+    }
+
+    public void testConcurrentBatchesAndNetworkLoss() throws Exception {
+        logAsync(105, LATENCIES);
+        Thread.sleep(10L);
+        // call onLost() asynchronously to logAsync's onDnsEvent() calls.
+        mCallbackCaptor.getValue().onLost(new Network(105));
+
+        // do not verify unpredictable batch
+        verify(mLog, timeout(500).times(1)).log(any());
+    }
+
+    void log(int netId, int[] latencies) {
+        for (int l : latencies) {
+            mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
+        }
+    }
+
+    void logAsync(int netId, int[] latencies) {
+        new Thread() {
+            public void run() {
+                log(netId, latencies);
+            }
+        }.start();
+    }
+
+    void verifyLoggedEvents(DnsEvent... expected) {
+        verifyLoggedEvents(0, expected);
+    }
+
+    void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
+        verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
+        for (DnsEvent got : mEvCaptor.getAllValues()) {
+            OptionalInt index = IntStream.range(0, expectedEvents.length)
+                    .filter(i -> eventsEqual(expectedEvents[i], got))
+                    .findFirst();
+            // Don't match same expected event more than once.
+            index.ifPresent(i -> expectedEvents[i] = null);
+            assertTrue(index.isPresent());
+        }
+    }
+
+    /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
+    static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
+        return (expected == got) || ((expected != null) && (got != null)
+                && (expected.netId == got.netId)
+                && Arrays.equals(expected.eventTypes, got.eventTypes)
+                && Arrays.equals(expected.returnCodes, got.returnCodes)
+                && Arrays.equals(expected.latenciesMs, got.latenciesMs));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 6cb4a82..80be62b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -357,5 +357,10 @@
         TelephonyManager getTelephonyManager() {
             return context.telephonyManager;
         }
+
+        @Override
+        boolean isBuildDebuggable() {
+            return context.buildMock.isDebuggable;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 2d96bff..01b2c3b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -839,6 +839,12 @@
         );
 
         assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
+
+        // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner
+        // and once for clearing it.
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
         // TODO Check other calls.
     }
 
@@ -2117,6 +2123,76 @@
         assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
     }
 
+    public void testForceUpdateUserSetupComplete_permission() {
+        // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
+        try {
+            dpm.forceUpdateUserSetupComplete();
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testForceUpdateUserSetupComplete_systemUser() {
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        // GIVEN calling from user 20
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        try {
+            dpm.forceUpdateUserSetupComplete();
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testForceUpdateUserSetupComplete_userbuild() {
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        final int userId = UserHandle.USER_SYSTEM;
+        // GIVEN userComplete is false in SettingsProvider
+        setUserSetupCompleteForUser(false, userId);
+
+        // GIVEN userComplete is true in DPM
+        DevicePolicyManagerService.DevicePolicyData userData =
+                new DevicePolicyManagerService.DevicePolicyData(userId);
+        userData.mUserSetupComplete = true;
+        dpms.mUserData.put(UserHandle.USER_SYSTEM, userData);
+
+        // GIVEN it's user build
+        mContext.buildMock.isDebuggable = false;
+
+        assertTrue(dpms.hasUserSetupCompleted());
+
+        dpm.forceUpdateUserSetupComplete();
+
+        // THEN the state in dpms is not changed
+        assertTrue(dpms.hasUserSetupCompleted());
+    }
+
+    public void testForceUpdateUserSetupComplete_userDebugbuild() {
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        final int userId = UserHandle.USER_SYSTEM;
+        // GIVEN userComplete is false in SettingsProvider
+        setUserSetupCompleteForUser(false, userId);
+
+        // GIVEN userComplete is true in DPM
+        DevicePolicyManagerService.DevicePolicyData userData =
+                new DevicePolicyManagerService.DevicePolicyData(userId);
+        userData.mUserSetupComplete = true;
+        dpms.mUserData.put(UserHandle.USER_SYSTEM, userData);
+
+        // GIVEN it's userdebug build
+        mContext.buildMock.isDebuggable = true;
+
+        assertTrue(dpms.hasUserSetupCompleted());
+
+        dpm.forceUpdateUserSetupComplete();
+
+        // THEN the state in dpms is not changed
+        assertFalse(dpms.hasUserSetupCompleted());
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 0783afc..37430ad 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -132,6 +132,10 @@
         }
     }
 
+    public static class BuildMock {
+        public boolean isDebuggable = true;
+    }
+
     public static class PowerManagerForMock {
         public WakeLock newWakeLock(int levelAndFlags, String tag) {
             return null;
@@ -272,6 +276,8 @@
 
     private final ArrayList<UserInfo> mUserInfos = new ArrayList<>();
 
+    public final BuildMock buildMock = new BuildMock();
+
     public DpmMockContext(Context context, File dataDir) {
         realTestContext = context;
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index c80ca6c..b4b74b3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -131,7 +131,7 @@
 
         doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
                 eq(admin.getPackageName()),
-                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                anyInt(),
                 eq(UserHandle.getUserId(packageUid)));
 
         // Set up queryBroadcastReceivers().
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/notification/BuzzBeepBlinkTest.java b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index d51f2d8..5fe000a 100644
--- a/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -15,10 +15,20 @@
  */
 package com.android.server.notification;
 
+import com.android.server.lights.Light;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.Notification.Builder;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.app.NotificationChannel;
+import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -26,9 +36,11 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.StatusBarNotification;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.mockito.Mock;
@@ -45,11 +57,15 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-public class BuzzBeepBlinkTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BuzzBeepBlinkTest {
 
     @Mock AudioManager mAudioManager;
     @Mock Vibrator mVibrator;
     @Mock android.media.IRingtonePlayer mRingtonePlayer;
+    @Mock StatusBarManagerInternal mStatusBar;
+    @Mock Light mLight;
     @Mock Handler mHandler;
 
     private NotificationManagerService mService;
@@ -62,7 +78,16 @@
     private int mScore = 10;
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
 
-    @Override
+    private static final long[] CUSTOM_VIBRATION = new long[] {
+            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+    private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
+    private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
+    private static final int CUSTOM_LIGHT_ON = 10000;
+    private static final int CUSTOM_LIGHT_OFF = 10000;
+
+    @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
@@ -76,6 +101,9 @@
         mService.setVibrator(mVibrator);
         mService.setSystemReady(true);
         mService.setHandler(mHandler);
+        mService.setStatusBarManager(mStatusBar);
+        mService.setLights(mLight);
+        mService.setScreenOn(false);
         mService.setSystemNotificationSound("beep!");
     }
 
@@ -85,56 +113,85 @@
 
     private NotificationRecord getNoisyOtherNotification() {
         return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                true /* noisy */, true /* buzzy*/);
+                true /* noisy */, true /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getBeepyNotification() {
         return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/);
+                true /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getBeepyOnceNotification() {
         return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                true /* noisy */, false /* buzzy*/);
+                true /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getQuietNotification() {
         return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                false /* noisy */, false /* buzzy*/);
+                false /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getQuietOtherNotification() {
         return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                false /* noisy */, false /* buzzy*/);
+                false /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getQuietOnceNotification() {
         return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, false /* buzzy*/);
+                false /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getInsistentBeepyNotification() {
         return getNotificationRecord(mId, true /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/);
+                true /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getBuzzyNotification() {
         return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                false /* noisy */, true /* buzzy*/);
+                false /* noisy */, true /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getBuzzyOnceNotification() {
         return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, true /* buzzy*/);
+                false /* noisy */, true /* buzzy*/, false /* lights */);
     }
 
     private NotificationRecord getInsistentBuzzyNotification() {
         return getNotificationRecord(mId, true /* insistent */, false /* once */,
-                false /* noisy */, true /* buzzy*/);
+                false /* noisy */, true /* buzzy*/, false /* lights */);
+    }
+
+    private NotificationRecord getLightsNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, true /* buzzy*/, true /* lights */);
+    }
+
+    private NotificationRecord getCustomBuzzyOnceNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, true /* buzzy*/, false /* lights */,
+                false /* defaultVibration */, true /* defaultSound */, true /* defaultLights */);
+    }
+
+    private NotificationRecord getCustomBeepyNotification() {
+        return getNotificationRecord(mId, false /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/, false /* lights */,
+                true /* defaultVibration */, false /* defaultSound */, true /* defaultLights */);
+    }
+
+    private NotificationRecord getCustomLightsNotification() {
+        return getNotificationRecord(mId, false /* insistent */, true /* once */,
+                false /* noisy */, true /* buzzy*/, true /* lights */,
+                true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */);
     }
 
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
-            boolean noisy, boolean buzzy) {
+            boolean noisy, boolean buzzy, boolean lights) {
+        return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true, true);
+    }
+
+    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
+            boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
+            boolean defaultSound, boolean defaultLights) {
         final Builder builder = new Builder(getContext())
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -143,10 +200,25 @@
 
         int defaults = 0;
         if (noisy) {
-            defaults |= Notification.DEFAULT_SOUND;
+            if (defaultSound) {
+                defaults |= Notification.DEFAULT_SOUND;
+            } else {
+                builder.setSound(CUSTOM_SOUND);
+            }
         }
         if (buzzy) {
-            defaults |= Notification.DEFAULT_VIBRATE;
+            if (defaultVibration) {
+                defaults |= Notification.DEFAULT_VIBRATE;
+            } else {
+                builder.setVibrate(CUSTOM_VIBRATION);
+            }
+        }
+        if (lights) {
+            if (defaultLights) {
+                defaults |= Notification.DEFAULT_LIGHTS;
+            } else {
+                builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
+            }
         }
         builder.setDefaults(defaults);
 
@@ -156,7 +228,10 @@
         }
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid,
                 mScore, n, mUser, System.currentTimeMillis());
-        return new NotificationRecord(getContext(), sbn);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn,
+                new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "misc"));
+        mService.addNotification(r);
+        return r;
     }
 
     //
@@ -178,6 +253,11 @@
                 eq(false), (AudioAttributes) anyObject());
     }
 
+    private void verifyCustomBeep() throws RemoteException {
+        verify(mRingtonePlayer, times(1)).playAsync(eq(CUSTOM_SOUND), (UserHandle) anyObject(),
+                eq(false), (AudioAttributes) anyObject());
+    }
+
     private void verifyNeverStopAudio() throws RemoteException {
         verify(mRingtonePlayer, never()).stopAsync();
     }
@@ -201,6 +281,11 @@
                 eq(0), (AudioAttributes) anyObject());
     }
 
+    private void verifyCustomVibrate() {
+        verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), eq(CUSTOM_VIBRATION), eq(-1),
+                (AudioAttributes) anyObject());
+    }
+
     private void verifyStopVibrate() {
         verify(mVibrator, times(1)).cancel();
     }
@@ -209,7 +294,34 @@
         verify(mVibrator, never()).cancel();
     }
 
-    @SmallTest
+    private void verifyLights() {
+        verify(mStatusBar, times(1)).notificationLightPulse(anyInt(), anyInt(), anyInt());
+    }
+
+    private void verifyCustomLights() {
+        verify(mStatusBar, times(1)).notificationLightPulse(
+                eq(CUSTOM_LIGHT_COLOR), eq(CUSTOM_LIGHT_ON), eq(CUSTOM_LIGHT_OFF));
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    //
+    // Tests
+    //
+
+    @Test
+    public void testLights() throws Exception {
+        NotificationRecord r = getLightsNotification();
+        r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyLights();
+    }
+
+    @Test
     public void testBeep() throws Exception {
         NotificationRecord r = getBeepyNotification();
 
@@ -219,11 +331,42 @@
         verifyNeverVibrate();
     }
 
-    //
-    // Tests
-    //
+    @Test
+    public void testBeepFromChannel() throws Exception {
+        NotificationRecord r = getQuietNotification();
+        r.getChannel().setDefaultRingtone(Settings.System.DEFAULT_NOTIFICATION_URI);
+        r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
 
-    @SmallTest
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeepLooped();
+        verifyNeverVibrate();
+    }
+
+    @Test
+    public void testVibrateFromChannel() throws Exception {
+        NotificationRecord r = getQuietNotification();
+        r.getChannel().setVibration(true);
+        r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+        verifyVibrate();
+    }
+
+    @Test
+    public void testLightsFromChannel() throws Exception {
+        NotificationRecord r = getQuietNotification();
+        r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
+        r.getChannel().setLights(true);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyLights();
+    }
+
+    @Test
     public void testBeepInsistently() throws Exception {
         NotificationRecord r = getInsistentBeepyNotification();
 
@@ -232,7 +375,37 @@
         verifyBeep();
     }
 
-    @SmallTest
+    @Test
+    public void testChannelNoOverwriteCustomVibration() throws Exception {
+        NotificationRecord r = getCustomBuzzyOnceNotification();
+        r.getChannel().setVibration(true);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyCustomVibrate();
+    }
+
+    @Test
+    public void testChannelNoOverwriteCustomBeep() throws Exception {
+        NotificationRecord r = getCustomBeepyNotification();
+        r.getChannel().setDefaultRingtone(Settings.System.DEFAULT_RINGTONE_URI);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyCustomBeep();
+    }
+
+    @Test
+    public void testChannelNoOverwriteCustomLights() throws Exception {
+        NotificationRecord r = getCustomLightsNotification();
+        r.getChannel().setLights(true);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyCustomLights();
+    }
+
+    @Test
     public void testNoInterruptionForMin() throws Exception {
         NotificationRecord r = getBeepyNotification();
         r.setImportance(Ranking.IMPORTANCE_MIN, "foo");
@@ -243,7 +416,7 @@
         verifyNeverVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testNoInterruptionForIntercepted() throws Exception {
         NotificationRecord r = getBeepyNotification();
         r.setIntercepted(true);
@@ -254,7 +427,7 @@
         verifyNeverVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testBeepTwice() throws Exception {
         NotificationRecord r = getBeepyNotification();
 
@@ -268,7 +441,7 @@
         verifyBeepLooped();
     }
 
-    @SmallTest
+    @Test
     public void testHonorAlertOnlyOnceForBeep() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getBeepyOnceNotification();
@@ -283,7 +456,7 @@
         verifyNeverBeep();
     }
 
-    @SmallTest
+    @Test
     public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
         NotificationRecord r = getBeepyNotification();
 
@@ -294,7 +467,7 @@
         verifyNeverStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getBeepyOnceNotification();
@@ -306,7 +479,7 @@
         verifyNeverStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getQuietNotification();
@@ -323,7 +496,7 @@
         verifyNeverStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testQuietInterloperDoesNotCancelAudio() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord other = getQuietOtherNotification();
@@ -337,7 +510,7 @@
         verifyNeverStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testQuietUpdateCancelsAudio() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getQuietNotification();
@@ -352,7 +525,7 @@
         verifyStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testQuietOnceUpdateCancelsAudio() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getQuietOnceNotification();
@@ -367,7 +540,7 @@
         verifyStopAudio();
     }
 
-    @SmallTest
+    @Test
     public void testDemoteSoundToVibrate() throws Exception {
         NotificationRecord r = getBeepyNotification();
 
@@ -381,8 +554,8 @@
         verifyVibrate();
     }
 
-    @SmallTest
-    public void testDemotInsistenteSoundToVibrate() throws Exception {
+    @Test
+    public void testDemoteInsistenteSoundToVibrate() throws Exception {
         NotificationRecord r = getInsistentBeepyNotification();
 
         // the phone is quiet
@@ -394,7 +567,7 @@
         verifyVibrateLooped();
     }
 
-    @SmallTest
+    @Test
     public void testVibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
 
@@ -404,7 +577,7 @@
         verifyVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testInsistenteVibrate() throws Exception {
         NotificationRecord r = getInsistentBuzzyNotification();
 
@@ -412,7 +585,7 @@
         verifyVibrateLooped();
     }
 
-    @SmallTest
+    @Test
     public void testVibratTwice() throws Exception {
         NotificationRecord r = getBuzzyNotification();
 
@@ -426,7 +599,7 @@
         verifyVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testHonorAlertOnlyOnceForBuzz() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getBuzzyOnceNotification();
@@ -441,7 +614,7 @@
         verifyNeverVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
 
@@ -452,7 +625,7 @@
         verifyNeverStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getBuzzyOnceNotification();
@@ -464,7 +637,7 @@
         verifyNeverStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getQuietNotification();
@@ -481,7 +654,7 @@
         verifyNeverStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord other = getQuietOtherNotification();
@@ -495,7 +668,7 @@
         verifyNeverStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testQuietUpdateCancelsVibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getQuietNotification();
@@ -509,7 +682,7 @@
         verifyStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testQuietOnceUpdateCancelsvibrate() throws Exception {
         NotificationRecord r = getBuzzyNotification();
         NotificationRecord s = getQuietOnceNotification();
@@ -524,7 +697,7 @@
         verifyStopVibrate();
     }
 
-    @SmallTest
+    @Test
     public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
         NotificationRecord r = getBeepyNotification();
         NotificationRecord s = getQuietNotification();
diff --git a/services/tests/servicestests/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/servicestests/src/com/android/server/notification/ImportanceExtractorTest.java
new file mode 100644
index 0000000..3cbde1d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.notification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.app.NotificationManager;
+import android.app.NotificationChannel;
+import android.content.Context;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import static org.junit.Assert.assertEquals;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImportanceExtractorTest {
+
+    @Mock RankingConfig mConfig;
+
+    private String mPkg = "com.android.server.notification";
+    private int mId = 1001;
+    private int mOtherId = 1002;
+    private String mTag = null;
+    private int mUid = 1000;
+    private int mPid = 2000;
+    private int mScore = 10;
+    private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    private NotificationRecord getNotificationRecord(NotificationChannel channel) {
+        final Builder builder = new Builder(getContext())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setDefaults(Notification.DEFAULT_SOUND);
+
+        Notification n = builder.build();
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+                mPid, mScore, n, mUser, System.currentTimeMillis());
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        return r;
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    //
+    // Tests
+    //
+
+    @Test
+    public void testAppPreferenceChannelNone() throws Exception {
+        ImportanceExtractor extractor = new ImportanceExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
+          NotificationManager.IMPORTANCE_MIN);
+        NotificationChannel channel = new NotificationChannel("a", "a");
+        channel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
+
+        NotificationRecord r = getNotificationRecord(channel);
+
+        extractor.process(r);
+
+        assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_MIN);
+    }
+
+    @Test
+    public void testAppPreferenceChannelPermissive() throws Exception {
+        ImportanceExtractor extractor = new ImportanceExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
+          NotificationManager.IMPORTANCE_MIN);
+        NotificationChannel channel = new NotificationChannel("a", "a");
+        channel.setImportance(NotificationManager.IMPORTANCE_HIGH);
+
+        NotificationRecord r = getNotificationRecord(channel);
+
+        extractor.process(r);
+
+        assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_MIN);
+    }
+
+    @Test
+    public void testAppPreferenceChannelStrict() throws Exception {
+        ImportanceExtractor extractor = new ImportanceExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
+          NotificationManager.IMPORTANCE_HIGH);
+        NotificationChannel channel = new NotificationChannel("a", "a");
+        channel.setImportance(NotificationManager.IMPORTANCE_MIN);
+
+        NotificationRecord r = getNotificationRecord(channel);
+
+        extractor.process(r);
+
+        assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_MIN);
+    }
+
+    @Test
+    public void testNoAppPreferenceChannelPreference() throws Exception {
+        ImportanceExtractor extractor = new ImportanceExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
+          NotificationManager.IMPORTANCE_UNSPECIFIED);
+        NotificationChannel channel = new NotificationChannel("a", "a");
+        channel.setImportance(NotificationManager.IMPORTANCE_MIN);
+
+        NotificationRecord r = getNotificationRecord(channel);
+
+        extractor.process(r);
+
+        assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_MIN);
+    }
+
+    @Test
+    public void testNoPreferences() throws Exception {
+        ImportanceExtractor extractor = new ImportanceExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
+          NotificationManager.IMPORTANCE_UNSPECIFIED);
+        NotificationChannel channel = new NotificationChannel("a", "a");
+        channel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
+
+        NotificationRecord r = getNotificationRecord(channel);
+
+        extractor.process(r);
+
+        assertEquals(r.getUserImportance(), 
+             NotificationManager.IMPORTANCE_UNSPECIFIED);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index 32501ad..ee33dcc 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -15,18 +15,41 @@
  */
 package com.android.server.notification;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.internal.util.FastXmlSerializer;
+
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
 
 import android.app.Notification;
+import android.content.Context;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.net.Uri;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 
-public class RankingHelperTest extends AndroidTestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RankingHelperTest {
     @Mock NotificationUsageStats mUsageStats;
     @Mock RankingHandler handler;
 
@@ -42,7 +65,11 @@
     private NotificationRecord mRecordNoGroupSortA;
     private RankingHelper mHelper;
 
-    @Override
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         UserHandle user = UserHandle.ALL;
@@ -57,7 +84,8 @@
                 .setWhen(1205)
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
+                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user), 
+                getDefaultChannel());
 
         mNotiGroupGSortB = new Notification.Builder(getContext())
                 .setContentTitle("B")
@@ -66,21 +94,24 @@
                 .setWhen(1200)
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
+                "package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user), 
+                getDefaultChannel());
 
         mNotiNoGroup = new Notification.Builder(getContext())
                 .setContentTitle("C")
                 .setWhen(1201)
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user), 
+                getDefaultChannel());
 
         mNotiNoGroup2 = new Notification.Builder(getContext())
                 .setContentTitle("D")
                 .setWhen(1202)
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user), 
+                getDefaultChannel());
 
         mNotiNoGroupSortA = new Notification.Builder(getContext())
                 .setContentTitle("E")
@@ -88,10 +119,15 @@
                 .setSortKey("A")
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
-                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
+                "package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user), 
+                getDefaultChannel());
     }
 
-    @SmallTest
+    private NotificationChannel getDefaultChannel() {
+        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name");
+    }    
+
+    @Test
     public void testFindAfterRankingWithASplitGroup() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
         notificationList.add(mRecordGroupGSortA);
@@ -105,7 +141,7 @@
         assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0);
     }
 
-    @SmallTest
+    @Test
     public void testSortShouldNotThrowWithPlainNotifications() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
         notificationList.add(mRecordNoGroup);
@@ -113,7 +149,7 @@
         mHelper.sort(notificationList);
     }
 
-    @SmallTest
+    @Test
     public void testSortShouldNotThrowOneSorted() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
         notificationList.add(mRecordNoGroup);
@@ -121,23 +157,64 @@
         mHelper.sort(notificationList);
     }
 
-    @SmallTest
+    @Test
     public void testSortShouldNotThrowOneNotification() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
         notificationList.add(mRecordNoGroup);
         mHelper.sort(notificationList);
     }
 
-    @SmallTest
+    @Test
     public void testSortShouldNotThrowOneSortKey() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
         notificationList.add(mRecordGroupGSortB);
         mHelper.sort(notificationList);
     }
 
-    @SmallTest
+    @Test
     public void testSortShouldNotThrowOnEmptyList() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
         mHelper.sort(notificationList);
     }
+
+    @Test
+    public void testChannelXml() throws Exception {
+        String pkg = "com.android.server.notification";
+        int uid = 0;
+        NotificationChannel channel1 = new NotificationChannel("id1", "name1");
+        NotificationChannel channel2 = new NotificationChannel("id2", "name2");
+        channel2.setImportance(NotificationManager.IMPORTANCE_LOW);
+        channel2.setDefaultRingtone(new Uri.Builder().scheme("test").build());
+        channel2.setLights(true);
+        channel2.setBypassDnd(true);
+        channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+
+        mHelper.createNotificationChannel(pkg, uid, channel1);
+        mHelper.createNotificationChannel(pkg, uid, channel2);
+
+        byte[] data;
+        XmlSerializer serializer = new FastXmlSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        serializer.startDocument(null, true);
+        serializer.startTag(null, "ranking");
+        mHelper.writeXml(serializer, false);
+        serializer.endTag(null, "ranking");
+        serializer.endDocument();
+        serializer.flush();
+
+        mHelper.deleteNotificationChannel(pkg, uid, channel1.getId());
+        mHelper.deleteNotificationChannel(pkg, uid, channel2.getId());
+        mHelper.deleteNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
+        parser.nextTag();
+        mHelper.readXml(parser, false);
+
+        assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId()));
+        assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
+        assertNotNull(
+                mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
index 3278cf1..07f3162 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -15,27 +15,34 @@
  */
 package com.android.server.notification;
 
-
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class RateEstimatorTest extends AndroidTestCase {
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RateEstimatorTest {
     private long mTestStartTime;
     private RateEstimator mEstimator;
 
-    @Override
+    @Before
     public void setUp() {
         mTestStartTime = 1225731600000L;
         mEstimator = new RateEstimator();
     }
 
-    @SmallTest
+    @Test
     public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception {
         assertUpdateTime(mTestStartTime);
         assertUpdateTime(mTestStartTime - 1000L);
     }
 
-    @SmallTest
+    @Test
     public void testRunningTimeBackwardDoesntExplodeGet() throws Exception {
         assertUpdateTime(mTestStartTime);
         final float rate = mEstimator.getRate(mTestStartTime - 1000L);
@@ -43,13 +50,13 @@
         assertFalse(Float.isNaN(rate));
     }
 
-    @SmallTest
+    @Test
     public void testInstantaneousEventsDontExplodeUpdate() throws Exception {
         assertUpdateTime(mTestStartTime);
         assertUpdateTime(mTestStartTime);
     }
 
-    @SmallTest
+    @Test
     public void testInstantaneousEventsDontExplodeGet() throws Exception {
         assertUpdateTime(mTestStartTime);
         assertUpdateTime(mTestStartTime);
@@ -58,7 +65,7 @@
         assertFalse(Float.isNaN(rate));
     }
 
-    @SmallTest
+    @Test
     public void testInstantaneousBurstIsEstimatedUnderTwoPercent() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -67,7 +74,7 @@
         assertLessThan("Rate", rate, 20f);
     }
 
-    @SmallTest
+    @Test
     public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -76,7 +83,7 @@
         assertLessThan("Rate", rate, 20f);
     }
 
-    @SmallTest
+    @Test
     public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -85,7 +92,7 @@
         assertGreaterThan("Rate", rate, 900f);
     }
 
-    @SmallTest
+    @Test
     public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -95,7 +102,7 @@
         assertGreaterThan("Rate", rate, 90f);
     }
 
-    @SmallTest
+    @Test
     public void testRecoverQuicklyAfterSustainedBurst() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -104,7 +111,7 @@
         assertLessThan("Rate", rate, 2f);
     }
 
-    @SmallTest
+    @Test
     public void testEstimateShouldNotOvershoot() throws Exception {
         assertUpdateTime(mTestStartTime);
         long eventStart = mTestStartTime + 1000; // start event a long time after initialization
@@ -113,13 +120,13 @@
         assertLessThan("Rate", rate, 1000f);
     }
 
-    @SmallTest
+    @Test
     public void testGetRateWithoutUpdate() throws Exception {
         final float rate = mEstimator.getRate(mTestStartTime);
         assertLessThan("Rate", rate, 0.1f);
     }
 
-    @SmallTest
+    @Test
     public void testGetRateWithOneUpdate() throws Exception {
         assertUpdateTime(mTestStartTime);
         final float rate = mEstimator.getRate(mTestStartTime+1);
diff --git a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index a6fdee9..d09b858 100644
--- a/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -17,23 +17,31 @@
 
 import android.app.Notification;
 import android.os.Bundle;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableString;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 
-public class ValidateNotificationPeopleTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @SmallTest
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertEquals;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ValidateNotificationPeopleTest {
+
+    @Test
     public void testNoExtra() throws Exception {
         Bundle bundle = new Bundle();
         String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
         assertNull("lack of extra should return null", result);
     }
 
-    @SmallTest
+    @Test
     public void testSingleString() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
@@ -42,7 +50,7 @@
         assertStringArrayEquals("string should be in result[0]", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testSingleCharArray() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
@@ -51,7 +59,7 @@
         assertStringArrayEquals("char[] should be in result[0]", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testSingleCharSequence() throws Exception {
         String[] expected = { "foobar" };
         Bundle bundle = new Bundle();
@@ -60,7 +68,7 @@
         assertStringArrayEquals("charSequence should be in result[0]", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testStringArraySingle() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foobar" };
@@ -69,7 +77,7 @@
         assertStringArrayEquals("wrapped string should be in result[0]", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testStringArrayMultiple() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", "bar", "baz" };
@@ -78,7 +86,7 @@
         assertStringArrayEquals("testStringArrayMultiple", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testStringArrayNulls() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", null, "baz" };
@@ -87,7 +95,7 @@
         assertStringArrayEquals("testStringArrayNulls", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceArrayMultiple() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", "bar", "baz" };
@@ -100,7 +108,7 @@
         assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testMixedCharSequenceArrayList() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", "bar", "baz" };
@@ -117,7 +125,7 @@
         assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testStringArrayList() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", null, "baz" };
@@ -130,7 +138,7 @@
         assertStringArrayEquals("testStringArrayList", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceArrayList() throws Exception {
         Bundle bundle = new Bundle();
         String[] expected = { "foo", "bar", "baz" };
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/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 09bd12c..53c6a33 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -25,10 +25,13 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
@@ -64,6 +67,8 @@
 import java.io.PrintStream;
 import java.security.PublicKey;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
@@ -180,6 +185,10 @@
 
     private static final String PACKAGE_NAME = "com.android.bar";
     private static final String REAL_PACKAGE_NAME = "com.android.foo";
+    private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent";
+    private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01";
+    private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02";
+    private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03";
     private static final File INITIAL_CODE_PATH =
             new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1");
     private static final File UPDATED_CODE_PATH =
@@ -187,20 +196,177 @@
     private static final int INITIAL_VERSION_CODE = 10023;
     private static final int UPDATED_VERSION_CODE = 10025;
 
-    /** Update existing package; don't install */
     @Test
-    public void testUpdatePackageSetting01()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting pkgSetting01 = createPackageSetting(0 /*pkgFlags*/);
-        final PackageSetting oldPkgSetting01 = new PackageSetting(pkgSetting01);
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                pkgSetting01,
+    public void testPackageStateCopy01() {
+        final List<String> childPackageNames = new ArrayList<>();
+        childPackageNames.add(CHILD_PACKAGE_NAME_01);
+        childPackageNames.add(CHILD_PACKAGE_NAME_02);
+        childPackageNames.add(CHILD_PACKAGE_NAME_03);
+        final PackageSetting origPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME,
-                null /*realPkgName*/,
-                null /*originalPkg*/,
+                REAL_PACKAGE_NAME,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPathString*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                null /*cpuAbiOverrideString*/,
+                INITIAL_VERSION_CODE,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
+                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
+                PARENT_PACKAGE_NAME,
+                childPackageNames,
+                0);
+        final PackageSetting testPkgSetting01 = new PackageSetting(origPkgSetting01);
+        verifySettingCopy(origPkgSetting01, testPkgSetting01);
+    }
+
+    @Test
+    public void testPackageStateCopy02() {
+        final List<String> childPackageNames = new ArrayList<>();
+        childPackageNames.add(CHILD_PACKAGE_NAME_01);
+        childPackageNames.add(CHILD_PACKAGE_NAME_02);
+        childPackageNames.add(CHILD_PACKAGE_NAME_03);
+        final PackageSetting origPkgSetting01 = new PackageSetting(
+                PACKAGE_NAME /*pkgName*/,
+                REAL_PACKAGE_NAME /*realPkgName*/,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPathString*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                null /*cpuAbiOverrideString*/,
+                INITIAL_VERSION_CODE,
+                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
+                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
+                PARENT_PACKAGE_NAME,
+                childPackageNames,
+                0);
+        final PackageSetting testPkgSetting01 = new PackageSetting(
+                PACKAGE_NAME /*pkgName*/,
+                REAL_PACKAGE_NAME /*realPkgName*/,
+                UPDATED_CODE_PATH /*codePath*/,
+                UPDATED_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPathString*/,
+                null /*primaryCpuAbiString*/,
+                null /*secondaryCpuAbiString*/,
+                null /*cpuAbiOverrideString*/,
+                UPDATED_VERSION_CODE,
+                0 /*pkgFlags*/,
+                0 /*pkgPrivateFlags*/,
+                null /*parentPkgName*/,
+                null /*childPkgNames*/,
+                0);
+        testPkgSetting01.copyFrom(origPkgSetting01);
+        verifySettingCopy(origPkgSetting01, testPkgSetting01);
+    }
+
+    /** Update package */
+    @Test
+    public void testUpdatePackageSetting01() throws PackageManagerException {
+        final PackageSetting testPkgSetting01 =
+                createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
+        testPkgSetting01.setInstalled(false /*installed*/, 0 /*userId*/);
+        assertThat(testPkgSetting01.pkgFlags, is(0));
+        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
+        final PackageSetting oldPkgSetting01 = new PackageSetting(testPkgSetting01);
+        Settings.updatePackageSetting(
+                testPkgSetting01,
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
+                null /*legacyNativeLibraryPath*/,
+                "arm64-v8a" /*primaryCpuAbi*/,
+                "armeabi" /*secondaryCpuAbi*/,
+                0 /*pkgFlags*/,
+                0 /*pkgPrivateFlags*/,
+                null /*childPkgNames*/,
+                UserManagerService.getInstance());
+        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
+        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
+        assertThat(testPkgSetting01.origPackage, is(nullValue()));
+        assertThat(testPkgSetting01.pkgFlags, is(0));
+        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        final PackageUserState oldUserState = oldPkgSetting01.readUserState(0);
+        verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/,
+                false /*stopped*/, false /*installed*/);
+    }
+
+    /** Update package; package now on /system, install for user '0' */
+    @Test
+    public void testUpdatePackageSetting02() throws PackageManagerException {
+        final PackageSetting testPkgSetting01 =
+                createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
+        testPkgSetting01.setInstalled(false /*installed*/, 0 /*userId*/);
+        assertThat(testPkgSetting01.pkgFlags, is(0));
+        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
+        final PackageSetting oldPkgSetting01 = new PackageSetting(testPkgSetting01);
+        Settings.updatePackageSetting(
+                testPkgSetting01,
+                null /*disabledPkg*/,
+                null /*sharedUser*/,
+                UPDATED_CODE_PATH /*codePath*/,
+                null /*legacyNativeLibraryPath*/,
+                "arm64-v8a" /*primaryCpuAbi*/,
+                "armeabi" /*secondaryCpuAbi*/,
+                ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
+                ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
+                null /*childPkgNames*/,
+                UserManagerService.getInstance());
+        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
+        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
+        assertThat(testPkgSetting01.origPackage, is(nullValue()));
+        assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
+        assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        final PackageUserState oldUserState = oldPkgSetting01.readUserState(0);
+        // WARNING: When creating a shallow copy of the PackageSetting we do NOT create
+        // new contained objects. For example, this means that changes to the user state
+        // in testPkgSetting01 will also change the user state in its copy.
+        verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/,
+                false /*stopped*/, true /*installed*/);
+    }
+
+    /** Update package; changing shared user throws exception */
+    @Test
+    public void testUpdatePackageSetting03() {
+        final Settings testSettings01 = new Settings(new Object() /*lock*/);
+        final SharedUserSetting testUserSetting01 = createSharedUserSetting(
+                testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
+        final PackageSetting testPkgSetting01 =
+                createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
+        try {
+            Settings.updatePackageSetting(
+                    testPkgSetting01,
+                    null /*disabledPkg*/,
+                    testUserSetting01 /*sharedUser*/,
+                    UPDATED_CODE_PATH /*codePath*/,
+                    null /*legacyNativeLibraryPath*/,
+                    "arm64-v8a" /*primaryCpuAbi*/,
+                    "armeabi" /*secondaryCpuAbi*/,
+                    0 /*pkgFlags*/,
+                    0 /*pkgPrivateFlags*/,
+                    null /*childPkgNames*/,
+                    UserManagerService.getInstance());
+            fail("Expected a PackageManagerException");
+        } catch (PackageManagerException expected) {
+        }
+    }
+
+    /** Create a new PackageSetting based on an original package setting */
+    @Test
+    public void testCreateNewSetting01() {
+        final PackageSetting originalPkgSetting01 =
+                createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
+        final PackageSignatures originalSignatures = originalPkgSetting01.signatures;
+        final PackageSetting testPkgSetting01 = Settings.createNewSetting(
+                REAL_PACKAGE_NAME,
+                originalPkgSetting01 /*originalPkg*/,
+                null /*disabledPkg*/,
+                null /*realPkgName*/,
+                null /*sharedUser*/,
+                UPDATED_CODE_PATH /*codePath*/,
                 UPDATED_CODE_PATH /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
@@ -213,36 +379,37 @@
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
                 UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(pkgSetting01));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
-        assertThat(testPkgSetting01.origPackage, is(nullValue()));
+        assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+        assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, oldUserState, false /*userStateChanged*/);
+        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
+        assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
+        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
+        assertSame(testPkgSetting01.origPackage, originalPkgSetting01);
+        // signatures object must be different
+        assertNotSame(testPkgSetting01.signatures, originalSignatures);
+        assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE));
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
+                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
-    /** Update existing package; install for UserHandle.SYSTEM */
+    /** Create a new non-system PackageSetting */
     @Test
-    public void testUpdatePackageSetting02()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting pkgSetting01 = createPackageSetting(0 /*pkgFlags*/);
-        final PackageSetting oldPkgSetting01 = new PackageSetting(pkgSetting01);
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                pkgSetting01,
+    public void testCreateNewSetting02() {
+        final PackageSetting testPkgSetting01 = Settings.createNewSetting(
                 PACKAGE_NAME,
-                null /*realPkgName*/,
                 null /*originalPkg*/,
                 null /*disabledPkg*/,
+                null /*realPkgName*/,
                 null /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                INITIAL_VERSION_CODE /*versionCode*/,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
                 UserHandle.SYSTEM /*installUser*/,
@@ -250,104 +417,74 @@
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
                 UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(pkgSetting01));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
+        assertThat(testPkgSetting01.appId, is(0));
+        assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+        assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.origPackage, is(nullValue()));
         assertThat(testPkgSetting01.pkgFlags, is(0));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        // The user state won't be changed in this scenario; the default user state is for
-        // the package to be installed.
-        verifyUserState(userState, oldUserState, false /*userStateChanged*/,
-                false /*notLaunched*/, false /*stopped*/);
-    }
-
-    /** Update existing package; install for {@code null} */
-    @Test
-    public void testUpdatePackageSetting03()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting pkgSetting01 = createPackageSetting(0 /*pkgFlags*/);
-        final PackageSetting oldPkgSetting01 = new PackageSetting(pkgSetting01);
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                pkgSetting01,
-                PACKAGE_NAME,
-                null /*realPkgName*/,
-                null /*originalPkg*/,
-                null /*disabledPkg*/,
-                null /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
-                null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
-                0 /*pkgFlags*/,
-                0 /*pkgPrivateFlags*/,
-                null /*installUser*/,
-                true /*allowInstall*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
-                UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(pkgSetting01));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
-        assertThat(testPkgSetting01.origPackage, is(nullValue()));
-        assertThat(testPkgSetting01.pkgFlags, is(0));
-        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, oldUserState, false /*userStateChanged*/);
-    }
-
-    /** Update renamed package */
-    @Test
-    public void testUpdatePackageSetting04()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting originalPkgSetting = createPackageSetting(0 /*pkgFlags*/);
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                null /*pkgSetting*/,
-                PACKAGE_NAME,
-                null /*realPkgName*/,
-                originalPkgSetting /*originalPkg*/,
-                null /*disabledPkg*/,
-                null /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
-                null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
-                0 /*pkgFlags*/,
-                0 /*pkgPrivateFlags*/,
-                UserHandle.SYSTEM /*installUser*/,
-                false /*allowInstall*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
-                UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(not(originalPkgSetting)));
-        // ABI isn't pulled from the original package setting
         assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
+        assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
         assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
-        assertThat(testPkgSetting01.origPackage, is(originalPkgSetting));
-        assertThat(testPkgSetting01.pkgFlags, is(0));
-        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, PackageSettingBase.DEFAULT_USER_STATE /*oldUserState*/,
-                false /*userStateChanged*/);
+        assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
+        // by default, the package is considered stopped
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
+                true /*notLaunched*/, true /*stopped*/, true /*installed*/);
     }
 
-    /** Update new package */
+    /** Create PackageSetting for a shared user */
     @Test
-    public void testUpdatePackageSetting05()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                null /*pkgSetting*/,
+    public void testCreateNewSetting03() {
+        final Settings testSettings01 = new Settings(new Object() /*lock*/);
+        final SharedUserSetting testUserSetting01 = createSharedUserSetting(
+                testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
+        final PackageSetting testPkgSetting01 = Settings.createNewSetting(
                 PACKAGE_NAME,
-                null /*realPkgName*/,
                 null /*originalPkg*/,
                 null /*disabledPkg*/,
+                null /*realPkgName*/,
+                testUserSetting01 /*sharedUser*/,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPath*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                INITIAL_VERSION_CODE /*versionCode*/,
+                0 /*pkgFlags*/,
+                0 /*pkgPrivateFlags*/,
+                null /*installUser*/,
+                false /*allowInstall*/,
+                null /*parentPkgName*/,
+                null /*childPkgNames*/,
+                UserManagerService.getInstance());
+        assertThat(testPkgSetting01.appId, is(10064));
+        assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+        assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
+        assertThat(testPkgSetting01.origPackage, is(nullValue()));
+        assertThat(testPkgSetting01.pkgFlags, is(0));
+        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
+        assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
+        assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
+        assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
+        assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
+                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
+    }
+
+    /** Create a new PackageSetting based on a disabled package setting */
+    @Test
+    public void testCreateNewSetting04() {
+        final PackageSetting disabledPkgSetting01 =
+                createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
+        disabledPkgSetting01.appId = 10064;
+        final PackageSignatures disabledSignatures = disabledPkgSetting01.signatures;
+        final PackageSetting testPkgSetting01 = Settings.createNewSetting(
+                PACKAGE_NAME,
+                null /*originalPkg*/,
+                disabledPkgSetting01 /*disabledPkg*/,
+                null /*realPkgName*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
                 UPDATED_CODE_PATH /*resourcePath*/,
@@ -362,144 +499,34 @@
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
                 UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(notNullValue()));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
+        assertThat(testPkgSetting01.appId, is(10064));
+        assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+        assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.origPackage, is(nullValue()));
         assertThat(testPkgSetting01.pkgFlags, is(0));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, PackageSettingBase.DEFAULT_USER_STATE /*oldUserState*/,
-                false /*userStateChanged*/);
-    }
-
-    /** Update new package; install for {@code null} user */
-    @Test
-    public void testUpdatePackageSetting06()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                null /*pkgSetting*/,
-                PACKAGE_NAME,
-                null /*realPkgName*/,
-                null /*originalPkg*/,
-                null /*disabledPkg*/,
-                null /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
-                null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
-                0 /*pkgFlags*/,
-                0 /*pkgPrivateFlags*/,
-                null /*installUser*/,
-                true /*allowInstall*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
-                UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(notNullValue()));
         assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
+        assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
         assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
-        assertThat(testPkgSetting01.origPackage, is(nullValue()));
-        assertThat(testPkgSetting01.pkgFlags, is(0));
-        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, PackageSettingBase.DEFAULT_USER_STATE /*oldUserState*/,
-                true /*userStateChanged*/, true /*notLaunched*/, true /*stopped*/);
-    }
-
-    /** Update new package; install for UserHandle.SYSTEM */
-    @Test
-    public void testUpdatePackageSetting07()
-            throws ReflectiveOperationException, PackageManagerException {
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                null /*pkgSetting*/,
-                PACKAGE_NAME,
-                null /*realPkgName*/,
-                null /*originalPkg*/,
-                null /*disabledPkg*/,
-                null /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
-                null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
-                0 /*pkgFlags*/,
-                0 /*pkgPrivateFlags*/,
-                UserHandle.SYSTEM /*installUser*/,
-                true /*allowInstall*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
-                UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(notNullValue()));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
-        assertThat(testPkgSetting01.origPackage, is(nullValue()));
-        assertThat(testPkgSetting01.pkgFlags, is(0));
-        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, PackageSettingBase.DEFAULT_USER_STATE /*oldUserState*/,
-                true /*userStateChanged*/, true /*notLaunched*/, true /*stopped*/);
-    }
-
-    /** Update package, but, shared user changed; ensure old setting not modified */
-    @Test
-    public void testUpdatePackageSetting08()
-            throws ReflectiveOperationException, PackageManagerException {
-        final SharedUserSetting testSharedUser =
-                new SharedUserSetting("testSharedUser", 0 /*pkgFlags*/, 0 /*_pkgPrivateFlags*/);
-        testSharedUser.userId = Process.FIRST_APPLICATION_UID + 9995;
-        final PackageSetting pkgSetting01 = createPackageSetting(0 /*pkgFlags*/);
-        final PackageSetting oldPkgSetting01 = new PackageSetting(pkgSetting01);
-        final PackageSetting testPkgSetting01 = Settings.updatePackageSetting(
-                pkgSetting01,
-                PACKAGE_NAME,
-                null /*realPkgName*/,
-                null /*originalPkg*/,
-                null /*disabledPkg*/,
-                testSharedUser /*sharedUser*/,
-                UPDATED_CODE_PATH /*codePath*/,
-                UPDATED_CODE_PATH /*resourcePath*/,
-                null /*legacyNativeLibraryPath*/,
-                "arm64-v8a" /*primaryCpuAbi*/,
-                "armeabi" /*secondaryCpuAbi*/,
-                UPDATED_VERSION_CODE /*versionCode*/,
-                0 /*pkgFlags*/,
-                0 /*pkgPrivateFlags*/,
-                UserHandle.SYSTEM /*installUser*/,
-                true /*allowInstall*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
-                UserManagerService.getInstance());
-        assertThat(testPkgSetting01, is(not(pkgSetting01)));
-        assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
-        assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
-        assertThat(testPkgSetting01.origPackage, is(nullValue()));
-        assertThat(testPkgSetting01.appId, is(19995));
-        assertThat(testPkgSetting01.pkgFlags, is(0));
-        assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
-        // package setting should not have been modified
-        assertThat(pkgSetting01.primaryCpuAbiString, is("x86_64"));
-        assertThat(pkgSetting01.secondaryCpuAbiString, is("x86"));
-        final PackageUserState userState = testPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(UserHandle.USER_SYSTEM);
-        verifyUserState(userState, oldUserState, true /*userStateChanged*/,
-                true /*notLaunched*/, true /*stopped*/);
+        assertNotSame(testPkgSetting01.signatures, disabledSignatures);
+        assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE));
+        final PackageUserState userState = testPkgSetting01.readUserState(0);
+        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
+                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
     private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
             boolean userStateChanged) {
         verifyUserState(userState, oldUserState, userStateChanged, false /*notLaunched*/,
-                false /*stopped*/);
+                false /*stopped*/, true /*installed*/);
     }
 
     private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
-            boolean userStateChanged, boolean notLaunched, boolean stopped) {
+            boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) {
         assertThat(userState.blockUninstall, is(false));
         assertThat(userState.enabled, is(0));
         assertThat(userState.hidden, is(false));
-        assertThat(userState.installed, is(true));
+        assertThat(userState.installed, is(installed));
         assertThat(userState.notLaunched, is(notLaunched));
         assertThat(userState.stopped, is(stopped));
         assertThat(userState.suspended, is(false));
@@ -508,7 +535,81 @@
         }
     }
 
-    private PackageSetting createPackageSetting(int pkgFlags) {
+    private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
+        assertThat(origPkgSetting, is(not(testPkgSetting)));
+        assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
+        // different but equal objects
+        assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames);
+        assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames));
+        assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
+        assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
+        assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
+        assertThat(origPkgSetting.codePathString, is(testPkgSetting.codePathString));
+        assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString);
+        assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString));
+        assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime));
+        assertSame(origPkgSetting.installerPackageName, testPkgSetting.installerPackageName);
+        assertThat(origPkgSetting.installerPackageName, is(testPkgSetting.installerPackageName));
+        assertThat(origPkgSetting.installPermissionsFixed,
+                is(testPkgSetting.installPermissionsFixed));
+        assertThat(origPkgSetting.installStatus, is(testPkgSetting.installStatus));
+        assertThat(origPkgSetting.isOrphaned, is(testPkgSetting.isOrphaned));
+        assertSame(origPkgSetting.keySetData, testPkgSetting.keySetData);
+        assertThat(origPkgSetting.keySetData, is(testPkgSetting.keySetData));
+        assertThat(origPkgSetting.lastUpdateTime, is(testPkgSetting.lastUpdateTime));
+        assertSame(origPkgSetting.legacyNativeLibraryPathString,
+                testPkgSetting.legacyNativeLibraryPathString);
+        assertThat(origPkgSetting.legacyNativeLibraryPathString,
+                is(testPkgSetting.legacyNativeLibraryPathString));
+        assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
+        assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
+        assertThat(origPkgSetting.name, is(testPkgSetting.name));
+        // oldCodePaths is _not_ copied
+        // assertNotSame(origPkgSetting.oldCodePaths, testPkgSetting.oldCodePaths);
+        // assertThat(origPkgSetting.oldCodePaths, is(not(testPkgSetting.oldCodePaths)));
+        assertSame(origPkgSetting.origPackage, testPkgSetting.origPackage);
+        assertThat(origPkgSetting.origPackage, is(testPkgSetting.origPackage));
+        assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
+        assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
+        assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
+        // No equals() method for this object
+        // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg));
+        assertThat(origPkgSetting.pkgFlags, is(testPkgSetting.pkgFlags));
+        assertThat(origPkgSetting.pkgPrivateFlags, is(testPkgSetting.pkgPrivateFlags));
+        assertSame(origPkgSetting.primaryCpuAbiString, testPkgSetting.primaryCpuAbiString);
+        assertThat(origPkgSetting.primaryCpuAbiString, is(testPkgSetting.primaryCpuAbiString));
+        assertThat(origPkgSetting.realName, is(testPkgSetting.realName));
+        assertSame(origPkgSetting.resourcePath, testPkgSetting.resourcePath);
+        assertThat(origPkgSetting.resourcePath, is(testPkgSetting.resourcePath));
+        assertSame(origPkgSetting.resourcePathString, testPkgSetting.resourcePathString);
+        assertThat(origPkgSetting.resourcePathString, is(testPkgSetting.resourcePathString));
+        assertSame(origPkgSetting.secondaryCpuAbiString, testPkgSetting.secondaryCpuAbiString);
+        assertThat(origPkgSetting.secondaryCpuAbiString, is(testPkgSetting.secondaryCpuAbiString));
+        assertSame(origPkgSetting.sharedUser, testPkgSetting.sharedUser);
+        assertThat(origPkgSetting.sharedUser, is(testPkgSetting.sharedUser));
+        assertSame(origPkgSetting.signatures, testPkgSetting.signatures);
+        assertThat(origPkgSetting.signatures, is(testPkgSetting.signatures));
+        assertThat(origPkgSetting.timeStamp, is(testPkgSetting.timeStamp));
+        assertThat(origPkgSetting.uidError, is(testPkgSetting.uidError));
+        assertNotSame(origPkgSetting.getUserState(), is(testPkgSetting.getUserState()));
+        // No equals() method for SparseArray object
+        // assertThat(origPkgSetting.getUserState(), is(testPkgSetting.getUserState()));
+        assertSame(origPkgSetting.verificationInfo, testPkgSetting.verificationInfo);
+        assertThat(origPkgSetting.verificationInfo, is(testPkgSetting.verificationInfo));
+        assertThat(origPkgSetting.versionCode, is(testPkgSetting.versionCode));
+        assertSame(origPkgSetting.volumeUuid, testPkgSetting.volumeUuid);
+        assertThat(origPkgSetting.volumeUuid, is(testPkgSetting.volumeUuid));
+    }
+
+    private SharedUserSetting createSharedUserSetting(Settings settings, String userName,
+            int sharedUserId, int pkgFlags, int pkgPrivateFlags) {
+        return settings.addSharedUserLPw(
+                userName,
+                sharedUserId,
+                pkgFlags,
+                pkgPrivateFlags);
+    }
+    private PackageSetting createPackageSetting(int sharedUserId, int pkgFlags) {
         return new PackageSetting(
                 PACKAGE_NAME,
                 REAL_PACKAGE_NAME,
@@ -523,7 +624,7 @@
                 0 /*privateFlags*/,
                 null /*parentPackageName*/,
                 null /*childPackageNames*/,
-                0 /*sharedUserId*/);
+                sharedUserId);
     }
 
     private @NonNull List<UserInfo> createFakeUsers() {
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..3cfdc32 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -3813,9 +3813,9 @@
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
         addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
 
-        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
+        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackageForTest(
                 mService, CALLING_PACKAGE_1, USER_0);
-        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
+        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackageForTest(
                 mService, CALLING_PACKAGE_2, USER_0);
 
         checkCanRestoreTo(true, spi1, 10, "sig1");
@@ -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");
@@ -5234,6 +5359,12 @@
     /**
      * It's the case with preintalled apps -- when applyRestore() is called, the system
      * apps are already installed, so manifest shortcuts need to be re-published.
+     *
+     * Also, when a restore target app is already installed, and
+     * - if it has allowBackup=true, we'll restore normally, so all existing shortcuts will be
+     * replaced. (but manifest shortcuts will be re-published anyway.)  We log a warning on
+     * logcat.
+     * - if it has allowBackup=false, we don't touch any of the existing shortcuts.
      */
     public void testBackupAndRestore_appAlreadyInstalledWhenRestored() {
         // Pre-backup.  Same as testBackupAndRestore_manifestRePublished().
@@ -5265,6 +5396,19 @@
         mService.mPackageMonitor.onReceive(mServiceContext,
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
 
+        // Set up shortcuts for package 3, which won't be backed up / restored.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_3, 1);
+        mService.mPackageMonitor.onReceive(mServiceContext,
+                genPackageAddIntent(CALLING_PACKAGE_3, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(getManager().setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+
         // Make sure the manifest shortcuts have been published.
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerShortcuts())
@@ -5290,6 +5434,11 @@
                     .areAllDisabled();
         });
 
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1", "ms1");
+        });
+
         // Backup and *without restarting the service, just call applyRestore()*.
         {
             int prevUid = mInjectedCallingUid;
@@ -5329,6 +5478,12 @@
                     .areAllNotDynamic()
             ;
         });
+
+        // Package 3 still has the same shortcuts.
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1", "ms1");
+        });
     }
 
     public void testSaveAndLoad_crossProfile() {
@@ -5506,6 +5661,32 @@
                                 buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
                     });
         });
+        // Check the user-IDs.
+        assertEquals(USER_0,
+                mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1)
+                        .getOwnerUserId());
+        assertEquals(USER_0,
+                mService.getUserShortcutsLocked(USER_0).getPackageShortcuts(CALLING_PACKAGE_1)
+                        .getPackageUserId());
+        assertEquals(USER_P0,
+                mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1)
+                        .getOwnerUserId());
+        assertEquals(USER_P0,
+                mService.getUserShortcutsLocked(USER_P0).getPackageShortcuts(CALLING_PACKAGE_1)
+                        .getPackageUserId());
+
+        assertEquals(USER_0,
+                mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0)
+                        .getOwnerUserId());
+        assertEquals(USER_0,
+                mService.getUserShortcutsLocked(USER_0).getLauncherShortcuts(LAUNCHER_1, USER_0)
+                        .getPackageUserId());
+        assertEquals(USER_P0,
+                mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0)
+                        .getOwnerUserId());
+        assertEquals(USER_0,
+                mService.getUserShortcutsLocked(USER_P0).getLauncherShortcuts(LAUNCHER_1, USER_0)
+                        .getPackageUserId());
     }
 
     public void testOnApplicationActive_permission() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
index 3c99174..25f9100 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
@@ -68,7 +68,7 @@
                     /* fdin*/ null,
                     /* fdout*/ fd.getFileDescriptor(),
                     /* fderr*/ fd.getFileDescriptor(),
-                        args, rr);
+                        args, null, rr);
             }
             return readAll(out);
         } finally {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java
new file mode 100644
index 0000000..35967fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceIdRecyclingTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.pm;
+
+import android.content.pm.UserInfo;
+import android.os.Looper;
+import android.os.UserManagerInternal;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.MediumTest;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.LinkedHashSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * <p>Run with:<pre>
+ * m FrameworksServicesTests &&
+ * adb install \
+ * -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ * adb shell am instrument -e class com.android.server.pm.UserManagerServiceIdRecyclingTest \
+ * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UserManagerServiceIdRecyclingTest {
+    private UserManagerService mUserManagerService;
+
+    @Before
+    public void setup() {
+        // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+        // TODO: Remove once UMS supports proper dependency injection
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+    }
+
+    @Test
+    public void testUserCreateRecycleIdsAddAllThenRemove() {
+        // Add max possible users
+        for (int i = UserManagerService.MIN_USER_ID; i < UserManagerService.MAX_USER_ID; i++) {
+            int userId = mUserManagerService.getNextAvailableId();
+            assertEquals(i, userId);
+            mUserManagerService.putUserInfo(newUserInfo(userId));
+        }
+
+        assertNoNextIdAvailable("All ids should be assigned");
+        // Now remove RECENTLY_REMOVED_IDS_MAX_SIZE users in the middle
+        int startFrom = UserManagerService.MIN_USER_ID + 10000 /* arbitrary number */;
+        int lastId = startFrom + UserManagerService.MAX_RECENTLY_REMOVED_IDS_SIZE;
+        for (int i = startFrom; i < lastId; i++) {
+            removeUser(i);
+            assertNoNextIdAvailable("There is not enough recently removed users. "
+                    + "Next id should not be available. Failed at u" + i);
+        }
+
+        // Now remove first user
+        removeUser(UserManagerService.MIN_USER_ID);
+
+        // Released UserIDs should be returned in the FIFO order
+        int nextId = mUserManagerService.getNextAvailableId();
+        assertEquals(startFrom, nextId);
+    }
+
+    @Test
+    public void testUserCreateRecycleIdsOverflow() {
+        LinkedHashSet<Integer> queue = new LinkedHashSet<>();
+        // Make sure we can generate more than 2x ids without issues
+        for (int i = 0; i < UserManagerService.MAX_USER_ID * 2; i++) {
+            int userId = mUserManagerService.getNextAvailableId();
+            assertTrue("Returned id should not be recent. Id=" + userId + ". Recents=" + queue,
+                    queue.add(userId));
+            if (queue.size() > UserManagerService.MAX_RECENTLY_REMOVED_IDS_SIZE) {
+                queue.remove(queue.iterator().next());
+            }
+            mUserManagerService.putUserInfo(newUserInfo(userId));
+            removeUser(userId);
+        }
+    }
+
+    private void removeUser(int userId) {
+        mUserManagerService.removeUserInfo(userId);
+        mUserManagerService.addRemovingUserIdLocked(userId);
+    }
+
+    private void assertNoNextIdAvailable(String message) {
+        try {
+            mUserManagerService.getNextAvailableId();
+            fail(message);
+        } catch (IllegalStateException e) {
+            //OK
+        }
+    }
+
+    private static UserInfo newUserInfo(int userId) {
+        return new UserInfo(userId, "User " + userId, 0);
+    }
+}
+
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..6a434ca 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -39,9 +39,11 @@
 
 /** Test {@link UserManager} functionality. */
 public class UserManagerTest extends AndroidTestCase {
+    // Taken from UserManagerService
+    private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // 30 years
+
     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();
@@ -205,18 +207,28 @@
     @MediumTest
     public void testGetUserCreationTime() throws Exception {
         final int primaryUserId = mUserManager.getPrimaryUser().id;
+        final long startTime = System.currentTimeMillis();
         UserInfo profile = createProfileForUser("Managed 1",
                 UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+        final long endTime = System.currentTimeMillis();
         assertNotNull(profile);
-        assertTrue("creationTime must be set when the profile is created",
-                profile.creationTime > 0);
+        if (System.currentTimeMillis() > EPOCH_PLUS_30_YEARS) {
+            assertTrue("creationTime must be set when the profile is created",
+                    profile.creationTime >= startTime && profile.creationTime <= endTime);
+        } else {
+            assertTrue("creationTime must be 0 if the time is not > EPOCH_PLUS_30_years",
+                    profile.creationTime == 0);
+        }
         assertEquals(profile.creationTime, mUserManager.getUserCreationTime(
                 new UserHandle(profile.id)));
 
         long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
         assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(
                 new UserHandle(primaryUserId)));
+    }
 
+    @SmallTest
+    public void testGetUserCreationTime_nonExistentUser() throws Exception {
         try {
             int noSuchUserId = 100500;
             mUserManager.getUserCreationTime(new UserHandle(noSuchUserId));
@@ -225,7 +237,10 @@
             assertTrue("SecurityException should be thrown for nonexistent user, but was: " + e,
                     e instanceof SecurityException);
         }
+    }
 
+    @SmallTest
+    public void testGetUserCreationTime_otherUser() throws Exception {
         UserInfo user = createUser("User 1", 0);
         try {
             mUserManager.getUserCreationTime(new UserHandle(user.id));
@@ -347,16 +362,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..e4473ad
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -0,0 +1,460 @@
+/*
+ * 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.net.wifi.WifiManager;
+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.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.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 WifiManager mWifiManager;
+    private @Mock LockPatternUtils mLockPatternUtils;
+    private MockPreloadAppsInstaller 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 MockPreloadAppsInstaller(mContext);
+        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() {
+        FileUtils.deleteContentsAndDir(mTestPreloadsDir);
+    }
+
+    @Test
+    public void testDemoUserSetup() throws Exception {
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+        mLatch = new CountDownLatch(1);
+        final UserInfo userInfo = new UserInfo();
+        userInfo.id = TEST_DEMO_USER;
+        when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo);
+
+        setCameraPackage(TEST_CAMERA_PKG);
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+        assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
+                "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
+
+        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));
+
+        // 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_disableDemoMode() throws Exception {
+        final RetailDemoModeService.SettingsObserver observer =
+                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
+        final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
+        when(mUm.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM))
+                .thenReturn(false);
+        Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1);
+        // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially.
+        observer.onChange(false, deviceDemoModeUri);
+        final ArgumentCaptor<BroadcastReceiver> receiver =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
+
+        Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+        new File(mTestPreloadsDir, "dir1").mkdirs();
+        new File(mTestPreloadsDir, "file1").createNewFile();
+        Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0);
+        observer.onChange(false, deviceDemoModeUri);
+        verify(mContext).unregisterReceiver(receiver.getValue());
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, false, UserHandle.SYSTEM);
+        assertEquals("Package verifier enable value has not been reset", 1,
+                Settings.Global.getInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE));
+        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 testSettingsObserver_enableDemoMode() 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));
+
+        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));
+    }
+
+    @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);
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+        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);
+        verify(mWifiManager).setWifiEnabled(true);
+    }
+
+    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 MockPreloadAppsInstaller extends PreloadAppsInstaller {
+        MockPreloadAppsInstaller(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void installApps(int userId) {
+        }
+    }
+
+    private class TestInjector extends Injector {
+        private ArrayMap<String, String> mSystemProperties = new ArrayMap<>();
+
+        TestInjector() {
+            super(mContext);
+        }
+
+        @Override
+        Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        UserManager getUserManager() {
+            return mUm;
+        }
+
+        @Override
+        WifiManager getWifiManager() {
+            return mWifiManager;
+        }
+
+        @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
+        void destroyWakeLock() {
+        }
+
+        @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;
+        }
+
+        @Override
+        void publishLocalService(RetailDemoModeService service,
+                RetailDemoModeServiceInternal localService) {
+        }
+
+        String systemPropertiesGet(String key) {
+            return mSystemProperties.get(key);
+        }
+    }
+}
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/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 3341a3a..7f171fb 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.util.Base64;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
@@ -39,7 +40,12 @@
 
 /**
  * Tests for WebViewUpdateService
+ runtest --path frameworks/base/services/tests/servicestests/ \
+     -c com.android.server.webkit.WebViewUpdateServiceTest
  */
+// Use MediumTest instead of SmallTest as the implementation of WebViewUpdateService
+// is intended to work on several threads and uses at least one sleep/wait-statement.
+@MediumTest
 public class WebViewUpdateServiceTest extends AndroidTestCase {
     private final static String TAG = WebViewUpdateServiceTest.class.getSimpleName();
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
new file mode 100644
index 0000000..27d9d10
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -0,0 +1,98 @@
+/*
+ * 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.wm;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Tests for the {@link WindowState} class.
+ *
+ * Build: mmma -j32 frameworks/base/services/tests/servicestests
+ * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -w -e class com.android.server.wm.AppWindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class AppWindowTokenTests {
+
+    private static WindowManagerService sWm = null;
+    private final IWindow mIWindow = new TestIWindow();
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+    }
+
+    @Test
+    public void testFindMainWindow() throws Exception {
+        final TestAppWindowToken token = new TestAppWindowToken();
+
+        assertNull(token.findMainWindow());
+
+        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token);
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        token.addWindow(window1);
+        assertEquals(window1, token.findMainWindow());
+        window1.mAnimatingExit = true;
+        assertEquals(window1, token.findMainWindow());
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token);
+        token.addWindow(window2);
+        assertEquals(window2, token.findMainWindow());
+    }
+
+    private WindowState createWindow(WindowState parent, int type, WindowToken token) {
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+
+        return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
+                sWm.getDefaultDisplayContentLocked(), 0);
+    }
+
+    /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
+    private class TestAppWindowToken extends AppWindowToken {
+
+        TestAppWindowToken() {
+            super(sWm, null, false);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 8c6b007..fee4783 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -82,6 +82,18 @@
 public class TestWindowManagerPolicy implements WindowManagerPolicy {
     private static final String TAG = "TestWindowManagerPolicy";
 
+    private static WindowManagerService sWm = null;
+
+    static synchronized WindowManagerService getWindowManagerService(Context context) {
+        if (sWm == null) {
+            // We only want to do this once for the test process as we don't want WM to try to
+            // register a bunch of local services again.
+            sWm = WindowManagerService.main(
+                    context, null, true, false, false, new TestWindowManagerPolicy());
+        }
+        return sWm;
+    }
+
     @Override
     public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
             throws RemoteException {
@@ -718,4 +730,14 @@
     public boolean shouldRotateSeamlessly(int oldRotation, int newRotation) {
         return false;
     }
+
+    @Override
+    public void setTvPipVisibilityLw(boolean visible) {
+
+    }
+
+    @Override
+    public void setRecentsVisibilityLw(boolean visible) {
+
+   }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index bd7c0b3..6eb347b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -16,37 +16,60 @@
 
 package com.android.server.wm;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.res.Configuration;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import java.util.Comparator;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  * Test class for {@link WindowContainer}.
  *
  * Build: mmma -j32 frameworks/base/services/tests/servicestests
- * Install: adb install -r out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
  * Run: adb shell am instrument -w -e class com.android.server.wm.WindowContainerTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class WindowContainerTests extends AndroidTestCase {
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowContainerTests {
 
+    @Test
     public void testCreation() throws Exception {
-        final TestWindowContainer w = new TestWindowContainer();
+        final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build();
         assertNull("window must have no parent", w.getParentWindow());
         assertEquals("window must have no children", 0, w.getChildrenCount());
     }
 
+    @Test
     public void testAdd() throws Exception {
-        final TestWindowContainer root = new TestWindowContainer();
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
 
-        final TestWindowContainer layer1 = root.addChildWindow(1);
-        final TestWindowContainer secondLayer1 = root.addChildWindow(1);
-        final TestWindowContainer layer2 = root.addChildWindow(2);
-        final TestWindowContainer layerNeg1 = root.addChildWindow(-1);
-        final TestWindowContainer layerNeg2 = root.addChildWindow(-2);
-        final TestWindowContainer secondLayerNeg1 = root.addChildWindow(-1);
-        final TestWindowContainer layer0 = root.addChildWindow(0);
+        final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
+        final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1));
+        final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2));
+        final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1));
+        final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2));
+        final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1));
+        final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0));
 
         assertEquals(7, root.getChildrenCount());
 
@@ -67,14 +90,41 @@
         assertEquals(layer2, root.getChildAt(6));
     }
 
-    public void testHasChild() throws Exception {
-        final TestWindowContainer root = new TestWindowContainer();
+    @Test
+    public void testAdd_AlreadyHasParent() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
 
-        final TestWindowContainer child1 = root.addChildWindow(1);
-        final TestWindowContainer child2 = root.addChildWindow(1);
-        final TestWindowContainer child11 = child1.addChildWindow(1);
-        final TestWindowContainer child12 = child1.addChildWindow(1);
-        final TestWindowContainer child21 = child2.addChildWindow(1);
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child2 = root.addChildWindow();
+
+        boolean gotException = false;
+        try {
+            child1.addChildWindow(child2);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+
+        gotException = false;
+        try {
+            root.addChildWindow(child2);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+    }
+
+    @Test
+    public void testHasChild() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child12 = child1.addChildWindow();
+        final TestWindowContainer child21 = child2.addChildWindow();
 
         assertEquals(2, root.getChildrenCount());
         assertEquals(2, child1.getChildrenCount());
@@ -93,24 +143,29 @@
         assertTrue(child2.hasChild(child21));
         assertFalse(child2.hasChild(child11));
         assertFalse(child2.hasChild(child12));
-   }
+    }
 
-    public void testRemove() throws Exception {
-        final TestWindowContainer root = new TestWindowContainer();
+    @Test
+    public void testRemoveImmediately() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
 
-        final TestWindowContainer child1 = root.addChildWindow(1);
-        final TestWindowContainer child2 = root.addChildWindow(1);
-        final TestWindowContainer child11 = child1.addChildWindow(1);
-        final TestWindowContainer child12 = child1.addChildWindow(1);
-        final TestWindowContainer child21 = child2.addChildWindow(1);
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child12 = child1.addChildWindow();
+        final TestWindowContainer child21 = child2.addChildWindow();
 
-        child12.remove();
+        assertNotNull(child12.getParentWindow());
+        child12.removeImmediately();
         assertNull(child12.getParentWindow());
         assertEquals(1, child1.getChildrenCount());
         assertFalse(child1.hasChild(child12));
         assertFalse(root.hasChild(child12));
 
-        child2.remove();
+        assertTrue(root.hasChild(child2));
+        assertNotNull(child2.getParentWindow());
+        child2.removeImmediately();
         assertNull(child2.getParentWindow());
         assertNull(child21.getParentWindow());
         assertEquals(0, child2.getChildrenCount());
@@ -121,36 +176,391 @@
         assertTrue(root.hasChild(child1));
         assertTrue(root.hasChild(child11));
 
-        root.remove();
+        root.removeImmediately();
         assertEquals(0, root.getChildrenCount());
     }
 
+    @Test
+    public void testIsAnimating() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+
+        final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
+        final TestWindowContainer child21 = child2.addChildWindow();
+
+        assertTrue(root.isAnimating());
+        assertTrue(child1.isAnimating());
+        assertFalse(child11.isAnimating());
+        assertTrue(child12.isAnimating());
+        assertFalse(child2.isAnimating());
+        assertFalse(child21.isAnimating());
+    }
+
+    @Test
+    public void testIsVisible() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+
+        final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true));
+        final TestWindowContainer child21 = child2.addChildWindow();
+
+        assertFalse(root.isVisible());
+        assertTrue(child1.isVisible());
+        assertFalse(child11.isVisible());
+        assertTrue(child12.isVisible());
+        assertFalse(child2.isVisible());
+        assertFalse(child21.isVisible());
+    }
+
+    @Test
+    public void testRemoveChild() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child21 = child2.addChildWindow();
+
+        assertTrue(root.hasChild(child2));
+        assertTrue(root.hasChild(child21));
+        root.removeChild(child2);
+        assertFalse(root.hasChild(child2));
+        assertFalse(root.hasChild(child21));
+        assertNull(child2.getParentWindow());
+
+        boolean gotException = false;
+        assertTrue(root.hasChild(child11));
+        try {
+            // Can only detach our direct children.
+            root.removeChild(child11);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue(gotException);
+    }
+
+    @Test
+    public void testGetOrientation_Unset() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+        // Unspecified well because we didn't specify anything...
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+    }
+
+    @Test
+    public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+        builder.setIsVisible(false).setLayer(-1);
+        final TestWindowContainer invisible = root.addChildWindow(builder);
+        builder.setIsVisible(true).setLayer(-2);
+        final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
+        invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        // Landscape well because the container is visible and that is what we set on it above.
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
+        // Unset because the container isn't visible even though it has a child that thinks it is
+        // visible.
+        assertEquals(SCREEN_ORIENTATION_UNSET, invisible.getOrientation());
+        // Unspecified because we are visible and we didn't specify an orientation and there isn't
+        // a visible child.
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+
+        builder.setIsVisible(true).setLayer(-3);
+        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
+        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+
+    }
+
+    @Test
+    public void testGetOrientation_setBehind() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+        builder.setIsVisible(true).setLayer(-1);
+        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
+
+        builder.setIsVisible(true).setLayer(-2);
+        final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
+                visibleUnset.addChildWindow(builder);
+        visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
+        // Setting to visible behind will be used by the parents if there isn't another other
+        // container behind this one that has an orientation set.
+        assertEquals(SCREEN_ORIENTATION_BEHIND,
+                visibleUnsetChild1VisibleSetBehind.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+    }
+
+    @Test
+    public void testGetOrientation_fillsParent() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+        builder.setIsVisible(true).setLayer(-1);
+        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+        visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
+
+        builder.setLayer(1).setIsVisible(true);
+        final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
+        visibleUnspecifiedRootChild.setFillsParent(false);
+        visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
+        // Unset because the child doesn't fill the parent. May as well be invisible...
+        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
+        // The parent uses whatever orientation is set behind this container since it doesn't fill
+        // the parent.
+        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+
+        // Test case of child filling its parent, but its parent isn't filling its own parent.
+        builder.setLayer(2).setIsVisible(true);
+        final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
+                visibleUnspecifiedRootChild.addChildWindow(builder);
+        visibleUnspecifiedRootChildChildFillsParent.setOrientation(
+                SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT,
+                visibleUnspecifiedRootChildChildFillsParent.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+
+
+        visibleUnspecifiedRootChild.setFillsParent(true);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
+    }
+
+    @Test
+    public void testCompareTo() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+        final TestWindowContainer root = builder.setLayer(0).build();
+
+        final TestWindowContainer child1 = root.addChildWindow();
+        final TestWindowContainer child11 = child1.addChildWindow();
+        final TestWindowContainer child12 = child1.addChildWindow();
+
+        final TestWindowContainer child2 = root.addChildWindow();
+        final TestWindowContainer child21 = child2.addChildWindow();
+        final TestWindowContainer child22 = child2.addChildWindow();
+        final TestWindowContainer child23 = child2.addChildWindow();
+        final TestWindowContainer child221 = child22.addChildWindow();
+        final TestWindowContainer child222 = child22.addChildWindow();
+        final TestWindowContainer child223 = child22.addChildWindow();
+        final TestWindowContainer child2221 = child222.addChildWindow();
+        final TestWindowContainer child2222 = child222.addChildWindow();
+        final TestWindowContainer child2223 = child222.addChildWindow();
+
+        final TestWindowContainer root2 = builder.setLayer(0).build();
+
+        assertEquals(0, root.compareTo(root));
+        assertEquals(-1, child1.compareTo(child2));
+        assertEquals(1, child2.compareTo(child1));
+
+        boolean inTheSameTree = true;
+        try {
+            root.compareTo(root2);
+        } catch (IllegalArgumentException e) {
+            inTheSameTree = false;
+        }
+        assertFalse(inTheSameTree);
+
+        assertEquals(-1, child1.compareTo(child11));
+        assertEquals(1, child21.compareTo(root));
+        assertEquals(1, child21.compareTo(child12));
+        assertEquals(-1, child11.compareTo(child2));
+        assertEquals(1, child2221.compareTo(child11));
+        assertEquals(-1, child2222.compareTo(child223));
+        assertEquals(1, child2223.compareTo(child21));
+    }
+
+    @Test
+    public void testConfigurationInit() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+        // Check root container initial config.
+        final TestWindowContainer root = builder.setLayer(0).build();
+        assertEquals(Configuration.EMPTY, root.getOverrideConfiguration());
+        assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration());
+        assertEquals(Configuration.EMPTY, root.getConfiguration());
+
+        // Check child initial config.
+        final TestWindowContainer child1 = root.addChildWindow();
+        assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration());
+        assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration());
+        assertEquals(Configuration.EMPTY, child1.getConfiguration());
+
+        // Check child initial config if root has overrides.
+        final Configuration rootOverrideConfig = new Configuration();
+        rootOverrideConfig.fontScale = 1.3f;
+        root.onOverrideConfigurationChanged(rootOverrideConfig);
+        final TestWindowContainer child2 = root.addChildWindow();
+        assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration());
+        assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration());
+        assertEquals(rootOverrideConfig, child2.getConfiguration());
+
+        // Check child initial config if root has parent config set.
+        final Configuration rootParentConfig = new Configuration();
+        rootParentConfig.fontScale = 0.8f;
+        rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+        root.onConfigurationChanged(rootParentConfig);
+        final Configuration rootFullConfig = new Configuration(rootParentConfig);
+        rootFullConfig.updateFrom(rootOverrideConfig);
+
+        final TestWindowContainer child3 = root.addChildWindow();
+        assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration());
+        assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration());
+        assertEquals(rootFullConfig, child3.getConfiguration());
+    }
+
+    @Test
+    public void testConfigurationChangeOnAddRemove() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+        // Init root's config.
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final Configuration rootOverrideConfig = new Configuration();
+        rootOverrideConfig.fontScale = 1.3f;
+        root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+        // Init child's config.
+        final TestWindowContainer child = root.addChildWindow();
+        final Configuration childOverrideConfig = new Configuration();
+        childOverrideConfig.densityDpi = 320;
+        child.onOverrideConfigurationChanged(childOverrideConfig);
+
+        // Check configuration update when child is removed from parent.
+        root.removeChild(child);
+        assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+        assertEquals(childOverrideConfig, child.getMergedOverrideConfiguration());
+        assertEquals(childOverrideConfig, child.getConfiguration());
+
+        // It may be paranoia... but let's check if parent's config didn't change after removal.
+        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+        assertEquals(rootOverrideConfig, root.getConfiguration());
+
+        // Check configuration update when child is added to parent.
+        final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration());
+        mergedOverrideConfig.updateFrom(childOverrideConfig);
+        root.addChildWindow(child);
+        assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+        assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
+        assertEquals(mergedOverrideConfig, child.getConfiguration());
+    }
+
+    @Test
+    public void testConfigurationChangePropagation() throws Exception {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+        // Builds 3-level vertical hierarchy with one window container on each level.
+        // In addition to different overrides on each level, everyone in hierarchy will have one
+        // common overridden value - orientation;
+
+        // Init root's config.
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final Configuration rootOverrideConfig = new Configuration();
+        rootOverrideConfig.fontScale = 1.3f;
+        rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+        root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+        // Init children.
+        final TestWindowContainer child1 = root.addChildWindow();
+        final Configuration childOverrideConfig1 = new Configuration();
+        childOverrideConfig1.densityDpi = 320;
+        childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+        child1.onOverrideConfigurationChanged(childOverrideConfig1);
+
+        final TestWindowContainer child2 = child1.addChildWindow();
+        final Configuration childOverrideConfig2 = new Configuration();
+        childOverrideConfig2.screenWidthDp = 150;
+        childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT;
+        child2.onOverrideConfigurationChanged(childOverrideConfig2);
+
+        // Check configuration on all levels when root override is updated.
+        rootOverrideConfig.smallestScreenWidthDp = 200;
+        root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+        final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig);
+        mergedOverrideConfig1.updateFrom(childOverrideConfig1);
+        final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1);
+
+        final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1);
+        mergedOverrideConfig2.updateFrom(childOverrideConfig2);
+        final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2);
+
+        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+        assertEquals(rootOverrideConfig, root.getConfiguration());
+
+        assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+        assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+        assertEquals(mergedConfig1, child1.getConfiguration());
+
+        assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+        assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+        assertEquals(mergedConfig2, child2.getConfiguration());
+
+        // Check configuration on all levels when root parent config is updated.
+        final Configuration rootParentConfig = new Configuration();
+        rootParentConfig.screenHeightDp = 100;
+        rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+        root.onConfigurationChanged(rootParentConfig);
+        final Configuration mergedRootConfig = new Configuration(rootParentConfig);
+        mergedRootConfig.updateFrom(rootOverrideConfig);
+
+        mergedConfig1.setTo(mergedRootConfig);
+        mergedConfig1.updateFrom(mergedOverrideConfig1);
+
+        mergedConfig2.setTo(mergedConfig1);
+        mergedConfig2.updateFrom(mergedOverrideConfig2);
+
+        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+        assertEquals(mergedRootConfig, root.getConfiguration());
+
+        assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+        assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+        assertEquals(mergedConfig1, child1.getConfiguration());
+
+        assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+        assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+        assertEquals(mergedConfig2, child2.getConfiguration());
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
-    private class TestWindowContainer extends WindowContainer {
+    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
+        private boolean mIsAnimating;
+        private boolean mIsVisible;
+        private boolean mFillsParent;
 
         /**
          * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
          * of z-order and 1 otherwise.
          */
-        private final Comparator<WindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
-            final int layer1 = ((TestWindowContainer)w1).mLayer;
-            final int layer2 = ((TestWindowContainer)w2).mLayer;
+        private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
+            final int layer1 = w1.mLayer;
+            final int layer2 = w2.mLayer;
             if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
-                // We insert the child window into the list ordered by the mLayer.
-                // For same layers, the negative one should go below others; the positive one should
-                // go above others.
+                // We insert the child window into the list ordered by the mLayer. For same layers,
+                // the negative one should go below others; the positive one should go above others.
                 return -1;
             }
             return 1;
         };
 
-        TestWindowContainer() {
-            mLayer = 0;
-        }
-
-        TestWindowContainer(int layer) {
+        TestWindowContainer(int layer, boolean isAnimating, boolean isVisible) {
             mLayer = layer;
+            mIsAnimating = isAnimating;
+            mIsVisible = isVisible;
+            mFillsParent = true;
         }
 
         TestWindowContainer getParentWindow() {
@@ -161,15 +571,78 @@
             return mChildren.size();
         }
 
-        TestWindowContainer addChildWindow(int layer) {
-            TestWindowContainer child = new TestWindowContainer(layer);
+        TestWindowContainer addChildWindow(TestWindowContainer child) {
             addChild(child, mWindowSubLayerComparator);
             return child;
         }
 
+        TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
+            TestWindowContainer child = childBuilder.build();
+            addChild(child, mWindowSubLayerComparator);
+            return child;
+        }
+
+        TestWindowContainer addChildWindow() {
+            return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
+        }
+
         TestWindowContainer getChildAt(int index) {
-            return (TestWindowContainer) mChildren.get(index);
+            return mChildren.get(index);
+        }
+
+        @Override
+        boolean isAnimating() {
+            return mIsAnimating || super.isAnimating();
+        }
+
+        @Override
+        boolean isVisible() {
+            return mIsVisible;
+        }
+
+        @Override
+        boolean fillsParent() {
+            return mFillsParent;
+        }
+
+        void setFillsParent(boolean fillsParent) {
+            mFillsParent = fillsParent;
         }
     }
 
+    private class TestWindowContainerBuilder {
+        private int mLayer;
+        private boolean mIsAnimating;
+        private boolean mIsVisible;
+
+        public TestWindowContainerBuilder() {
+            reset();
+        }
+
+        TestWindowContainerBuilder setLayer(int layer) {
+            mLayer = layer;
+            return this;
+        }
+
+        TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
+            mIsAnimating = isAnimating;
+            return this;
+        }
+
+        TestWindowContainerBuilder setIsVisible(boolean isVisible) {
+            mIsVisible = isVisible;
+            return this;
+        }
+
+        TestWindowContainerBuilder reset() {
+            mLayer = 0;
+            mIsAnimating = false;
+            mIsVisible = false;
+            return this;
+        }
+
+        TestWindowContainer build() {
+            return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 64de15d..1259e0f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -16,45 +16,52 @@
 
 package com.android.server.wm;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.IWindow;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Tests for the {@link WindowState} class.
  *
  * Build: mmma -j32 frameworks/base/services/tests/servicestests
- * Install: adb install -r out/target/product/angler/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
  * Run: adb shell am instrument -w -e class com.android.server.wm.WindowStateTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
 @SmallTest
-public class WindowStateTests extends AndroidTestCase {
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowStateTests {
 
     private static WindowManagerService sWm = null;
     private WindowToken mWindowToken;
-    private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
     private final IWindow mIWindow = new TestIWindow();
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        final Context context = getContext();
-//        final InputManagerService im = new InputManagerService(context);
-        if (sWm == null) {
-            // We only want to do this once for the test process as we don't want WM to try to
-            // register a bunch of local services again.
-            sWm = WindowManagerService.main(context, /*im*/ null, true, false, false, mPolicy);
-        }
-        mWindowToken = new WindowToken(sWm, null, 0, false);
+        final Context context = InstrumentationRegistry.getTargetContext();
+        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+        mWindowToken = new WindowToken(sWm, new Binder(), 0, false);
     }
 
+    @Test
     public void testIsParentWindowHidden() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -71,6 +78,7 @@
         assertTrue(child2.isParentWindowHidden());
     }
 
+    @Test
     public void testIsChildWindow() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -83,6 +91,7 @@
         assertFalse(randomWindow.isChildWindow());
     }
 
+    @Test
     public void testHasChild() throws Exception {
         final WindowState win1 = createWindow(null, TYPE_APPLICATION);
         final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW);
@@ -103,6 +112,7 @@
         assertFalse(win2.hasChild(randomWindow));
     }
 
+    @Test
     public void testGetBottomChild() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         assertNull(parentWindow.getBottomChild());
@@ -126,6 +136,7 @@
         assertEquals(child4, parentWindow.getBottomChild());
     }
 
+    @Test
     public void testGetParentWindow() throws Exception {
         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW);
@@ -136,6 +147,7 @@
         assertEquals(parentWindow, child2.getParentWindow());
     }
 
+    @Test
     public void testGetTopParentWindow() throws Exception {
         final WindowState root = createWindow(null, TYPE_APPLICATION);
         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
new file mode 100644
index 0000000..3279886
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -0,0 +1,179 @@
+/*
+ * 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.wm;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for the {@link WindowState} class.
+ *
+ * Build: mmma -j32 frameworks/base/services/tests/servicestests
+ * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -w -e class com.android.server.wm.WindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowTokenTests {
+
+    private WindowManagerService mWm = null;
+    private final IWindow mIWindow = new TestIWindow();
+
+    @Before
+    public void setUp() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
+    }
+
+    @Test
+    public void testAddWindow() throws Exception {
+        final TestWindowToken token = new TestWindowToken();
+
+        assertEquals(0, token.getWindowsCount());
+
+        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+
+        token.addWindow(window1);
+        // NOTE: Child windows will not be added to the token as window containers can only
+        // contain/reference their direct children.
+        token.addWindow(window11);
+        token.addWindow(window12);
+        token.addWindow(window2);
+        token.addWindow(window3);
+
+        // Should not contain the child windows that were added above.
+        assertEquals(3, token.getWindowsCount());
+        assertTrue(token.hasWindow(window1));
+        assertFalse(token.hasWindow(window11));
+        assertFalse(token.hasWindow(window12));
+        assertTrue(token.hasWindow(window2));
+        assertTrue(token.hasWindow(window3));
+    }
+
+    @Test
+    public void testAdjustAnimLayer() throws Exception {
+        final TestWindowToken token = new TestWindowToken();
+        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token);
+
+        token.addWindow(window1);
+        token.addWindow(window2);
+        token.addWindow(window3);
+
+        final int adj = 50;
+        final int window2StartLayer = window2.mLayer = 100;
+        final int window3StartLayer = window3.mLayer = 200;
+        final int highestLayer = token.adjustAnimLayer(adj);
+
+        assertEquals(adj, window1.mWinAnimator.mAnimLayer);
+        assertEquals(adj, window11.mWinAnimator.mAnimLayer);
+        assertEquals(adj, window12.mWinAnimator.mAnimLayer);
+        assertEquals(window2StartLayer + adj, window2.mWinAnimator.mAnimLayer);
+        assertEquals(window3StartLayer + adj, window3.mWinAnimator.mAnimLayer);
+        assertEquals(window3StartLayer + adj, highestLayer);
+    }
+
+    @Test
+    public void testGetTopWindow() throws Exception {
+        final TestWindowToken token = new TestWindowToken();
+
+        assertNull(token.getTopWindow());
+
+        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
+        token.addWindow(window1);
+        assertEquals(window1, token.getTopWindow());
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        assertEquals(window12, token.getTopWindow());
+
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+        token.addWindow(window2);
+        // Since new windows are added to the bottom of the token, we would still expect the
+        // previous one to the top.
+        assertEquals(window12, token.getTopWindow());
+    }
+
+    @Test
+    public void testGetWindowIndex() throws Exception {
+        final TestWindowToken token = new TestWindowToken();
+
+        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token);
+        assertEquals(-1, token.getWindowIndex(window1));
+        token.addWindow(window1);
+        assertEquals(0, token.getWindowIndex(window1));
+        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token);
+        // Child windows should report the same index as their parents.
+        assertEquals(0, token.getWindowIndex(window11));
+        assertEquals(0, token.getWindowIndex(window12));
+
+        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token);
+        assertEquals(-1, token.getWindowIndex(window2));
+        token.addWindow(window2);
+        // Since new windows are added to the bottom of the token, we would expect the added window
+        // to be at index 0.
+        assertEquals(0, token.getWindowIndex(window2));
+        assertEquals(1, token.getWindowIndex(window1));
+    }
+
+    private WindowState createWindow(WindowState parent, int type, WindowToken token) {
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+
+        return new WindowState(mWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
+                mWm.getDefaultDisplayContentLocked(), 0);
+    }
+
+    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
+    private class TestWindowToken extends WindowToken {
+
+        TestWindowToken() {
+            super(mWm, null, 0, false);
+        }
+
+        int getWindowsCount() {
+            return mChildren.size();
+        }
+
+        boolean hasWindow(WindowState w) {
+            return mChildren.contains(w);
+        }
+    }
+}
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
index 701e058..dc97599 100644
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -19,13 +19,13 @@
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_JAVA_LIBRARIES := \
     mockito-target
 
 LOCAL_MODULE_TAGS := optional
 
 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..04104b5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -94,7 +94,7 @@
 
     static final String TAG = "UsageStatsService";
 
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = false; // Never submit with true
     static final boolean COMPRESS_TIME = false;
 
     private static final long TEN_SECONDS = 10 * 1000;
@@ -139,8 +139,8 @@
     long mSystemTimeSnapshot;
 
     boolean mAppIdleEnabled;
-    boolean mAppIdleParoled;
-    private boolean mScreenOn;
+    boolean mAppIdleTempParoled;
+    boolean mCharging;
     private long mLastAppIdleParoledTime;
 
     private volatile boolean mPendingOneTimeCheckIdleStates;
@@ -191,7 +191,7 @@
         mAppIdleEnabled = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_enableAutoPowerModes);
         if (mAppIdleEnabled) {
-            IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
+            IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
             deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
             deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
             getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
@@ -237,7 +237,7 @@
 
             mSystemServicesReady = true;
         } else if (phase == PHASE_BOOT_COMPLETED) {
-            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
+            setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
         }
     }
 
@@ -284,9 +284,8 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (BatteryManager.ACTION_CHARGING.equals(action)
-                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
-                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
+            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+                setChargingState(intent.getIntExtra("plugged", 0) != 0);
             } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
                 onDeviceIdleModeChanged();
             }
@@ -304,9 +303,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());
                 }
             }
         }
@@ -376,12 +375,21 @@
         }
     }
 
+    void setChargingState(boolean charging) {
+        synchronized (mLock) {
+            if (mCharging != charging) {
+                mCharging = charging;
+                postParoleStateChanged();
+            }
+        }
+    }
+
     /** Paroled here means temporary pardon from being inactive */
     void setAppIdleParoled(boolean paroled) {
         synchronized (mLock) {
-            if (mAppIdleParoled != paroled) {
-                mAppIdleParoled = paroled;
-                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
+            if (mAppIdleTempParoled != paroled) {
+                mAppIdleTempParoled = paroled;
+                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
                 if (paroled) {
                     postParoleEndTimeout();
                 } else {
@@ -393,6 +401,12 @@
         }
     }
 
+    boolean isParoledOrCharging() {
+        synchronized (mLock) {
+            return mAppIdleTempParoled || mCharging;
+        }
+    }
+
     private void postNextParoleTimeout() {
         if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
         mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
@@ -495,7 +509,7 @@
     /** Check if it's been a while since last parole and let idle apps do some work */
     void checkParoleTimeout() {
         synchronized (mLock) {
-            if (!mAppIdleParoled) {
+            if (!mAppIdleTempParoled) {
                 final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
                 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
                     if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
@@ -786,7 +800,7 @@
     }
 
     boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime) {
-        if (mAppIdleParoled) {
+        if (isParoledOrCharging()) {
             return false;
         }
         return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
@@ -989,8 +1003,9 @@
     }
 
     void informParoleStateChanged() {
+        final boolean paroled = isParoledOrCharging();
         for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
-            listener.onParoleStateChanged(mAppIdleParoled);
+            listener.onParoleStateChanged(paroled);
         }
     }
 
@@ -1005,9 +1020,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);
     }
 
@@ -1072,9 +1087,9 @@
 
             pw.println();
             pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
-            pw.print(" mAppIdleParoled="); pw.print(mAppIdleParoled);
-            pw.print(" mScreenOn="); pw.println(mScreenOn);
-            pw.print("mLastAppIdleParoledTime=");
+            pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
+            pw.print(" mCharging="); pw.print(mCharging);
+            pw.print(" mLastAppIdleParoledTime=");
             TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
             pw.println();
         }
@@ -1139,7 +1154,8 @@
                     break;
 
                 case MSG_PAROLE_STATE_CHANGED:
-                    if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
+                    if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
+                            + ", Charging state:" + mCharging);
                     informParoleStateChanged();
                     break;
 
@@ -1466,7 +1482,7 @@
 
         @Override
         public boolean isAppIdleParoleOn() {
-            return mAppIdleParoled;
+            return isParoledOrCharging();
         }
 
         @Override
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index efd479f..220626a 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -137,7 +137,7 @@
     private final Context mContext;
     private final ContentResolver mContentResolver;
     @GuardedBy("mLock")
-    private UsbSettingsManager mCurrentSettings;
+    private UsbProfileGroupSettingsManager mCurrentSettings;
     private NotificationManager mNotificationManager;
     private final boolean mHasUsbAccessory;
     private boolean mUseUsbNotification;
@@ -150,6 +150,7 @@
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
     private final UsbAlsaManager mUsbAlsaManager;
+    private final UsbSettingsManager mSettingsManager;
     private Intent mBroadcastedIntent;
 
     private class AdbSettingsObserver extends ContentObserver {
@@ -192,9 +193,11 @@
         }
     };
 
-    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
+    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
+            UsbSettingsManager settingsManager) {
         mContext = context;
         mUsbAlsaManager = alsaManager;
+        mSettingsManager = settingsManager;
         mContentResolver = context.getContentResolver();
         PackageManager pm = mContext.getPackageManager();
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
@@ -218,7 +221,7 @@
                 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
     }
 
-    private UsbSettingsManager getCurrentSettings() {
+    private UsbProfileGroupSettingsManager getCurrentSettings() {
         synchronized (mLock) {
             return mCurrentSettings;
         }
@@ -255,10 +258,10 @@
         mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
     }
 
-    public void setCurrentUser(int userId, UsbSettingsManager settings) {
+    public void setCurrentUser(int newCurrentUserId, UsbProfileGroupSettingsManager settings) {
         synchronized (mLock) {
             mCurrentSettings = settings;
-            mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
+            mHandler.obtainMessage(MSG_USER_SWITCHED, newCurrentUserId, 0).sendToTarget();
         }
     }
 
@@ -584,7 +587,7 @@
 
                 if (mCurrentAccessory != null) {
                     if (mBootCompleted) {
-                        getCurrentSettings().accessoryDetached(mCurrentAccessory);
+                        mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
                     }
                     mCurrentAccessory = null;
                     mAccessoryStrings = null;
@@ -947,7 +950,7 @@
     }
 
     /* opens the currently attached USB accessory */
-    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+    public ParcelFileDescriptor openAccessory(UsbAccessory accessory, UsbUserSettingsManager settings) {
         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
         if (currentAccessory == null) {
             throw new IllegalArgumentException("no accessory attached");
@@ -958,7 +961,7 @@
                     + currentAccessory;
             throw new IllegalArgumentException(error);
         }
-        getCurrentSettings().checkPermission(accessory);
+        settings.checkPermission(accessory);
         return nativeOpenAccessory();
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 965341e..b789e17 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
@@ -24,13 +26,12 @@
 import android.hardware.usb.UsbInterface;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -59,29 +60,53 @@
     private ArrayList<UsbEndpoint> mNewEndpoints;
 
     private final UsbAlsaManager mUsbAlsaManager;
+    private final UsbSettingsManager mSettingsManager;
 
     @GuardedBy("mLock")
-    private UsbSettingsManager mCurrentSettings;
+    private UsbProfileGroupSettingsManager mCurrentSettings;
 
-    public UsbHostManager(Context context, UsbAlsaManager alsaManager) {
+    @GuardedBy("mLock")
+    private ComponentName mUsbDeviceConnectionHandler;
+
+    public UsbHostManager(Context context, UsbAlsaManager alsaManager,
+            UsbSettingsManager settingsManager) {
         mContext = context;
         mHostBlacklist = context.getResources().getStringArray(
                 com.android.internal.R.array.config_usbHostBlacklist);
         mUsbAlsaManager = alsaManager;
+        mSettingsManager = settingsManager;
+        String deviceConnectionHandler = context.getResources().getString(
+                com.android.internal.R.string.config_UsbDeviceConnectionHandling_component);
+        if (!TextUtils.isEmpty(deviceConnectionHandler)) {
+            setUsbDeviceConnectionHandler(ComponentName.unflattenFromString(
+                    deviceConnectionHandler));
+        }
     }
 
-    public void setCurrentSettings(UsbSettingsManager settings) {
+    public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) {
         synchronized (mLock) {
             mCurrentSettings = settings;
         }
     }
 
-    private UsbSettingsManager getCurrentSettings() {
+    private UsbProfileGroupSettingsManager getCurrentUserSettings() {
         synchronized (mLock) {
             return mCurrentSettings;
         }
     }
 
+    public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
+        synchronized (mLock) {
+            mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
+        }
+    }
+
+    private @Nullable ComponentName getUsbDeviceConnectionHandler() {
+        synchronized (mLock) {
+            return mUsbDeviceConnectionHandler;
+        }
+    }
+
     private boolean isBlackListed(String deviceName) {
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
@@ -219,10 +244,20 @@
         synchronized (mLock) {
             if (mNewDevice != null) {
                 mNewDevice.setConfigurations(
-                        mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()]));
+                        mNewConfigurations.toArray(
+                                new UsbConfiguration[mNewConfigurations.size()]));
                 mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
                 Slog.d(TAG, "Added device " + mNewDevice);
-                getCurrentSettings().deviceAttached(mNewDevice);
+
+                // It is fine to call this only for the current user as all broadcasts are sent to
+                // all profiles of the user and the dialogs should only show once.
+                ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
+                if (usbDeviceConnectionHandler == null) {
+                    getCurrentUserSettings().deviceAttached(mNewDevice);
+                } else {
+                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
+                            usbDeviceConnectionHandler);
+                }
                 mUsbAlsaManager.usbDeviceAdded(mNewDevice);
             } else {
                 Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
@@ -242,7 +277,8 @@
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
                 mUsbAlsaManager.usbDeviceRemoved(device);
-                getCurrentSettings().deviceDetached(device);
+                mSettingsManager.usbDeviceRemoved(device);
+                getCurrentUserSettings().usbDeviceRemoved(device);
             }
         }
     }
@@ -270,7 +306,7 @@
     }
 
     /* Opens the specified USB device */
-    public ParcelFileDescriptor openDevice(String deviceName) {
+    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {
         synchronized (mLock) {
             if (isBlackListed(deviceName)) {
                 throw new SecurityException("USB device is on a restricted bus");
@@ -281,7 +317,7 @@
                 throw new IllegalArgumentException(
                         "device " + deviceName + " does not exist or is restricted");
             }
-            getCurrentSettings().checkPermission(device);
+            settings.checkPermission(device);
             return nativeOpenDevice(deviceName);
         }
     }
@@ -292,6 +328,9 @@
             for (String name : mDevices.keySet()) {
                 pw.println("  " + name + ": " + mDevices.get(name));
             }
+            if (mUsbDeviceConnectionHandler != null) {
+                pw.println("Default USB Host Connection handler: " + mUsbDeviceConnectionHandler);
+            }
         }
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
new file mode 100644
index 0000000..cc0fb8d
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -0,0 +1,1300 @@
+/*
+ * 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.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.content.res.XmlResourceParser;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.Immutable;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import libcore.io.IoUtils;
+
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+
+class UsbProfileGroupSettingsManager {
+    private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    /** Legacy settings file, before multi-user */
+    private static final File sSingleUserSettingsFile = new File(
+            "/data/system/usb_device_manager.xml");
+
+    /** The parent user (main user of the profile group) */
+    private final UserHandle mParentUser;
+
+    private final AtomicFile mSettingsFile;
+    private final boolean mDisablePermissionDialogs;
+
+    private final Context mContext;
+
+    private final PackageManager mPackageManager;
+
+    private final UserManager mUserManager;
+    private final @NonNull UsbSettingsManager mSettingsManager;
+
+    // Maps DeviceFilter to user preferred application package
+    private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();
+    // Maps AccessoryFilter to user preferred application package
+    private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();
+
+    private final Object mLock = new Object();
+
+    /**
+     * A package of a user.
+     */
+    @Immutable
+    private static class UserPackage {
+        /** User */
+        final @NonNull UserHandle user;
+
+        /** Package name */
+        final @NonNull String packageName;
+
+        /**
+         * Create a description of a per user package.
+         *
+         * @param packageName The name of the package
+         * @param user The user
+         */
+        private UserPackage(@NonNull String packageName, @NonNull UserHandle user) {
+            this.packageName = packageName;
+            this.user = user;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof UserPackage)) {
+                return false;
+            } else {
+                UserPackage other = (UserPackage)obj;
+
+                return user.equals(user) && packageName.equals(other.packageName);
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            int result = user.hashCode();
+            result = 31 * result + packageName.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return user.getIdentifier() + "/" + packageName;
+        }
+    }
+
+    // This class is used to describe a USB device.
+    // When used in HashMaps all values must be specified,
+    // but wildcards can be used for any of the fields in
+    // the package meta-data.
+    private static class DeviceFilter {
+        // USB Vendor ID (or -1 for unspecified)
+        public final int mVendorId;
+        // USB Product ID (or -1 for unspecified)
+        public final int mProductId;
+        // USB device or interface class (or -1 for unspecified)
+        public final int mClass;
+        // USB device subclass (or -1 for unspecified)
+        public final int mSubclass;
+        // USB device protocol (or -1 for unspecified)
+        public final int mProtocol;
+        // USB device manufacturer name string (or null for unspecified)
+        public final String mManufacturerName;
+        // USB device product name string (or null for unspecified)
+        public final String mProductName;
+        // USB device serial number string (or null for unspecified)
+        public final String mSerialNumber;
+
+        public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
+                            String manufacturer, String product, String serialnum) {
+            mVendorId = vid;
+            mProductId = pid;
+            mClass = clasz;
+            mSubclass = subclass;
+            mProtocol = protocol;
+            mManufacturerName = manufacturer;
+            mProductName = product;
+            mSerialNumber = serialnum;
+        }
+
+        public DeviceFilter(UsbDevice device) {
+            mVendorId = device.getVendorId();
+            mProductId = device.getProductId();
+            mClass = device.getDeviceClass();
+            mSubclass = device.getDeviceSubclass();
+            mProtocol = device.getDeviceProtocol();
+            mManufacturerName = device.getManufacturerName();
+            mProductName = device.getProductName();
+            mSerialNumber = device.getSerialNumber();
+        }
+
+        public static DeviceFilter read(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            int vendorId = -1;
+            int productId = -1;
+            int deviceClass = -1;
+            int deviceSubclass = -1;
+            int deviceProtocol = -1;
+            String manufacturerName = null;
+            String productName = null;
+            String serialNumber = null;
+
+            int count = parser.getAttributeCount();
+            for (int i = 0; i < count; i++) {
+                String name = parser.getAttributeName(i);
+                String value = parser.getAttributeValue(i);
+                // Attribute values are ints or strings
+                if ("manufacturer-name".equals(name)) {
+                    manufacturerName = value;
+                } else if ("product-name".equals(name)) {
+                    productName = value;
+                } else if ("serial-number".equals(name)) {
+                    serialNumber = value;
+                } else {
+                    int intValue = -1;
+                    int radix = 10;
+                    if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
+                        (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
+                        // allow hex values starting with 0x or 0X
+                        radix = 16;
+                        value = value.substring(2);
+                    }
+                    try {
+                        intValue = Integer.parseInt(value, radix);
+                    } catch (NumberFormatException e) {
+                        Slog.e(TAG, "invalid number for field " + name, e);
+                        continue;
+                    }
+                    if ("vendor-id".equals(name)) {
+                        vendorId = intValue;
+                    } else if ("product-id".equals(name)) {
+                        productId = intValue;
+                    } else if ("class".equals(name)) {
+                        deviceClass = intValue;
+                    } else if ("subclass".equals(name)) {
+                        deviceSubclass = intValue;
+                    } else if ("protocol".equals(name)) {
+                        deviceProtocol = intValue;
+                    }
+                }
+            }
+            return new DeviceFilter(vendorId, productId,
+                    deviceClass, deviceSubclass, deviceProtocol,
+                    manufacturerName, productName, serialNumber);
+        }
+
+        public void write(XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, "usb-device");
+            if (mVendorId != -1) {
+                serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
+            }
+            if (mProductId != -1) {
+                serializer.attribute(null, "product-id", Integer.toString(mProductId));
+            }
+            if (mClass != -1) {
+                serializer.attribute(null, "class", Integer.toString(mClass));
+            }
+            if (mSubclass != -1) {
+                serializer.attribute(null, "subclass", Integer.toString(mSubclass));
+            }
+            if (mProtocol != -1) {
+                serializer.attribute(null, "protocol", Integer.toString(mProtocol));
+            }
+            if (mManufacturerName != null) {
+                serializer.attribute(null, "manufacturer-name", mManufacturerName);
+            }
+            if (mProductName != null) {
+                serializer.attribute(null, "product-name", mProductName);
+            }
+            if (mSerialNumber != null) {
+                serializer.attribute(null, "serial-number", mSerialNumber);
+            }
+            serializer.endTag(null, "usb-device");
+        }
+
+        private boolean matches(int clasz, int subclass, int protocol) {
+            return ((mClass == -1 || clasz == mClass) &&
+                    (mSubclass == -1 || subclass == mSubclass) &&
+                    (mProtocol == -1 || protocol == mProtocol));
+        }
+
+        public boolean matches(UsbDevice device) {
+            if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
+            if (mProductId != -1 && device.getProductId() != mProductId) return false;
+            if (mManufacturerName != null && device.getManufacturerName() == null) return false;
+            if (mProductName != null && device.getProductName() == null) return false;
+            if (mSerialNumber != null && device.getSerialNumber() == null) return false;
+            if (mManufacturerName != null && device.getManufacturerName() != null &&
+                !mManufacturerName.equals(device.getManufacturerName())) return false;
+            if (mProductName != null && device.getProductName() != null &&
+                !mProductName.equals(device.getProductName())) return false;
+            if (mSerialNumber != null && device.getSerialNumber() != null &&
+                !mSerialNumber.equals(device.getSerialNumber())) return false;
+
+            // check device class/subclass/protocol
+            if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
+                    device.getDeviceProtocol())) return true;
+
+            // if device doesn't match, check the interfaces
+            int count = device.getInterfaceCount();
+            for (int i = 0; i < count; i++) {
+                UsbInterface intf = device.getInterface(i);
+                 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
+                        intf.getInterfaceProtocol())) return true;
+            }
+
+            return false;
+        }
+
+        public boolean matches(DeviceFilter f) {
+            if (mVendorId != -1 && f.mVendorId != mVendorId) return false;
+            if (mProductId != -1 && f.mProductId != mProductId) return false;
+            if (f.mManufacturerName != null && mManufacturerName == null) return false;
+            if (f.mProductName != null && mProductName == null) return false;
+            if (f.mSerialNumber != null && mSerialNumber == null) return false;
+            if (mManufacturerName != null && f.mManufacturerName != null &&
+                !mManufacturerName.equals(f.mManufacturerName)) return false;
+            if (mProductName != null && f.mProductName != null &&
+                !mProductName.equals(f.mProductName)) return false;
+            if (mSerialNumber != null && f.mSerialNumber != null &&
+                !mSerialNumber.equals(f.mSerialNumber)) return false;
+
+            // check device class/subclass/protocol
+            return matches(f.mClass, f.mSubclass, f.mProtocol);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            // can't compare if we have wildcard strings
+            if (mVendorId == -1 || mProductId == -1 ||
+                    mClass == -1 || mSubclass == -1 || mProtocol == -1) {
+                return false;
+            }
+            if (obj instanceof DeviceFilter) {
+                DeviceFilter filter = (DeviceFilter)obj;
+
+                if (filter.mVendorId != mVendorId ||
+                        filter.mProductId != mProductId ||
+                        filter.mClass != mClass ||
+                        filter.mSubclass != mSubclass ||
+                        filter.mProtocol != mProtocol) {
+                    return(false);
+                }
+                if ((filter.mManufacturerName != null &&
+                        mManufacturerName == null) ||
+                    (filter.mManufacturerName == null &&
+                        mManufacturerName != null) ||
+                    (filter.mProductName != null &&
+                        mProductName == null)  ||
+                    (filter.mProductName == null &&
+                        mProductName != null) ||
+                    (filter.mSerialNumber != null &&
+                        mSerialNumber == null)  ||
+                    (filter.mSerialNumber == null &&
+                        mSerialNumber != null)) {
+                    return(false);
+                }
+                if  ((filter.mManufacturerName != null &&
+                        mManufacturerName != null &&
+                        !mManufacturerName.equals(filter.mManufacturerName)) ||
+                     (filter.mProductName != null &&
+                        mProductName != null &&
+                        !mProductName.equals(filter.mProductName)) ||
+                     (filter.mSerialNumber != null &&
+                        mSerialNumber != null &&
+                        !mSerialNumber.equals(filter.mSerialNumber))) {
+                    return(false);
+                }
+                return(true);
+            }
+            if (obj instanceof UsbDevice) {
+                UsbDevice device = (UsbDevice)obj;
+                if (device.getVendorId() != mVendorId ||
+                        device.getProductId() != mProductId ||
+                        device.getDeviceClass() != mClass ||
+                        device.getDeviceSubclass() != mSubclass ||
+                        device.getDeviceProtocol() != mProtocol) {
+                    return(false);
+                }
+                if ((mManufacturerName != null && device.getManufacturerName() == null) ||
+                        (mManufacturerName == null && device.getManufacturerName() != null) ||
+                        (mProductName != null && device.getProductName() == null) ||
+                        (mProductName == null && device.getProductName() != null) ||
+                        (mSerialNumber != null && device.getSerialNumber() == null) ||
+                        (mSerialNumber == null && device.getSerialNumber() != null)) {
+                    return(false);
+                }
+                if ((device.getManufacturerName() != null &&
+                        !mManufacturerName.equals(device.getManufacturerName())) ||
+                        (device.getProductName() != null &&
+                            !mProductName.equals(device.getProductName())) ||
+                        (device.getSerialNumber() != null &&
+                            !mSerialNumber.equals(device.getSerialNumber()))) {
+                    return(false);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return (((mVendorId << 16) | mProductId) ^
+                    ((mClass << 16) | (mSubclass << 8) | mProtocol));
+        }
+
+        @Override
+        public String toString() {
+            return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+                    ",mClass=" + mClass + ",mSubclass=" + mSubclass +
+                    ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
+                    ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
+                    "]";
+        }
+    }
+
+    // This class is used to describe a USB accessory.
+    // When used in HashMaps all values must be specified,
+    // but wildcards can be used for any of the fields in
+    // the package meta-data.
+    private static class AccessoryFilter {
+        // USB accessory manufacturer (or null for unspecified)
+        public final String mManufacturer;
+        // USB accessory model (or null for unspecified)
+        public final String mModel;
+        // USB accessory version (or null for unspecified)
+        public final String mVersion;
+
+        public AccessoryFilter(String manufacturer, String model, String version) {
+            mManufacturer = manufacturer;
+            mModel = model;
+            mVersion = version;
+        }
+
+        public AccessoryFilter(UsbAccessory accessory) {
+            mManufacturer = accessory.getManufacturer();
+            mModel = accessory.getModel();
+            mVersion = accessory.getVersion();
+        }
+
+        public static AccessoryFilter read(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            String manufacturer = null;
+            String model = null;
+            String version = null;
+
+            int count = parser.getAttributeCount();
+            for (int i = 0; i < count; i++) {
+                String name = parser.getAttributeName(i);
+                String value = parser.getAttributeValue(i);
+
+                if ("manufacturer".equals(name)) {
+                    manufacturer = value;
+                } else if ("model".equals(name)) {
+                    model = value;
+                } else if ("version".equals(name)) {
+                    version = value;
+                }
+             }
+             return new AccessoryFilter(manufacturer, model, version);
+        }
+
+        public void write(XmlSerializer serializer)throws IOException {
+            serializer.startTag(null, "usb-accessory");
+            if (mManufacturer != null) {
+                serializer.attribute(null, "manufacturer", mManufacturer);
+            }
+            if (mModel != null) {
+                serializer.attribute(null, "model", mModel);
+            }
+            if (mVersion != null) {
+                serializer.attribute(null, "version", mVersion);
+            }
+            serializer.endTag(null, "usb-accessory");
+        }
+
+        public boolean matches(UsbAccessory acc) {
+            if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
+            if (mModel != null && !acc.getModel().equals(mModel)) return false;
+            if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
+            return true;
+        }
+
+        public boolean matches(AccessoryFilter f) {
+            if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
+            if (mModel != null && !f.mModel.equals(mModel)) return false;
+            if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
+            return true;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            // can't compare if we have wildcard strings
+            if (mManufacturer == null || mModel == null || mVersion == null) {
+                return false;
+            }
+            if (obj instanceof AccessoryFilter) {
+                AccessoryFilter filter = (AccessoryFilter)obj;
+                return (mManufacturer.equals(filter.mManufacturer) &&
+                        mModel.equals(filter.mModel) &&
+                        mVersion.equals(filter.mVersion));
+            }
+            if (obj instanceof UsbAccessory) {
+                UsbAccessory accessory = (UsbAccessory)obj;
+                return (mManufacturer.equals(accessory.getManufacturer()) &&
+                        mModel.equals(accessory.getModel()) &&
+                        mVersion.equals(accessory.getVersion()));
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+                    (mModel == null ? 0 : mModel.hashCode()) ^
+                    (mVersion == null ? 0 : mVersion.hashCode()));
+        }
+
+        @Override
+        public String toString() {
+            return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
+                                "\", mModel=\"" + mModel +
+                                "\", mVersion=\"" + mVersion + "\"]";
+        }
+    }
+
+    private class MyPackageMonitor extends PackageMonitor {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            handlePackageUpdate(packageName);
+        }
+
+        @Override
+        public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            handlePackageUpdate(packageName);
+            return false;
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            clearDefaults(packageName, UserHandle.getUserHandleForUid(uid));
+        }
+    }
+
+    MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+
+    private final MtpNotificationManager mMtpNotificationManager;
+
+    /**
+     * Create new settings manager for a profile group.
+     *
+     * @param context The context of the service
+     * @param user The parent profile
+     * @param settingsManager The settings manager of the service
+     */
+    UsbProfileGroupSettingsManager(@NonNull Context context, @NonNull UserHandle user,
+            @NonNull UsbSettingsManager settingsManager) {
+        if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
+
+        Context parentUserContext;
+        try {
+            parentUserContext = context.createPackageContextAsUser("android", 0, user);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("Missing android package");
+        }
+
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mSettingsManager = settingsManager;
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+        mParentUser = user;
+        mSettingsFile = new AtomicFile(new File(
+                Environment.getUserSystemDirectory(user.getIdentifier()),
+                "usb_device_manager.xml"));
+
+        mDisablePermissionDialogs = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_disableUsbPermissionDialogs);
+
+        synchronized (mLock) {
+            if (UserHandle.SYSTEM.equals(user)) {
+                upgradeSingleUserLocked();
+            }
+            readSettingsLocked();
+        }
+
+        mPackageMonitor.register(context, null, true);
+        mMtpNotificationManager = new MtpNotificationManager(
+                parentUserContext,
+                new MtpNotificationManager.OnOpenInAppListener() {
+                    @Override
+                    public void onOpenInApp(UsbDevice device) {
+                        resolveActivity(createDeviceAttachedIntent(device), device);
+                    }
+                });
+    }
+
+    private void readPreference(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        String packageName = null;
+
+        // If not set, assume it to be the parent profile
+        UserHandle user = mParentUser;
+
+        int count = parser.getAttributeCount();
+        for (int i = 0; i < count; i++) {
+            if ("package".equals(parser.getAttributeName(i))) {
+                packageName = parser.getAttributeValue(i);
+            }
+            if ("user".equals(parser.getAttributeName(i))) {
+                // Might return null if user is not known anymore
+                user = mUserManager
+                        .getUserForSerialNumber(Integer.parseInt(parser.getAttributeValue(i)));
+            }
+        }
+
+        XmlUtils.nextElement(parser);
+        if ("usb-device".equals(parser.getName())) {
+            DeviceFilter filter = DeviceFilter.read(parser);
+            if (user != null) {
+                mDevicePreferenceMap.put(filter, new UserPackage(packageName, user));
+            }
+        } else if ("usb-accessory".equals(parser.getName())) {
+            AccessoryFilter filter = AccessoryFilter.read(parser);
+            if (user != null) {
+                mAccessoryPreferenceMap.put(filter, new UserPackage(packageName, user));
+            }
+        }
+        XmlUtils.nextElement(parser);
+    }
+
+    /**
+     * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
+     * Should only by called by owner.
+     */
+    private void upgradeSingleUserLocked() {
+        if (sSingleUserSettingsFile.exists()) {
+            mDevicePreferenceMap.clear();
+            mAccessoryPreferenceMap.clear();
+
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(sSingleUserSettingsFile);
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(fis, StandardCharsets.UTF_8.name());
+
+                XmlUtils.nextElement(parser);
+                while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                    final String tagName = parser.getName();
+                    if ("preference".equals(tagName)) {
+                        readPreference(parser);
+                    } else {
+                        XmlUtils.nextElement(parser);
+                    }
+                }
+            } catch (IOException e) {
+                Log.wtf(TAG, "Failed to read single-user settings", e);
+            } catch (XmlPullParserException e) {
+                Log.wtf(TAG, "Failed to read single-user settings", e);
+            } finally {
+                IoUtils.closeQuietly(fis);
+            }
+
+            writeSettingsLocked();
+
+            // Success or failure, we delete single-user file
+            sSingleUserSettingsFile.delete();
+        }
+    }
+
+    private void readSettingsLocked() {
+        if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
+
+        mDevicePreferenceMap.clear();
+        mAccessoryPreferenceMap.clear();
+
+        FileInputStream stream = null;
+        try {
+            stream = mSettingsFile.openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+            XmlUtils.nextElement(parser);
+            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                String tagName = parser.getName();
+                if ("preference".equals(tagName)) {
+                    readPreference(parser);
+                } else {
+                    XmlUtils.nextElement(parser);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            if (DEBUG) Slog.d(TAG, "settings file not found");
+        } catch (Exception e) {
+            Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
+            mSettingsFile.delete();
+        } finally {
+            IoUtils.closeQuietly(stream);
+        }
+    }
+
+    private void writeSettingsLocked() {
+        if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
+
+        FileOutputStream fos = null;
+        try {
+            fos = mSettingsFile.startWrite();
+
+            FastXmlSerializer serializer = new FastXmlSerializer();
+            serializer.setOutput(fos, StandardCharsets.UTF_8.name());
+            serializer.startDocument(null, true);
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+            serializer.startTag(null, "settings");
+
+            for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
+                serializer.startTag(null, "preference");
+                serializer.attribute(null, "package", mDevicePreferenceMap.get(filter).packageName);
+                serializer.attribute(null, "user",
+                        String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user)));
+                filter.write(serializer);
+                serializer.endTag(null, "preference");
+            }
+
+            for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+                serializer.startTag(null, "preference");
+                serializer.attribute(null, "package",
+                        mAccessoryPreferenceMap.get(filter).packageName);
+                serializer.attribute(null, "user",
+                        String.valueOf(getSerial(mAccessoryPreferenceMap.get(filter).user)));
+                filter.write(serializer);
+                serializer.endTag(null, "preference");
+            }
+
+            serializer.endTag(null, "settings");
+            serializer.endDocument();
+
+            mSettingsFile.finishWrite(fos);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write settings", e);
+            if (fos != null) {
+                mSettingsFile.failWrite(fos);
+            }
+        }
+    }
+
+    // Checks to see if a package matches a device or accessory.
+    // Only one of device and accessory should be non-null.
+    private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
+            UsbDevice device, UsbAccessory accessory) {
+        if (info.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+            return true;
+        }
+
+        ActivityInfo ai = info.activityInfo;
+
+        XmlResourceParser parser = null;
+        try {
+            parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
+            if (parser == null) {
+                Slog.w(TAG, "no meta-data for " + info);
+                return false;
+            }
+
+            XmlUtils.nextElement(parser);
+            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                String tagName = parser.getName();
+                if (device != null && "usb-device".equals(tagName)) {
+                    DeviceFilter filter = DeviceFilter.read(parser);
+                    if (filter.matches(device)) {
+                        return true;
+                    }
+                }
+                else if (accessory != null && "usb-accessory".equals(tagName)) {
+                    AccessoryFilter filter = AccessoryFilter.read(parser);
+                    if (filter.matches(accessory)) {
+                        return true;
+                    }
+                }
+                XmlUtils.nextElement(parser);
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to load component info " + info.toString(), e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        return false;
+    }
+
+    /**
+     * Resolve all activities that match an intent for all profiles of this group.
+     *
+     * @param intent The intent to resolve
+     *
+     * @return The {@link ResolveInfo}s for all profiles of the group
+     */
+    private @NonNull ArrayList<ResolveInfo> queryIntentActivitiesForAllProfiles(
+            @NonNull Intent intent) {
+        List<UserInfo> profiles = mUserManager.getEnabledProfiles(mParentUser.getIdentifier());
+
+        ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
+        int numProfiles = profiles.size();
+        for (int i = 0; i < numProfiles; i++) {
+            resolveInfos.addAll(mPackageManager.queryIntentActivitiesAsUser(intent,
+                    PackageManager.GET_META_DATA, profiles.get(i).id));
+        }
+
+        return resolveInfos;
+    }
+
+    private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
+        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+        List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
+        int count = resolveInfos.size();
+        for (int i = 0; i < count; i++) {
+            ResolveInfo resolveInfo = resolveInfos.get(i);
+            if (packageMatchesLocked(resolveInfo, intent.getAction(), device, null)) {
+                matches.add(resolveInfo);
+            }
+        }
+        return matches;
+    }
+
+    private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
+            UsbAccessory accessory, Intent intent) {
+        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+        List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
+        int count = resolveInfos.size();
+        for (int i = 0; i < count; i++) {
+            ResolveInfo resolveInfo = resolveInfos.get(i);
+            if (packageMatchesLocked(resolveInfo, intent.getAction(), null, accessory)) {
+                matches.add(resolveInfo);
+            }
+        }
+        return matches;
+    }
+
+    public void deviceAttached(UsbDevice device) {
+        final Intent intent = createDeviceAttachedIntent(device);
+
+        // Send broadcast to running activities with registered intent
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+
+        if (MtpNotificationManager.shouldShowNotification(mPackageManager, device)) {
+            // Show notification if the device is MTP storage.
+            mMtpNotificationManager.showNotification(device);
+        } else {
+            resolveActivity(intent, device);
+        }
+    }
+
+    private void resolveActivity(Intent intent, UsbDevice device) {
+        ArrayList<ResolveInfo> matches;
+        String defaultPackage = null;
+        UserHandle user = null;
+        synchronized (mLock) {
+            matches = getDeviceMatchesLocked(device, intent);
+            // Launch our default activity directly, if we have one.
+            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
+            UserPackage userPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
+            if (userPackage != null) {
+                defaultPackage = userPackage.packageName;
+                user = userPackage.user;
+            }
+        }
+
+        // Start activity with registered intent
+        resolveActivity(intent, matches, defaultPackage, user, device, null);
+    }
+
+    public void deviceAttachedForFixedHandler(UsbDevice device, ComponentName component) {
+        final Intent intent = createDeviceAttachedIntent(device);
+
+        // Send broadcast to running activity with registered intent
+        mContext.sendBroadcast(intent);
+
+        ApplicationInfo appInfo;
+        try {
+            appInfo = mPackageManager.getApplicationInfo(component.getPackageName(), 0);
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Default USB handling package not found: " + component.getPackageName());
+            return;
+        }
+
+        mSettingsManager.getSettingsForUser(UserHandle.getUserId(appInfo.uid))
+                .grantDevicePermission(device, appInfo.uid);
+
+        Intent activityIntent = new Intent(intent);
+        activityIntent.setComponent(component);
+        try {
+            mContext.startActivityAsUser(activityIntent, mParentUser);
+        } catch (ActivityNotFoundException e) {
+            Slog.e(TAG, "unable to start activity " + activityIntent);
+        }
+    }
+
+    /**
+     * Remove notifications for a usb device.
+     *
+     * @param device The device the notifications are for.
+     */
+    void usbDeviceRemoved(@NonNull UsbDevice device) {
+        mMtpNotificationManager.hideNotification(device.getDeviceId());
+    }
+
+    public void accessoryAttached(UsbAccessory accessory) {
+        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        ArrayList<ResolveInfo> matches;
+        String defaultPackage = null;
+        UserHandle user = null;
+        synchronized (mLock) {
+            matches = getAccessoryMatchesLocked(accessory, intent);
+            // Launch our default activity directly, if we have one.
+            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
+            UserPackage userPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
+            if (userPackage != null) {
+                defaultPackage = userPackage.packageName;
+                user = userPackage.user;
+            }
+        }
+
+        resolveActivity(intent, matches, defaultPackage, user, null, accessory);
+    }
+
+    /**
+     * Start the appropriate package when an device/accessory got attached.
+     *
+     * @param intent The intent to start the package
+     * @param matches The available resolutions of the intent
+     * @param defaultPackage The default package for the device (if set)
+     * @param defaultUser The user of the default package (if package is set)
+     * @param device The device if a device was attached
+     * @param accessory The accessory if a device was attached
+     */
+    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
+            @Nullable String defaultPackage, @Nullable UserHandle defaultUser,
+            @Nullable UsbDevice device, @Nullable UsbAccessory accessory) {
+        int count = matches.size();
+
+        // don't show the resolver activity if there are no choices available
+        if (count == 0) {
+            if (accessory != null) {
+                String uri = accessory.getUri();
+                if (uri != null && uri.length() > 0) {
+                    // display URI to user
+                    Intent dialogIntent = new Intent();
+                    dialogIntent.setClassName("com.android.systemui",
+                            "com.android.systemui.usb.UsbAccessoryUriActivity");
+                    dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+                    dialogIntent.putExtra("uri", uri);
+                    try {
+                        mContext.startActivityAsUser(dialogIntent, mParentUser);
+                    } catch (ActivityNotFoundException e) {
+                        Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
+                    }
+                }
+            }
+
+            // do nothing
+            return;
+        }
+
+        ResolveInfo defaultRI = null;
+        if (count == 1 && defaultPackage == null) {
+            // Check to see if our single choice is on the system partition.
+            // If so, treat it as our default without calling UsbResolverActivity
+            ResolveInfo rInfo = matches.get(0);
+            if (rInfo.activityInfo != null &&
+                    rInfo.activityInfo.applicationInfo != null &&
+                    (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                defaultRI = rInfo;
+            }
+
+            if (mDisablePermissionDialogs) {
+                // bypass dialog and launch the only matching activity
+                rInfo = matches.get(0);
+                if (rInfo.activityInfo != null) {
+                    defaultPackage = rInfo.activityInfo.packageName;
+                    defaultUser = UserHandle.getUserHandleForUid(
+                            rInfo.activityInfo.applicationInfo.uid);
+                }
+            }
+        }
+
+        if (defaultRI == null && defaultPackage != null) {
+            // look for default activity
+            for (int i = 0; i < count; i++) {
+                ResolveInfo rInfo = matches.get(i);
+                if (rInfo.activityInfo != null &&
+                        defaultPackage.equals(rInfo.activityInfo.packageName) &&
+                        defaultUser.getIdentifier() ==
+                                UserHandle.getUserId(rInfo.activityInfo.applicationInfo.uid)) {
+                    defaultRI = rInfo;
+                    break;
+                }
+            }
+        }
+
+        if (defaultRI != null) {
+            UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser(
+                    UserHandle.getUserId(defaultRI.activityInfo.applicationInfo.uid));
+            // grant permission for default activity
+            if (device != null) {
+                defaultRIUserSettings.
+                        grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
+            } else if (accessory != null) {
+                defaultRIUserSettings.grantAccessoryPermission(accessory,
+                                defaultRI.activityInfo.applicationInfo.uid);
+            }
+
+            // start default activity directly
+            try {
+                intent.setComponent(
+                        new ComponentName(defaultRI.activityInfo.packageName,
+                                defaultRI.activityInfo.name));
+
+                UserHandle user = UserHandle.getUserHandleForUid(
+                        defaultRI.activityInfo.applicationInfo.uid);
+                mContext.startActivityAsUser(intent, user);
+            } catch (ActivityNotFoundException e) {
+                Slog.e(TAG, "startActivity failed", e);
+            }
+        } else {
+            Intent resolverIntent = new Intent();
+            resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            UserHandle user;
+
+            if (count == 1) {
+                ResolveInfo rInfo = matches.get(0);
+
+                // start UsbConfirmActivity if there is only one choice
+                resolverIntent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbConfirmActivity");
+                resolverIntent.putExtra("rinfo", rInfo);
+                user = UserHandle.getUserHandleForUid(rInfo.activityInfo.applicationInfo.uid);
+
+                if (device != null) {
+                    resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
+                } else {
+                    resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+                }
+            } else {
+                user = mParentUser;
+
+                // start UsbResolverActivity so user can choose an activity
+                resolverIntent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbResolverActivity");
+                resolverIntent.putParcelableArrayListExtra("rlist", matches);
+                resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
+            }
+            try {
+                mContext.startActivityAsUser(resolverIntent, user);
+            } catch (ActivityNotFoundException e) {
+                Slog.e(TAG, "unable to start activity " + resolverIntent, e);
+            }
+        }
+    }
+
+    private boolean clearCompatibleMatchesLocked(String packageName, DeviceFilter filter) {
+        boolean changed = false;
+        for (DeviceFilter test : mDevicePreferenceMap.keySet()) {
+            if (filter.matches(test)) {
+                mDevicePreferenceMap.remove(test);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
+        boolean changed = false;
+        for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
+            if (filter.matches(test)) {
+                mAccessoryPreferenceMap.remove(test);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
+            String metaDataName) {
+        XmlResourceParser parser = null;
+        boolean changed = false;
+
+        try {
+            parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
+            if (parser == null) return false;
+
+            XmlUtils.nextElement(parser);
+            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                String tagName = parser.getName();
+                if ("usb-device".equals(tagName)) {
+                    DeviceFilter filter = DeviceFilter.read(parser);
+                    if (clearCompatibleMatchesLocked(packageName, filter)) {
+                        changed = true;
+                    }
+                }
+                else if ("usb-accessory".equals(tagName)) {
+                    AccessoryFilter filter = AccessoryFilter.read(parser);
+                    if (clearCompatibleMatchesLocked(packageName, filter)) {
+                        changed = true;
+                    }
+                }
+                XmlUtils.nextElement(parser);
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        return changed;
+    }
+
+    // Check to see if the package supports any USB devices or accessories.
+    // If so, clear any non-matching preferences for matching devices/accessories.
+    private void handlePackageUpdate(String packageName) {
+        synchronized (mLock) {
+            PackageInfo info;
+            boolean changed = false;
+
+            try {
+                info = mPackageManager.getPackageInfo(packageName,
+                        PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+            } catch (NameNotFoundException e) {
+                Slog.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+                return;
+            }
+
+            ActivityInfo[] activities = info.activities;
+            if (activities == null) return;
+            for (int i = 0; i < activities.length; i++) {
+                // check for meta-data, both for devices and accessories
+                if (handlePackageUpdateLocked(packageName, activities[i],
+                        UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+                    changed = true;
+                }
+                if (handlePackageUpdateLocked(packageName, activities[i],
+                        UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+                    changed = true;
+                }
+            }
+
+            if (changed) {
+                writeSettingsLocked();
+            }
+        }
+    }
+
+    /**
+     * Get the serial number for a user handle.
+     *
+     * @param user The user handle
+     *
+     * @return The serial number
+     */
+    private int getSerial(@NonNull UserHandle user) {
+        return mUserManager.getUserSerialNumber(user.getIdentifier());
+    }
+
+    /**
+     * Set a package as default handler for a device.
+     *
+     * @param device The device that should be handled by default
+     * @param packageName The default handler package
+     * @param user The user the package belongs to
+     */
+    void setDevicePackage(@NonNull UsbDevice device, @Nullable String packageName,
+            @Nullable UserHandle user) {
+        DeviceFilter filter = new DeviceFilter(device);
+        boolean changed = false;
+        synchronized (mLock) {
+            if (packageName == null) {
+                changed = (mDevicePreferenceMap.remove(filter) != null);
+            } else {
+                changed = !packageName.equals(mDevicePreferenceMap.get(filter));
+                if (changed) {
+                    mDevicePreferenceMap.put(filter, new UserPackage(packageName, user));
+                }
+            }
+            if (changed) {
+                writeSettingsLocked();
+            }
+        }
+    }
+
+    /**
+     * Set a package as default handler for a accessory.
+     *
+     * @param accessory The accessory that should be handled by default
+     * @param packageName The default handler package
+     * @param user The user the package belongs to
+     */
+    void setAccessoryPackage(@NonNull UsbAccessory accessory, @Nullable String packageName,
+            @Nullable UserHandle user) {
+        AccessoryFilter filter = new AccessoryFilter(accessory);
+        boolean changed = false;
+        synchronized (mLock) {
+            if (packageName == null) {
+                changed = (mAccessoryPreferenceMap.remove(filter) != null);
+            } else {
+                changed = !packageName.equals(mAccessoryPreferenceMap.get(filter));
+                if (changed) {
+                    mAccessoryPreferenceMap.put(filter, new UserPackage(packageName, user));
+                }
+            }
+            if (changed) {
+                writeSettingsLocked();
+            }
+        }
+    }
+
+    /**
+     * Check if a package has is the default handler for any usb device or accessory.
+     *
+     * @param packageName The package name
+     * @param user The user the package belongs to
+     *
+     * @return {@code true} iff the package is default for any usb device or accessory
+     */
+    boolean hasDefaults(@NonNull String packageName, @NonNull UserHandle user) {
+        UserPackage userPackage = new UserPackage(packageName, user);
+        synchronized (mLock) {
+            if (mDevicePreferenceMap.values().contains(userPackage)) return true;
+            if (mAccessoryPreferenceMap.values().contains(userPackage)) return true;
+            return false;
+        }
+    }
+
+    /**
+     * Clear defaults for a package from any preference.
+     *
+     * @param packageName The package to remove
+     * @param user The user the package belongs to
+     */
+    void clearDefaults(@NonNull String packageName, @NonNull UserHandle user) {
+        UserPackage userPackage = new UserPackage(packageName, user);
+
+        synchronized (mLock) {
+            if (clearPackageDefaultsLocked(userPackage)) {
+                writeSettingsLocked();
+            }
+        }
+    }
+
+    /**
+     * Clear defaults for a package from any preference (does not persist).
+     *
+     * @param userPackage The package to remove
+     *
+     * @return {@code true} iff at least one preference was cleared
+     */
+    private boolean clearPackageDefaultsLocked(@NonNull UserPackage userPackage) {
+        boolean cleared = false;
+        synchronized (mLock) {
+            if (mDevicePreferenceMap.containsValue(userPackage)) {
+                // make a copy of the key set to avoid ConcurrentModificationException
+                Object[] keys = mDevicePreferenceMap.keySet().toArray();
+                for (int i = 0; i < keys.length; i++) {
+                    Object key = keys[i];
+                    if (userPackage.equals(mDevicePreferenceMap.get(key))) {
+                        mDevicePreferenceMap.remove(key);
+                        cleared = true;
+                    }
+                }
+            }
+            if (mAccessoryPreferenceMap.containsValue(userPackage)) {
+                // make a copy of the key set to avoid ConcurrentModificationException
+                Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
+                for (int i = 0; i < keys.length; i++) {
+                    Object key = keys[i];
+                    if (userPackage.equals(mAccessoryPreferenceMap.get(key))) {
+                        mAccessoryPreferenceMap.remove(key);
+                        cleared = true;
+                    }
+                }
+            }
+            return cleared;
+        }
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            pw.println("Device preferences:");
+            for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
+                pw.println("  " + filter + ": " + mDevicePreferenceMap.get(filter));
+            }
+            pw.println("Accessory preferences:");
+            for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+                pw.println("  " + filter + ": " + mAccessoryPreferenceMap.get(filter));
+            }
+        }
+    }
+
+    private static Intent createDeviceAttachedIntent(UsbDevice device) {
+        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return intent;
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index d6dbe90..02c7214 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,9 +16,11 @@
 
 package com.android.server.usb;
 
+import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -35,7 +37,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -74,57 +75,65 @@
                 mUsbService.bootCompleted();
             }
         }
+
+        @Override
+        public void onSwitchUser(int newUserId) {
+            mUsbService.onSwitchUser(newUserId);
+        }
+
+        @Override
+        public void onStopUser(int userHandle) {
+            mUsbService.onStopUser(userHandle);
+        }
     }
 
     private static final String TAG = "UsbService";
 
     private final Context mContext;
+    private final UserManager mUserManager;
 
     private UsbDeviceManager mDeviceManager;
     private UsbHostManager mHostManager;
     private UsbPortManager mPortManager;
     private final UsbAlsaManager mAlsaManager;
 
+    private final UsbSettingsManager mSettingsManager;
+
+    /**
+     * The user id of the current user. There might be several profiles (with separate user ids)
+     * per user.
+     */
+    @GuardedBy("mLock")
+    private @UserIdInt int mCurrentUserId;
+
     private final Object mLock = new Object();
 
-    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
-    @GuardedBy("mLock")
-    private final SparseArray<UsbSettingsManager>
-            mSettingsByUser = new SparseArray<UsbSettingsManager>();
-
-    private UsbSettingsManager getSettingsForUser(int userId) {
-        synchronized (mLock) {
-            UsbSettingsManager settings = mSettingsByUser.get(userId);
-            if (settings == null) {
-                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
-                mSettingsByUser.put(userId, settings);
-            }
-            return settings;
-        }
+    private UsbUserSettingsManager getSettingsForUser(@UserIdInt int userIdInt) {
+        return mSettingsManager.getSettingsForUser(userIdInt);
     }
 
     public UsbService(Context context) {
         mContext = context;
 
+        mUserManager = context.getSystemService(UserManager.class);
+        mSettingsManager = new UsbSettingsManager(context);
         mAlsaManager = new UsbAlsaManager(context);
 
         final PackageManager pm = mContext.getPackageManager();
         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
-            mHostManager = new UsbHostManager(context, mAlsaManager);
+            mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
         }
         if (new File("/sys/class/android_usb").exists()) {
-            mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
+            mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager);
         }
         if (mHostManager != null || mDeviceManager != null) {
             mPortManager = new UsbPortManager(context);
         }
 
-        setCurrentUser(UserHandle.USER_SYSTEM);
+        onSwitchUser(UserHandle.USER_SYSTEM);
 
         final IntentFilter filter = new IntentFilter();
         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mReceiver, filter, null, null);
     }
@@ -132,15 +141,8 @@
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
             final String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                setCurrentUser(userId);
-            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                synchronized (mLock) {
-                    mSettingsByUser.remove(userId);
-                }
-            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                     .equals(action)) {
                 if (mDeviceManager != null) {
                     mDeviceManager.updateUserRestrictions();
@@ -149,14 +151,36 @@
         }
     };
 
-    private void setCurrentUser(int userId) {
-        final UsbSettingsManager userSettings = getSettingsForUser(userId);
-        if (mHostManager != null) {
-            mHostManager.setCurrentSettings(userSettings);
+    /**
+     * Set new {@link #mCurrentUserId} and propagate it to other modules.
+     *
+     * @param newUserId The user id of the new current user.
+     */
+    private void onSwitchUser(@UserIdInt int newUserId) {
+        synchronized (mLock) {
+            mCurrentUserId = newUserId;
+
+            // The following two modules need to know about the current profile group. If they need
+            // to distinguish by profile of the user, the id has to be passed in the call to the
+            // module.
+            UsbProfileGroupSettingsManager settings =
+                    mSettingsManager.getSettingsForProfileGroup(UserHandle.of(newUserId));
+            if (mHostManager != null) {
+                mHostManager.setCurrentUserSettings(settings);
+            }
+            if (mDeviceManager != null) {
+                mDeviceManager.setCurrentUser(newUserId, settings);
+            }
         }
-        if (mDeviceManager != null) {
-            mDeviceManager.setCurrentUser(userId, userSettings);
-        }
+    }
+
+    /**
+     * Execute operations when a user is stopped.
+     *
+     * @param stoppedUserId The id of the used that is stopped
+     */
+    private void onStopUser(@UserIdInt int stoppedUserId) {
+        mSettingsManager.remove(stoppedUserId);
     }
 
     public void systemReady() {
@@ -187,14 +211,45 @@
         }
     }
 
+    /**
+     * Check if the calling user is in the same profile group as the {@link #mCurrentUserId
+     * current user}.
+     *
+     * @return Iff the caller is in the current user's profile group
+     */
+    private boolean isCallerInCurrentUserProfileGroupLocked() {
+        int userIdInt = UserHandle.getCallingUserId();
+
+        long ident = clearCallingIdentity();
+        try {
+            return mUserManager.isSameProfileGroup(userIdInt, mCurrentUserId);
+        } finally {
+            restoreCallingIdentity(ident);
+        }
+    }
+
     /* Opens the specified USB device (host mode) */
     @Override
     public ParcelFileDescriptor openDevice(String deviceName) {
+        ParcelFileDescriptor fd = null;
+
         if (mHostManager != null) {
-            return mHostManager.openDevice(deviceName);
-        } else {
-            return null;
+            synchronized (mLock) {
+                if (deviceName != null) {
+                    int userIdInt = UserHandle.getCallingUserId();
+                    boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
+
+                    if (isCurrentUser) {
+                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt));
+                    } else {
+                        Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
+                               " as user is not active.");
+                    }
+                }
+            }
         }
+
+        return fd;
     }
 
     /* returns the currently attached USB accessory (device mode) */
@@ -211,22 +266,43 @@
     @Override
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
         if (mDeviceManager != null) {
-            return mDeviceManager.openAccessory(accessory);
-        } else {
-            return null;
+            int userIdInt = UserHandle.getCallingUserId();
+
+            synchronized (mLock) {
+                boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
+
+                if (isCurrentUser) {
+                    return mDeviceManager.openAccessory(accessory, getSettingsForUser(userIdInt));
+                } else {
+                    Slog.w(TAG, "Cannot open " + accessory + " for user " + userIdInt +
+                            " as user is not active.");
+                }
+            }
         }
+
+        return null;
     }
 
     @Override
     public void setDevicePackage(UsbDevice device, String packageName, int userId) {
+        device = Preconditions.checkNotNull(device);
+
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        getSettingsForUser(userId).setDevicePackage(device, packageName);
+
+        UserHandle user = UserHandle.of(userId);
+        mSettingsManager.getSettingsForProfileGroup(user).setDevicePackage(device, packageName,
+                user);
     }
 
     @Override
     public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
+        accessory = Preconditions.checkNotNull(accessory);
+
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
+
+        UserHandle user = UserHandle.of(userId);
+        mSettingsManager.getSettingsForProfileGroup(user).setAccessoryPackage(accessory,
+                packageName, user);
     }
 
     @Override
@@ -270,14 +346,22 @@
 
     @Override
     public boolean hasDefaults(String packageName, int userId) {
+        packageName = Preconditions.checkStringNotEmpty(packageName);
+
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        return getSettingsForUser(userId).hasDefaults(packageName);
+
+        UserHandle user = UserHandle.of(userId);
+        return mSettingsManager.getSettingsForProfileGroup(user).hasDefaults(packageName, user);
     }
 
     @Override
     public void clearDefaults(String packageName, int userId) {
+        packageName = Preconditions.checkStringNotEmpty(packageName);
+
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        getSettingsForUser(userId).clearDefaults(packageName);
+
+        UserHandle user = UserHandle.of(userId);
+        mSettingsManager.getSettingsForProfileGroup(user).clearDefaults(packageName, user);
     }
 
     @Override
@@ -385,6 +469,21 @@
     }
 
     @Override
+    public void setUsbDeviceConnectionHandler(ComponentName usbDeviceConnectionHandler) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        synchronized (mLock) {
+            if (mCurrentUserId == UserHandle.getCallingUserId()) {
+                if (mHostManager != null) {
+                    mHostManager.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler);
+                }
+            } else {
+                throw new IllegalArgumentException("Only the current user can register a usb " +
+                        "connection handler");
+            }
+        }
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
@@ -405,16 +504,7 @@
                 }
                 mAlsaManager.dump(pw);
 
-                synchronized (mLock) {
-                    for (int i = 0; i < mSettingsByUser.size(); i++) {
-                        final int userId = mSettingsByUser.keyAt(i);
-                        final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
-                        pw.println("Settings for user " + userId + ":");
-                        pw.increaseIndent();
-                        settings.dump(pw);
-                        pw.decreaseIndent();
-                    }
-                }
+                mSettingsManager.dump(pw);
             } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
                 final String portId = args[1];
                 final int powerRole;
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index de9ede3..b251d26 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -1,1253 +1,195 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *       http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ *  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.usb;
 
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.res.XmlResourceParser;
+import android.content.pm.UserInfo;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
-import android.os.Binder;
-import android.os.Environment;
-import android.os.Process;
 import android.os.UserHandle;
-import android.util.AtomicFile;
-import android.util.Log;
+import android.os.UserManager;
 import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.util.Xml;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.XmlUtils;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import libcore.io.IoUtils;
-
+/**
+ * Maintains all {@link UsbUserSettingsManager} for all users.
+ */
 class UsbSettingsManager {
-    private static final String TAG = "UsbSettingsManager";
+    private static final String LOG_TAG = UsbSettingsManager.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    /** Legacy settings file, before multi-user */
-    private static final File sSingleUserSettingsFile = new File(
-            "/data/system/usb_device_manager.xml");
+    /** Context to be used by this module */
+    private final @NonNull Context mContext;
 
-    private final UserHandle mUser;
-    private final AtomicFile mSettingsFile;
-    private final boolean mDisablePermissionDialogs;
+    /** Map from user id to {@link UsbUserSettingsManager} for the user */
+    @GuardedBy("mSettingsByUser")
+    private final SparseArray<UsbUserSettingsManager> mSettingsByUser = new SparseArray<>();
 
-    private final Context mContext;
-    private final Context mUserContext;
-    private final PackageManager mPackageManager;
+    /**
+     * Map from the parent profile's user id to {@link UsbProfileGroupSettingsManager} for the
+     * group.
+     */
+    @GuardedBy("mSettingsByProfileGroup")
+    private final SparseArray<UsbProfileGroupSettingsManager> mSettingsByProfileGroup
+            = new SparseArray<>();
+    private UserManager mUserManager;
 
-    // Temporary mapping USB device name to list of UIDs with permissions for the device
-    private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
-            new HashMap<String, SparseBooleanArray>();
-    // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
-    private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
-            new HashMap<UsbAccessory, SparseBooleanArray>();
-    // Maps DeviceFilter to user preferred application package
-    private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
-            new HashMap<DeviceFilter, String>();
-    // Maps AccessoryFilter to user preferred application package
-    private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
-            new HashMap<AccessoryFilter, String>();
-
-    private final Object mLock = new Object();
-
-    // This class is used to describe a USB device.
-    // When used in HashMaps all values must be specified,
-    // but wildcards can be used for any of the fields in
-    // the package meta-data.
-    private static class DeviceFilter {
-        // USB Vendor ID (or -1 for unspecified)
-        public final int mVendorId;
-        // USB Product ID (or -1 for unspecified)
-        public final int mProductId;
-        // USB device or interface class (or -1 for unspecified)
-        public final int mClass;
-        // USB device subclass (or -1 for unspecified)
-        public final int mSubclass;
-        // USB device protocol (or -1 for unspecified)
-        public final int mProtocol;
-        // USB device manufacturer name string (or null for unspecified)
-        public final String mManufacturerName;
-        // USB device product name string (or null for unspecified)
-        public final String mProductName;
-        // USB device serial number string (or null for unspecified)
-        public final String mSerialNumber;
-
-        public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
-                            String manufacturer, String product, String serialnum) {
-            mVendorId = vid;
-            mProductId = pid;
-            mClass = clasz;
-            mSubclass = subclass;
-            mProtocol = protocol;
-            mManufacturerName = manufacturer;
-            mProductName = product;
-            mSerialNumber = serialnum;
-        }
-
-        public DeviceFilter(UsbDevice device) {
-            mVendorId = device.getVendorId();
-            mProductId = device.getProductId();
-            mClass = device.getDeviceClass();
-            mSubclass = device.getDeviceSubclass();
-            mProtocol = device.getDeviceProtocol();
-            mManufacturerName = device.getManufacturerName();
-            mProductName = device.getProductName();
-            mSerialNumber = device.getSerialNumber();
-        }
-
-        public static DeviceFilter read(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            int vendorId = -1;
-            int productId = -1;
-            int deviceClass = -1;
-            int deviceSubclass = -1;
-            int deviceProtocol = -1;
-            String manufacturerName = null;
-            String productName = null;
-            String serialNumber = null;
-
-            int count = parser.getAttributeCount();
-            for (int i = 0; i < count; i++) {
-                String name = parser.getAttributeName(i);
-                String value = parser.getAttributeValue(i);
-                // Attribute values are ints or strings
-                if ("manufacturer-name".equals(name)) {
-                    manufacturerName = value;
-                } else if ("product-name".equals(name)) {
-                    productName = value;
-                } else if ("serial-number".equals(name)) {
-                    serialNumber = value;
-                } else {
-                    int intValue = -1;
-                    int radix = 10;
-                    if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
-                        (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
-                        // allow hex values starting with 0x or 0X
-                        radix = 16;
-                        value = value.substring(2);
-                    }
-                    try {
-                        intValue = Integer.parseInt(value, radix);
-                    } catch (NumberFormatException e) {
-                        Slog.e(TAG, "invalid number for field " + name, e);
-                        continue;
-                    }
-                    if ("vendor-id".equals(name)) {
-                        vendorId = intValue;
-                    } else if ("product-id".equals(name)) {
-                        productId = intValue;
-                    } else if ("class".equals(name)) {
-                        deviceClass = intValue;
-                    } else if ("subclass".equals(name)) {
-                        deviceSubclass = intValue;
-                    } else if ("protocol".equals(name)) {
-                        deviceProtocol = intValue;
-                    }
-                }
-            }
-            return new DeviceFilter(vendorId, productId,
-                    deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, serialNumber);
-        }
-
-        public void write(XmlSerializer serializer) throws IOException {
-            serializer.startTag(null, "usb-device");
-            if (mVendorId != -1) {
-                serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
-            }
-            if (mProductId != -1) {
-                serializer.attribute(null, "product-id", Integer.toString(mProductId));
-            }
-            if (mClass != -1) {
-                serializer.attribute(null, "class", Integer.toString(mClass));
-            }
-            if (mSubclass != -1) {
-                serializer.attribute(null, "subclass", Integer.toString(mSubclass));
-            }
-            if (mProtocol != -1) {
-                serializer.attribute(null, "protocol", Integer.toString(mProtocol));
-            }
-            if (mManufacturerName != null) {
-                serializer.attribute(null, "manufacturer-name", mManufacturerName);
-            }
-            if (mProductName != null) {
-                serializer.attribute(null, "product-name", mProductName);
-            }
-            if (mSerialNumber != null) {
-                serializer.attribute(null, "serial-number", mSerialNumber);
-            }
-            serializer.endTag(null, "usb-device");
-        }
-
-        private boolean matches(int clasz, int subclass, int protocol) {
-            return ((mClass == -1 || clasz == mClass) &&
-                    (mSubclass == -1 || subclass == mSubclass) &&
-                    (mProtocol == -1 || protocol == mProtocol));
-        }
-
-        public boolean matches(UsbDevice device) {
-            if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
-            if (mProductId != -1 && device.getProductId() != mProductId) return false;
-            if (mManufacturerName != null && device.getManufacturerName() == null) return false;
-            if (mProductName != null && device.getProductName() == null) return false;
-            if (mSerialNumber != null && device.getSerialNumber() == null) return false;
-            if (mManufacturerName != null && device.getManufacturerName() != null &&
-                !mManufacturerName.equals(device.getManufacturerName())) return false;
-            if (mProductName != null && device.getProductName() != null &&
-                !mProductName.equals(device.getProductName())) return false;
-            if (mSerialNumber != null && device.getSerialNumber() != null &&
-                !mSerialNumber.equals(device.getSerialNumber())) return false;
-
-            // check device class/subclass/protocol
-            if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
-                    device.getDeviceProtocol())) return true;
-
-            // if device doesn't match, check the interfaces
-            int count = device.getInterfaceCount();
-            for (int i = 0; i < count; i++) {
-                UsbInterface intf = device.getInterface(i);
-                 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
-                        intf.getInterfaceProtocol())) return true;
-            }
-
-            return false;
-        }
-
-        public boolean matches(DeviceFilter f) {
-            if (mVendorId != -1 && f.mVendorId != mVendorId) return false;
-            if (mProductId != -1 && f.mProductId != mProductId) return false;
-            if (f.mManufacturerName != null && mManufacturerName == null) return false;
-            if (f.mProductName != null && mProductName == null) return false;
-            if (f.mSerialNumber != null && mSerialNumber == null) return false;
-            if (mManufacturerName != null && f.mManufacturerName != null &&
-                !mManufacturerName.equals(f.mManufacturerName)) return false;
-            if (mProductName != null && f.mProductName != null &&
-                !mProductName.equals(f.mProductName)) return false;
-            if (mSerialNumber != null && f.mSerialNumber != null &&
-                !mSerialNumber.equals(f.mSerialNumber)) return false;
-
-            // check device class/subclass/protocol
-            return matches(f.mClass, f.mSubclass, f.mProtocol);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            // can't compare if we have wildcard strings
-            if (mVendorId == -1 || mProductId == -1 ||
-                    mClass == -1 || mSubclass == -1 || mProtocol == -1) {
-                return false;
-            }
-            if (obj instanceof DeviceFilter) {
-                DeviceFilter filter = (DeviceFilter)obj;
-
-                if (filter.mVendorId != mVendorId ||
-                        filter.mProductId != mProductId ||
-                        filter.mClass != mClass ||
-                        filter.mSubclass != mSubclass ||
-                        filter.mProtocol != mProtocol) {
-                    return(false);
-                }
-                if ((filter.mManufacturerName != null &&
-                        mManufacturerName == null) ||
-                    (filter.mManufacturerName == null &&
-                        mManufacturerName != null) ||
-                    (filter.mProductName != null &&
-                        mProductName == null)  ||
-                    (filter.mProductName == null &&
-                        mProductName != null) ||
-                    (filter.mSerialNumber != null &&
-                        mSerialNumber == null)  ||
-                    (filter.mSerialNumber == null &&
-                        mSerialNumber != null)) {
-                    return(false);
-                }
-                if  ((filter.mManufacturerName != null &&
-                        mManufacturerName != null &&
-                        !mManufacturerName.equals(filter.mManufacturerName)) ||
-                     (filter.mProductName != null &&
-                        mProductName != null &&
-                        !mProductName.equals(filter.mProductName)) ||
-                     (filter.mSerialNumber != null &&
-                        mSerialNumber != null &&
-                        !mSerialNumber.equals(filter.mSerialNumber))) {
-                    return(false);
-                }
-                return(true);
-            }
-            if (obj instanceof UsbDevice) {
-                UsbDevice device = (UsbDevice)obj;
-                if (device.getVendorId() != mVendorId ||
-                        device.getProductId() != mProductId ||
-                        device.getDeviceClass() != mClass ||
-                        device.getDeviceSubclass() != mSubclass ||
-                        device.getDeviceProtocol() != mProtocol) {
-                    return(false);
-                }
-                if ((mManufacturerName != null && device.getManufacturerName() == null) ||
-                        (mManufacturerName == null && device.getManufacturerName() != null) ||
-                        (mProductName != null && device.getProductName() == null) ||
-                        (mProductName == null && device.getProductName() != null) ||
-                        (mSerialNumber != null && device.getSerialNumber() == null) ||
-                        (mSerialNumber == null && device.getSerialNumber() != null)) {
-                    return(false);
-                }
-                if ((device.getManufacturerName() != null &&
-                        !mManufacturerName.equals(device.getManufacturerName())) ||
-                        (device.getProductName() != null &&
-                            !mProductName.equals(device.getProductName())) ||
-                        (device.getSerialNumber() != null &&
-                            !mSerialNumber.equals(device.getSerialNumber()))) {
-                    return(false);
-                }
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return (((mVendorId << 16) | mProductId) ^
-                    ((mClass << 16) | (mSubclass << 8) | mProtocol));
-        }
-
-        @Override
-        public String toString() {
-            return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
-                    ",mClass=" + mClass + ",mSubclass=" + mSubclass +
-                    ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
-                    ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
-                    "]";
-        }
-    }
-
-    // This class is used to describe a USB accessory.
-    // When used in HashMaps all values must be specified,
-    // but wildcards can be used for any of the fields in
-    // the package meta-data.
-    private static class AccessoryFilter {
-        // USB accessory manufacturer (or null for unspecified)
-        public final String mManufacturer;
-        // USB accessory model (or null for unspecified)
-        public final String mModel;
-        // USB accessory version (or null for unspecified)
-        public final String mVersion;
-
-        public AccessoryFilter(String manufacturer, String model, String version) {
-            mManufacturer = manufacturer;
-            mModel = model;
-            mVersion = version;
-        }
-
-        public AccessoryFilter(UsbAccessory accessory) {
-            mManufacturer = accessory.getManufacturer();
-            mModel = accessory.getModel();
-            mVersion = accessory.getVersion();
-        }
-
-        public static AccessoryFilter read(XmlPullParser parser)
-                throws XmlPullParserException, IOException {
-            String manufacturer = null;
-            String model = null;
-            String version = null;
-
-            int count = parser.getAttributeCount();
-            for (int i = 0; i < count; i++) {
-                String name = parser.getAttributeName(i);
-                String value = parser.getAttributeValue(i);
-
-                if ("manufacturer".equals(name)) {
-                    manufacturer = value;
-                } else if ("model".equals(name)) {
-                    model = value;
-                } else if ("version".equals(name)) {
-                    version = value;
-                }
-             }
-             return new AccessoryFilter(manufacturer, model, version);
-        }
-
-        public void write(XmlSerializer serializer)throws IOException {
-            serializer.startTag(null, "usb-accessory");
-            if (mManufacturer != null) {
-                serializer.attribute(null, "manufacturer", mManufacturer);
-            }
-            if (mModel != null) {
-                serializer.attribute(null, "model", mModel);
-            }
-            if (mVersion != null) {
-                serializer.attribute(null, "version", mVersion);
-            }
-            serializer.endTag(null, "usb-accessory");
-        }
-
-        public boolean matches(UsbAccessory acc) {
-            if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
-            if (mModel != null && !acc.getModel().equals(mModel)) return false;
-            if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
-            return true;
-        }
-
-        public boolean matches(AccessoryFilter f) {
-            if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
-            if (mModel != null && !f.mModel.equals(mModel)) return false;
-            if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
-            return true;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            // can't compare if we have wildcard strings
-            if (mManufacturer == null || mModel == null || mVersion == null) {
-                return false;
-            }
-            if (obj instanceof AccessoryFilter) {
-                AccessoryFilter filter = (AccessoryFilter)obj;
-                return (mManufacturer.equals(filter.mManufacturer) &&
-                        mModel.equals(filter.mModel) &&
-                        mVersion.equals(filter.mVersion));
-            }
-            if (obj instanceof UsbAccessory) {
-                UsbAccessory accessory = (UsbAccessory)obj;
-                return (mManufacturer.equals(accessory.getManufacturer()) &&
-                        mModel.equals(accessory.getModel()) &&
-                        mVersion.equals(accessory.getVersion()));
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
-                    (mModel == null ? 0 : mModel.hashCode()) ^
-                    (mVersion == null ? 0 : mVersion.hashCode()));
-        }
-
-        @Override
-        public String toString() {
-            return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
-                                "\", mModel=\"" + mModel +
-                                "\", mVersion=\"" + mVersion + "\"]";
-        }
-    }
-
-    private class MyPackageMonitor extends PackageMonitor {
-        @Override
-        public void onPackageAdded(String packageName, int uid) {
-            handlePackageUpdate(packageName);
-        }
-
-        @Override
-        public boolean onPackageChanged(String packageName, int uid, String[] components) {
-            handlePackageUpdate(packageName);
-            return false;
-        }
-
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            clearDefaults(packageName);
-        }
-    }
-
-    MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
-
-    private final MtpNotificationManager mMtpNotificationManager;
-
-    public UsbSettingsManager(Context context, UserHandle user) {
-        if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
-
-        try {
-            mUserContext = context.createPackageContextAsUser("android", 0, user);
-        } catch (NameNotFoundException e) {
-            throw new RuntimeException("Missing android package");
-        }
-
+    public UsbSettingsManager(@NonNull Context context) {
         mContext = context;
-        mPackageManager = mUserContext.getPackageManager();
-
-        mUser = user;
-        mSettingsFile = new AtomicFile(new File(
-                Environment.getUserSystemDirectory(user.getIdentifier()),
-                "usb_device_manager.xml"));
-
-        mDisablePermissionDialogs = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_disableUsbPermissionDialogs);
-
-        synchronized (mLock) {
-            if (UserHandle.SYSTEM.equals(user)) {
-                upgradeSingleUserLocked();
-            }
-            readSettingsLocked();
-        }
-
-        mPackageMonitor.register(mUserContext, null, true);
-        mMtpNotificationManager = new MtpNotificationManager(
-                context,
-                new MtpNotificationManager.OnOpenInAppListener() {
-                    @Override
-                    public void onOpenInApp(UsbDevice device) {
-                        resolveActivity(createDeviceAttachedIntent(device), device);
-                    }
-                });
-    }
-
-    private void readPreference(XmlPullParser parser)
-            throws XmlPullParserException, IOException {
-        String packageName = null;
-        int count = parser.getAttributeCount();
-        for (int i = 0; i < count; i++) {
-            if ("package".equals(parser.getAttributeName(i))) {
-                packageName = parser.getAttributeValue(i);
-                break;
-            }
-        }
-        XmlUtils.nextElement(parser);
-        if ("usb-device".equals(parser.getName())) {
-            DeviceFilter filter = DeviceFilter.read(parser);
-            mDevicePreferenceMap.put(filter, packageName);
-        } else if ("usb-accessory".equals(parser.getName())) {
-            AccessoryFilter filter = AccessoryFilter.read(parser);
-            mAccessoryPreferenceMap.put(filter, packageName);
-        }
-        XmlUtils.nextElement(parser);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
     }
 
     /**
-     * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
-     * Should only by called by owner.
+     * Get the {@link UsbUserSettingsManager} for a user.
+     *
+     * @param userId The id of the user
+     *
+     * @return The settings for the user
      */
-    private void upgradeSingleUserLocked() {
-        if (sSingleUserSettingsFile.exists()) {
-            mDevicePreferenceMap.clear();
-            mAccessoryPreferenceMap.clear();
-
-            FileInputStream fis = null;
-            try {
-                fis = new FileInputStream(sSingleUserSettingsFile);
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(fis, StandardCharsets.UTF_8.name());
-
-                XmlUtils.nextElement(parser);
-                while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
-                    final String tagName = parser.getName();
-                    if ("preference".equals(tagName)) {
-                        readPreference(parser);
-                    } else {
-                        XmlUtils.nextElement(parser);
-                    }
-                }
-            } catch (IOException e) {
-                Log.wtf(TAG, "Failed to read single-user settings", e);
-            } catch (XmlPullParserException e) {
-                Log.wtf(TAG, "Failed to read single-user settings", e);
-            } finally {
-                IoUtils.closeQuietly(fis);
+    @NonNull UsbUserSettingsManager getSettingsForUser(@UserIdInt int userId) {
+        synchronized (mSettingsByUser) {
+            UsbUserSettingsManager settings = mSettingsByUser.get(userId);
+            if (settings == null) {
+                settings = new UsbUserSettingsManager(mContext, new UserHandle(userId));
+                mSettingsByUser.put(userId, settings);
             }
-
-            writeSettingsLocked();
-
-            // Success or failure, we delete single-user file
-            sSingleUserSettingsFile.delete();
+            return settings;
         }
     }
 
-    private void readSettingsLocked() {
-        if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
+    /**
+     * Get the {@link UsbProfileGroupSettingsManager} for a user.
+     *
+     * @param user Any user of the profile group
+     *
+     * @return The settings for the profile group
+     */
+    @NonNull UsbProfileGroupSettingsManager getSettingsForProfileGroup(@NonNull UserHandle user) {
+        UserHandle parentUser;
 
-        mDevicePreferenceMap.clear();
-        mAccessoryPreferenceMap.clear();
-
-        FileInputStream stream = null;
-        try {
-            stream = mSettingsFile.openRead();
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
-
-            XmlUtils.nextElement(parser);
-            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
-                String tagName = parser.getName();
-                if ("preference".equals(tagName)) {
-                    readPreference(parser);
-                } else {
-                    XmlUtils.nextElement(parser);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            if (DEBUG) Slog.d(TAG, "settings file not found");
-        } catch (Exception e) {
-            Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
-            mSettingsFile.delete();
-        } finally {
-            IoUtils.closeQuietly(stream);
-        }
-    }
-
-    private void writeSettingsLocked() {
-        if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
-
-        FileOutputStream fos = null;
-        try {
-            fos = mSettingsFile.startWrite();
-
-            FastXmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(fos, StandardCharsets.UTF_8.name());
-            serializer.startDocument(null, true);
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-            serializer.startTag(null, "settings");
-
-            for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
-                serializer.startTag(null, "preference");
-                serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
-                filter.write(serializer);
-                serializer.endTag(null, "preference");
-            }
-
-            for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
-                serializer.startTag(null, "preference");
-                serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter));
-                filter.write(serializer);
-                serializer.endTag(null, "preference");
-            }
-
-            serializer.endTag(null, "settings");
-            serializer.endDocument();
-
-            mSettingsFile.finishWrite(fos);
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed to write settings", e);
-            if (fos != null) {
-                mSettingsFile.failWrite(fos);
-            }
-        }
-    }
-
-    // Checks to see if a package matches a device or accessory.
-    // Only one of device and accessory should be non-null.
-    private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
-            UsbDevice device, UsbAccessory accessory) {
-        ActivityInfo ai = info.activityInfo;
-
-        XmlResourceParser parser = null;
-        try {
-            parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
-            if (parser == null) {
-                Slog.w(TAG, "no meta-data for " + info);
-                return false;
-            }
-
-            XmlUtils.nextElement(parser);
-            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
-                String tagName = parser.getName();
-                if (device != null && "usb-device".equals(tagName)) {
-                    DeviceFilter filter = DeviceFilter.read(parser);
-                    if (filter.matches(device)) {
-                        return true;
-                    }
-                }
-                else if (accessory != null && "usb-accessory".equals(tagName)) {
-                    AccessoryFilter filter = AccessoryFilter.read(parser);
-                    if (filter.matches(accessory)) {
-                        return true;
-                    }
-                }
-                XmlUtils.nextElement(parser);
-            }
-        } catch (Exception e) {
-            Slog.w(TAG, "Unable to load component info " + info.toString(), e);
-        } finally {
-            if (parser != null) parser.close();
-        }
-        return false;
-    }
-
-    private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
-        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
-        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
-                PackageManager.GET_META_DATA);
-        int count = resolveInfos.size();
-        for (int i = 0; i < count; i++) {
-            ResolveInfo resolveInfo = resolveInfos.get(i);
-            if (packageMatchesLocked(resolveInfo, intent.getAction(), device, null)) {
-                matches.add(resolveInfo);
-            }
-        }
-        return matches;
-    }
-
-    private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
-            UsbAccessory accessory, Intent intent) {
-        ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
-        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
-                PackageManager.GET_META_DATA);
-        int count = resolveInfos.size();
-        for (int i = 0; i < count; i++) {
-            ResolveInfo resolveInfo = resolveInfos.get(i);
-            if (packageMatchesLocked(resolveInfo, intent.getAction(), null, accessory)) {
-                matches.add(resolveInfo);
-            }
-        }
-        return matches;
-    }
-
-    public void deviceAttached(UsbDevice device) {
-        final Intent intent = createDeviceAttachedIntent(device);
-
-        // Send broadcast to running activity with registered intent
-        mUserContext.sendBroadcast(intent);
-
-        if (MtpNotificationManager.shouldShowNotification(mPackageManager, device)) {
-            // Show notification if the device is MTP storage.
-            mMtpNotificationManager.showNotification(device);
+        UserInfo parentUserInfo = mUserManager.getProfileParent(user.getIdentifier());
+        if (parentUserInfo != null) {
+            parentUser = parentUserInfo.getUserHandle();
         } else {
-            resolveActivity(intent, device);
+            parentUser = user;
+        }
+
+        synchronized (mSettingsByProfileGroup) {
+            UsbProfileGroupSettingsManager settings = mSettingsByProfileGroup.get(
+                    parentUser.getIdentifier());
+            if (settings == null) {
+                settings = new UsbProfileGroupSettingsManager(mContext, parentUser, this);
+                mSettingsByProfileGroup.put(parentUser.getIdentifier(), settings);
+            }
+            return settings;
         }
     }
 
-    private void resolveActivity(Intent intent, UsbDevice device) {
-        ArrayList<ResolveInfo> matches;
-        String defaultPackage;
-        synchronized (mLock) {
-            matches = getDeviceMatchesLocked(device, intent);
-            // Launch our default activity directly, if we have one.
-            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
-            defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
+    /**
+     * Remove the settings for a user.
+     *
+     * @param userIdToRemove The user o remove
+     */
+    void remove(@UserIdInt int userIdToRemove) {
+        synchronized (mSettingsByUser) {
+            mSettingsByUser.remove(userIdToRemove);
         }
-
-        // Start activity with registered intent
-        resolveActivity(intent, matches, defaultPackage, device, null);
     }
 
-    public void deviceDetached(UsbDevice device) {
-        // clear temporary permissions for the device
-        mDevicePermissionMap.remove(device.getDeviceName());
+    /**
+     * Dump all settings of all users.
+     *
+     * @param pw The writer to dump to
+     */
+    void dump(@NonNull IndentingPrintWriter pw) {
+        synchronized (mSettingsByUser) {
+            int numUsers = mSettingsByUser.size();
+            for (int i = 0; i < numUsers; i++) {
+                final int userId = mSettingsByUser.keyAt(i);
+                final UsbUserSettingsManager settings = mSettingsByUser.valueAt(i);
+                pw.println("Settings for user " + userId + ":");
+                pw.increaseIndent();
+                try {
+                    settings.dump(pw);
+                } finally {
+                    pw.decreaseIndent();
+                }
+            }
+        }
+
+        synchronized (mSettingsByProfileGroup) {
+            int numProfileGroups = mSettingsByProfileGroup.size();
+            for (int i = 0; i < numProfileGroups; i++) {
+                final int parentUserId = mSettingsByProfileGroup.keyAt(i);
+                final UsbProfileGroupSettingsManager settings = mSettingsByProfileGroup.valueAt(i);
+                pw.println("Settings for profile group " + parentUserId + ":");
+                pw.increaseIndent();
+                try {
+                    settings.dump(pw);
+                } finally {
+                    pw.decreaseIndent();
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove temporary access permission and broadcast that a device was removed.
+     *
+     * @param device The device that is removed
+     */
+    void usbDeviceRemoved(@NonNull UsbDevice device) {
+        synchronized (mSettingsByUser) {
+            for (int i = 0; i < mSettingsByUser.size(); i++) {
+                // clear temporary permissions for the device
+                mSettingsByUser.valueAt(i).removeDevicePermissions(device);
+            }
+        }
 
         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
 
-        mMtpNotificationManager.hideNotification(device.getDeviceId());
-    }
-
-    public void accessoryAttached(UsbAccessory accessory) {
-        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
-        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        ArrayList<ResolveInfo> matches;
-        String defaultPackage;
-        synchronized (mLock) {
-            matches = getAccessoryMatchesLocked(accessory, intent);
-            // Launch our default activity directly, if we have one.
-            // Otherwise we will start the UsbResolverActivity to allow the user to choose.
-            defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
+        if (DEBUG) {
+            Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
         }
-
-        resolveActivity(intent, matches, defaultPackage, null, accessory);
-    }
-
-    public void accessoryDetached(UsbAccessory accessory) {
-        // clear temporary permissions for the accessory
-        mAccessoryPermissionMap.remove(accessory);
-
-        Intent intent = new Intent(
-                UsbManager.ACTION_USB_ACCESSORY_DETACHED);
-        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
-            String defaultPackage, UsbDevice device, UsbAccessory accessory) {
-        int count = matches.size();
-
-        // don't show the resolver activity if there are no choices available
-        if (count == 0) {
-            if (accessory != null) {
-                String uri = accessory.getUri();
-                if (uri != null && uri.length() > 0) {
-                    // display URI to user
-                    // start UsbResolverActivity so user can choose an activity
-                    Intent dialogIntent = new Intent();
-                    dialogIntent.setClassName("com.android.systemui",
-                            "com.android.systemui.usb.UsbAccessoryUriActivity");
-                    dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-                    dialogIntent.putExtra("uri", uri);
-                    try {
-                        mUserContext.startActivityAsUser(dialogIntent, mUser);
-                    } catch (ActivityNotFoundException e) {
-                        Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
-                    }
-                }
-            }
-
-            // do nothing
-            return;
-        }
-
-        ResolveInfo defaultRI = null;
-        if (count == 1 && defaultPackage == null) {
-            // Check to see if our single choice is on the system partition.
-            // If so, treat it as our default without calling UsbResolverActivity
-            ResolveInfo rInfo = matches.get(0);
-            if (rInfo.activityInfo != null &&
-                    rInfo.activityInfo.applicationInfo != null &&
-                    (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                defaultRI = rInfo;
-            }
-
-            if (mDisablePermissionDialogs) {
-                // bypass dialog and launch the only matching activity
-                rInfo = matches.get(0);
-                if (rInfo.activityInfo != null) {
-                    defaultPackage = rInfo.activityInfo.packageName;
-                }
+    /**
+     * Remove temporary access permission and broadcast that a accessory was removed.
+     *
+     * @param accessory The accessory that is removed
+     */
+    void usbAccessoryRemoved(@NonNull UsbAccessory accessory) {
+        synchronized (mSettingsByUser) {
+            for (int i = 0; i < mSettingsByUser.size(); i++) {
+                // clear temporary permissions for the accessory
+                mSettingsByUser.valueAt(i).removeAccessoryPermissions(accessory);
             }
         }
 
-        if (defaultRI == null && defaultPackage != null) {
-            // look for default activity
-            for (int i = 0; i < count; i++) {
-                ResolveInfo rInfo = matches.get(i);
-                if (rInfo.activityInfo != null &&
-                        defaultPackage.equals(rInfo.activityInfo.packageName)) {
-                    defaultRI = rInfo;
-                    break;
-                }
-            }
-        }
-
-        if (defaultRI != null) {
-            // grant permission for default activity
-            if (device != null) {
-                grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
-            } else if (accessory != null) {
-                grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
-            }
-
-            // start default activity directly
-            try {
-                intent.setComponent(
-                        new ComponentName(defaultRI.activityInfo.packageName,
-                                defaultRI.activityInfo.name));
-                mUserContext.startActivityAsUser(intent, mUser);
-            } catch (ActivityNotFoundException e) {
-                Slog.e(TAG, "startActivity failed", e);
-            }
-        } else {
-            Intent resolverIntent = new Intent();
-            resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-            if (count == 1) {
-                // start UsbConfirmActivity if there is only one choice
-                resolverIntent.setClassName("com.android.systemui",
-                        "com.android.systemui.usb.UsbConfirmActivity");
-                resolverIntent.putExtra("rinfo", matches.get(0));
-
-                if (device != null) {
-                    resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
-                } else {
-                    resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-                }
-            } else {
-                // start UsbResolverActivity so user can choose an activity
-                resolverIntent.setClassName("com.android.systemui",
-                        "com.android.systemui.usb.UsbResolverActivity");
-                resolverIntent.putParcelableArrayListExtra("rlist", matches);
-                resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
-            }
-            try {
-                mUserContext.startActivityAsUser(resolverIntent, mUser);
-            } catch (ActivityNotFoundException e) {
-                Slog.e(TAG, "unable to start activity " + resolverIntent);
-            }
-        }
-    }
-
-    private boolean clearCompatibleMatchesLocked(String packageName, DeviceFilter filter) {
-        boolean changed = false;
-        for (DeviceFilter test : mDevicePreferenceMap.keySet()) {
-            if (filter.matches(test)) {
-                mDevicePreferenceMap.remove(test);
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
-        boolean changed = false;
-        for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
-            if (filter.matches(test)) {
-                mAccessoryPreferenceMap.remove(test);
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
-            String metaDataName) {
-        XmlResourceParser parser = null;
-        boolean changed = false;
-
-        try {
-            parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
-            if (parser == null) return false;
-
-            XmlUtils.nextElement(parser);
-            while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
-                String tagName = parser.getName();
-                if ("usb-device".equals(tagName)) {
-                    DeviceFilter filter = DeviceFilter.read(parser);
-                    if (clearCompatibleMatchesLocked(packageName, filter)) {
-                        changed = true;
-                    }
-                }
-                else if ("usb-accessory".equals(tagName)) {
-                    AccessoryFilter filter = AccessoryFilter.read(parser);
-                    if (clearCompatibleMatchesLocked(packageName, filter)) {
-                        changed = true;
-                    }
-                }
-                XmlUtils.nextElement(parser);
-            }
-        } catch (Exception e) {
-            Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
-        } finally {
-            if (parser != null) parser.close();
-        }
-        return changed;
-    }
-
-    // Check to see if the package supports any USB devices or accessories.
-    // If so, clear any non-matching preferences for matching devices/accessories.
-    private void handlePackageUpdate(String packageName) {
-        synchronized (mLock) {
-            PackageInfo info;
-            boolean changed = false;
-
-            try {
-                info = mPackageManager.getPackageInfo(packageName,
-                        PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
-            } catch (NameNotFoundException e) {
-                Slog.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
-                return;
-            }
-
-            ActivityInfo[] activities = info.activities;
-            if (activities == null) return;
-            for (int i = 0; i < activities.length; i++) {
-                // check for meta-data, both for devices and accessories
-                if (handlePackageUpdateLocked(packageName, activities[i],
-                        UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
-                    changed = true;
-                }
-                if (handlePackageUpdateLocked(packageName, activities[i],
-                        UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
-                    changed = true;
-                }
-            }
-
-            if (changed) {
-                writeSettingsLocked();
-            }
-        }
-    }
-
-    public boolean hasPermission(UsbDevice device) {
-        synchronized (mLock) {
-            int uid = Binder.getCallingUid();
-            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
-                return true;
-            }
-            SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
-            if (uidList == null) {
-                return false;
-            }
-            return uidList.get(uid);
-        }
-    }
-
-    public boolean hasPermission(UsbAccessory accessory) {
-        synchronized (mLock) {
-            int uid = Binder.getCallingUid();
-            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
-                return true;
-            }
-            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
-            if (uidList == null) {
-                return false;
-            }
-            return uidList.get(uid);
-        }
-    }
-
-    public void checkPermission(UsbDevice device) {
-        if (!hasPermission(device)) {
-            throw new SecurityException("User has not given permission to device " + device);
-        }
-    }
-
-    public void checkPermission(UsbAccessory accessory) {
-        if (!hasPermission(accessory)) {
-            throw new SecurityException("User has not given permission to accessory " + accessory);
-        }
-    }
-
-    private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
-        final int uid = Binder.getCallingUid();
-
-        // compare uid with packageName to foil apps pretending to be someone else
-        try {
-            ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
-            if (aInfo.uid != uid) {
-                throw new IllegalArgumentException("package " + packageName +
-                        " does not match caller's uid " + uid);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new IllegalArgumentException("package " + packageName + " not found");
-        }
-
-        long identity = Binder.clearCallingIdentity();
-        intent.setClassName("com.android.systemui",
-                "com.android.systemui.usb.UsbPermissionActivity");
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.putExtra(Intent.EXTRA_INTENT, pi);
-        intent.putExtra("package", packageName);
-        intent.putExtra(Intent.EXTRA_UID, uid);
-        try {
-            mUserContext.startActivityAsUser(intent, mUser);
-        } catch (ActivityNotFoundException e) {
-            Slog.e(TAG, "unable to start UsbPermissionActivity");
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
-      Intent intent = new Intent();
-
-        // respond immediately if permission has already been granted
-      if (hasPermission(device)) {
-            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
-            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
-            try {
-                pi.send(mUserContext, 0, intent);
-            } catch (PendingIntent.CanceledException e) {
-                if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
-            }
-            return;
-        }
-
-        // start UsbPermissionActivity so user can choose an activity
-        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        requestPermissionDialog(intent, packageName, pi);
-    }
-
-    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
-        Intent intent = new Intent();
-
-        // respond immediately if permission has already been granted
-        if (hasPermission(accessory)) {
-            intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
-            try {
-                pi.send(mUserContext, 0, intent);
-            } catch (PendingIntent.CanceledException e) {
-                if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
-            }
-            return;
-        }
-
+        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-        requestPermissionDialog(intent, packageName, pi);
-    }
-
-    public void setDevicePackage(UsbDevice device, String packageName) {
-        DeviceFilter filter = new DeviceFilter(device);
-        boolean changed = false;
-        synchronized (mLock) {
-            if (packageName == null) {
-                changed = (mDevicePreferenceMap.remove(filter) != null);
-            } else {
-                changed = !packageName.equals(mDevicePreferenceMap.get(filter));
-                if (changed) {
-                    mDevicePreferenceMap.put(filter, packageName);
-                }
-            }
-            if (changed) {
-                writeSettingsLocked();
-            }
-        }
-    }
-
-    public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
-        AccessoryFilter filter = new AccessoryFilter(accessory);
-        boolean changed = false;
-        synchronized (mLock) {
-            if (packageName == null) {
-                changed = (mAccessoryPreferenceMap.remove(filter) != null);
-            } else {
-                changed = !packageName.equals(mAccessoryPreferenceMap.get(filter));
-                if (changed) {
-                    mAccessoryPreferenceMap.put(filter, packageName);
-                }
-            }
-            if (changed) {
-                writeSettingsLocked();
-            }
-        }
-    }
-
-    public void grantDevicePermission(UsbDevice device, int uid) {
-        synchronized (mLock) {
-            String deviceName = device.getDeviceName();
-            SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
-            if (uidList == null) {
-                uidList = new SparseBooleanArray(1);
-                mDevicePermissionMap.put(deviceName, uidList);
-            }
-            uidList.put(uid, true);
-        }
-    }
-
-    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
-        synchronized (mLock) {
-            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
-            if (uidList == null) {
-                uidList = new SparseBooleanArray(1);
-                mAccessoryPermissionMap.put(accessory, uidList);
-            }
-            uidList.put(uid, true);
-        }
-    }
-
-    public boolean hasDefaults(String packageName) {
-        synchronized (mLock) {
-            if (mDevicePreferenceMap.values().contains(packageName)) return true;
-            if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
-            return false;
-        }
-    }
-
-    public void clearDefaults(String packageName) {
-        synchronized (mLock) {
-            if (clearPackageDefaultsLocked(packageName)) {
-                writeSettingsLocked();
-            }
-        }
-    }
-
-    private boolean clearPackageDefaultsLocked(String packageName) {
-        boolean cleared = false;
-        synchronized (mLock) {
-            if (mDevicePreferenceMap.containsValue(packageName)) {
-                // make a copy of the key set to avoid ConcurrentModificationException
-                Object[] keys = mDevicePreferenceMap.keySet().toArray();
-                for (int i = 0; i < keys.length; i++) {
-                    Object key = keys[i];
-                    if (packageName.equals(mDevicePreferenceMap.get(key))) {
-                        mDevicePreferenceMap.remove(key);
-                        cleared = true;
-                    }
-                }
-            }
-            if (mAccessoryPreferenceMap.containsValue(packageName)) {
-                // make a copy of the key set to avoid ConcurrentModificationException
-                Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
-                for (int i = 0; i < keys.length; i++) {
-                    Object key = keys[i];
-                    if (packageName.equals(mAccessoryPreferenceMap.get(key))) {
-                        mAccessoryPreferenceMap.remove(key);
-                        cleared = true;
-                    }
-                }
-            }
-            return cleared;
-        }
-    }
-
-    public void dump(IndentingPrintWriter pw) {
-        synchronized (mLock) {
-            pw.println("Device permissions:");
-            for (String deviceName : mDevicePermissionMap.keySet()) {
-                pw.print("  " + deviceName + ": ");
-                SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
-                int count = uidList.size();
-                for (int i = 0; i < count; i++) {
-                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
-                }
-                pw.println();
-            }
-            pw.println("Accessory permissions:");
-            for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
-                pw.print("  " + accessory + ": ");
-                SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
-                int count = uidList.size();
-                for (int i = 0; i < count; i++) {
-                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
-                }
-                pw.println();
-            }
-            pw.println("Device preferences:");
-            for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
-                pw.println("  " + filter + ": " + mDevicePreferenceMap.get(filter));
-            }
-            pw.println("Accessory preferences:");
-            for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
-                pw.println("  " + filter + ": " + mAccessoryPreferenceMap.get(filter));
-            }
-        }
-    }
-
-    private static Intent createDeviceAttachedIntent(UsbDevice device) {
-        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
-        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return intent;
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
new file mode 100644
index 0000000..4a34ece
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2011 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.usb;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+import android.os.Binder;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.util.HashMap;
+
+class UsbUserSettingsManager {
+    private static final String TAG = "UsbUserSettingsManager";
+    private static final boolean DEBUG = false;
+
+    private final UserHandle mUser;
+    private final boolean mDisablePermissionDialogs;
+
+    private final Context mUserContext;
+    private final PackageManager mPackageManager;
+
+    // Temporary mapping USB device name to list of UIDs with permissions for the device
+    private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
+            new HashMap<String, SparseBooleanArray>();
+    // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
+    private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
+            new HashMap<UsbAccessory, SparseBooleanArray>();
+
+    private final Object mLock = new Object();
+
+    public UsbUserSettingsManager(Context context, UserHandle user) {
+        if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
+
+        try {
+            mUserContext = context.createPackageContextAsUser("android", 0, user);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("Missing android package");
+        }
+
+        mPackageManager = mUserContext.getPackageManager();
+
+        mUser = user;
+
+        mDisablePermissionDialogs = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_disableUsbPermissionDialogs);
+    }
+
+    /**
+     * Remove all access permission for a device.
+     *
+     * @param device The device the permissions are for
+     */
+    void removeDevicePermissions(@NonNull UsbDevice device) {
+        synchronized (mLock) {
+            mDevicePermissionMap.remove(device.getDeviceName());
+        }
+    }
+
+    /**
+     * Remove all access permission for a accessory.
+     *
+     * @param accessory The accessory the permissions are for
+     */
+    void removeAccessoryPermissions(@NonNull UsbAccessory accessory) {
+        synchronized (mLock) {
+            mAccessoryPermissionMap.remove(accessory);
+        }
+    }
+
+
+    public boolean hasPermission(UsbDevice device) {
+        synchronized (mLock) {
+            int uid = Binder.getCallingUid();
+            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
+                return true;
+            }
+            SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
+            if (uidList == null) {
+                return false;
+            }
+            return uidList.get(uid);
+        }
+    }
+
+    public boolean hasPermission(UsbAccessory accessory) {
+        synchronized (mLock) {
+            int uid = Binder.getCallingUid();
+            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
+                return true;
+            }
+            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+            if (uidList == null) {
+                return false;
+            }
+            return uidList.get(uid);
+        }
+    }
+
+    public void checkPermission(UsbDevice device) {
+        if (!hasPermission(device)) {
+            throw new SecurityException("User has not given permission to device " + device);
+        }
+    }
+
+    public void checkPermission(UsbAccessory accessory) {
+        if (!hasPermission(accessory)) {
+            throw new SecurityException("User has not given permission to accessory " + accessory);
+        }
+    }
+
+    private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
+        final int uid = Binder.getCallingUid();
+
+        // compare uid with packageName to foil apps pretending to be someone else
+        try {
+            ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
+            if (aInfo.uid != uid) {
+                throw new IllegalArgumentException("package " + packageName +
+                        " does not match caller's uid " + uid);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException("package " + packageName + " not found");
+        }
+
+        long identity = Binder.clearCallingIdentity();
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.usb.UsbPermissionActivity");
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(Intent.EXTRA_INTENT, pi);
+        intent.putExtra("package", packageName);
+        intent.putExtra(Intent.EXTRA_UID, uid);
+        try {
+            mUserContext.startActivityAsUser(intent, mUser);
+        } catch (ActivityNotFoundException e) {
+            Slog.e(TAG, "unable to start UsbPermissionActivity");
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
+      Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+      if (hasPermission(device)) {
+            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+            try {
+                pi.send(mUserContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        // start UsbPermissionActivity so user can choose an activity
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        requestPermissionDialog(intent, packageName, pi);
+    }
+
+    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+        Intent intent = new Intent();
+
+        // respond immediately if permission has already been granted
+        if (hasPermission(accessory)) {
+            intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+            try {
+                pi.send(mUserContext, 0, intent);
+            } catch (PendingIntent.CanceledException e) {
+                if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
+            }
+            return;
+        }
+
+        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+        requestPermissionDialog(intent, packageName, pi);
+    }
+
+    public void grantDevicePermission(UsbDevice device, int uid) {
+        synchronized (mLock) {
+            String deviceName = device.getDeviceName();
+            SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+            if (uidList == null) {
+                uidList = new SparseBooleanArray(1);
+                mDevicePermissionMap.put(deviceName, uidList);
+            }
+            uidList.put(uid, true);
+        }
+    }
+
+    public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
+        synchronized (mLock) {
+            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+            if (uidList == null) {
+                uidList = new SparseBooleanArray(1);
+                mAccessoryPermissionMap.put(accessory, uidList);
+            }
+            uidList.put(uid, true);
+        }
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            pw.println("Device permissions:");
+            for (String deviceName : mDevicePermissionMap.keySet()) {
+                pw.print("  " + deviceName + ": ");
+                SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+                int count = uidList.size();
+                for (int i = 0; i < count; i++) {
+                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
+                }
+                pw.println();
+            }
+            pw.println("Accessory permissions:");
+            for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+                pw.print("  " + accessory + ": ");
+                SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+                int count = uidList.size();
+                for (int i = 0; i < count; i++) {
+                    pw.print(Integer.toString(uidList.keyAt(i)) + " ");
+                }
+                pw.println();
+            }
+        }
+    }
+}
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..c006185 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -327,7 +327,7 @@
      *
      * @hide
      */
-    public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0;
+    public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
 
     /**
      * Whether the call is a generic conference, where we do not know the precise state of
@@ -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);
 
@@ -629,8 +655,8 @@
             builder.append("Properties:");
         }
 
-        if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) {
-            builder.append(isLong ? " PROPERTY_SHOW_CALLBACK_NUMBER" : " clbk");
+        if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
+            builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
         }
 
         if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
@@ -707,7 +733,6 @@
      * {@link android.telecom.InCallService.VideoCall}.
      */
     public static abstract class VideoProvider {
-
         /**
          * Video is not being received (no protocol pause was issued).
          * @see #handleCallSessionEvent(int)
@@ -792,6 +817,14 @@
         private static final int MSG_SET_PAUSE_IMAGE = 11;
         private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
 
+        private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE";
+        private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME";
+        private static final String SESSION_EVENT_TX_START_STR = "TX_START";
+        private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
+        private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
+        private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+        private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
+
         private VideoProvider.VideoProviderHandler mMessageHandler;
         private final VideoProvider.VideoProviderBinder mBinder;
 
@@ -1302,6 +1335,32 @@
                 }
             }
         }
+
+        /**
+         * Returns a string representation of a call session event.
+         *
+         * @param event A call session event passed to {@link #handleCallSessionEvent(int)}.
+         * @return String representation of the call session event.
+         * @hide
+         */
+        public static String sessionEventToString(int event) {
+            switch (event) {
+                case SESSION_EVENT_CAMERA_FAILURE:
+                    return SESSION_EVENT_CAMERA_FAILURE_STR;
+                case SESSION_EVENT_CAMERA_READY:
+                    return SESSION_EVENT_CAMERA_READY_STR;
+                case SESSION_EVENT_RX_PAUSE:
+                    return SESSION_EVENT_RX_PAUSE_STR;
+                case SESSION_EVENT_RX_RESUME:
+                    return SESSION_EVENT_RX_RESUME_STR;
+                case SESSION_EVENT_TX_START:
+                    return SESSION_EVENT_TX_START_STR;
+                case SESSION_EVENT_TX_STOP:
+                    return SESSION_EVENT_TX_STOP_STR;
+                default:
+                    return SESSION_EVENT_UNKNOWN_STR + " " + event;
+            }
+        }
     }
 
     private final Listener mConnectionDeathListener = new Listener() {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0c75630..7b68a4c 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1082,7 +1082,7 @@
      *
      * @param connectionManagerPhoneAccount See description at
      *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
-     * @param request Details about the incoming call.
+     * @param request Details about the outgoing call.
      * @return The {@code Connection} object to satisfy this call, or {@code null} to
      *         not handle the call.
      */
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index df6715d..69de89d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -449,8 +449,8 @@
     }
 
     /**
-     * Called when a {@link Call} has received a connection event issued by the
-     * {@link ConnectionService}.
+     * Unused; to handle connection events issued by a {@link ConnectionService}, implement the
+     * {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)} callback.
      * <p>
      * See {@link Connection#sendConnectionEvent(String, Bundle)}.
      *
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index dc8eaf6..f030115 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -638,7 +638,12 @@
         mConnectionCapabilities = connection.getConnectionCapabilities();
         mConnectionProperties = connection.getConnectionProperties();
         mVideoState = connection.getVideoState();
-        mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
+        IVideoProvider videoProvider = connection.getVideoProvider();
+        if (videoProvider != null) {
+            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+        } else {
+            mVideoProvider = null;
+        }
         mIsVoipAudioMode = connection.getIsVoipAudioMode();
         mStatusHints = connection.getStatusHints();
         mAddress = connection.getHandle();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e666986..deed6d4 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -87,6 +87,14 @@
             KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
 
     /**
+     * Flag indicating whether radio is to be restarted on error PDP_FAIL_REGULAR_DEACTIVATION
+     * This is false by default.
+     */
+    public static final String
+            KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL =
+                    "restart_radio_on_pdp_fail_regular_deactivation_bool";
+
+    /**
      * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
      * The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
      * consistent with the regular Dialer, this value should agree with the corresponding values
@@ -174,6 +182,13 @@
     public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
 
     /**
+     * Since the default voicemail number is empty, if a SIM card does not have a voicemail number
+     * available the user cannot use voicemail. This flag allows the user to edit the voicemail
+     * number in such cases, and is false by default.
+     */
+    public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL= "editable_voicemail_number_bool";
+
+    /**
      * Determine whether the voicemail notification is persistent in the notification bar. If true,
      * the voicemail notifications cannot be dismissed from the notification bar.
      */
@@ -246,6 +261,37 @@
     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";
+
+    /**
+     * Where there is no preloaded voicemail number on a SIM card, specifies the carrier's default
+     * voicemail number.
+     * When empty string, no default voicemail number is specified.
+     */
+    public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+
+
+    /**
      * 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.
@@ -253,6 +299,16 @@
     public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
 
     /**
+     * Specifies a map from dialstrings to replacements for roaming network service numbers which
+     * cannot be replaced on the carrier side.
+     * <p>
+     * Individual entries have the format:
+     * [dialstring to replace]:[replacement]
+     */
+    public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY =
+            "dial_string_replace_string_array";
+
+    /**
      * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
      * calling settings will not include an option for "wifi only".  If true, the wifi calling
      * settings will include an option for "wifi only"
@@ -263,13 +319,23 @@
             "carrier_wfc_supports_wifi_only_bool";
 
     /**
-     * Default WFC_IMS_mode 0: WIFI_ONLY
-     *                      1: CELLULAR_PREFERRED
-     *                      2: WIFI_PREFERRED
+     * Default WFC_IMS_MODE for home network   0: WIFI_ONLY
+     *                                         1: CELLULAR_PREFERRED
+     *                                         2: WIFI_PREFERRED
      * @hide
      */
     public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
             "carrier_default_wfc_ims_mode_int";
+
+    /**
+     * Default WFC_IMS_MODE for roaming
+     * See {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} for valid values.
+     *
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT =
+            "carrier_default_wfc_ims_roaming_mode_int";
+
     /**
      * Default WFC_IMS_enabled: true VoWiFi by default is on
      *                          false VoWiFi by default is off
@@ -410,18 +476,11 @@
             "disable_severe_when_extreme_disabled_bool";
 
     /**
-     * The data call APN retry configuration for default type APN.
+     * The data call retry configuration for different types of APN.
      * @hide
      */
-    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING =
-            "carrier_data_call_retry_config_default_string";
-
-    /**
-     * The data call APN retry configuration for other type APNs.
-     * @hide
-     */
-    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING =
-            "carrier_data_call_retry_config_others_string";
+    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
+            "carrier_data_call_retry_config_strings";
 
     /**
      * Delay between trying APN from the pool
@@ -554,6 +613,15 @@
     public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
 
     /**
+     * Determines whether High Definition audio property is displayed in the dialer UI.
+     * If {@code false}, remove the HD audio property from the connection so that HD audio related
+     * UI is not displayed. If {@code true}, keep HD audio property as it is configured.
+     * @hide
+     */
+    public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL =
+            "display_hd_audio_property_bool";
+
+    /**
      * Determines whether video conference calls are supported by a carrier.  When {@code true},
      * video calls can be merged into conference calls, {@code false} otherwiwse.
      * <p>
@@ -651,6 +719,20 @@
     public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
 
     /**
+     * APN types that user is not allowed to modify
+     * @hide
+     */
+    public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY =
+            "read_only_apn_types_string_array";
+
+    /**
+     * APN fields that user is not allowed to modify
+     * @hide
+     */
+    public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY =
+            "read_only_apn_fields_string_array";
+
+    /**
      * Boolean indicating if intent for emergency call state changes should be broadcast
      * @hide
      */
@@ -786,6 +868,14 @@
             "duration_blocking_disabled_after_emergency_int";
 
     /**
+     * For carriers which require an empty flash to be sent before sending the normal 3-way calling
+     * flash, the duration in milliseconds of the empty flash to send.  When {@code 0}, no empty
+     * flash is sent.
+     */
+    public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
+
+
+    /**
      * @hide
      * The default value for preferred CDMA roaming mode (aka CDMA system select.)
      *          CDMA_ROAMING_MODE_RADIO_DEFAULT = the default roaming mode from the radio
@@ -853,6 +943,11 @@
 
     /**
      * Flag indicating whether the carrier supports the Hold command while in an IMS call.
+     * <p>
+     * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately
+     * controls whether this carrier configuration option is used.  Where
+     * {@code config_device_respects_hold_carrier_config} is false, the value of the
+     * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored.
      * @hide
      */
     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
@@ -919,6 +1014,32 @@
     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 RCS configuration server URL. This URL is used to initiate RCS provisioning.
+     */
+    public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
+
+    /**
+     * Determine whether user can change Wi-Fi Calling preference in roaming.
+     * {@code false} - roaming preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT} is
+     *                 the same as home preference {@link KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT}
+     *                 and cannot be changed.
+     * {@code true}  - roaming preference can be changed by user independently.
+     *
+     * @hide
+     */
+    public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
+            "editable_wfc_roaming_mode_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -933,12 +1054,16 @@
         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.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
         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);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL, false);
         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
+        sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
@@ -966,11 +1091,13 @@
         sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
         sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
+        sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
         sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
         sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
         sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
+        sDefaults.putBoolean(KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, false);
         sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
         sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
@@ -986,14 +1113,17 @@
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
+        sDefaults.putStringArray(KEY_READ_ONLY_APN_TYPES_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
-        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING,
-                "default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
-                        + "320000:5000,640000:5000,1280000:5000,1800000:5000");
-        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING,
-                "max_retries=3, 5000, 5000, 5000");
+        sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
+                "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
+                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
+                "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
+                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
+                "others:max_retries=3, 5000, 5000, 5000"});
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
@@ -1007,12 +1137,15 @@
         sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_DIAL_STRING_REPLACE_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
         sDefaults.putInt(KEY_GSM_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
+        sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false);
+        sDefaults.putBoolean(KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
@@ -1063,6 +1196,7 @@
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
         sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
         sDefaults.putInt(KEY_CDMA_ROAMING_MODE_INT, CDMA_ROAMING_MODE_RADIO_DEFAULT);
+        sDefaults.putString(KEY_RCS_CONFIG_SERVER_URL_STRING, "");
 
         // Carrier Signalling Receivers
         sDefaults.putStringArray(KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY, null);
@@ -1085,6 +1219,8 @@
         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);
+        sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/ClientRequestStats.aidl b/telephony/java/android/telephony/ClientRequestStats.aidl
new file mode 100644
index 0000000..206ee70
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.aidl
@@ -0,0 +1,22 @@
+/*
+** 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.
+*/
+
+package android.telephony;
+
+/**
+ * @hide
+ */
+parcelable  ClientRequestStats;
diff --git a/telephony/java/android/telephony/ClientRequestStats.java b/telephony/java/android/telephony/ClientRequestStats.java
new file mode 100644
index 0000000..381c847
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.java
@@ -0,0 +1,175 @@
+/*
+ * 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyHistogram;
+import android.util.SparseArray;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parcelable class to store Client request statistics information.
+ *
+ * @hide
+ */
+public final class ClientRequestStats implements Parcelable {
+    public static final Parcelable.Creator<ClientRequestStats> CREATOR =
+            new Parcelable.Creator<ClientRequestStats>() {
+
+                public ClientRequestStats createFromParcel(Parcel in) {
+                    return new ClientRequestStats(in);
+                }
+
+                public ClientRequestStats[] newArray(int size) {
+                    return new ClientRequestStats[size];
+                }
+            };
+    private static final int REQUEST_HISTOGRAM_BUCKET_COUNT = 5;
+    private String mCallingPackage;
+    /* completed requests wake lock time in milli seconds */
+    private long mCompletedRequestsWakelockTime = 0;
+    private long mCompletedRequestsCount = 0;
+    private long mPendingRequestsWakelockTime = 0;
+    private long mPendingRequestsCount = 0;
+    private SparseArray<TelephonyHistogram> mRequestHistograms =
+            new SparseArray<TelephonyHistogram>();
+
+    public ClientRequestStats(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public ClientRequestStats() {
+    }
+
+    public ClientRequestStats(ClientRequestStats clientRequestStats) {
+        mCallingPackage = clientRequestStats.getCallingPackage();
+        mCompletedRequestsCount = clientRequestStats.getCompletedRequestsCount();
+        mCompletedRequestsWakelockTime = clientRequestStats.getCompletedRequestsWakelockTime();
+        mPendingRequestsCount = clientRequestStats.getPendingRequestsCount();
+        mPendingRequestsWakelockTime = clientRequestStats.getPendingRequestsWakelockTime();
+
+        List<TelephonyHistogram> list = clientRequestStats.getRequestHistograms();
+        for (TelephonyHistogram entry : list) {
+            mRequestHistograms.put(entry.getId(), entry);
+        }
+    }
+
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    public void setCallingPackage(String mCallingPackage) {
+        this.mCallingPackage = mCallingPackage;
+    }
+
+    public long getCompletedRequestsWakelockTime() {
+        return mCompletedRequestsWakelockTime;
+    }
+
+    public void addCompletedWakelockTime(long completedRequestsWakelockTime) {
+        this.mCompletedRequestsWakelockTime += completedRequestsWakelockTime;
+    }
+
+    public long getPendingRequestsWakelockTime() {
+        return mPendingRequestsWakelockTime;
+    }
+
+    public void setPendingRequestsWakelockTime(long pendingRequestsWakelockTime) {
+        this.mPendingRequestsWakelockTime = pendingRequestsWakelockTime;
+    }
+
+    public long getCompletedRequestsCount() {
+        return mCompletedRequestsCount;
+    }
+
+    public void incrementCompletedRequestsCount() {
+        this.mCompletedRequestsCount++;
+    }
+
+    public long getPendingRequestsCount() {
+        return mPendingRequestsCount;
+    }
+
+    public void setPendingRequestsCount(long pendingRequestsCount) {
+        this.mPendingRequestsCount = pendingRequestsCount;
+    }
+
+    public List<TelephonyHistogram> getRequestHistograms() {
+        List<TelephonyHistogram> list;
+        synchronized (mRequestHistograms) {
+            list = new ArrayList<>(mRequestHistograms.size());
+            for (int i = 0; i < mRequestHistograms.size(); i++) {
+                TelephonyHistogram entry = new TelephonyHistogram(mRequestHistograms.valueAt(i));
+                list.add(entry);
+            }
+        }
+        return list;
+    }
+
+    public void updateRequestHistograms(int requestId, int time) {
+        synchronized (mRequestHistograms) {
+            TelephonyHistogram entry = mRequestHistograms.get(requestId);
+            if (entry == null) {
+                entry = new TelephonyHistogram(TelephonyHistogram.TELEPHONY_CATEGORY_RIL,
+                        requestId, REQUEST_HISTOGRAM_BUCKET_COUNT);
+                mRequestHistograms.put(requestId, entry);
+            }
+            entry.addTimeTaken(time);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ClientRequestStats{" +
+                "mCallingPackage='" + mCallingPackage + '\'' +
+                ", mCompletedRequestsWakelockTime=" + mCompletedRequestsWakelockTime +
+                ", mCompletedRequestsCount=" + mCompletedRequestsCount +
+                ", mPendingRequestsWakelockTime=" + mPendingRequestsWakelockTime +
+                ", mPendingRequestsCount=" + mPendingRequestsCount +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public void readFromParcel(Parcel in) {
+        mCallingPackage = in.readString();
+        mCompletedRequestsWakelockTime = in.readLong();
+        mCompletedRequestsCount = in.readLong();
+        mPendingRequestsWakelockTime = in.readLong();
+        mPendingRequestsCount = in.readLong();
+        ArrayList<TelephonyHistogram> requestHistograms = new ArrayList<TelephonyHistogram>();
+        in.readTypedList(requestHistograms, TelephonyHistogram.CREATOR);
+        for (TelephonyHistogram h : requestHistograms) {
+            mRequestHistograms.put(h.getId(), h);
+        }
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mCallingPackage);
+        dest.writeLong(mCompletedRequestsWakelockTime);
+        dest.writeLong(mCompletedRequestsCount);
+        dest.writeLong(mPendingRequestsWakelockTime);
+        dest.writeLong(mPendingRequestsCount);
+        dest.writeTypedList(getRequestHistograms());
+    }
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index f5e422d..0334254 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -226,6 +226,13 @@
      */
     public static final int DATA_LIMIT_REACHED = 55;
 
+    /**
+     * The emergency call was terminated because it was dialed on the wrong SIM slot.
+     * The call needs to be redialed the other slot.
+     * {@hide}
+     */
+    public static final int DIALED_ON_WRONG_SLOT = 56;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Please assign the new type the next id value below.
@@ -234,14 +241,14 @@
     // 4) Update toString() with the newly added disconnect type.
     // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
     //
-    // NextId: 56
+    // NextId: 57
     //*********************************************************************************************
 
     /** Smallest valid value for call disconnect codes. */
     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
 
     /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = DATA_LIMIT_REACHED;
+    public static final int MAXIMUM_VALID_VALUE = DIALED_ON_WRONG_SLOT;
 
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
@@ -361,6 +368,8 @@
             return "DATA_DISABLED";
         case DATA_LIMIT_REACHED:
             return "DATA_LIMIT_REACHED";
+        case DIALED_ON_WRONG_SLOT:
+            return "DIALED_ON_WRONG_SLOT";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 6b2ae3e..152b868 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.CountryDetector;
 import android.net.Uri;
@@ -3021,4 +3022,79 @@
         return SubscriptionManager.getDefaultVoiceSubscriptionId();
     }
     //==== End of utility methods used only in compareStrictly() =====
+
+
+    /*
+     * The config held calling number conversion map, expected to convert to emergency number.
+     */
+    private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray(
+            com.android.internal.R.array.config_convert_to_emergency_number_map);
+    /**
+     * Check whether conversion to emergency number is enabled
+     *
+     * @return {@code true} when conversion to emergency numbers is enabled,
+     *         {@code false} otherwise
+     *
+     * @hide
+     */
+    public static boolean isConvertToEmergencyNumberEnabled() {
+        return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0;
+    }
+
+    /**
+     * Converts to emergency number based on the conversion map.
+     * The conversion map is declared as config_convert_to_emergency_number_map.
+     *
+     * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling
+     * this function.
+     *
+     * @return The converted emergency number if the number matches conversion map,
+     * otherwise original number.
+     *
+     * @hide
+     */
+    public static String convertToEmergencyNumber(String number) {
+        if (TextUtils.isEmpty(number)) {
+            return number;
+        }
+
+        String normalizedNumber = normalizeNumber(number);
+
+        // The number is already emergency number. Skip conversion.
+        if (isEmergencyNumber(normalizedNumber)) {
+            return number;
+        }
+
+        for (String convertMap : CONVERT_TO_EMERGENCY_MAP) {
+            if (DBG) log("convertToEmergencyNumber: " + convertMap);
+            String[] entry = null;
+            String[] filterNumbers = null;
+            String convertedNumber = null;
+            if (!TextUtils.isEmpty(convertMap)) {
+                entry = convertMap.split(":");
+            }
+            if (entry != null && entry.length == 2) {
+                convertedNumber = entry[1];
+                if (!TextUtils.isEmpty(entry[0])) {
+                    filterNumbers = entry[0].split(",");
+                }
+            }
+            // Skip if the format of entry is invalid
+            if (TextUtils.isEmpty(convertedNumber) || filterNumbers == null
+                    || filterNumbers.length == 0) {
+                continue;
+            }
+
+            for (String filterNumber : filterNumbers) {
+                if (DBG) log("convertToEmergencyNumber: filterNumber = " + filterNumber
+                        + ", convertedNumber = " + convertedNumber);
+                if (!TextUtils.isEmpty(filterNumber) && filterNumber.equals(normalizedNumber)) {
+                    if (DBG) log("convertToEmergencyNumber: Matched. Successfully converted to: "
+                            + convertedNumber);
+                    return convertedNumber;
+                }
+            }
+        }
+        return number;
+    }
 }
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index b530a64..d657bae 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -29,32 +29,38 @@
 public class RadioAccessFamily implements Parcelable {
 
     // Radio Access Family
+    // 2G
     public static final int RAF_UNKNOWN = (1 <<  ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN);
+    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
     public static final int RAF_GPRS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS);
     public static final int RAF_EDGE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE);
-    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
     public static final int RAF_IS95A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A);
     public static final int RAF_IS95B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B);
     public static final int RAF_1xRTT = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
+    // 3G
     public static final int RAF_EVDO_0 = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0);
     public static final int RAF_EVDO_A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A);
-    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
-    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
-    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
     public static final int RAF_EVDO_B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B);
     public static final int RAF_EHRPD = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
-    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+    public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA);
+    public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA);
+    public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
     public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP);
-    public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM);
+    public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
     public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA);
+    // 4G
+    public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
     public static final int RAF_LTE_CA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA);
 
     // Grouping of RAFs
+    // 2G
     private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
-    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
     private static final int CDMA = RAF_IS95A | RAF_IS95B | RAF_1xRTT;
+    // 3G
     private static final int EVDO = RAF_EVDO_0 | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD;
+    private static final int HS = RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP;
     private static final int WCDMA = HS | RAF_UMTS;
+    // 4G
     private static final int LTE = RAF_LTE | RAF_LTE_CA;
 
     /* Phone ID of phone */
@@ -239,6 +245,24 @@
         return raf;
     }
 
+    /**
+     * Returns the highest capability of the RadioAccessFamily (4G > 3G > 2G).
+     * @param raf The RadioAccessFamily that we wish to filter
+     * @return The highest radio capability
+     */
+    public static int getHighestRafCapability(int raf) {
+        if ((LTE & raf) > 0) {
+            return TelephonyManager.NETWORK_CLASS_4_G;
+        }
+        if ((EVDO|HS|WCDMA & raf) > 0) {
+            return TelephonyManager.NETWORK_CLASS_3_G;
+        }
+        if((GSM|CDMA & raf) > 0) {
+            return TelephonyManager.NETWORK_CLASS_2_G;
+        }
+        return TelephonyManager.NETWORK_CLASS_UNKNOWN;
+    }
+
     public static int getNetworkTypeFromRaf(int raf) {
         int type;
 
diff --git a/telephony/java/android/telephony/Rlog.java b/telephony/java/android/telephony/Rlog.java
index b4f400f..cd0a012 100644
--- a/telephony/java/android/telephony/Rlog.java
+++ b/telephony/java/android/telephony/Rlog.java
@@ -16,8 +16,15 @@
 
 package android.telephony;
 
+import android.text.TextUtils;
 import android.util.Log;
 
+import android.util.Base64;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
 /**
  * A class to log strings to the RADIO LOG.
  *
@@ -87,11 +94,52 @@
 
     /**
      * Redact personally identifiable information for production users.
-     * If log tag is loggable in verbose mode, return the original string, otherwise return XXX.
+     * @param tag used to identify the source of a log message
+     * @param pii the personally identifiable information we want to apply secure hash on.
+     * @return If tag is loggable in verbose mode or pii is null, return the original input.
+     * otherwise return a secure Hash of input pii
      */
     public static String pii(String tag, Object pii) {
-        return (isLoggable(tag, Log.VERBOSE) ? String.valueOf(pii) : "XXX");
+        String val = String.valueOf(pii);
+        if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
+            return val;
+        }
+        return "[" + secureHash(val.getBytes()) + "]";
     }
 
+    /**
+     * Redact personally identifiable information for production users.
+     * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
+     * @param pii the personally identifiable information we want to apply secure hash on.
+     * @return If enablePiiLogging is set to true or pii is null, return the original input.
+     * otherwise return a secure Hash of input pii
+     */
+    public static String pii(boolean enablePiiLogging, Object pii) {
+        String val = String.valueOf(pii);
+        if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
+            return val;
+        }
+        return "[" + secureHash(val.getBytes()) + "]";
+    }
+
+    /**
+     * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+     *
+     * @return the hash
+     * @param input the bytes for which the secure hash should be computed.
+     */
+    private static String secureHash(byte[] input) {
+        MessageDigest messageDigest;
+
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            return "####";
+        }
+
+        byte[] result = messageDigest.digest(input);
+        return Base64.encodeToString(
+                result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+    }
 }
 
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 6229ed9..cf2d27e 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -340,7 +340,7 @@
         String iccIdToPrint = null;
         if (iccId != null) {
             if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
-                iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX";
+                iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
             } else {
                 iccIdToPrint = iccId;
             }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4138aa0..5b63199 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -37,6 +37,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.ClientRequestStats;
 import android.telephony.TelephonyHistogram;
 import android.util.Log;
 
@@ -705,6 +706,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 +728,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
      */
@@ -1629,6 +1663,12 @@
         }
     }
 
+    /**
+     * Network Class Definitions.
+     * Do not change this order, it is used for sorting during emergency calling in
+     * {@link TelephonyConnectionService#getFirstPhoneForEmergencyCall()}. Any newer technologies
+     * should be added after the current definitions.
+     */
     /** Unknown network class. {@hide} */
     public static final int NETWORK_CLASS_UNKNOWN = 0;
     /** Class of broadly defined "2G" networks. {@hide} */
@@ -5649,5 +5689,27 @@
             Log.e(TAG, "Error calling ITelephony#setPolicyDataEnabled", e);
         }
     }
+
+    /**
+     * Get Client request stats which will contain statistical information
+     * on each request made by client.
+     * Callers require either READ_PRIVILEGED_PHONE_STATE or
+     * READ_PHONE_STATE to retrieve the information.
+     * @param subId sub id
+     * @return List of Client Request Stats
+     * @hide
+     */
+    public List<ClientRequestStats> getClientRequestStats(int subId) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getClientRequestStats(getOpPackageName(), subId);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e);
+        }
+
+        return null;
+    }
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a8eaf36..c72b32a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -24,6 +24,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CellInfo;
+import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
@@ -1182,4 +1183,14 @@
      * @hide
      */
     void setPolicyDataEnabled(boolean enabled, int subId);
+
+
+    /**
+     * Get Client request stats which will contain statistical information
+     * on each request made by client.
+     * @param callingPackage package making the call.
+     * @param subId Subscription index
+     * @hide
+     */
+    List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index b417a1c..fdc68b9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -140,6 +140,18 @@
     /** APN type for Emergency PDN. This is not an IA apn, but is used
      * for access to carrier services in an emergency call situation. */
     public static final String APN_TYPE_EMERGENCY = "emergency";
+    /** Array of all APN types */
+    public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
+            APN_TYPE_MMS,
+            APN_TYPE_SUPL,
+            APN_TYPE_DUN,
+            APN_TYPE_HIPRI,
+            APN_TYPE_FOTA,
+            APN_TYPE_IMS,
+            APN_TYPE_CBS,
+            APN_TYPE_IA,
+            APN_TYPE_EMERGENCY
+    };
 
     public static final int RIL_CARD_MAX_APPS    = 8;
 
diff --git a/tests/Assist/res/drawable/assistant.xml b/tests/Assist/res/drawable/assistant.xml
index 2a89dda..56fe2de 100644
--- a/tests/Assist/res/drawable/assistant.xml
+++ b/tests/Assist/res/drawable/assistant.xml
@@ -19,9 +19,6 @@
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
     <path
-        android:pathData="M0 0h48v48H0z"
-        android:fillColor="#00000000"/>
-    <path
         android:fillColor="#FF000000"
         android:pathData="M38.0,4.0L10.0,4.0C7.79,4.0 6.0,5.79 6.0,8.0l0.0,28.0c0.0,2.21 1.79,4.0 4.0,4.0l8.0,0.0l6.0,6.0 6.0,-6.0l8.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zM27.75,25.75L24.0,34.0l-3.75,-8.25L12.0,22.0l8.25,-3.75L24.0,10.0l3.75,8.25L36.0,22.0l-8.25,3.75z"/>
 </vector>
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
index 0b58243..eb8f6c3 100644
--- a/tests/Camera2Tests/CameraToo/tests/Android.mk
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -20,6 +20,6 @@
 LOCAL_INSTRUMENTATION_FOR := CameraToo
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
 
 include $(BUILD_PACKAGE)
diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java
index 0111bc6..2ad0da9 100644
--- a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java
+++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java
@@ -15,6 +15,17 @@
         Decoder d = new Decoder(ByteBuffer.wrap(data));
 
         mViews = new ArrayList<>(100);
+
+        boolean dataIncludesWindowPosition = (data[0] == 'S');
+        Short windowLeftKey = null, windowTopKey = null;
+        Integer windowLeftValue = null, windowTopValue = null;
+        if (dataIncludesWindowPosition) {
+            windowLeftKey = (Short) d.readObject();
+            windowLeftValue = (Integer) d.readObject();
+            windowTopKey = (Short) d.readObject();
+            windowTopValue = (Integer) d.readObject();
+        }
+
         while (d.hasRemaining()) {
             Object o = d.readObject();
             if (o instanceof Map) {
@@ -27,6 +38,11 @@
             return;
         }
 
+        if (dataIncludesWindowPosition) {
+          mViews.get(0).put(windowLeftKey, windowLeftValue);
+          mViews.get(0).put(windowTopKey, windowTopValue);
+        }
+
         // the last one is the property map
         Map<Short,Object> idMap = mViews.remove(mViews.size() - 1);
         mIds = reverse(idMap);
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/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 12143b7..cb5f6c7 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -93,13 +93,21 @@
         </activity>
         <activity
             android:name=".TrivialRecyclerViewActivity"
-            android:label="General/Trivial Recycler ListView" >
+            android:label="General/Trivial RecyclerView" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.android.test.uibench.TEST" />
             </intent-filter>
         </activity>
         <activity
+            android:name=".SlowBindRecyclerViewActivity"
+            android:label="General/Slow Bind RecyclerView" >
+        <intent-filter>
+            <action android:name="android.intent.action.MAIN" />
+            <category android:name="com.android.test.uibench.TEST" />
+        </intent-filter>
+        </activity>
+        <activity
             android:name=".ActivityTransition"
             android:label="Transitions/Activity Transition" >
             <intent-filter>
diff --git a/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
new file mode 100644
index 0000000..e32862f
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/SlowBindRecyclerViewActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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.test.uibench;
+
+import android.content.Context;
+import android.os.Trace;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import com.android.test.uibench.recyclerview.RvBoxAdapter;
+import com.android.test.uibench.recyclerview.RvCompatListActivity;
+
+import java.util.concurrent.TimeUnit;
+
+public class SlowBindRecyclerViewActivity extends RvCompatListActivity {
+    /**
+     * Spin wait. Used instead of sleeping so a core is used up for the duration, and so
+     * traces/sampled profiling show the sections as expensive, and not just a scheduling mistake.
+     */
+    private static void spinWaitMs(long ms) {
+        long start = System.nanoTime();
+        while (System.nanoTime() - start < TimeUnit.MILLISECONDS.toNanos(ms));
+    }
+
+    @Override
+    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
+        return new GridLayoutManager(context, 3);
+    }
+
+    @Override
+    protected RecyclerView.Adapter createAdapter() {
+        return new RvBoxAdapter(this, TextUtils.buildSimpleStringList()) {
+            @Override
+            public void onBindViewHolder(ViewHolder holder, int position) {
+                Trace.beginSection("bind item " + position);
+
+                spinWaitMs(3);
+                super.onBindViewHolder(holder, position);
+                Trace.endSection();
+            }
+        };
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
new file mode 100644
index 0000000..3440f19
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvBoxAdapter.java
@@ -0,0 +1,99 @@
+/*
+ * 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.test.uibench.recyclerview;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class RvBoxAdapter extends RecyclerView.Adapter<RvBoxAdapter.ViewHolder> {
+
+    private int mBackground;
+
+    private List<String> mValues;
+
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        public TextView mTextView;
+
+        public ViewHolder(TextView v) {
+            super(v);
+            mTextView = v;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + " '" + mTextView.getText();
+        }
+    }
+
+    public RvBoxAdapter(Context context, String[] strings) {
+        TypedValue val = new TypedValue();
+        if (context.getTheme() != null) {
+            context.getTheme().resolveAttribute(
+                    android.R.attr.selectableItemBackground, val, true);
+        }
+        mBackground = val.resourceId;
+        mValues = new ArrayList<>();
+        Collections.addAll(mValues, strings);
+    }
+
+    @Override
+    public RvBoxAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
+        h.mTextView.setMinimumHeight(128);
+        h.mTextView.setPadding(20, 0, 20, 0);
+        h.mTextView.setFocusable(true);
+        h.mTextView.setBackgroundResource(mBackground);
+        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        lp.leftMargin = 10;
+        lp.rightMargin = 5;
+        lp.topMargin = 20;
+        lp.bottomMargin = 15;
+        h.mTextView.setLayoutParams(lp);
+        return h;
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        holder.mTextView.setText(position + ":" + mValues.get(position));
+        holder.mTextView.setMinHeight((200 + mValues.get(position).length() * 10));
+        holder.mTextView.setBackgroundColor(getBackgroundColor(position));
+    }
+
+    private int getBackgroundColor(int position) {
+        switch (position % 4) {
+            case 0: return Color.LTGRAY;
+            case 1: return Color.RED;
+            case 2: return Color.DKGRAY;
+            case 3: return Color.BLUE;
+        }
+        return Color.TRANSPARENT;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mValues.size();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
index e08dbc6..939b661 100644
--- a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
@@ -26,7 +26,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
 
 import com.android.test.uibench.R;
 
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
new file mode 100644
index 0000000..3137a73
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
@@ -0,0 +1,35 @@
+# 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AoapTestDeviceApp
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
new file mode 100644
index 0000000..99bb520
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        package="com.android.hardware.usb.aoapdevicetest" >
+    <application android:label="UsbAoapDeviceTestApp" >
+        <activity android:name=".UsbAoapDeviceTestActivity"
+            android:configChanges="keyboard|keyboardHidden" >
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+            </intent-filter>
+            <meta-data
+                android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                android:resource="@xml/accessory_filter"/>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.xml
new file mode 100644
index 0000000..cc71cf9
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/layout/device.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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+</LinearLayout>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml
new file mode 100644
index 0000000..d854a45
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/res/xml/accessory_filter.xml
@@ -0,0 +1,18 @@
+<?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>
+    <usb-accessory model="AOAP Test App" manufacturer="Android"/>
+</resources>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
new file mode 100644
index 0000000..aa4f8ca
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
@@ -0,0 +1,183 @@
+/*
+ * 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.hardware.usb.aoapdevicetest;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import libcore.io.IoUtils;
+
+public class UsbAoapDeviceTestActivity extends Activity {
+    private static final String TAG = UsbAoapDeviceTestActivity.class.getSimpleName();
+    private static final boolean DBG = true;
+
+    private static final String ACTION_USB_ACCESSORY_PERMISSION =
+            "com.android.hardware.usb.aoapdevicetest.ACTION_USB_ACCESSORY_PERMISSION";
+
+    private UsbManager mUsbManager;
+    private AccessoryReceiver mReceiver;
+    private ParcelFileDescriptor mFd;
+    private ReaderThread mReaderThread;
+    private UsbAccessory mAccessory;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.device);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        filter.addAction(ACTION_USB_ACCESSORY_PERMISSION);
+        mReceiver = new AccessoryReceiver();
+        registerReceiver(mReceiver, filter);
+
+        Intent intent = getIntent();
+        if (intent.getAction().equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+            UsbAccessory accessory =
+                    (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null) {
+                onAccessoryAttached(accessory);
+            } else {
+                throw new RuntimeException("USB accessory is null.");
+            }
+        } else {
+            finish();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        IoUtils.closeQuietly(mFd);
+        if (mReaderThread != null) {
+            mReaderThread.requestToQuit();
+            try {
+                mReaderThread.join(1000);
+            } catch (InterruptedException e) {
+            }
+            if (mReaderThread.isAlive()) { // reader thread stuck
+                Log.w(TAG, "ReaderThread still alive");
+            }
+        }
+    }
+
+    private void onAccessoryAttached(UsbAccessory accessory) {
+        Log.i(TAG, "Starting AOAP discovery protocol, accessory attached: " + accessory);
+        // Check whether we have permission to access the accessory.
+        if (!mUsbManager.hasPermission(accessory)) {
+            Log.i(TAG, "Prompting the user for access to the accessory.");
+            Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION);
+            intent.setPackage(getPackageName());
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+            mUsbManager.requestPermission(accessory, pendingIntent);
+            return;
+        }
+        mFd = mUsbManager.openAccessory(accessory);
+        if (mFd == null) {
+            Log.e(TAG, "UsbManager.openAccessory returned null");
+            finish();
+            return;
+        }
+        mAccessory = accessory;
+        mReaderThread = new ReaderThread(mFd);
+        mReaderThread.start();
+    }
+
+    private void onAccessoryDetached(UsbAccessory accessory) {
+        Log.i(TAG, "Accessory detached: " + accessory);
+        finish();
+    }
+
+    private class ReaderThread extends Thread {
+        private boolean mShouldQuit = false;
+        private final FileInputStream mInputStream;
+        private final FileOutputStream mOutputStream;
+        private final byte[] mBuffer = new byte[16384];
+
+        private ReaderThread(ParcelFileDescriptor fd) {
+            super("AOAP");
+            mInputStream = new FileInputStream(fd.getFileDescriptor());
+            mOutputStream = new FileOutputStream(fd.getFileDescriptor());
+        }
+
+        private synchronized void requestToQuit() {
+            mShouldQuit = true;
+        }
+
+        private synchronized boolean shouldQuit() {
+            return mShouldQuit;
+        }
+
+        @Override
+        public void run() {
+            while (!shouldQuit()) {
+                try {
+                    int read = mInputStream.read(mBuffer);
+                } catch (IOException e) {
+                    Log.i(TAG, "ReaderThread IOException", e);
+                    // AOAP App should release FD when IOException happens.
+                    // If FD is kept, device will not behave nicely on reset and multiple reset
+                    // can be required.
+                    finish();
+                    return;
+                }
+            }
+        }
+    }
+
+    private class AccessoryReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+            if (accessory != null) {
+                String action = intent.getAction();
+                if (action.equals(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+                    onAccessoryAttached(accessory);
+                } else if (action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)) {
+                    if (mAccessory != null && mAccessory.equals(accessory)) {
+                        onAccessoryDetached(accessory);
+                    }
+                } else if (action.equals(ACTION_USB_ACCESSORY_PERMISSION)) {
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        Log.i(TAG, "Accessory permission granted: " + accessory);
+                        onAccessoryAttached(accessory);
+                    } else {
+                        Log.e(TAG, "Accessory permission denied: " + accessory);
+                        finish();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
new file mode 100644
index 0000000..354e8c9
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
@@ -0,0 +1,35 @@
+# 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AoapTestHostApp
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
new file mode 100644
index 0000000..8cc470e
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        package="com.android.hardware.usb.aoaphosttest" >
+    <application android:label="UsbAoapHostTestApp" >
+      <activity android:name=".UsbAoapHostTestActivity"
+            android:configChanges="keyboard|keyboardHidden" >
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+            </intent-filter>
+            <meta-data
+                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+                android:resource="@xml/usb_device_filter"/>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.xml
new file mode 100644
index 0000000..cc71cf9
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/layout/host.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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+</LinearLayout>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml
new file mode 100644
index 0000000..0509e89
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/res/xml/usb_device_filter.xml
@@ -0,0 +1,24 @@
+<?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>
+    <!-- Android USB accessory: accessory -->
+    <usb-device vendor-id="16601" product-id="11520" />
+    <!-- Android USB accessory: accessory + adb -->
+    <usb-device vendor-id="16601" product-id="11521" />
+    <!-- not suppoted by UsbService, but external host management can use this. -->
+    <usb-aoap-device model="AOAP Test App" manufacturer="Android" version="1.0" />
+</resources>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java
new file mode 100644
index 0000000..6e2dc5d
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/src/com/android/hardware/usb/aoaphosttest/UsbAoapHostTestActivity.java
@@ -0,0 +1,165 @@
+/*
+ * 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.hardware.usb.aoaphosttest;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+public class UsbAoapHostTestActivity extends Activity {
+
+    private static final String TAG = UsbAoapHostTestActivity.class.getSimpleName();
+
+    private UsbManager mUsbManager;
+    private UsbStateReceiver mReceiver;
+    private UsbDevice mUsbDevice;
+    private UsbDeviceConnection mUsbConnection;
+    private ReaderThread mReaderThread;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.host);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        mReceiver = new UsbStateReceiver();
+        registerReceiver(mReceiver, filter);
+
+        Intent intent = getIntent();
+        if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+            mUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            mUsbConnection = mUsbManager.openDevice(mUsbDevice);
+            mReaderThread = new ReaderThread(mUsbDevice, mUsbConnection);
+            mReaderThread.start();
+        } else {
+            finish();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        if (mUsbConnection != null) {
+            mUsbConnection.close();
+        }
+        if (mReaderThread != null) {
+            mReaderThread.requestToQuit();
+            try {
+                mReaderThread.join(1000);
+            } catch (InterruptedException e) {
+            }
+            if (mReaderThread.isAlive()) { // reader thread stuck
+                throw new RuntimeException("ReaderThread still alive");
+            }
+        }
+    }
+
+    private static boolean isDevicesMatching(UsbDevice l, UsbDevice r) {
+        if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId() &&
+                TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
+            return true;
+        }
+        return false;
+    }
+
+    private class ReaderThread extends Thread {
+        private boolean mShouldQuit = false;
+        private final UsbDevice mDevice;
+        private final UsbDeviceConnection mUsbConnection;
+        private final UsbEndpoint mBulkIn;
+        private final UsbEndpoint mBulkOut;
+        private final byte[] mBuffer = new byte[16384];
+
+        private ReaderThread(UsbDevice device, UsbDeviceConnection conn) {
+            super("AOAP");
+            mDevice = device;
+            mUsbConnection = conn;
+            UsbInterface iface = mDevice.getInterface(0);
+            // Setup bulk endpoints.
+            UsbEndpoint bulkIn = null;
+            UsbEndpoint bulkOut = null;
+            for (int i = 0; i < iface.getEndpointCount(); i++) {
+                UsbEndpoint ep = iface.getEndpoint(i);
+                if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
+                    if (bulkIn == null) {
+                        bulkIn = ep;
+                    }
+                } else {
+                    if (bulkOut == null) {
+                        bulkOut = ep;
+                    }
+                }
+            }
+            if (bulkIn == null || bulkOut == null) {
+                throw new IllegalStateException("Unable to find bulk endpoints");
+            }
+            mBulkIn = bulkIn;
+            mBulkOut = bulkOut;
+        }
+
+        private synchronized void requestToQuit() {
+            mShouldQuit = true;
+        }
+
+        private synchronized boolean shouldQuit() {
+            return mShouldQuit;
+        }
+
+        @Override
+        public void run() {
+            while (!shouldQuit()) {
+                int read = mUsbConnection.bulkTransfer(mBulkIn, mBuffer, mBuffer.length,
+                        Integer.MAX_VALUE);
+                if (read < 0) {
+                    throw new RuntimeException("bulkTransfer failed, read = " + read);
+                }
+            }
+        }
+    }
+
+    private class UsbStateReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
+                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                if (isDevicesMatching(mUsbDevice, device)) {
+                    finish();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
new file mode 100644
index 0000000..2d6d6ea8
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
@@ -0,0 +1,37 @@
+# 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp
+
+LOCAL_PRIVILEGED_MODULE := true
+# TODO remove tests tag
+#LOCAL_MODULE_TAGS := tests
+#LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..97bbefb
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        package="com.android.hardware.usb.externalmanagementtest" >
+
+    <uses-permission android:name="android.permission.MANAGE_USB" />
+    <application android:label="UsbHostExternalManagementTestApp" >
+        <activity android:name=".UsbHostManagementActivity"
+            android:configChanges="keyboard|keyboardHidden" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml
new file mode 100644
index 0000000..5191184
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/layout/host_management.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+    <TextView android:id="@+id/device_info_text"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:text="@string/current_device"
+        />
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="horizontal" >
+        <Button android:id="@+id/start_aoap_button"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/start_aoap"
+        />
+        <Button android:id="@+id/start_aoap_activity_button"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/start_aoap_activity"
+        />
+        <Button android:id="@+id/reset_button"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/usb_reset"
+            />
+        <Button android:id="@+id/finish_button"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/finish_app"
+            />
+    </LinearLayout>
+    <TextView android:id="@+id/aoap_apps_text"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:text="@string/aoap_app_msg"
+        />
+
+</LinearLayout>
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/values/strings.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/values/strings.xml
new file mode 100644
index 0000000..79d2c43
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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_title">UsbHostExternalManagementTestApp</string>
+    <string name="current_device">No device</string>
+    <string name="aoap_app_msg">AOAP App message</string>
+    <string name="usb_reset">Reset USB</string>
+    <string name="start_aoap">Start Test AOAP</string>
+    <string name="start_aoap_activity">Start Test AOAP Activity</string>
+    <string name="finish_app">Finish</string>
+</resources>
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/AoapInterface.java b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/AoapInterface.java
new file mode 100644
index 0000000..89dc441
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/AoapInterface.java
@@ -0,0 +1,135 @@
+/**
+ * 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.hardware.usb.externalmanagementtest;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+public class AoapInterface {
+    /**
+     * Use Google Vendor ID when in accessory mode
+     */
+    public static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+    /**
+     * Product ID to use when in accessory mode
+     */
+    public static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+    /**
+     * Product ID to use when in accessory mode and adb is enabled
+     */
+    public static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+    /**
+     * Indexes for strings sent by the host via ACCESSORY_SEND_STRING
+     */
+    public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+    public static final int ACCESSORY_STRING_MODEL = 1;
+    public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+    public static final int ACCESSORY_STRING_VERSION = 3;
+    public static final int ACCESSORY_STRING_URI = 4;
+    public static final int ACCESSORY_STRING_SERIAL = 5;
+
+    /**
+     * Control request for retrieving device's protocol version
+     *
+     *  requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_GET_PROTOCOL
+     *  value:          0
+     *  index:          0
+     *  data            version number (16 bits little endian)
+     *                     1 for original accessory support
+     *                     2 adds HID and device to host audio support
+     */
+    public static final int ACCESSORY_GET_PROTOCOL = 51;
+
+    /**
+     * Control request for host to send a string to the device
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SEND_STRING
+     *  value:          0
+     *  index:          string ID
+     *  data            zero terminated UTF8 string
+     *
+     *  The device can later retrieve these strings via the
+     *  ACCESSORY_GET_STRING_* ioctls
+     */
+    public static final int ACCESSORY_SEND_STRING = 52;
+
+    /**
+     * Control request for starting device in accessory mode.
+     * The host sends this after setting all its strings to the device.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_START
+     *  value:          0
+     *  index:          0
+     *  data            none
+     */
+    public static final int ACCESSORY_START = 53;
+
+    /**
+     * Max payload size for AOAP. Limited by driver.
+     */
+    public static final int MAX_PAYLOAD_SIZE = 16384;
+
+    private static final String TAG = AoapInterface.class.getSimpleName();
+
+    public static int getProtocol(UsbDeviceConnection conn) {
+        byte buffer[] = new byte[2];
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+        if (len != 2) {
+            return -1;
+        }
+        return (buffer[1] << 8) | buffer[0];
+    }
+
+    public static void sendString(UsbDeviceConnection conn, int index, String string) {
+        byte[] buffer = (string + "\0").getBytes();
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_SEND_STRING, 0, index,
+                buffer, buffer.length, 10000);
+        if (len != buffer.length) {
+            throw new RuntimeException("Failed to send string " + index + ": \"" + string + "\"");
+        } else {
+            Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
+        }
+    }
+
+    public static void sendAoapStart(UsbDeviceConnection conn) {
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_START, 0, 0, null, 0, 10000);
+        if (len < 0) {
+            throw new RuntimeException("control transfer for accessory start failed:" + len);
+        }
+    }
+
+    public static boolean isDeviceInAoapMode(UsbDevice device) {
+        final int vid = device.getVendorId();
+        final int pid = device.getProductId();
+        return vid == USB_ACCESSORY_VENDOR_ID
+                && (pid == USB_ACCESSORY_PRODUCT_ID
+                        || pid == USB_ACCESSORY_ADB_PRODUCT_ID);
+    }
+}
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java
new file mode 100644
index 0000000..1cb394e
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbDeviceStateController.java
@@ -0,0 +1,326 @@
+/*
+ * 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.hardware.usb.externalmanagementtest;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.LinkedList;
+
+import dalvik.system.CloseGuard;
+
+public class UsbDeviceStateController {
+
+    public interface UsbDeviceStateListener {
+        void onDeviceResetComplete(UsbDevice device);
+        void onAoapStartComplete(UsbDevice devie);
+    }
+
+    private static final String TAG = UsbDeviceStateController.class.getSimpleName();
+
+    private static final int MAX_USB_STATE_CHANGE_WAIT = 5;
+    private static final long USB_STATE_CHANGE_WAIT_TIMEOUT_MS = 500;
+
+    private final Context mContext;
+    private final UsbDeviceStateListener mListener;
+    private final UsbManager mUsbManager;
+    private final HandlerThread mHandlerThread;
+    private final UsbStateHandler mHandler;
+    private final UsbDeviceBroadcastReceiver mUsbStateBroadcastReceiver;
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private final Object mUsbConnectionChangeWait = new Object();
+    private final LinkedList<UsbDevice> mDevicesRemoved = new LinkedList<>();
+    private final LinkedList<UsbDevice> mDevicesAdded = new LinkedList<>();
+    private boolean mShouldQuit = false;
+
+    public UsbDeviceStateController(Context context, UsbDeviceStateListener listener,
+            UsbManager usbManager) {
+        mContext = context;
+        mListener = listener;
+        mUsbManager = usbManager;
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mCloseGuard.open("release");
+        mHandler = new UsbStateHandler(mHandlerThread.getLooper());
+        mUsbStateBroadcastReceiver = new UsbDeviceBroadcastReceiver();
+    }
+
+    public void init() {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        mContext.registerReceiver(mUsbStateBroadcastReceiver, filter);
+    }
+
+    public void release() {
+        mCloseGuard.close();
+        mContext.unregisterReceiver(mUsbStateBroadcastReceiver);
+        synchronized (mUsbConnectionChangeWait) {
+            mShouldQuit = true;
+            mUsbConnectionChangeWait.notifyAll();
+        }
+        mHandlerThread.quit();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            release();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    public void startDeviceReset(UsbDevice device) {
+        mHandler.requestDeviceReset(device);
+    }
+
+    public void startAoap(AoapSwitchRequest request) {
+        mHandler.requestAoap(request);
+    }
+
+    private void doHandleDeviceReset(UsbDevice device) {
+        boolean isInAoap = AoapInterface.isDeviceInAoapMode(device);
+        UsbDevice completedDevice = null;
+        if (isInAoap) {
+            completedDevice = resetUsbDeviceAndConfirmModeChange(device);
+        } else {
+            UsbDeviceConnection conn = openConnection(device);
+            if (conn == null) {
+                throw new RuntimeException("cannot open conneciton for device: " + device);
+            } else {
+                try {
+                    if (!conn.resetDevice()) {
+                        throw new RuntimeException("resetDevice failed for devie: " + device);
+                    } else {
+                        completedDevice = device;
+                    }
+                } finally {
+                    conn.close();
+                }
+            }
+        }
+        mListener.onDeviceResetComplete(completedDevice);
+    }
+
+    private void doHandleAoapStart(AoapSwitchRequest request) {
+        UsbDevice device = request.device;
+        boolean isInAoap = AoapInterface.isDeviceInAoapMode(device);
+        if (isInAoap) {
+            device = resetUsbDeviceAndConfirmModeChange(device);
+            if (device == null) {
+                mListener.onAoapStartComplete(null);
+                return;
+            }
+        }
+        UsbDeviceConnection connection = openConnection(device);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
+                request.manufacturer);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
+                request.model);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
+                request.description);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION,
+                request.version);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI, request.uri);
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, request.serial);
+        AoapInterface.sendAoapStart(connection);
+        device = resetUsbDeviceAndConfirmModeChange(device);
+        if (device == null) {
+            mListener.onAoapStartComplete(null);
+        }
+        if (!AoapInterface.isDeviceInAoapMode(device)) {
+            Log.w(TAG, "Device not in AOAP mode after switching: " + device);
+            mListener.onAoapStartComplete(device);
+        }
+        mListener.onAoapStartComplete(device);
+    }
+
+    private UsbDevice resetUsbDeviceAndConfirmModeChange(UsbDevice device) {
+        int retry = 0;
+        boolean removalDetected = false;
+        while (retry < MAX_USB_STATE_CHANGE_WAIT) {
+            UsbDeviceConnection connNow = openConnection(device);
+            if (connNow == null) {
+                removalDetected = true;
+                break;
+            }
+            connNow.resetDevice();
+            connNow.close();
+            synchronized (mUsbConnectionChangeWait) {
+                try {
+                    mUsbConnectionChangeWait.wait(USB_STATE_CHANGE_WAIT_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    break;
+                }
+                if (mShouldQuit) {
+                    return null;
+                }
+                if (isDeviceRemovedLocked(device)) {
+                    removalDetected = true;
+                    break;
+                }
+            }
+            retry++;
+        }
+        if (!removalDetected) {
+            Log.w(TAG, "resetDevice failed for device, device still in the same mode: " + device);
+            return null;
+        }
+        retry = 0;
+        UsbDevice newlyAttached = null;
+        while (retry < MAX_USB_STATE_CHANGE_WAIT) {
+            synchronized (mUsbConnectionChangeWait) {
+                try {
+                    mUsbConnectionChangeWait.wait(USB_STATE_CHANGE_WAIT_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    break;
+                }
+                if (mShouldQuit) {
+                    return null;
+                }
+                newlyAttached = checkDeviceAttachedLocked(device);
+            }
+            if (newlyAttached != null) {
+                break;
+            }
+            retry++;
+        }
+        if (newlyAttached == null) {
+            Log.w(TAG, "resetDevice failed for device, device disconnected: " + device);
+            return null;
+        }
+        return newlyAttached;
+    }
+
+    private boolean isDeviceRemovedLocked(UsbDevice device) {
+        for (UsbDevice removed : mDevicesRemoved) {
+            if (UsbUtil.isDevicesMatching(device, removed)) {
+                mDevicesRemoved.clear();
+                return true;
+            }
+        }
+        mDevicesRemoved.clear();
+        return false;
+    }
+
+    private UsbDevice checkDeviceAttachedLocked(UsbDevice device) {
+        for (UsbDevice attached : mDevicesAdded) {
+            if (UsbUtil.isTheSameDevice(device, attached)) {
+                mDevicesAdded.clear();
+                return attached;
+            }
+        }
+        mDevicesAdded.clear();
+        return null;
+    }
+
+    public UsbDeviceConnection openConnection(UsbDevice device) {
+        mUsbManager.grantPermission(device);
+        return mUsbManager.openDevice(device);
+    }
+
+    private void handleUsbDeviceAttached(UsbDevice device) {
+        synchronized (mUsbConnectionChangeWait) {
+            mDevicesAdded.add(device);
+            mUsbConnectionChangeWait.notifyAll();
+        }
+    }
+
+    private void handleUsbDeviceDetached(UsbDevice device) {
+        synchronized (mUsbConnectionChangeWait) {
+            mDevicesRemoved.add(device);
+            mUsbConnectionChangeWait.notifyAll();
+        }
+    }
+
+    private class UsbStateHandler extends Handler {
+        private final int MSG_RESET_DEVICE = 1;
+        private final int MSG_AOAP = 2;
+
+        private UsbStateHandler(Looper looper) {
+            super(looper);
+        }
+
+        private void requestDeviceReset(UsbDevice device) {
+            Message msg = obtainMessage(MSG_RESET_DEVICE, device);
+            sendMessage(msg);
+        }
+
+        private void requestAoap(AoapSwitchRequest request) {
+            Message msg = obtainMessage(MSG_AOAP, request);
+            sendMessage(msg);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_RESET_DEVICE:
+                    doHandleDeviceReset((UsbDevice) msg.obj);
+                    break;
+                case MSG_AOAP:
+                    doHandleAoapStart((AoapSwitchRequest) msg.obj);
+                    break;
+            }
+        }
+    }
+
+    private class UsbDeviceBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
+                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                handleUsbDeviceDetached(device);
+            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                handleUsbDeviceAttached(device);
+            }
+        }
+    }
+
+    public static class AoapSwitchRequest {
+        public final UsbDevice device;
+        public final String manufacturer;
+        public final String model;
+        public final String description;
+        public final String version;
+        public final String uri;
+        public final String serial;
+
+        public AoapSwitchRequest(UsbDevice device, String manufacturer, String model,
+                String description, String version, String uri, String serial) {
+            this.device = device;
+            this.manufacturer = manufacturer;
+            this.model = model;
+            this.description = description;
+            this.version = version;
+            this.uri = uri;
+            this.serial = serial;
+        }
+    }
+}
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbHostManagementActivity.java b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbHostManagementActivity.java
new file mode 100644
index 0000000..2d9226f
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbHostManagementActivity.java
@@ -0,0 +1,246 @@
+/*
+ * 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.hardware.usb.externalmanagementtest;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.net.nsd.NsdManager.DiscoveryListener;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.hardware.usb.externalmanagementtest.UsbDeviceStateController.AoapSwitchRequest;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+public class UsbHostManagementActivity extends Activity
+        implements UsbDeviceStateController.UsbDeviceStateListener {
+
+    private static final String TAG = UsbHostManagementActivity.class.getSimpleName();
+
+    private static final String AOAP_APP_PACKAGE_NAME = "com.android.hardware.usb.aoaphosttest";
+    private static final String AOAP_APP_ACTIVITY_NAME =
+            "com.android.hardware.usb.aoaphosttest.UsbAoapHostTestActivity";
+
+    private TextView mDeviceInfoText;
+    private Button mStartAoapButton;
+    private Button mStartAoapActivityButton;
+    private TextView mAoapAppLog;
+    private Button mResetUsbButton;
+    private Button mFinishButton;
+    private UsbDevice mUsbDevice = null;
+    private final UsbDeviceConnectionListener mConnectionListener =
+            new UsbDeviceConnectionListener();
+    private UsbDeviceStateController mUsbDeviceStateController;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.host_management);
+        mDeviceInfoText = (TextView) findViewById(R.id.device_info_text);
+        mStartAoapButton = (Button) findViewById(R.id.start_aoap_button);
+        mStartAoapActivityButton = (Button) findViewById(R.id.start_aoap_activity_button);
+        mAoapAppLog = (TextView) findViewById(R.id.aoap_apps_text);
+        mResetUsbButton = (Button) findViewById(R.id.reset_button);
+        mFinishButton = (Button) findViewById(R.id.finish_button);
+
+        Intent intent = getIntent();
+        if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+            mUsbDevice = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        }
+        UsbManager usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+        if (mUsbDevice == null) {
+            LinkedList<UsbDevice> devices = UsbUtil.findAllPossibleAndroidDevices(usbManager);
+            if (devices.size() > 0) {
+                mUsbDevice = devices.getLast();
+            }
+        }
+        updateDevice(mUsbDevice);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        registerReceiver(mConnectionListener, filter);
+
+        mStartAoapButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mUsbDevice == null) {
+                    return;
+                }
+                startAoap(mUsbDevice);
+            }
+        });
+        mStartAoapActivityButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mUsbDevice == null) {
+                    return;
+                }
+                startAoapActivity(mUsbDevice);
+            }
+        });
+        mResetUsbButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mUsbDevice == null) {
+                    return;
+                }
+                resetDevice(mUsbDevice);
+            }
+        });
+        mFinishButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                finish();
+            }
+        });
+
+        mUsbDeviceStateController = new UsbDeviceStateController(this, this, usbManager);
+        mUsbDeviceStateController.init();
+    }
+
+
+    private void startAoap(UsbDevice device) {
+        AoapSwitchRequest request = new AoapSwitchRequest(device, "Android", "AOAP Test App", "",
+                "1.0", "", "");
+        mUsbDeviceStateController.startAoap(request);
+    }
+
+    private void startAoapActivity(UsbDevice device) {
+        if (!AoapInterface.isDeviceInAoapMode(device)) {
+            Log.w(TAG, "Device not in AOAP mode:" + device);
+            return;
+        }
+        PackageManager pm = getPackageManager();
+        PackageInfo pi = null;
+        try {
+            pi = pm.getPackageInfo(AOAP_APP_PACKAGE_NAME, 0);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "AOAP Test app not found:" + AOAP_APP_PACKAGE_NAME);
+        }
+        int uid = pi.applicationInfo.uid;
+        UsbManager usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+        usbManager.grantPermission(device, uid);
+        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+        intent.setComponent(new ComponentName(AOAP_APP_PACKAGE_NAME, AOAP_APP_ACTIVITY_NAME));
+        startActivity(intent);
+    }
+
+    private void resetDevice(UsbDevice device) {
+        Log.i(TAG, "resetDevice");
+        mUsbDeviceStateController.startDeviceReset(device);
+    }
+
+    private void dumpUsbDevices() {
+        UsbManager usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+        HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
+        StringBuilder sb = new StringBuilder();
+        sb.append("Usb devices\n");
+        for (UsbDevice device : devices.values()) {
+            sb.append(device.toString() + "\n");
+        }
+        Log.i(TAG, sb.toString());
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.i(TAG, "onDestroy");
+        super.onDestroy();
+        unregisterReceiver(mConnectionListener);
+        mUsbDeviceStateController.release();
+    }
+
+    private void handleUsbDeviceAttached(UsbDevice device) {
+        boolean deviceReplaced = false;
+        if (mUsbDevice == null) {
+            deviceReplaced = true;
+        } else {
+            UsbManager usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+            if (!UsbUtil.isDeviceConnected(usbManager, mUsbDevice)) {
+                deviceReplaced = true;
+            }
+        }
+        if (deviceReplaced) {
+            Log.i(TAG, "device attached:" + device);
+            updateDevice(device);
+        }
+    }
+
+    private void handleUsbDeviceDetached(UsbDevice device) {
+        if (mUsbDevice != null && UsbUtil.isDevicesMatching(mUsbDevice, device)) {
+            Log.i(TAG, "device removed ");
+            updateDevice(device);
+        }
+    }
+
+    private void updateDevice(UsbDevice device) {
+        mUsbDevice = device;
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mUsbDevice == null) {
+                    mDeviceInfoText.setText("disconnected");
+                } else {
+                    mDeviceInfoText.setText(mUsbDevice.toString());
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onDeviceResetComplete(UsbDevice device) {
+        updateDevice(device);
+    }
+
+
+    @Override
+    public void onAoapStartComplete(UsbDevice device) {
+        updateDevice(device);
+    }
+
+    private class UsbDeviceConnectionListener extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
+                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                handleUsbDeviceDetached(device);
+            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+                UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                handleUsbDeviceAttached(device);
+            }
+        }
+    }
+}
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbUtil.java b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbUtil.java
new file mode 100644
index 0000000..8d0f73e
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/src/com/android/hardware/usb/externalmanagementtest/UsbUtil.java
@@ -0,0 +1,87 @@
+/*
+ * 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.hardware.usb.externalmanagementtest;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import android.content.Context;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.text.TextUtils;
+
+public class UsbUtil {
+    public static final String ADB_INTERFACE_NAME = "ADB Interface";
+    public static final String AOAP_INTERFACE_NAME = "Android Accessory Interface";
+    public static final String MTP_INTERFACE_NAME = "MTP";
+
+    public static LinkedList<UsbDevice> findAllPossibleAndroidDevices(UsbManager usbManager) {
+        HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
+        LinkedList<UsbDevice> androidDevices = null;
+        for (UsbDevice device : devices.values()) {
+            if (possiblyAndroid(device)) {
+                if (androidDevices == null) {
+                    androidDevices = new LinkedList<>();
+                }
+                androidDevices.add(device);
+            }
+        }
+        return androidDevices;
+    }
+
+    public static boolean possiblyAndroid(UsbDevice device) {
+        int numInterfaces = device.getInterfaceCount();
+        for (int i = 0; i < numInterfaces; i++) {
+            UsbInterface usbInterface = device.getInterface(i);
+            String interfaceName = usbInterface.getName();
+            // more thorough check can be added, later
+            if (AOAP_INTERFACE_NAME.equals(interfaceName) ||
+                    ADB_INTERFACE_NAME.equals(interfaceName) ||
+                    MTP_INTERFACE_NAME.equals(interfaceName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isTheSameDevice(UsbDevice l, UsbDevice r) {
+        if (TextUtils.equals(l.getManufacturerName(), r.getManufacturerName()) &&
+                TextUtils.equals(l.getProductName(), r.getProductName()) &&
+                TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean isDevicesMatching(UsbDevice l, UsbDevice r) {
+        if (l.getVendorId() == r.getVendorId() && l.getProductId() == r.getProductId() &&
+                TextUtils.equals(l.getSerialNumber(), r.getSerialNumber())) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean isDeviceConnected(UsbManager usbManager, UsbDevice device) {
+        HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
+        for (UsbDevice dev : devices.values()) {
+            if (isDevicesMatching(dev, device)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index cbc6c76..5fdf0dd 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -1,6 +1,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.test.voiceinteraction">
 
+    <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="25" />
+
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
     <uses-permission android:name="android.permission.READ_LOGS" />
 
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 2a490d1..04f46d9 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -61,7 +61,7 @@
     liblog \
     libcutils \
     libexpat \
-    libziparchive-host \
+    libziparchive \
     libbase
 
 aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER_FROM_FILE)\"
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index d80aaba..9b62e14 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -540,7 +540,7 @@
 }
 
 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
-                              const char* name, const char* reason, bool sdk23) {
+                              const char* name, const String8& reason, bool sdk23) {
     String8 name8(name);
     ssize_t idx = impliedFeatures->indexOfKey(name8);
     if (idx < 0) {
@@ -553,7 +553,7 @@
     if (feature->impliedBySdk23 && !sdk23) {
         feature->impliedBySdk23 = false;
     }
-    feature->reasons.add(String8(reason));
+    feature->reasons.add(reason);
 }
 
 static void printFeatureGroupImpl(const FeatureGroup& grp,
@@ -651,50 +651,58 @@
                                             bool impliedBySdk23Permission) {
     if (name == "android.permission.CAMERA") {
         addImpliedFeature(impliedFeatures, "android.hardware.camera",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+                          String8::format("requested %s permission", name.string()),
+                          impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
-        addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+        if (targetSdk < SDK_LOLLIPOP) {
+            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
+                              String8::format("requested %s permission", name.string()),
+                              impliedBySdk23Permission);
+            addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
+                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
+                              impliedBySdk23Permission);
+        }
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
-    } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
-        addImpliedFeature(impliedFeatures, "android.hardware.location",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+                String8::format("requested %s permission", name.string()),
+                impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
-        addImpliedFeature(impliedFeatures, "android.hardware.location.network",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+        if (targetSdk < SDK_LOLLIPOP) {
+            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
+                              String8::format("requested %s permission", name.string()),
+                              impliedBySdk23Permission);
+            addImpliedFeature(impliedFeatures, "android.hardware.location.network",
+                              String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
+                              impliedBySdk23Permission);
+        }
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
-    } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+                          String8::format("requested %s permission", name.string()),
+                          impliedBySdk23Permission);
+    } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
+               name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
                name == "android.permission.INSTALL_LOCATION_PROVIDER") {
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+                          String8::format("requested %s permission", name.string()),
+                          impliedBySdk23Permission);
     } else if (name == "android.permission.BLUETOOTH" ||
                name == "android.permission.BLUETOOTH_ADMIN") {
-        if (targetSdk > 4) {
+        if (targetSdk > SDK_DONUT) {
             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
-                    String8::format("requested %s permission", name.string())
-                    .string(), impliedBySdk23Permission);
+                              String8::format("requested %s permission", name.string()),
+                              impliedBySdk23Permission);
             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
-                    "targetSdkVersion > 4", impliedBySdk23Permission);
+                              String8::format("targetSdkVersion > %d", SDK_DONUT),
+                              impliedBySdk23Permission);
         }
     } else if (name == "android.permission.RECORD_AUDIO") {
         addImpliedFeature(impliedFeatures, "android.hardware.microphone",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+                          String8::format("requested %s permission", name.string()),
+                          impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
                name == "android.permission.CHANGE_WIFI_STATE" ||
                name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
         addImpliedFeature(impliedFeatures, "android.hardware.wifi",
-                String8::format("requested %s permission", name.string())
-                .string(), impliedBySdk23Permission);
+                          String8::format("requested %s permission", name.string()),
+                          impliedBySdk23Permission);
     } else if (name == "android.permission.CALL_PHONE" ||
                name == "android.permission.CALL_PRIVILEGED" ||
                name == "android.permission.MODIFY_PHONE_STATE" ||
@@ -707,8 +715,8 @@
                name == "android.permission.WRITE_APN_SETTINGS" ||
                name == "android.permission.WRITE_SMS") {
         addImpliedFeature(impliedFeatures, "android.hardware.telephony",
-                String8("requested a telephony permission").string(),
-                impliedBySdk23Permission);
+                          String8("requested a telephony permission"),
+                          impliedBySdk23Permission);
     }
 }
 
@@ -1273,7 +1281,7 @@
                         const size_t NL = locales.size();
                         for (size_t i=0; i<NL; i++) {
                             const char* localeStr =  locales[i].string();
-                            assets.setLocale(localeStr != NULL ? localeStr : "");
+                            assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
                             String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
                                     &error);
                             if (llabel != "") {
@@ -1678,18 +1686,18 @@
                             if (error == "") {
                                 if (orien == 0 || orien == 6 || orien == 8) {
                                     // Requests landscape, sensorLandscape, or reverseLandscape.
-                                    addImpliedFeature(&impliedFeatures,
-                                                      "android.hardware.screen.landscape",
-                                                      "one or more activities have specified a "
-                                                      "landscape orientation",
-                                                      false);
+                                    addImpliedFeature(
+                                            &impliedFeatures, "android.hardware.screen.landscape",
+                                            String8("one or more activities have specified a "
+                                                    "landscape orientation"),
+                                            false);
                                 } else if (orien == 1 || orien == 7 || orien == 9) {
                                     // Requests portrait, sensorPortrait, or reversePortrait.
-                                    addImpliedFeature(&impliedFeatures,
-                                                      "android.hardware.screen.portrait",
-                                                      "one or more activities have specified a "
-                                                      "portrait orientation",
-                                                      false);
+                                    addImpliedFeature(
+                                            &impliedFeatures, "android.hardware.screen.portrait",
+                                            String8("one or more activities have specified a "
+                                                    "portrait orientation"),
+                                            false);
                                 }
                             }
                         } else if (tag == "uses-library") {
@@ -2054,7 +2062,7 @@
             // directly or implied, required or not), then the faketouch feature is implied.
             if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
                 addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
-                                  "default feature for all apps", false);
+                                  String8("default feature for all apps"), false);
             }
 
             const size_t numFeatureGroups = featureGroups.size();
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 1e7875d..75a3160 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -23,12 +23,8 @@
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
 
 #if !defined(_WIN32)
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
 #  define STATUST(x) x
 #else
-#  define ZD "%ld"
-#  define ZD_TYPE long
 #  define STATUST(x) (status_t)x
 #endif
 
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/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 37a4933..866291a 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -14,12 +14,8 @@
 
 // SSIZE: mingw does not have signed size_t == ssize_t.
 #if !defined(_WIN32)
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
 #  define SSIZE(x) x
 #else
-#  define ZD "%ld"
-#  define ZD_TYPE long
 #  define SSIZE(x) (signed size_t)x
 #endif
 
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 625b0bf..253bcca 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -12,7 +12,6 @@
 
 #include <androidfw/ResourceTypes.h>
 #include <utils/String16.h>
-#include <utils/TypeHelpers.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -179,13 +178,5 @@
     Vector<size_t>                          mOriginalPosToNewPos;
 };
 
-// The entry types are trivially movable because all fields they contain, including
-// the vectors and strings, are trivially movable.
-namespace android {
-    ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry);
-    ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style_span);
-    ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style);
-};
-
 #endif
 
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 4f38e94..b57d4db 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -23,7 +23,11 @@
 main := Main.cpp
 sources := \
 	compile/IdAssigner.cpp \
+	compile/InlineXmlFormatParser.cpp \
+	compile/NinePatch.cpp \
 	compile/Png.cpp \
+	compile/PngChunkFilter.cpp \
+	compile/PngCrunch.cpp \
 	compile/PseudolocaleGenerator.cpp \
 	compile/Pseudolocalizer.cpp \
 	compile/XmlIdCollector.cpp \
@@ -31,15 +35,19 @@
 	flatten/Archive.cpp \
 	flatten/TableFlattener.cpp \
 	flatten/XmlFlattener.cpp \
+	io/File.cpp \
 	io/FileSystem.cpp \
+	io/Io.cpp \
 	io/ZipArchive.cpp \
 	link/AutoVersioner.cpp \
 	link/ManifestFixer.cpp \
 	link/ProductFilter.cpp \
 	link/PrivateAttributeMover.cpp \
 	link/ReferenceLinker.cpp \
+	link/ResourceDeduper.cpp \
 	link/TableMerger.cpp \
 	link/VersionCollapser.cpp \
+	link/XmlNamespaceRemover.cpp \
 	link/XmlReferenceLinker.cpp \
 	process/SymbolTable.cpp \
 	proto/ProtoHelpers.cpp \
@@ -53,6 +61,7 @@
 	util/Util.cpp \
 	ConfigDescription.cpp \
 	Debug.cpp \
+	DominatorTree.cpp \
 	Flags.cpp \
 	java/AnnotationProcessor.cpp \
 	java/ClassDefinition.cpp \
@@ -74,8 +83,12 @@
 
 sources += Format.proto
 
+sourcesJni :=
+
 testSources := \
 	compile/IdAssigner_test.cpp \
+	compile/InlineXmlFormatParser_test.cpp \
+	compile/NinePatch_test.cpp \
 	compile/PseudolocaleGenerator_test.cpp \
 	compile/Pseudolocalizer_test.cpp \
 	compile/XmlIdCollector_test.cpp \
@@ -87,8 +100,10 @@
 	link/PrivateAttributeMover_test.cpp \
 	link/ProductFilter_test.cpp \
 	link/ReferenceLinker_test.cpp \
+	link/ResourceDeduper_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 \
@@ -99,6 +114,7 @@
 	util/StringPiece_test.cpp \
 	util/Util_test.cpp \
 	ConfigDescription_test.cpp \
+	DominatorTree_test.cpp \
 	java/AnnotationProcessor_test.cpp \
 	java/JavaClassGenerator_test.cpp \
 	java/ManifestClassGenerator_test.cpp \
@@ -130,7 +146,7 @@
 	liblog \
 	libcutils \
 	libexpat \
-	libziparchive-host \
+	libziparchive \
 	libpng \
 	libbase \
 	libprotobuf-cpp-lite
@@ -171,6 +187,25 @@
 LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+
+# ==========================================================
+# Build the host shared library: libaapt2_jni
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaapt2_jni
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(cFlags)
+LOCAL_CFLAGS_darwin := $(cFlags_darwin)
+LOCAL_CFLAGS_windows := $(cFlags_windows)
+LOCAL_CPPFLAGS := $(cppFlags)
+LOCAL_C_INCLUDES := $(protoIncludes)
+LOCAL_SRC_FILES := $(sourcesJni)
+LOCAL_STATIC_LIBRARIES := libaapt2 $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
 # ==========================================================
 # Build the host tests: libaapt2_tests
 # ==========================================================
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index c1697e7..1812d96 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -789,4 +789,96 @@
     return copy;
 }
 
+bool ConfigDescription::dominates(const ConfigDescription& o) const {
+    if (*this == defaultConfig() || *this == o) {
+        return true;
+    }
+    return matchWithDensity(o)
+            && !o.matchWithDensity(*this)
+            && !isMoreSpecificThan(o)
+            && !o.hasHigherPrecedenceThan(*this);
+}
+
+bool ConfigDescription::hasHigherPrecedenceThan(const ConfigDescription& o) const {
+    // The order of the following tests defines the importance of one
+    // configuration parameter over another. Those tests first are more
+    // important, trumping any values in those following them.
+    // The ordering should be the same as ResTable_config#isBetterThan.
+    if (mcc || o.mcc) return (!o.mcc);
+    if (mnc || o.mnc) return (!o.mnc);
+    if (language[0] || o.language[0]) return (!o.language[0]);
+    if (country[0] || o.country[0]) return (!o.country[0]);
+    // Script and variant require either a language or country, both of which
+    // have higher precedence.
+    if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
+        return !(o.screenLayout & MASK_LAYOUTDIR);
+    }
+    if (smallestScreenWidthDp || o.smallestScreenWidthDp) return (!o.smallestScreenWidthDp);
+    if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
+    if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
+    if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
+        return !(o.screenLayout & MASK_SCREENSIZE);
+    }
+    if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
+        return !(o.screenLayout & MASK_SCREENLONG);
+    }
+    if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
+        return !(o.screenLayout2 & MASK_SCREENROUND);
+    }
+    if (orientation || o.orientation) return (!o.orientation);
+    if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
+        return !(o.uiMode & MASK_UI_MODE_TYPE);
+    }
+    if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
+        return !(o.uiMode & MASK_UI_MODE_NIGHT);
+    }
+    if (density || o.density) return (!o.density);
+    if (touchscreen || o.touchscreen) return (!o.touchscreen);
+    if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
+        return !(o.inputFlags & MASK_KEYSHIDDEN);
+    }
+    if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
+        return !(o.inputFlags & MASK_NAVHIDDEN);
+    }
+    if (keyboard || o.keyboard) return (!o.keyboard);
+    if (navigation || o.navigation) return (!o.navigation);
+    if (screenWidth || o.screenWidth) return (!o.screenWidth);
+    if (screenHeight || o.screenHeight) return (!o.screenHeight);
+    if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
+    if (minorVersion || o.minorVersion) return (!o.minorVersion);
+    // Both configurations have nothing defined except some possible future
+    // value. Returning the comparison of the two configurations is a
+    // "best effort" at this point to protect against incorrect dominations.
+    return *this != o;
+}
+
+bool ConfigDescription::conflictsWith(const ConfigDescription& o) const {
+    // This method should be updated as new configuration parameters are
+    // introduced (e.g. screenConfig2).
+    auto pred = [](const uint32_t a, const uint32_t b) -> bool {
+        return a == 0 || b == 0 || a == b;
+    };
+    // The values here can be found in ResTable_config#match. Density and range
+    // values can't lead to conflicts, and are ignored.
+    return !pred(mcc, o.mcc)
+            || !pred(mnc, o.mnc)
+            || !pred(locale, o.locale)
+            || !pred(screenLayout & MASK_LAYOUTDIR, o.screenLayout & MASK_LAYOUTDIR)
+            || !pred(screenLayout & MASK_SCREENLONG, o.screenLayout & MASK_SCREENLONG)
+            || !pred(screenLayout & MASK_UI_MODE_TYPE, o.screenLayout & MASK_UI_MODE_TYPE)
+            || !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE)
+            || !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT)
+            || !pred(screenLayout2 & MASK_SCREENROUND, o.screenLayout2 & MASK_SCREENROUND)
+            || !pred(orientation, o.orientation)
+            || !pred(touchscreen, o.touchscreen)
+            || !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN)
+            || !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN)
+            || !pred(keyboard, o.keyboard)
+            || !pred(navigation, o.navigation);
+}
+
+bool ConfigDescription::isCompatibleWith(const ConfigDescription& o) const {
+    return !conflictsWith(o) && !dominates(o) && !o.dominates(*this);
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 6858c62..d801621 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -59,14 +59,50 @@
     ConfigDescription& operator=(const ConfigDescription& o);
     ConfigDescription& operator=(ConfigDescription&& o);
 
+    ConfigDescription copyWithoutSdkVersion() const;
+
+    /**
+     * A configuration X dominates another configuration Y, if X has at least the
+     * precedence of Y and X is strictly more general than Y: for any type defined
+     * by X, the same type is defined by Y with a value equal to or, in the case
+     * of ranges, more specific than that of X.
+     *
+     * For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It
+     * does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.
+     */
+    bool dominates(const ConfigDescription& o) const;
+
+    /**
+     * Returns true if this configuration defines a more important configuration
+     * parameter than o. For example, "en" has higher precedence than "v23",
+     * whereas "en" has the same precedence as "en-v23".
+     */
+    bool hasHigherPrecedenceThan(const ConfigDescription& o) const;
+
+    /**
+     * A configuration conflicts with another configuration if both
+     * configurations define an incompatible configuration parameter. An
+     * incompatible configuration parameter is a non-range, non-density parameter
+     * that is defined in both configurations as a different, non-default value.
+     */
+    bool conflictsWith(const ConfigDescription& o) const;
+
+    /**
+     * A configuration is compatible with another configuration if both
+     * configurations can match a common concrete device configuration and are
+     * unrelated by domination. For example, land-v11 conflicts with port-v21
+     * but is compatible with v21 (both land-v11 and v21 would match en-land-v23).
+     */
+    bool isCompatibleWith(const ConfigDescription& o) const;
+
+    bool matchWithDensity(const ConfigDescription& o) const;
+
     bool operator<(const ConfigDescription& o) const;
     bool operator<=(const ConfigDescription& o) const;
     bool operator==(const ConfigDescription& o) const;
     bool operator!=(const ConfigDescription& o) const;
     bool operator>=(const ConfigDescription& o) const;
     bool operator>(const ConfigDescription& o) const;
-
-    ConfigDescription copyWithoutSdkVersion() const;
 };
 
 inline ConfigDescription::ConfigDescription() {
@@ -103,6 +139,10 @@
     return *this;
 }
 
+inline bool ConfigDescription::matchWithDensity(const ConfigDescription& o) const {
+    return match(o) && (density == 0 || density == o.density);
+}
+
 inline bool ConfigDescription::operator<(const ConfigDescription& o) const {
     return compare(o) < 0;
 }
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 19bd521..304e571 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -247,5 +247,59 @@
     }
 }
 
+namespace {
+
+class XmlPrinter : public xml::Visitor {
+public:
+    using xml::Visitor::visit;
+
+    void visit(xml::Element* el) override {
+        std::cerr << mPrefix;
+        std::cerr << "E: ";
+        if (!el->namespaceUri.empty()) {
+            std::cerr << el->namespaceUri << ":";
+        }
+        std::cerr << el->name << " (line=" << el->lineNumber << ")\n";
+
+        for (const xml::Attribute& attr : el->attributes) {
+            std::cerr << mPrefix << "  A: ";
+            if (!attr.namespaceUri.empty()) {
+                std::cerr << attr.namespaceUri << ":";
+            }
+            std::cerr << attr.name << "=" << attr.value << "\n";
+        }
+
+        const size_t previousSize = mPrefix.size();
+        mPrefix += "  ";
+        xml::Visitor::visit(el);
+        mPrefix.resize(previousSize);
+    }
+
+    void visit(xml::Namespace* ns) override {
+        std::cerr << mPrefix;
+        std::cerr << "N: " << ns->namespacePrefix << "=" << ns->namespaceUri
+                << " (line=" << ns->lineNumber << ")\n";
+
+        const size_t previousSize = mPrefix.size();
+        mPrefix += "  ";
+        xml::Visitor::visit(ns);
+        mPrefix.resize(previousSize);
+    }
+
+    void visit(xml::Text* text) override {
+        std::cerr << mPrefix;
+        std::cerr << "T: '" << text->text << "'\n";
+    }
+
+private:
+    std::string mPrefix;
+};
+
+} // namespace
+
+void Debug::dumpXml(xml::XmlResource* doc) {
+    XmlPrinter printer;
+    doc->root->accept(&printer);
+}
 
 } // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index fbe6477..c0fcbf1 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -19,6 +19,7 @@
 
 #include "Resource.h"
 #include "ResourceTable.h"
+#include "xml/XmlDom.h"
 
 // Include for printf-like debugging.
 #include <iostream>
@@ -34,6 +35,7 @@
     static void printStyleGraph(ResourceTable* table,
                                 const ResourceName& targetStyle);
     static void dumpHex(const void* data, size_t len);
+    static void dumpXml(xml::XmlResource* doc);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/DominatorTree.cpp b/tools/aapt2/DominatorTree.cpp
new file mode 100644
index 0000000..29587a8
--- /dev/null
+++ b/tools/aapt2/DominatorTree.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "ConfigDescription.h"
+#include "DominatorTree.h"
+
+#include <algorithm>
+
+namespace aapt {
+
+DominatorTree::DominatorTree(
+        const std::vector<std::unique_ptr<ResourceConfigValue>>& configs) {
+    for (const auto& config : configs) {
+        mProductRoots[config->product].tryAddChild(
+                util::make_unique<Node>(config.get(), nullptr));
+    }
+}
+
+void DominatorTree::accept(Visitor* visitor) {
+    for (auto& entry : mProductRoots) {
+        visitor->visitTree(entry.first, &entry.second);
+    }
+}
+
+bool DominatorTree::Node::tryAddChild(std::unique_ptr<Node> newChild) {
+    assert(newChild->mValue && "cannot add a root or empty node as a child");
+    if (mValue && !dominates(newChild.get())) {
+        // This is not the root and the child dominates us.
+        return false;
+    }
+    return addChild(std::move(newChild));
+}
+
+bool DominatorTree::Node::addChild(std::unique_ptr<Node> newChild) {
+    bool hasDominatedChildren = false;
+    // Demote children dominated by the new config.
+    for (auto& child : mChildren) {
+        if (newChild->dominates(child.get())) {
+            child->mParent = newChild.get();
+            newChild->mChildren.push_back(std::move(child));
+            child = {};
+            hasDominatedChildren = true;
+        }
+    }
+    // Remove dominated children.
+    if (hasDominatedChildren) {
+        mChildren.erase(std::remove_if(mChildren.begin(), mChildren.end(),
+                [](const std::unique_ptr<Node>& child) -> bool {
+            return child == nullptr;
+        }), mChildren.end());
+    }
+    // Add the new config to a child if a child dominates the new config.
+    for (auto& child : mChildren) {
+        if (child->dominates(newChild.get())) {
+            child->addChild(std::move(newChild));
+            return true;
+        }
+    }
+    // The new config is not dominated by a child, so add it here.
+    newChild->mParent = this;
+    mChildren.push_back(std::move(newChild));
+    return true;
+}
+
+bool DominatorTree::Node::dominates(const Node* other) const {
+    // Check root node dominations.
+    if (other->isRootNode()) {
+        return isRootNode();
+    } else if (isRootNode()) {
+        return true;
+    }
+    // Neither node is a root node; compare the configurations.
+    return mValue->config.dominates(other->mValue->config);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/DominatorTree.h b/tools/aapt2/DominatorTree.h
new file mode 100644
index 0000000..ad2df0e
--- /dev/null
+++ b/tools/aapt2/DominatorTree.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_DOMINATOR_TREE_H
+#define AAPT_DOMINATOR_TREE_H
+
+#include "ResourceTable.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * A dominator tree of configurations as defined by resolution rules for Android
+ * resources.
+ *
+ * A node in the tree represents a resource configuration.
+ *
+ * The tree has the following property:
+ *
+ * Each child of a given configuration defines a strict superset of qualifiers
+ * and has a value that is at least as specific as that of its ancestors. A
+ * value is "at least as specific" if it is either identical or it represents a
+ * stronger requirement.
+ * For example, v21 is more specific than v11, and w1200dp is more specific than
+ * w800dp.
+ *
+ * The dominator tree relies on the underlying configurations passed to it. If
+ * the configurations passed to the dominator tree go out of scope, the tree
+ * will exhibit undefined behavior.
+ */
+class DominatorTree {
+public:
+    explicit DominatorTree(const std::vector<std::unique_ptr<ResourceConfigValue>>& configs);
+
+    class Node {
+    public:
+        explicit Node(ResourceConfigValue* value = nullptr, Node* parent = nullptr) :
+                mValue(value), mParent(parent) {
+        }
+
+        inline ResourceConfigValue* value() const {
+            return mValue;
+        }
+
+        inline Node* parent() const {
+            return mParent;
+        }
+
+        inline bool isRootNode() const {
+            return !mValue;
+        }
+
+        inline const std::vector<std::unique_ptr<Node>>& children() const {
+            return mChildren;
+        }
+
+        bool tryAddChild(std::unique_ptr<Node> newChild);
+
+    private:
+        bool addChild(std::unique_ptr<Node> newChild);
+        bool dominates(const Node* other) const;
+
+        ResourceConfigValue* mValue;
+        Node* mParent;
+        std::vector<std::unique_ptr<Node>> mChildren;
+
+        DISALLOW_COPY_AND_ASSIGN(Node);
+    };
+
+    struct Visitor {
+        virtual ~Visitor() = default;
+        virtual void visitTree(const std::string& product, Node* root) = 0;
+    };
+
+    class BottomUpVisitor : public Visitor {
+    public:
+        virtual ~BottomUpVisitor() = default;
+
+        void visitTree(const std::string& product, Node* root) override {
+            for (auto& child : root->children()) {
+                visitNode(child.get());
+            }
+        }
+
+        virtual void visitConfig(Node* node) = 0;
+
+    private:
+        void visitNode(Node* node) {
+            for (auto& child : node->children()) {
+                visitNode(child.get());
+            }
+            visitConfig(node);
+        }
+    };
+
+    void accept(Visitor* visitor);
+
+    inline const std::map<std::string, Node>& getProductRoots() const {
+        return mProductRoots;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(DominatorTree);
+
+    std::map<std::string, Node> mProductRoots;
+};
+
+} // namespace aapt
+
+#endif // AAPT_DOMINATOR_TREE_H
diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp
new file mode 100644
index 0000000..fb850e4
--- /dev/null
+++ b/tools/aapt2/DominatorTree_test.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 "DominatorTree.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+namespace {
+
+class PrettyPrinter : public DominatorTree::Visitor {
+public:
+    explicit PrettyPrinter(const int indent = 2) : mIndent(indent) {
+    }
+
+    void visitTree(const std::string& product, DominatorTree::Node* root) override {
+        for (auto& child : root->children()) {
+            visitNode(child.get(), 0);
+        }
+    }
+
+    std::string toString(DominatorTree* tree) {
+        mBuffer.str("");
+        mBuffer.clear();
+        tree->accept(this);
+        return mBuffer.str();
+    }
+
+private:
+    void visitConfig(const DominatorTree::Node* node, const int indent) {
+        auto configString = node->value()->config.toString();
+        mBuffer << std::string(indent, ' ')
+                << (configString.isEmpty() ? "<default>" : configString)
+                << std::endl;
+    }
+
+    void visitNode(const DominatorTree::Node* node, const int indent) {
+        visitConfig(node, indent);
+        for (const auto& child : node->children()) {
+            visitNode(child.get(), indent + mIndent);
+        }
+    }
+
+    std::stringstream mBuffer;
+    const int mIndent = 2;
+};
+
+} // namespace
+
+TEST(DominatorTreeTest, DefaultDominatesEverything) {
+    const ConfigDescription defaultConfig = {};
+    const ConfigDescription landConfig = test::parseConfigOrDie("land");
+    const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land-v13");
+
+    std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+    configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, ""));
+
+    DominatorTree tree(configs);
+    PrettyPrinter printer;
+
+    std::string expected =
+            "<default>\n"
+            "  land\n"
+            "  sw600dp-land-v13\n";
+    EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+TEST(DominatorTreeTest, ProductsAreDominatedSeparately) {
+    const ConfigDescription defaultConfig = {};
+    const ConfigDescription landConfig = test::parseConfigOrDie("land");
+    const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land-v13");
+
+    std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+    configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, "phablet"));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, "phablet"));
+
+    DominatorTree tree(configs);
+    PrettyPrinter printer;
+
+    std::string expected =
+            "<default>\n"
+            "  land\n"
+            "<default>\n"
+            "  sw600dp-land-v13\n";
+    EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+TEST(DominatorTreeTest, MoreSpecificConfigurationsAreDominated) {
+    const ConfigDescription defaultConfig = {};
+    const ConfigDescription enConfig = test::parseConfigOrDie("en");
+    const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+    const ConfigDescription ldrtlConfig = test::parseConfigOrDie("ldrtl-v4");
+    const ConfigDescription ldrtlXhdpiConfig = test::parseConfigOrDie("ldrtl-xhdpi-v4");
+    const ConfigDescription sw300dpConfig = test::parseConfigOrDie("sw300dp-v13");
+    const ConfigDescription sw540dpConfig = test::parseConfigOrDie("sw540dp-v14");
+    const ConfigDescription sw600dpConfig = test::parseConfigOrDie("sw600dp-v14");
+    const ConfigDescription sw720dpConfig = test::parseConfigOrDie("sw720dp-v13");
+    const ConfigDescription v20Config = test::parseConfigOrDie("v20");
+
+    std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+    configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(enConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(enV21Config, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(ldrtlConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(ldrtlXhdpiConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw300dpConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw540dpConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(sw720dpConfig, ""));
+    configs.push_back(util::make_unique<ResourceConfigValue>(v20Config, ""));
+
+    DominatorTree tree(configs);
+    PrettyPrinter printer;
+
+    std::string expected =
+            "<default>\n"
+            "  en\n"
+            "    en-v21\n"
+            "  ldrtl-v4\n"
+            "    ldrtl-xhdpi-v4\n"
+            "  sw300dp-v13\n"
+            "    sw540dp-v14\n"
+            "      sw600dp-v14\n"
+            "    sw720dp-v13\n"
+            "  v20\n";
+    EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Format.proto b/tools/aapt2/Format.proto
index d05425c..0917129 100644
--- a/tools/aapt2/Format.proto
+++ b/tools/aapt2/Format.proto
@@ -34,7 +34,7 @@
 		optional string resource_name = 1;
 		optional uint32 line_no = 2;
 	}
-	
+
 	optional string resource_name = 1;
 	optional ConfigDescription config = 2;
 	optional string source_path = 3;
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index ed55f85..f3f70d6 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -25,7 +25,7 @@
 static const char* sMajorVersion = "2";
 
 // Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "1";
+static const char* sMinorVersion = "2";
 
 int printVersion() {
     std::cerr << "Android Asset Packaging Tool (aapt) "
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/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index bcdf401..c430c46 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -152,7 +152,7 @@
                 break;
             }
 
-            spanStack.back().lastChar = builder.str().size() - 1;
+            spanStack.back().lastChar = builder.utf16Len() - 1;
             outStyleString->spans.push_back(spanStack.back());
             spanStack.pop_back();
 
@@ -185,12 +185,12 @@
                 spanName += attrIter->value;
             }
 
-            if (builder.str().size() > std::numeric_limits<uint32_t>::max()) {
+            if (builder.utf16Len() > std::numeric_limits<uint32_t>::max()) {
                 mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
                              << "style string '" << builder.str() << "' is too long");
                 error = true;
             } else {
-                spanStack.push_back(Span{ spanName, static_cast<uint32_t>(builder.str().size()) });
+                spanStack.push_back(Span{ spanName, static_cast<uint32_t>(builder.utf16Len()) });
             }
 
         } else if (event == xml::XmlPullParser::Event::kComment) {
@@ -925,35 +925,6 @@
             Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())), val.data };
 }
 
-static Maybe<Reference> parseXmlAttributeName(StringPiece str) {
-    str = util::trimWhitespace(str);
-    const char* start = str.data();
-    const char* const end = start + str.size();
-    const char* p = start;
-
-    Reference ref;
-    if (p != end && *p == '*') {
-        ref.privateReference = true;
-        start++;
-        p++;
-    }
-
-    StringPiece package;
-    StringPiece name;
-    while (p != end) {
-        if (*p == ':') {
-            package = StringPiece(start, p - start);
-            name = StringPiece(p + 1, end - (p + 1));
-            break;
-        }
-        p++;
-    }
-
-    ref.name = ResourceName(package.toString(), ResourceType::kAttr,
-                        name.empty() ? str.toString() : name.toString());
-    return Maybe<Reference>(std::move(ref));
-}
-
 bool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) {
     const Source source = mSource.withLine(parser->getLineNumber());
 
@@ -963,7 +934,7 @@
         return false;
     }
 
-    Maybe<Reference> maybeKey = parseXmlAttributeName(maybeName.value());
+    Maybe<Reference> maybeKey = ResourceUtils::parseXmlAttributeName(maybeName.value());
     if (!maybeKey) {
         mDiag->error(DiagMessage(source) << "invalid attribute name '" << maybeName.value() << "'");
         return false;
@@ -1226,7 +1197,7 @@
 
             // If this is a declaration, the package name may be in the name. Separate these out.
             // Eg. <attr name="android:text" />
-            Maybe<Reference> maybeRef = parseXmlAttributeName(maybeName.value());
+            Maybe<Reference> maybeRef = ResourceUtils::parseXmlAttributeName(maybeName.value());
             if (!maybeRef) {
                 mDiag->error(DiagMessage(itemSource) << "<attr> tag has invalid name '"
                              << maybeName.value() << "'");
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 3d03a88..e097740 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -90,6 +90,40 @@
     ASSERT_TRUE(testParse(input));
 }
 
+TEST_F(ResourceParserTest, ParseStyledString) {
+    // Use a surrogate pair unicode point so that we can verify that the span indices
+    // use UTF-16 length and not UTF-18 length.
+    std::string input = "<string name=\"foo\">This is my aunt\u2019s <b>string</b></string>";
+    ASSERT_TRUE(testParse(input));
+
+    StyledString* str = test::getValue<StyledString>(&mTable, "string/foo");
+    ASSERT_NE(nullptr, str);
+
+    const std::string expectedStr = "This is my aunt\u2019s string";
+    EXPECT_EQ(expectedStr, *str->value->str);
+    EXPECT_EQ(1u, str->value->spans.size());
+
+    EXPECT_EQ(std::string("b"), *str->value->spans[0].name);
+    EXPECT_EQ(17u, str->value->spans[0].firstChar);
+    EXPECT_EQ(23u, str->value->spans[0].lastChar);
+}
+
+TEST_F(ResourceParserTest, ParseStringWithWhitespace) {
+    std::string input = "<string name=\"foo\">  This is what  I think  </string>";
+    ASSERT_TRUE(testParse(input));
+
+    String* str = test::getValue<String>(&mTable, "string/foo");
+    ASSERT_NE(nullptr, str);
+    EXPECT_EQ(std::string("This is what I think"), *str->value);
+
+    input = "<string name=\"foo2\">\"  This is what  I think  \"</string>";
+    ASSERT_TRUE(testParse(input));
+
+    str = test::getValue<String>(&mTable, "string/foo2");
+    ASSERT_NE(nullptr, str);
+    EXPECT_EQ(std::string("  This is what  I think  "), *str->value);
+}
+
 TEST_F(ResourceParserTest, IgnoreXliffTags) {
     std::string input = "<string name=\"foo\" \n"
                         "        xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n"
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 460de0e..bdc6a8c 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -201,36 +201,51 @@
 }
 
 /**
- * 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.
+ * The default handler for collisions.
+ *
+ * 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.
  */
-int ResourceTable::resolveValueCollision(Value* existing, Value* incoming) {
+ResourceTable::CollisionResult ResourceTable::resolveValueCollision(
+        Value* existing, Value* incoming) {
     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
             // already exists. Keep the existing.
-            return -1;
+            return CollisionResult::kKeepOriginal;
         } else if (existing->isWeak()) {
             // Override the weak resource with the new strong resource.
-            return 1;
+            return CollisionResult::kTakeNew;
         }
         // The existing and incoming values are strong, this is an error
         // if the values are not both attributes.
-        return 0;
+        return CollisionResult::kConflict;
     }
 
     if (!existingAttr) {
         if (existing->isWeak()) {
             // The existing value is not an attribute and it is weak,
             // so take the incoming attribute value.
-            return 1;
+            return CollisionResult::kTakeNew;
         }
         // The existing value is not an attribute and it is strong,
         // so the incoming attribute value is an error.
-        return 0;
+        return CollisionResult::kConflict;
     }
 
     assert(incomingAttr && existingAttr);
@@ -245,20 +260,20 @@
         // The two attributes are both DECLs, but they are plain attributes
         // with the same formats.
         // Keep the strongest one.
-        return existingAttr->isWeak() ? 1 : -1;
+        return existingAttr->isWeak() ? CollisionResult::kTakeNew : CollisionResult::kKeepOriginal;
     }
 
     if (existingAttr->isWeak() && existingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
         // Any incoming attribute is better than this.
-        return 1;
+        return CollisionResult::kTakeNew;
     }
 
     if (incomingAttr->isWeak() && incomingAttr->typeMask == android::ResTable_map::TYPE_ANY) {
         // The incoming attribute may be a USE instead of a DECL.
         // Keep the existing attribute.
-        return -1;
+        return CollisionResult::kKeepOriginal;
     }
-    return 0;
+    return CollisionResult::kConflict;
 }
 
 static constexpr const char* kValidNameChars = "._-";
@@ -312,7 +327,7 @@
     fileRef->setSource(source);
     fileRef->file = file;
     return addResourceImpl(name, ResourceId{}, config, StringPiece{}, std::move(fileRef),
-                           kValidNameChars, resolveValueCollision, diag);
+                           validChars, resolveValueCollision, diag);
 }
 
 bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
@@ -340,7 +355,7 @@
                                     const StringPiece& product,
                                     std::unique_ptr<Value> value,
                                     const char* validChars,
-                                    const std::function<int(Value*,Value*)>& conflictResolver,
+                                    const CollisionResolverFunc& conflictResolver,
                                     IDiagnostics* diag) {
     assert(value && "value can't be nullptr");
     assert(diag && "diagnostics can't be nullptr");
@@ -404,17 +419,22 @@
         configValue->value = std::move(value);
 
     } else {
-        int collisionResult = conflictResolver(configValue->value.get(), value.get());
-        if (collisionResult > 0) {
+        switch (conflictResolver(configValue->value.get(), value.get())) {
+        case CollisionResult::kTakeNew:
             // Take the incoming value.
             configValue->value = std::move(value);
-        } else if (collisionResult == 0) {
+            break;
+
+        case CollisionResult::kConflict:
             diag->error(DiagMessage(value->getSource())
-                        << "duplicate value for resource '" << name << "' "
-                        << "with config '" << config << "'");
+                                    << "duplicate value for resource '" << name << "' "
+                                    << "with config '" << config << "'");
             diag->error(DiagMessage(configValue->value->getSource())
-                        << "resource previously defined here");
+                                    << "resource previously defined here");
             return false;
+
+        case CollisionResult::kKeepOriginal:
+            break;
         }
     }
 
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 6b52a43..6c246d0 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -38,8 +38,8 @@
 
 enum class SymbolState {
     kUndefined,
+    kPrivate,
     kPublic,
-    kPrivate
 };
 
 /**
@@ -185,13 +185,18 @@
 public:
     ResourceTable() = default;
 
+    enum class CollisionResult {
+        kKeepOriginal,
+        kConflict,
+        kTakeNew
+    };
+
+    using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;
+
     /**
      * When a collision of resources occurs, this method decides which value to keep.
-     * Returns -1 if the existing value should be chosen.
-     * Returns 0 if the collision can not be resolved (error).
-     * Returns 1 if the incoming value should be chosen.
      */
-    static int resolveValueCollision(Value* existing, Value* incoming);
+    static CollisionResult resolveValueCollision(Value* existing, Value* incoming);
 
     bool addResource(const ResourceNameRef& name,
                      const ConfigDescription& config,
@@ -285,6 +290,15 @@
 private:
     ResourceTablePackage* findOrCreatePackage(const StringPiece& name);
 
+    bool addResourceImpl(const ResourceNameRef& name,
+                         const ResourceId& resId,
+                         const ConfigDescription& config,
+                         const StringPiece& product,
+                         std::unique_ptr<Value> value,
+                         const char* validChars,
+                         const CollisionResolverFunc& conflictResolver,
+                         IDiagnostics* diag);
+
     bool addFileReferenceImpl(const ResourceNameRef& name,
                               const ConfigDescription& config,
                               const Source& source,
@@ -293,15 +307,6 @@
                               const char* validChars,
                               IDiagnostics* diag);
 
-    bool addResourceImpl(const ResourceNameRef& name,
-                         const ResourceId& resId,
-                         const ConfigDescription& config,
-                         const StringPiece& product,
-                         std::unique_ptr<Value> value,
-                         const char* validChars,
-                         const std::function<int(Value*,Value*)>& conflictResolver,
-                         IDiagnostics* diag);
-
     bool setSymbolStateImpl(const ResourceNameRef& name,
                             const ResourceId& resId,
                             const Symbol& symbol,
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 11619fa..73a194e 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -268,6 +268,35 @@
     return result;
 }
 
+Maybe<Reference> parseXmlAttributeName(const StringPiece& str) {
+    StringPiece trimmedStr = util::trimWhitespace(str);
+    const char* start = trimmedStr.data();
+    const char* const end = start + trimmedStr.size();
+    const char* p = start;
+
+    Reference ref;
+    if (p != end && *p == '*') {
+        ref.privateReference = true;
+        start++;
+        p++;
+    }
+
+    StringPiece package;
+    StringPiece name;
+    while (p != end) {
+        if (*p == ':') {
+            package = StringPiece(start, p - start);
+            name = StringPiece(p + 1, end - (p + 1));
+            break;
+        }
+        p++;
+    }
+
+    ref.name = ResourceName(package.toString(), ResourceType::kAttr,
+                        name.empty() ? trimmedStr.toString() : name.toString());
+    return Maybe<Reference>(std::move(ref));
+}
+
 std::unique_ptr<Reference> tryParseReference(const StringPiece& str, bool* outCreate) {
     ResourceNameRef ref;
     bool privateRef = false;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 244047b..555203b 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -111,6 +111,14 @@
 Maybe<Reference> parseStyleParentReference(const StringPiece& str, std::string* outError);
 
 /*
+ * Returns a Reference if the string `str` was parsed as a valid XML attribute name.
+ * The valid format for an XML attribute name is:
+ *
+ * package:entry
+ */
+Maybe<Reference> parseXmlAttributeName(const StringPiece& str);
+
+/*
  * Returns a Reference object if the string was parsed as a resource or attribute reference,
  * ( @[+][package:]type/name | ?[package:]type/name ) setting outCreate to true if
  * the '+' was present in the string.
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 73682ab..492155d 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -18,12 +18,12 @@
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
 #include "ValueVisitor.h"
-#include "io/File.h"
 #include "util/Util.h"
 
 #include <algorithm>
 #include <androidfw/ResourceTypes.h>
 #include <limits>
+#include <set>
 
 namespace aapt {
 
@@ -65,7 +65,7 @@
     *out << "(raw string) " << *value;
 }
 
-Reference::Reference() : referenceType(Reference::Type::kResource) {
+Reference::Reference() : referenceType(Type::kResource) {
 }
 
 Reference::Reference(const ResourceNameRef& n, Type t) :
@@ -75,6 +75,10 @@
 Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
 }
 
+Reference::Reference(const ResourceNameRef& n, const ResourceId& i) :
+        name(n.toResourceName()), id(i), referenceType(Type::kResource) {
+}
+
 bool Reference::equals(const Value* value) const {
     const Reference* other = valueCast<Reference>(value);
     if (!other) {
@@ -732,4 +736,35 @@
         << "]";
 }
 
+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;
+}
+
+struct NameOnlyComparator {
+    bool operator()(const Reference& a, const Reference& b) const {
+        return a.name < b.name;
+    }
+};
+
+void Styleable::mergeWith(Styleable* other) {
+    // Compare only names, because some References may already have their IDs assigned
+    // (framework IDs that don't change).
+    std::set<Reference, NameOnlyComparator> 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..5e5d1f3 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -172,6 +172,7 @@
     Reference();
     explicit Reference(const ResourceNameRef& n, Type type = Type::kResource);
     explicit Reference(const ResourceId& i, Type type = Type::kResource);
+    explicit Reference(const ResourceNameRef& n, const ResourceId& i);
 
     bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
@@ -179,6 +180,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 +338,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/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 39e4489..dbd8062 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -20,6 +20,7 @@
 #include "ResourceParser.h"
 #include "ResourceTable.h"
 #include "compile/IdAssigner.h"
+#include "compile/InlineXmlFormatParser.h"
 #include "compile/Png.h"
 #include "compile/PseudolocaleGenerator.h"
 #include "compile/XmlIdCollector.h"
@@ -35,10 +36,15 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/io/coded_stream.h>
 
+#include <android-base/errors.h>
+#include <android-base/file.h>
 #include <dirent.h>
 #include <fstream>
 #include <string>
 
+using google::protobuf::io::CopyingOutputStreamAdaptor;
+using google::protobuf::io::ZeroCopyOutputStream;
+
 namespace aapt {
 
 struct ResourcePathData {
@@ -238,13 +244,14 @@
         return false;
     }
 
-    std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(&table);
-
-    // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
+    // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->finishEntry().
     {
-        google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+        // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+        // interface.
+        CopyingOutputStreamAdaptor copyingAdaptor(writer);
 
-        if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
+        std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(&table);
+        if (!pbTable->SerializeToZeroCopyStream(&copyingAdaptor)) {
             context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
             return false;
         }
@@ -266,21 +273,23 @@
         return false;
     }
 
-    // Create the header.
-    std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
-
+    // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->finishEntry().
     {
-        // The stream must be destroyed before we finish the entry, or else
-        // some data won't be flushed.
         // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
         // interface.
-        google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
-        CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
-        for (const BigBuffer::Block& block : buffer) {
-            if (!outputStream.Write(block.buffer.get(), block.size)) {
-                diag->error(DiagMessage(outputPath) << "failed to write data");
-                return false;
-            }
+        CopyingOutputStreamAdaptor copyingAdaptor(writer);
+        CompiledFileOutputStream outputStream(&copyingAdaptor);
+
+        // Number of CompiledFiles.
+        outputStream.WriteLittleEndian32(1);
+
+        std::unique_ptr<pb::CompiledFile> compiledFile = serializeCompiledFileToPb(file);
+        outputStream.WriteCompiledFile(compiledFile.get());
+        outputStream.WriteData(&buffer);
+
+        if (outputStream.HadError()) {
+            diag->error(DiagMessage(outputPath) << "failed to write data");
+            return false;
         }
     }
 
@@ -300,17 +309,21 @@
         return false;
     }
 
-    // Create the header.
-    std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
-
+    // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->finishEntry().
     {
-        // The stream must be destroyed before we finish the entry, or else
-        // some data won't be flushed.
         // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
         // interface.
-        google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
-        CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
-        if (!outputStream.Write(map.getDataPtr(), map.getDataLength())) {
+        CopyingOutputStreamAdaptor copyingAdaptor(writer);
+        CompiledFileOutputStream outputStream(&copyingAdaptor);
+
+        // Number of CompiledFiles.
+        outputStream.WriteLittleEndian32(1);
+
+        std::unique_ptr<pb::CompiledFile> compiledFile = serializeCompiledFileToPb(file);
+        outputStream.WriteCompiledFile(compiledFile.get());
+        outputStream.WriteData(map.getDataPtr(), map.getDataLength());
+
+        if (outputStream.HadError()) {
             diag->error(DiagMessage(outputPath) << "failed to write data");
             return false;
         }
@@ -323,9 +336,34 @@
     return true;
 }
 
+static bool flattenXmlToOutStream(IAaptContext* context, const StringPiece& outputPath,
+                                  xml::XmlResource* xmlRes,
+                                  CompiledFileOutputStream* out) {
+    BigBuffer buffer(1024);
+    XmlFlattenerOptions xmlFlattenerOptions;
+    xmlFlattenerOptions.keepRawValues = true;
+    XmlFlattener flattener(&buffer, xmlFlattenerOptions);
+    if (!flattener.consume(context, xmlRes)) {
+        return false;
+    }
+
+    std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(xmlRes->file);
+    out->WriteCompiledFile(pbCompiledFile.get());
+    out->WriteData(&buffer);
+
+    if (out->HadError()) {
+        context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write data");
+        return false;
+    }
+    return true;
+}
+
 static bool compileXml(IAaptContext* context, const CompileOptions& options,
                        const ResourcePathData& pathData, IArchiveWriter* writer,
                        const std::string& outputPath) {
+    if (context->verbose()) {
+        context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling XML");
+    }
 
     std::unique_ptr<xml::XmlResource> xmlRes;
     {
@@ -344,34 +382,97 @@
         return false;
     }
 
+    xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
+    xmlRes->file.config = pathData.config;
+    xmlRes->file.source = pathData.source;
+
     // Collect IDs that are defined here.
     XmlIdCollector collector;
     if (!collector.consume(context, xmlRes.get())) {
         return false;
     }
 
-    xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
-    xmlRes->file.config = pathData.config;
-    xmlRes->file.source = pathData.source;
-
-    BigBuffer buffer(1024);
-    XmlFlattenerOptions xmlFlattenerOptions;
-    xmlFlattenerOptions.keepRawValues = true;
-    XmlFlattener flattener(&buffer, xmlFlattenerOptions);
-    if (!flattener.consume(context, xmlRes.get())) {
+    // Look for and process any <aapt:attr> tags and create sub-documents.
+    InlineXmlFormatParser inlineXmlFormatParser;
+    if (!inlineXmlFormatParser.consume(context, xmlRes.get())) {
         return false;
     }
 
-    if (!writeHeaderAndBufferToWriter(outputPath, xmlRes->file, buffer, writer,
-                                      context->getDiagnostics())) {
+    // Start the entry so we can write the header.
+    if (!writer->startEntry(outputPath, 0)) {
+        context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open file");
+        return false;
+    }
+
+    // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->finishEntry().
+    {
+        // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+        // interface.
+        CopyingOutputStreamAdaptor copyingAdaptor(writer);
+        CompiledFileOutputStream outputStream(&copyingAdaptor);
+
+        std::vector<std::unique_ptr<xml::XmlResource>>& inlineDocuments =
+                inlineXmlFormatParser.getExtractedInlineXmlDocuments();
+
+        // Number of CompiledFiles.
+        outputStream.WriteLittleEndian32(1 + inlineDocuments.size());
+
+        if (!flattenXmlToOutStream(context, outputPath, xmlRes.get(), &outputStream)) {
+            return false;
+        }
+
+        for (auto& inlineXmlDoc : inlineDocuments) {
+            if (!flattenXmlToOutStream(context, outputPath, inlineXmlDoc.get(), &outputStream)) {
+                return false;
+            }
+        }
+    }
+
+    if (!writer->finishEntry()) {
+        context->getDiagnostics()->error(DiagMessage(outputPath)
+                                         << "failed to finish writing data");
         return false;
     }
     return true;
 }
 
+class BigBufferOutputStream : public io::OutputStream {
+public:
+    explicit BigBufferOutputStream(BigBuffer* buffer) : mBuffer(buffer) {
+    }
+
+    bool Next(void** data, int* len) override {
+        size_t count;
+        *data = mBuffer->nextBlock(&count);
+        *len = static_cast<int>(count);
+        return true;
+    }
+
+    void BackUp(int count) override {
+        mBuffer->backUp(count);
+    }
+
+    int64_t ByteCount() const override {
+        return mBuffer->size();
+    }
+
+    bool HadError() const override {
+        return false;
+    }
+
+private:
+    BigBuffer* mBuffer;
+
+    DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
+};
+
 static bool compilePng(IAaptContext* context, const CompileOptions& options,
                        const ResourcePathData& pathData, IArchiveWriter* writer,
                        const std::string& outputPath) {
+    if (context->verbose()) {
+        context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling PNG");
+    }
+
     BigBuffer buffer(4096);
     ResourceFile resFile;
     resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
@@ -379,16 +480,90 @@
     resFile.source = pathData.source;
 
     {
-        std::ifstream fin(pathData.source.path, std::ifstream::binary);
-        if (!fin) {
-            context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno));
+        std::string content;
+        if (!android::base::ReadFileToString(pathData.source.path, &content)) {
+            context->getDiagnostics()->error(DiagMessage(pathData.source)
+                                             << android::base::SystemErrorCodeToString(errno));
             return false;
         }
 
-        Png png(context->getDiagnostics());
-        if (!png.process(pathData.source, &fin, &buffer, {})) {
+        BigBuffer crunchedPngBuffer(4096);
+        BigBufferOutputStream crunchedPngBufferOut(&crunchedPngBuffer);
+
+        // Ensure that we only keep the chunks we care about if we end up
+        // using the original PNG instead of the crunched one.
+        PngChunkFilter pngChunkFilter(content);
+        std::unique_ptr<Image> image = readPng(context, &pngChunkFilter);
+        if (!image) {
             return false;
         }
+
+        std::unique_ptr<NinePatch> ninePatch;
+        if (pathData.extension == "9.png") {
+            std::string err;
+            ninePatch = NinePatch::create(image->rows.get(), image->width, image->height, &err);
+            if (!ninePatch) {
+                context->getDiagnostics()->error(DiagMessage() << err);
+                return false;
+            }
+
+            // Remove the 1px border around the NinePatch.
+            // Basically the row array is shifted up by 1, and the length is treated
+            // as height - 2.
+            // For each row, shift the array to the left by 1, and treat the length as width - 2.
+            image->width -= 2;
+            image->height -= 2;
+            memmove(image->rows.get(), image->rows.get() + 1, image->height * sizeof(uint8_t**));
+            for (int32_t h = 0; h < image->height; h++) {
+                memmove(image->rows[h], image->rows[h] + 4, image->width * 4);
+            }
+
+            if (context->verbose()) {
+                context->getDiagnostics()->note(DiagMessage(pathData.source)
+                                                << "9-patch: " << *ninePatch);
+            }
+        }
+
+        // Write the crunched PNG.
+        if (!writePng(context, image.get(), ninePatch.get(), &crunchedPngBufferOut, {})) {
+            return false;
+        }
+
+        if (ninePatch != nullptr
+                || crunchedPngBufferOut.ByteCount() <= pngChunkFilter.ByteCount()) {
+            // No matter what, we must use the re-encoded PNG, even if it is larger.
+            // 9-patch images must be re-encoded since their borders are stripped.
+            buffer.appendBuffer(std::move(crunchedPngBuffer));
+        } else {
+            // The re-encoded PNG is larger than the original, and there is
+            // no mandatory transformation. Use the original.
+            if (context->verbose()) {
+                context->getDiagnostics()->note(DiagMessage(pathData.source)
+                                                << "original PNG is smaller than crunched PNG"
+                                                << ", using original");
+            }
+
+            PngChunkFilter pngChunkFilterAgain(content);
+            BigBuffer filteredPngBuffer(4096);
+            BigBufferOutputStream filteredPngBufferOut(&filteredPngBuffer);
+            io::copy(&filteredPngBufferOut, &pngChunkFilterAgain);
+            buffer.appendBuffer(std::move(filteredPngBuffer));
+        }
+
+        if (context->verbose()) {
+            // For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
+            // This will help catch exotic cases where the new code may generate larger PNGs.
+            std::stringstream legacyStream(content);
+            BigBuffer legacyBuffer(4096);
+            Png png(context->getDiagnostics());
+            if (!png.process(pathData.source, &legacyStream, &legacyBuffer, {})) {
+                return false;
+            }
+
+            context->getDiagnostics()->note(DiagMessage(pathData.source)
+                                            << "legacy=" << legacyBuffer.size()
+                                            << " new=" << buffer.size());
+        }
     }
 
     if (!writeHeaderAndBufferToWriter(outputPath, resFile, buffer, writer,
@@ -401,6 +576,10 @@
 static bool compileFile(IAaptContext* context, const CompileOptions& options,
                         const ResourcePathData& pathData, IArchiveWriter* writer,
                         const std::string& outputPath) {
+    if (context->verbose()) {
+        context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling file");
+    }
+
     BigBuffer buffer(256);
     ResourceFile resFile;
     resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
diff --git a/tools/aapt2/compile/Image.h b/tools/aapt2/compile/Image.h
new file mode 100644
index 0000000..fda6a3a
--- /dev/null
+++ b/tools/aapt2/compile/Image.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_COMPILE_IMAGE_H
+#define AAPT_COMPILE_IMAGE_H
+
+#include <android-base/macros.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * An in-memory image, loaded from disk, with pixels in RGBA_8888 format.
+ */
+class Image {
+public:
+    explicit Image() = default;
+
+    /**
+     * A `height` sized array of pointers, where each element points to a
+     * `width` sized row of RGBA_8888 pixels.
+     */
+    std::unique_ptr<uint8_t*[]> rows;
+
+    /**
+     * The width of the image in RGBA_8888 pixels. This is int32_t because of 9-patch data
+     * format limitations.
+     */
+    int32_t width = 0;
+
+    /**
+     * The height of the image in RGBA_8888 pixels. This is int32_t because of 9-patch data
+     * format limitations.
+     */
+    int32_t height = 0;
+
+    /**
+     * Buffer to the raw image data stored sequentially.
+     * Use `rows` to access the data on a row-by-row basis.
+     */
+    std::unique_ptr<uint8_t[]> data;
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(Image);
+};
+
+/**
+ * A range of pixel values, starting at 'start' and ending before 'end' exclusive. Or rather [a, b).
+ */
+struct Range {
+    int32_t start = 0;
+    int32_t end = 0;
+
+    explicit Range() = default;
+    inline explicit Range(int32_t s, int32_t e) : start(s), end(e) {
+    }
+};
+
+inline bool operator==(const Range& left, const Range& right) {
+    return left.start == right.start && left.end == right.end;
+}
+
+/**
+ * Inset lengths from all edges of a rectangle. `left` and `top` are measured from the left and top
+ * edges, while `right` and `bottom` are measured from the right and bottom edges, respectively.
+ */
+struct Bounds {
+    int32_t left = 0;
+    int32_t top = 0;
+    int32_t right = 0;
+    int32_t bottom = 0;
+
+    explicit Bounds() = default;
+    inline explicit Bounds(int32_t l, int32_t t, int32_t r, int32_t b) :
+            left(l), top(t), right(r), bottom(b) {
+    }
+
+    bool nonZero() const;
+};
+
+inline bool Bounds::nonZero() const {
+    return left != 0 || top != 0 || right != 0 || bottom != 0;
+}
+
+inline bool operator==(const Bounds& left, const Bounds& right) {
+    return left.left == right.left && left.top == right.top &&
+            left.right == right.right && left.bottom == right.bottom;
+}
+
+/**
+ * Contains 9-patch data from a source image. All measurements exclude the 1px border of the
+ * source 9-patch image.
+ */
+class NinePatch {
+public:
+    static std::unique_ptr<NinePatch> create(uint8_t** rows,
+                                             const int32_t width, const int32_t height,
+                                             std::string* errOut);
+
+    /**
+     * Packs the RGBA_8888 data pointed to by pixel into a uint32_t
+     * with format 0xAARRGGBB (the way 9-patch expects it).
+     */
+    static uint32_t packRGBA(const uint8_t* pixel);
+
+    /**
+     * 9-patch content padding/insets. All positions are relative to the 9-patch
+     * NOT including the 1px thick source border.
+     */
+    Bounds padding;
+
+    /**
+     * Optical layout bounds/insets. This overrides the padding for
+     * layout purposes. All positions are relative to the 9-patch
+     * NOT including the 1px thick source border.
+     * See https://developer.android.com/about/versions/android-4.3.html#OpticalBounds
+     */
+    Bounds layoutBounds;
+
+    /**
+     * Outline of the image, calculated based on opacity.
+     */
+    Bounds outline;
+
+    /**
+     * The computed radius of the outline. If non-zero, the outline is a rounded-rect.
+     */
+    float outlineRadius = 0.0f;
+
+    /**
+     * The largest alpha value within the outline.
+     */
+    uint32_t outlineAlpha = 0x000000ffu;
+
+    /**
+     * Horizontal regions of the image that are stretchable.
+     * All positions are relative to the 9-patch
+     * NOT including the 1px thick source border.
+     */
+    std::vector<Range> horizontalStretchRegions;
+
+    /**
+     * Vertical regions of the image that are stretchable.
+     * All positions are relative to the 9-patch
+     * NOT including the 1px thick source border.
+     */
+    std::vector<Range> verticalStretchRegions;
+
+    /**
+     * The colors within each region, fixed or stretchable.
+     * For w*h regions, the color of region (x,y) is addressable
+     * via index y*w + x.
+     */
+    std::vector<uint32_t> regionColors;
+
+    /**
+     * Returns serialized data containing the original basic 9-patch meta data.
+     * Optical layout bounds and round rect outline data must be serialized
+     * separately using serializeOpticalLayoutBounds() and serializeRoundedRectOutline().
+     */
+    std::unique_ptr<uint8_t[]> serializeBase(size_t* outLen) const;
+
+    /**
+     * Serializes the layout bounds.
+     */
+    std::unique_ptr<uint8_t[]> serializeLayoutBounds(size_t* outLen) const;
+
+    /**
+     * Serializes the rounded-rect outline.
+     */
+    std::unique_ptr<uint8_t[]> serializeRoundedRectOutline(size_t* outLen) const;
+
+private:
+    explicit NinePatch() = default;
+
+    DISALLOW_COPY_AND_ASSIGN(NinePatch);
+};
+
+::std::ostream& operator<<(::std::ostream& out, const Range& range);
+::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds);
+::std::ostream& operator<<(::std::ostream& out, const NinePatch& ninePatch);
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_IMAGE_H */
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
new file mode 100644
index 0000000..f965bff
--- /dev/null
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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 "Debug.h"
+#include "ResourceUtils.h"
+#include "compile/InlineXmlFormatParser.h"
+#include "util/Util.h"
+#include "xml/XmlDom.h"
+#include "xml/XmlUtil.h"
+
+#include <android-base/macros.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+namespace {
+
+/**
+ * XML Visitor that will find all <aapt:attr> elements for extraction.
+ */
+class Visitor : public xml::PackageAwareVisitor {
+public:
+    using xml::PackageAwareVisitor::visit;
+
+    struct InlineDeclaration {
+        xml::Element* el;
+        std::string attrNamespaceUri;
+        std::string attrName;
+    };
+
+    explicit Visitor(IAaptContext* context, xml::XmlResource* xmlResource) :
+            mContext(context), mXmlResource(xmlResource) {
+    }
+
+    void visit(xml::Element* el) override {
+        if (el->namespaceUri != xml::kSchemaAapt || el->name != "attr") {
+            xml::PackageAwareVisitor::visit(el);
+            return;
+        }
+
+        const Source& src = mXmlResource->file.source.withLine(el->lineNumber);
+
+        xml::Attribute* attr = el->findAttribute({}, "name");
+        if (!attr) {
+            mContext->getDiagnostics()->error(DiagMessage(src) << "missing 'name' attribute");
+            mError = true;
+            return;
+        }
+
+        Maybe<Reference> ref = ResourceUtils::parseXmlAttributeName(attr->value);
+        if (!ref) {
+            mContext->getDiagnostics()->error(DiagMessage(src) << "invalid XML attribute '"
+                                              << attr->value << "'");
+            mError = true;
+            return;
+        }
+
+        const ResourceName& name = ref.value().name.value();
+
+        // Use an empty string for the compilation package because we don't want to default to
+        // the local package if the user specified name="style" or something. This should just
+        // be the default namespace.
+        Maybe<xml::ExtractedPackage> maybePkg = transformPackageAlias(name.package, {});
+        if (!maybePkg) {
+            mContext->getDiagnostics()->error(DiagMessage(src) << "invalid namespace prefix '"
+                                              << name.package << "'");
+            mError = true;
+            return;
+        }
+
+        const xml::ExtractedPackage& pkg = maybePkg.value();
+        const bool privateNamespace = pkg.privateNamespace || ref.value().privateReference;
+
+        InlineDeclaration decl;
+        decl.el = el;
+        decl.attrName = name.entry;
+        if (!pkg.package.empty()) {
+            decl.attrNamespaceUri = xml::buildPackageNamespace(pkg.package, privateNamespace);
+        }
+
+        mInlineDeclarations.push_back(std::move(decl));
+    }
+
+    const std::vector<InlineDeclaration>& getInlineDeclarations() const {
+        return mInlineDeclarations;
+    }
+
+    bool hasError() const {
+        return mError;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(Visitor);
+
+    IAaptContext* mContext;
+    xml::XmlResource* mXmlResource;
+    std::vector<InlineDeclaration> mInlineDeclarations;
+    bool mError = false;
+};
+
+} // namespace
+
+bool InlineXmlFormatParser::consume(IAaptContext* context, xml::XmlResource* doc) {
+    Visitor visitor(context, doc);
+    doc->root->accept(&visitor);
+    if (visitor.hasError()) {
+        return false;
+    }
+
+    size_t nameSuffixCounter = 0;
+    for (const Visitor::InlineDeclaration& decl : visitor.getInlineDeclarations()) {
+        auto newDoc = util::make_unique<xml::XmlResource>();
+        newDoc->file.config = doc->file.config;
+        newDoc->file.source = doc->file.source.withLine(decl.el->lineNumber);
+        newDoc->file.name = doc->file.name;
+
+        // Modify the new entry name. We need to suffix the entry with a number to avoid
+        // local collisions, then mangle it with the empty package, such that it won't show up
+        // in R.java.
+
+        newDoc->file.name.entry = NameMangler::mangleEntry(
+                {}, newDoc->file.name.entry + "__" + std::to_string(nameSuffixCounter));
+
+        // Extracted elements must be the only child of <aapt:attr>.
+        // Make sure there is one root node in the children (ignore empty text).
+        for (auto& child : decl.el->children) {
+            const Source childSource = doc->file.source.withLine(child->lineNumber);
+            if (xml::Text* t = xml::nodeCast<xml::Text>(child.get())) {
+                if (!util::trimWhitespace(t->text).empty()) {
+                    context->getDiagnostics()->error(DiagMessage(childSource)
+                                                     << "can't extract text into its own resource");
+                    return false;
+                }
+            } else if (newDoc->root) {
+                context->getDiagnostics()->error(DiagMessage(childSource)
+                                                 << "inline XML resources must have a single root");
+                return false;
+            } else {
+                newDoc->root = std::move(child);
+                newDoc->root->parent = nullptr;
+            }
+        }
+
+        // Walk up and find the parent element.
+        xml::Node* node = decl.el;
+        xml::Element* parentEl = nullptr;
+        while (node->parent && (parentEl = xml::nodeCast<xml::Element>(node->parent)) == nullptr) {
+            node = node->parent;
+        }
+
+        if (!parentEl) {
+            context->getDiagnostics()->error(DiagMessage(newDoc->file.source)
+                                             << "no suitable parent for inheriting attribute");
+            return false;
+        }
+
+        // Add the inline attribute to the parent.
+        parentEl->attributes.push_back(xml::Attribute{
+                decl.attrNamespaceUri, decl.attrName, "@" + newDoc->file.name.toString() });
+
+        // Delete the subtree.
+        for (auto iter = parentEl->children.begin(); iter != parentEl->children.end(); ++iter) {
+            if (iter->get() == node) {
+                parentEl->children.erase(iter);
+                break;
+            }
+        }
+
+        mQueue.push_back(std::move(newDoc));
+
+        nameSuffixCounter++;
+    }
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.h b/tools/aapt2/compile/InlineXmlFormatParser.h
new file mode 100644
index 0000000..69065fd
--- /dev/null
+++ b/tools/aapt2/compile/InlineXmlFormatParser.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_COMPILE_INLINEXMLFORMATPARSER_H
+#define AAPT_COMPILE_INLINEXMLFORMATPARSER_H
+
+#include "process/IResourceTableConsumer.h"
+
+#include <android-base/macros.h>
+#include <memory>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * Extracts Inline XML definitions into their own xml::XmlResource objects.
+ *
+ * Inline XML looks like:
+ *
+ * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ *                  xmlns:aapt="http://schemas.android.com/aapt" >
+ *   <aapt:attr name="android:drawable" >
+ *     <vector
+ *       android:height="64dp"
+ *       android:width="64dp"
+ *       android:viewportHeight="600"
+ *       android:viewportWidth="600"/>
+ *   </aapt:attr>
+ * </animated-vector>
+ *
+ * The <vector> will be extracted into its own XML file and <animated-vector> will
+ * gain an attribute 'android:drawable' set to a reference to the extracted <vector> resource.
+ */
+class InlineXmlFormatParser : public IXmlResourceConsumer {
+public:
+    explicit InlineXmlFormatParser() = default;
+
+    bool consume(IAaptContext* context, xml::XmlResource* doc) override;
+
+    std::vector<std::unique_ptr<xml::XmlResource>>& getExtractedInlineXmlDocuments() {
+        return mQueue;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(InlineXmlFormatParser);
+
+    std::vector<std::unique_ptr<xml::XmlResource>> mQueue;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_INLINEXMLFORMATPARSER_H */
diff --git a/tools/aapt2/compile/InlineXmlFormatParser_test.cpp b/tools/aapt2/compile/InlineXmlFormatParser_test.cpp
new file mode 100644
index 0000000..8d62210
--- /dev/null
+++ b/tools/aapt2/compile/InlineXmlFormatParser_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 "compile/InlineXmlFormatParser.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+TEST(InlineXmlFormatParserTest, PassThrough) {
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
+      <View xmlns:android="http://schemas.android.com/apk/res/android">
+        <View android:text="hey">
+          <View android:id="hi" />
+        </View>
+      </View>)EOF");
+
+    InlineXmlFormatParser parser;
+    ASSERT_TRUE(parser.consume(context.get(), doc.get()));
+    EXPECT_EQ(0u, parser.getExtractedInlineXmlDocuments().size());
+}
+
+TEST(InlineXmlFormatParserTest, ExtractOneXmlResource) {
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
+      <View1 xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:aapt="http://schemas.android.com/aapt">
+        <aapt:attr name="android:text">
+          <View2 android:text="hey">
+            <View3 android:id="hi" />
+          </View2>
+        </aapt:attr>
+      </View1>)EOF");
+
+    doc->file.name = test::parseNameOrDie("layout/main");
+
+    InlineXmlFormatParser parser;
+    ASSERT_TRUE(parser.consume(context.get(), doc.get()));
+
+    // One XML resource should have been extracted.
+    EXPECT_EQ(1u, parser.getExtractedInlineXmlDocuments().size());
+
+    xml::Element* el = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, el);
+
+    EXPECT_EQ("View1", el->name);
+
+    // The <aapt:attr> tag should be extracted.
+    EXPECT_EQ(nullptr, el->findChild(xml::kSchemaAapt, "attr"));
+
+    // The 'android:text' attribute should be set with a reference.
+    xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, "text");
+    ASSERT_NE(nullptr, attr);
+
+    ResourceNameRef nameRef;
+    ASSERT_TRUE(ResourceUtils::parseReference(attr->value, &nameRef));
+
+    xml::XmlResource* extractedDoc = parser.getExtractedInlineXmlDocuments()[0].get();
+    ASSERT_NE(nullptr, extractedDoc);
+
+    // Make sure the generated reference is correct.
+    EXPECT_EQ(nameRef.package, extractedDoc->file.name.package);
+    EXPECT_EQ(nameRef.type, extractedDoc->file.name.type);
+    EXPECT_EQ(nameRef.entry, extractedDoc->file.name.entry);
+
+    // Verify the structure of the extracted XML.
+    el = xml::findRootElement(extractedDoc);
+    ASSERT_NE(nullptr, el);
+    EXPECT_EQ("View2", el->name);
+    EXPECT_NE(nullptr, el->findChild({}, "View3"));
+}
+
+TEST(InlineXmlFormatParserTest, ExtractTwoXmlResources) {
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
+      <View1 xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:aapt="http://schemas.android.com/aapt">
+        <aapt:attr name="android:text">
+          <View2 android:text="hey">
+            <View3 android:id="hi" />
+          </View2>
+        </aapt:attr>
+
+        <aapt:attr name="android:drawable">
+          <vector />
+        </aapt:attr>
+      </View1>)EOF");
+
+    doc->file.name = test::parseNameOrDie("layout/main");
+
+    InlineXmlFormatParser parser;
+    ASSERT_TRUE(parser.consume(context.get(), doc.get()));
+    ASSERT_EQ(2u, parser.getExtractedInlineXmlDocuments().size());
+
+    xml::Element* el = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, el);
+
+    EXPECT_EQ("View1", el->name);
+
+    xml::Attribute* attrText = el->findAttribute(xml::kSchemaAndroid, "text");
+    ASSERT_NE(nullptr, attrText);
+
+    xml::Attribute* attrDrawable = el->findAttribute(xml::kSchemaAndroid, "drawable");
+    ASSERT_NE(nullptr, attrDrawable);
+
+    // The two extracted resources should have different names.
+    EXPECT_NE(attrText->value, attrDrawable->value);
+
+    // The child <aapt:attr> elements should be gone.
+    EXPECT_EQ(nullptr, el->findChild(xml::kSchemaAapt, "attr"));
+
+    xml::XmlResource* extractedDocText = parser.getExtractedInlineXmlDocuments()[0].get();
+    ASSERT_NE(nullptr, extractedDocText);
+    el = xml::findRootElement(extractedDocText);
+    ASSERT_NE(nullptr, el);
+    EXPECT_EQ("View2", el->name);
+
+    xml::XmlResource* extractedDocDrawable = parser.getExtractedInlineXmlDocuments()[1].get();
+    ASSERT_NE(nullptr, extractedDocDrawable);
+    el = xml::findRootElement(extractedDocDrawable);
+    ASSERT_NE(nullptr, el);
+    EXPECT_EQ("vector", el->name);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
new file mode 100644
index 0000000..0fc1c5d
--- /dev/null
+++ b/tools/aapt2/compile/NinePatch.cpp
@@ -0,0 +1,676 @@
+/*
+ * 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 "compile/Image.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+// Colors in the format 0xAARRGGBB (the way 9-patch expects it).
+constexpr static const uint32_t kColorOpaqueWhite = 0xffffffffu;
+constexpr static const uint32_t kColorOpaqueBlack = 0xff000000u;
+constexpr static const uint32_t kColorOpaqueRed   = 0xffff0000u;
+
+constexpr static const uint32_t kPrimaryColor = kColorOpaqueBlack;
+constexpr static const uint32_t kSecondaryColor = kColorOpaqueRed;
+
+/**
+ * Returns the alpha value encoded in the 0xAARRGBB encoded pixel.
+ */
+static uint32_t getAlpha(uint32_t color);
+
+/**
+ * Determines whether a color on an ImageLine is valid.
+ * A 9patch image may use a transparent color as neutral,
+ * or a fully opaque white color as neutral, based on the
+ * pixel color at (0,0) of the image. One or the other is fine,
+ * but we need to ensure consistency throughout the image.
+ */
+class ColorValidator {
+public:
+    virtual ~ColorValidator() = default;
+
+    /**
+     * Returns true if the color specified is a neutral color
+     * (no padding, stretching, or optical bounds).
+     */
+    virtual bool isNeutralColor(uint32_t color) const = 0;
+
+    /**
+     * Returns true if the color is either a neutral color
+     * or one denoting padding, stretching, or optical bounds.
+     */
+    bool isValidColor(uint32_t color) const {
+        switch (color) {
+        case kPrimaryColor:
+        case kSecondaryColor:
+            return true;
+        }
+        return isNeutralColor(color);
+    }
+};
+
+// Walks an ImageLine and records Ranges of primary and secondary colors.
+// The primary color is black and is used to denote a padding or stretching range,
+// depending on which border we're iterating over.
+// The secondary color is red and is used to denote optical bounds.
+//
+// An ImageLine is a templated-interface that would look something like this if it
+// were polymorphic:
+//
+// class ImageLine {
+// public:
+//      virtual int32_t getLength() const = 0;
+//      virtual uint32_t getColor(int32_t idx) const = 0;
+// };
+//
+template <typename ImageLine>
+static bool fillRanges(const ImageLine* imageLine,
+                       const ColorValidator* colorValidator,
+                       std::vector<Range>* primaryRanges,
+                       std::vector<Range>* secondaryRanges,
+                       std::string* err) {
+    const int32_t length = imageLine->getLength();
+
+    uint32_t lastColor = 0xffffffffu;
+    for (int32_t idx = 1; idx < length - 1; idx++) {
+        const uint32_t color = imageLine->getColor(idx);
+        if (!colorValidator->isValidColor(color)) {
+            *err = "found an invalid color";
+            return false;
+        }
+
+        if (color != lastColor) {
+            // We are ending a range. Which range?
+            // note: encode the x offset without the final 1 pixel border.
+            if (lastColor == kPrimaryColor) {
+                primaryRanges->back().end = idx - 1;
+            } else if (lastColor == kSecondaryColor) {
+                secondaryRanges->back().end = idx - 1;
+            }
+
+            // We are starting a range. Which range?
+            // note: encode the x offset without the final 1 pixel border.
+            if (color == kPrimaryColor) {
+                primaryRanges->push_back(Range(idx - 1, length - 2));
+            } else if (color == kSecondaryColor) {
+                secondaryRanges->push_back(Range(idx - 1, length - 2));
+            }
+            lastColor = color;
+        }
+    }
+    return true;
+}
+
+/**
+ * Iterates over a row in an image. Implements the templated ImageLine interface.
+ */
+class HorizontalImageLine {
+public:
+    explicit HorizontalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+                                 int32_t length) :
+            mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mLength(length) {
+    }
+
+    inline int32_t getLength() const {
+        return mLength;
+    }
+
+    inline uint32_t getColor(int32_t idx) const {
+        return NinePatch::packRGBA(mRows[mYOffset] + (idx + mXOffset) * 4);
+    }
+
+private:
+    uint8_t** mRows;
+    int32_t mXOffset, mYOffset, mLength;
+
+    DISALLOW_COPY_AND_ASSIGN(HorizontalImageLine);
+};
+
+/**
+ * Iterates over a column in an image. Implements the templated ImageLine interface.
+ */
+class VerticalImageLine {
+public:
+    explicit VerticalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+                               int32_t length) :
+            mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mLength(length) {
+    }
+
+    inline int32_t getLength() const {
+        return mLength;
+    }
+
+    inline uint32_t getColor(int32_t idx) const {
+        return NinePatch::packRGBA(mRows[mYOffset + idx] + (mXOffset * 4));
+    }
+
+private:
+    uint8_t** mRows;
+    int32_t mXOffset, mYOffset, mLength;
+
+    DISALLOW_COPY_AND_ASSIGN(VerticalImageLine);
+};
+
+class DiagonalImageLine {
+public:
+    explicit DiagonalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+                               int32_t xStep, int32_t yStep, int32_t length) :
+            mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mXStep(xStep), mYStep(yStep),
+            mLength(length) {
+    }
+
+    inline int32_t getLength() const {
+        return mLength;
+    }
+
+    inline uint32_t getColor(int32_t idx) const {
+        return NinePatch::packRGBA(
+                mRows[mYOffset + (idx * mYStep)] + ((idx + mXOffset) * mXStep) * 4);
+    }
+
+private:
+    uint8_t** mRows;
+    int32_t mXOffset, mYOffset, mXStep, mYStep, mLength;
+
+    DISALLOW_COPY_AND_ASSIGN(DiagonalImageLine);
+};
+
+class TransparentNeutralColorValidator : public ColorValidator {
+public:
+    bool isNeutralColor(uint32_t color) const override {
+        return getAlpha(color) == 0;
+    }
+};
+
+class WhiteNeutralColorValidator : public ColorValidator {
+public:
+    bool isNeutralColor(uint32_t color) const override {
+        return color == kColorOpaqueWhite;
+    }
+};
+
+inline static uint32_t getAlpha(uint32_t color) {
+    return (color & 0xff000000u) >> 24;
+}
+
+static bool populateBounds(const std::vector<Range>& padding,
+                           const std::vector<Range>& layoutBounds,
+                           const std::vector<Range>& stretchRegions,
+                           const int32_t length,
+                           int32_t* paddingStart, int32_t* paddingEnd,
+                           int32_t* layoutStart, int32_t* layoutEnd,
+                           const StringPiece& edgeName,
+                           std::string* err) {
+    if (padding.size() > 1) {
+        std::stringstream errStream;
+        errStream << "too many padding sections on " << edgeName << " border";
+        *err = errStream.str();
+        return false;
+    }
+
+    *paddingStart = 0;
+    *paddingEnd = 0;
+    if (!padding.empty()) {
+        const Range& range = padding.front();
+        *paddingStart = range.start;
+        *paddingEnd = length - range.end;
+    } else if (!stretchRegions.empty()) {
+        // No padding was defined. Compute the padding from the first and last
+        // stretch regions.
+        *paddingStart = stretchRegions.front().start;
+        *paddingEnd = length - stretchRegions.back().end;
+    }
+
+    if (layoutBounds.size() > 2) {
+        std::stringstream errStream;
+        errStream << "too many layout bounds sections on " << edgeName << " border";
+        *err = errStream.str();
+        return false;
+    }
+
+    *layoutStart = 0;
+    *layoutEnd = 0;
+    if (layoutBounds.size() >= 1) {
+        const Range& range = layoutBounds.front();
+        // If there is only one layout bound segment, it might not start at 0, but then it should
+        // end at length.
+        if (range.start != 0 && range.end != length) {
+            std::stringstream errStream;
+            errStream << "layout bounds on " << edgeName << " border must start at edge";
+            *err = errStream.str();
+            return false;
+        }
+        *layoutStart = range.end;
+
+        if (layoutBounds.size() >= 2) {
+            const Range& range = layoutBounds.back();
+            if (range.end != length) {
+                std::stringstream errStream;
+                errStream << "layout bounds on " << edgeName << " border must start at edge";
+                *err = errStream.str();
+                return false;
+            }
+            *layoutEnd = length - range.start;
+        }
+    }
+    return true;
+}
+
+static int32_t calculateSegmentCount(const std::vector<Range>& stretchRegions, int32_t length) {
+    if (stretchRegions.size() == 0) {
+        return 0;
+    }
+
+    const bool startIsFixed = stretchRegions.front().start != 0;
+    const bool endIsFixed = stretchRegions.back().end != length;
+    int32_t modifier = 0;
+    if (startIsFixed && endIsFixed) {
+        modifier = 1;
+    } else if (!startIsFixed && !endIsFixed) {
+        modifier = -1;
+    }
+    return static_cast<int32_t>(stretchRegions.size()) * 2 + modifier;
+}
+
+static uint32_t getRegionColor(uint8_t** rows, const Bounds& region) {
+    // Sample the first pixel to compare against.
+    const uint32_t expectedColor = NinePatch::packRGBA(rows[region.top] + region.left * 4);
+    for (int32_t y = region.top; y < region.bottom; y++) {
+        const uint8_t* row = rows[y];
+        for (int32_t x = region.left; x < region.right; x++) {
+            const uint32_t color = NinePatch::packRGBA(row + x * 4);
+            if (getAlpha(color) == 0) {
+                // The color is transparent.
+                // If the expectedColor is not transparent, NO_COLOR.
+                if (getAlpha(expectedColor) != 0) {
+                    return android::Res_png_9patch::NO_COLOR;
+                }
+            } else if (color != expectedColor) {
+                return android::Res_png_9patch::NO_COLOR;
+            }
+        }
+    }
+
+    if (getAlpha(expectedColor) == 0) {
+        return android::Res_png_9patch::TRANSPARENT_COLOR;
+    }
+    return expectedColor;
+}
+
+// Fills outColors with each 9-patch section's colour. If the whole section is transparent,
+// it gets the special TRANSPARENT colour. If the whole section is the same colour, it is assigned
+// that colour. Otherwise it gets the special NO_COLOR colour.
+//
+// Note that the rows contain the 9-patch 1px border, and the indices in the stretch regions are
+// already offset to exclude the border. This means that each time the rows are accessed,
+// the indices must be offset by 1.
+//
+// width and height also include the 9-patch 1px border.
+static void calculateRegionColors(uint8_t** rows,
+                                  const std::vector<Range>& horizontalStretchRegions,
+                                  const std::vector<Range>& verticalStretchRegions,
+                                  const int32_t width, const int32_t height,
+                                  std::vector<uint32_t>* outColors) {
+    int32_t nextTop = 0;
+    Bounds bounds;
+    auto rowIter = verticalStretchRegions.begin();
+    while (nextTop != height) {
+        if (rowIter != verticalStretchRegions.end()) {
+            if (nextTop != rowIter->start) {
+                // This is a fixed segment.
+                // Offset the bounds by 1 to accommodate the border.
+                bounds.top = nextTop + 1;
+                bounds.bottom = rowIter->start + 1;
+                nextTop = rowIter->start;
+            } else {
+                // This is a stretchy segment.
+                // Offset the bounds by 1 to accommodate the border.
+                bounds.top = rowIter->start + 1;
+                bounds.bottom = rowIter->end + 1;
+                nextTop = rowIter->end;
+                ++rowIter;
+            }
+        } else {
+            // This is the end, fixed section.
+            // Offset the bounds by 1 to accommodate the border.
+            bounds.top = nextTop + 1;
+            bounds.bottom = height + 1;
+            nextTop = height;
+         }
+
+        int32_t nextLeft = 0;
+        auto colIter = horizontalStretchRegions.begin();
+        while (nextLeft != width) {
+            if (colIter != horizontalStretchRegions.end()) {
+                if (nextLeft != colIter->start) {
+                    // This is a fixed segment.
+                    // Offset the bounds by 1 to accommodate the border.
+                    bounds.left = nextLeft + 1;
+                    bounds.right = colIter->start + 1;
+                    nextLeft = colIter->start;
+                } else {
+                    // This is a stretchy segment.
+                    // Offset the bounds by 1 to accommodate the border.
+                    bounds.left = colIter->start + 1;
+                    bounds.right = colIter->end + 1;
+                    nextLeft = colIter->end;
+                    ++colIter;
+                }
+            } else {
+                // This is the end, fixed section.
+                // Offset the bounds by 1 to accommodate the border.
+                bounds.left = nextLeft + 1;
+                bounds.right = width + 1;
+                nextLeft = width;
+            }
+            outColors->push_back(getRegionColor(rows, bounds));
+        }
+    }
+}
+
+// Calculates the insets of a row/column of pixels based on where the largest alpha value begins
+// (on both sides).
+template <typename ImageLine>
+static void findOutlineInsets(const ImageLine* imageLine, int32_t* outStart, int32_t* outEnd) {
+    *outStart = 0;
+    *outEnd = 0;
+
+    const int32_t length = imageLine->getLength();
+    if (length < 3) {
+        return;
+    }
+
+    // If the length is odd, we want both sides to process the center pixel,
+    // so we use two different midpoints (to account for < and <= in the different loops).
+    const int32_t mid2 = length / 2;
+    const int32_t mid1 = mid2 + (length % 2);
+
+    uint32_t maxAlpha = 0;
+    for (int32_t i = 0; i < mid1 && maxAlpha != 0xff; i++) {
+        uint32_t alpha = getAlpha(imageLine->getColor(i));
+        if (alpha > maxAlpha) {
+            maxAlpha = alpha;
+            *outStart = i;
+        }
+    }
+
+    maxAlpha = 0;
+    for (int32_t i = length - 1; i >= mid2 && maxAlpha != 0xff; i--) {
+        uint32_t alpha = getAlpha(imageLine->getColor(i));
+        if (alpha > maxAlpha) {
+            maxAlpha = alpha;
+            *outEnd = length - (i + 1);
+        }
+    }
+    return;
+}
+
+template <typename ImageLine>
+static uint32_t findMaxAlpha(const ImageLine* imageLine) {
+    const int32_t length = imageLine->getLength();
+    uint32_t maxAlpha = 0;
+    for (int32_t idx = 0; idx < length && maxAlpha != 0xff; idx++) {
+        uint32_t alpha = getAlpha(imageLine->getColor(idx));
+        if (alpha > maxAlpha) {
+            maxAlpha = alpha;
+        }
+    }
+    return maxAlpha;
+}
+
+// Pack the pixels in as 0xAARRGGBB (as 9-patch expects it).
+uint32_t NinePatch::packRGBA(const uint8_t* pixel) {
+    return (pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
+}
+
+std::unique_ptr<NinePatch> NinePatch::create(uint8_t** rows,
+                                             const int32_t width, const int32_t height,
+                                             std::string* err) {
+    if (width < 3 || height < 3) {
+        *err = "image must be at least 3x3 (1x1 image with 1 pixel border)";
+        return {};
+    }
+
+    std::vector<Range> horizontalPadding;
+    std::vector<Range> horizontalOpticalBounds;
+    std::vector<Range> verticalPadding;
+    std::vector<Range> verticalOpticalBounds;
+    std::vector<Range> unexpectedRanges;
+    std::unique_ptr<ColorValidator> colorValidator;
+
+    if (rows[0][3] == 0) {
+        colorValidator = util::make_unique<TransparentNeutralColorValidator>();
+    } else if (packRGBA(rows[0]) == kColorOpaqueWhite) {
+        colorValidator = util::make_unique<WhiteNeutralColorValidator>();
+    } else {
+        *err = "top-left corner pixel must be either opaque white or transparent";
+        return {};
+    }
+
+    // Private constructor, can't use make_unique.
+    auto ninePatch = std::unique_ptr<NinePatch>(new NinePatch());
+
+    HorizontalImageLine topRow(rows, 0, 0, width);
+    if (!fillRanges(&topRow, colorValidator.get(), &ninePatch->horizontalStretchRegions,
+                    &unexpectedRanges, err)) {
+        return {};
+    }
+
+    if (!unexpectedRanges.empty()) {
+        const Range& range = unexpectedRanges[0];
+        std::stringstream errStream;
+        errStream << "found unexpected optical bounds (red pixel) on top border "
+                << "at x=" << range.start + 1;
+        *err = errStream.str();
+        return {};
+    }
+
+    VerticalImageLine leftCol(rows, 0, 0, height);
+    if (!fillRanges(&leftCol, colorValidator.get(), &ninePatch->verticalStretchRegions,
+                    &unexpectedRanges, err)) {
+        return {};
+    }
+
+    if (!unexpectedRanges.empty()) {
+        const Range& range = unexpectedRanges[0];
+        std::stringstream errStream;
+        errStream << "found unexpected optical bounds (red pixel) on left border "
+                << "at y=" << range.start + 1;
+        return {};
+    }
+
+    HorizontalImageLine bottomRow(rows, 0, height - 1, width);
+    if (!fillRanges(&bottomRow, colorValidator.get(), &horizontalPadding,
+                    &horizontalOpticalBounds, err)) {
+        return {};
+    }
+
+    if (!populateBounds(horizontalPadding, horizontalOpticalBounds,
+                        ninePatch->horizontalStretchRegions, width - 2,
+                        &ninePatch->padding.left, &ninePatch->padding.right,
+                        &ninePatch->layoutBounds.left, &ninePatch->layoutBounds.right,
+                        "bottom", err)) {
+        return {};
+    }
+
+    VerticalImageLine rightCol(rows, width - 1, 0, height);
+    if (!fillRanges(&rightCol, colorValidator.get(), &verticalPadding,
+                    &verticalOpticalBounds, err)) {
+        return {};
+    }
+
+    if (!populateBounds(verticalPadding, verticalOpticalBounds,
+                        ninePatch->verticalStretchRegions, height - 2,
+                        &ninePatch->padding.top, &ninePatch->padding.bottom,
+                        &ninePatch->layoutBounds.top, &ninePatch->layoutBounds.bottom,
+                        "right", err)) {
+        return {};
+    }
+
+    // Fill the region colors of the 9-patch.
+    const int32_t numRows = calculateSegmentCount(ninePatch->horizontalStretchRegions, width - 2);
+    const int32_t numCols = calculateSegmentCount(ninePatch->verticalStretchRegions, height - 2);
+    if ((int64_t) numRows * (int64_t) numCols > 0x7f) {
+        *err = "too many regions in 9-patch";
+        return {};
+    }
+
+    ninePatch->regionColors.reserve(numRows * numCols);
+    calculateRegionColors(rows, ninePatch->horizontalStretchRegions,
+                          ninePatch->verticalStretchRegions,
+                          width - 2, height - 2,
+                          &ninePatch->regionColors);
+
+    // Compute the outline based on opacity.
+
+    // Find left and right extent of 9-patch content on center row.
+    HorizontalImageLine midRow(rows, 1, height / 2, width - 2);
+    findOutlineInsets(&midRow, &ninePatch->outline.left, &ninePatch->outline.right);
+
+    // Find top and bottom extent of 9-patch content on center column.
+    VerticalImageLine midCol(rows, width / 2, 1, height - 2);
+    findOutlineInsets(&midCol, &ninePatch->outline.top, &ninePatch->outline.bottom);
+
+    const int32_t outlineWidth = (width - 2) - ninePatch->outline.left - ninePatch->outline.right;
+    const int32_t outlineHeight = (height - 2) - ninePatch->outline.top - ninePatch->outline.bottom;
+
+    // Find the largest alpha value within the outline area.
+    HorizontalImageLine outlineMidRow(rows,
+                                      1 + ninePatch->outline.left,
+                                      1 + ninePatch->outline.top + (outlineHeight / 2),
+                                      outlineWidth);
+    VerticalImageLine outlineMidCol(rows,
+                                    1 + ninePatch->outline.left + (outlineWidth / 2),
+                                    1 + ninePatch->outline.top,
+                                    outlineHeight);
+    ninePatch->outlineAlpha = std::max(findMaxAlpha(&outlineMidRow), findMaxAlpha(&outlineMidCol));
+
+    // Assuming the image is a round rect, compute the radius by marching
+    // diagonally from the top left corner towards the center.
+    DiagonalImageLine diagonal(rows, 1 + ninePatch->outline.left, 1 + ninePatch->outline.top,
+                               1, 1, std::min(outlineWidth, outlineHeight));
+    int32_t topLeft, bottomRight;
+    findOutlineInsets(&diagonal, &topLeft, &bottomRight);
+
+    /* Determine source radius based upon inset:
+     *     sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
+     *     sqrt(2) * r = sqrt(2) * i + r
+     *     (sqrt(2) - 1) * r = sqrt(2) * i
+     *     r = sqrt(2) / (sqrt(2) - 1) * i
+     */
+    ninePatch->outlineRadius = 3.4142f * topLeft;
+    return ninePatch;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeBase(size_t* outLen) const {
+    android::Res_png_9patch data;
+    data.numXDivs = static_cast<uint8_t>(horizontalStretchRegions.size()) * 2;
+    data.numYDivs = static_cast<uint8_t>(verticalStretchRegions.size()) * 2;
+    data.numColors = static_cast<uint8_t>(regionColors.size());
+    data.paddingLeft = padding.left;
+    data.paddingRight = padding.right;
+    data.paddingTop = padding.top;
+    data.paddingBottom = padding.bottom;
+
+    auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[data.serializedSize()]);
+    android::Res_png_9patch::serialize(data,
+                                       (const int32_t*) horizontalStretchRegions.data(),
+                                       (const int32_t*) verticalStretchRegions.data(),
+                                       regionColors.data(),
+                                       buffer.get());
+    // Convert to file endianness.
+    reinterpret_cast<android::Res_png_9patch*>(buffer.get())->deviceToFile();
+
+    *outLen = data.serializedSize();
+    return buffer;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeLayoutBounds(size_t* outLen) const {
+    size_t chunkLen = sizeof(uint32_t) * 4;
+    auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunkLen]);
+    uint8_t* cursor = buffer.get();
+
+    memcpy(cursor, &layoutBounds.left, sizeof(layoutBounds.left));
+    cursor += sizeof(layoutBounds.left);
+
+    memcpy(cursor, &layoutBounds.top, sizeof(layoutBounds.top));
+    cursor += sizeof(layoutBounds.top);
+
+    memcpy(cursor, &layoutBounds.right, sizeof(layoutBounds.right));
+    cursor += sizeof(layoutBounds.right);
+
+    memcpy(cursor, &layoutBounds.bottom, sizeof(layoutBounds.bottom));
+    cursor += sizeof(layoutBounds.bottom);
+
+    *outLen = chunkLen;
+    return buffer;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeRoundedRectOutline(size_t* outLen) const {
+    size_t chunkLen = sizeof(uint32_t) * 6;
+    auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunkLen]);
+    uint8_t* cursor = buffer.get();
+
+    memcpy(cursor, &outline.left, sizeof(outline.left));
+    cursor += sizeof(outline.left);
+
+    memcpy(cursor, &outline.top, sizeof(outline.top));
+    cursor += sizeof(outline.top);
+
+    memcpy(cursor, &outline.right, sizeof(outline.right));
+    cursor += sizeof(outline.right);
+
+    memcpy(cursor, &outline.bottom, sizeof(outline.bottom));
+    cursor += sizeof(outline.bottom);
+
+    *((float*) cursor) = outlineRadius;
+    cursor += sizeof(outlineRadius);
+
+    *((uint32_t*) cursor) = outlineAlpha;
+
+    *outLen = chunkLen;
+    return buffer;
+}
+
+::std::ostream& operator<<(::std::ostream& out, const Range& range) {
+    return out << "[" << range.start << ", " << range.end << ")";
+}
+
+::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds) {
+    return out << "l=" << bounds.left
+            << " t=" << bounds.top
+            << " r=" << bounds.right
+            << " b=" << bounds.bottom;
+}
+
+::std::ostream& operator<<(::std::ostream& out, const NinePatch& ninePatch) {
+    return out << "horizontalStretch:" << util::joiner(ninePatch.horizontalStretchRegions, " ")
+            << " verticalStretch:" << util::joiner(ninePatch.verticalStretchRegions, " ")
+            << " padding: " << ninePatch.padding
+            << ", bounds: " << ninePatch.layoutBounds
+            << ", outline: " << ninePatch.outline
+            << " rad=" << ninePatch.outlineRadius
+            << " alpha=" << ninePatch.outlineAlpha;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/NinePatch_test.cpp b/tools/aapt2/compile/NinePatch_test.cpp
new file mode 100644
index 0000000..3106ff8
--- /dev/null
+++ b/tools/aapt2/compile/NinePatch_test.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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 "compile/Image.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+// Pixels are in RGBA_8888 packing.
+
+#define RED   "\xff\x00\x00\xff"
+#define BLUE  "\x00\x00\xff\xff"
+#define GREEN "\xff\x00\x00\xff"
+#define GR_70 "\xff\x00\x00\xb3"
+#define GR_50 "\xff\x00\x00\x80"
+#define GR_20 "\xff\x00\x00\x33"
+#define BLACK "\x00\x00\x00\xff"
+#define WHITE "\xff\xff\xff\xff"
+#define TRANS "\x00\x00\x00\x00"
+
+static uint8_t* k2x2[] = {
+        (uint8_t*) WHITE WHITE,
+        (uint8_t*) WHITE WHITE,
+};
+
+static uint8_t* kMixedNeutralColor3x3[] = {
+        (uint8_t*) WHITE BLACK TRANS,
+        (uint8_t*) TRANS RED   TRANS,
+        (uint8_t*) WHITE WHITE WHITE,
+};
+
+static uint8_t* kTransparentNeutralColor3x3[] = {
+        (uint8_t*) TRANS BLACK TRANS,
+        (uint8_t*) BLACK RED   BLACK,
+        (uint8_t*) TRANS BLACK TRANS,
+};
+
+static uint8_t* kSingleStretch7x6[] = {
+        (uint8_t*) WHITE WHITE BLACK BLACK BLACK WHITE WHITE,
+        (uint8_t*) WHITE RED   RED   RED   RED   RED   WHITE,
+        (uint8_t*) BLACK RED   RED   RED   RED   RED   WHITE,
+        (uint8_t*) BLACK RED   RED   RED   RED   RED   WHITE,
+        (uint8_t*) WHITE RED   RED   RED   RED   RED   WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kMultipleStretch10x7[] = {
+        (uint8_t*) WHITE WHITE BLACK WHITE BLACK BLACK WHITE BLACK WHITE WHITE,
+        (uint8_t*) BLACK RED   BLUE  RED   BLUE  BLUE  RED   BLUE  RED   WHITE,
+        (uint8_t*) BLACK RED   BLUE  RED   BLUE  BLUE  RED   BLUE  RED   WHITE,
+        (uint8_t*) WHITE RED   BLUE  RED   BLUE  BLUE  RED   BLUE  RED   WHITE,
+        (uint8_t*) BLACK RED   BLUE  RED   BLUE  BLUE  RED   BLUE  RED   WHITE,
+        (uint8_t*) BLACK RED   BLUE  RED   BLUE  BLUE  RED   BLUE  RED   WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kPadding6x5[] = {
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE BLACK,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE BLACK BLACK WHITE WHITE,
+};
+
+static uint8_t* kLayoutBoundsWrongEdge3x3[] = {
+        (uint8_t*) WHITE RED   WHITE,
+        (uint8_t*) RED   WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE,
+};
+
+static uint8_t* kLayoutBoundsNotEdgeAligned5x5[] = {
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE RED   WHITE WHITE,
+};
+
+static uint8_t* kLayoutBounds5x5[] = {
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE RED   WHITE RED   WHITE,
+};
+
+static uint8_t* kAsymmetricLayoutBounds5x5[] = {
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE RED   WHITE WHITE WHITE,
+};
+
+static uint8_t* kPaddingAndLayoutBounds5x5[] = {
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE WHITE WHITE WHITE BLACK,
+        (uint8_t*) WHITE WHITE WHITE WHITE RED,
+        (uint8_t*) WHITE RED   BLACK RED   WHITE,
+};
+
+static uint8_t* kColorfulImage5x5[] = {
+        (uint8_t*) WHITE BLACK WHITE BLACK WHITE,
+        (uint8_t*) BLACK RED   BLUE  GREEN WHITE,
+        (uint8_t*) BLACK RED   GREEN GREEN WHITE,
+        (uint8_t*) WHITE TRANS BLUE  GREEN WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineOpaque10x10[] = {
+        (uint8_t*) WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineTranslucent10x10[] = {
+        (uint8_t*) WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+        (uint8_t*) WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineOffsetTranslucent12x10[] = {
+        (uint8_t*) WHITE WHITE WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+        (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineRadius5x5[] = {
+        (uint8_t*) WHITE BLACK BLACK BLACK WHITE,
+        (uint8_t*) BLACK TRANS GREEN TRANS WHITE,
+        (uint8_t*) BLACK GREEN GREEN GREEN WHITE,
+        (uint8_t*) BLACK TRANS GREEN TRANS WHITE,
+        (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kStretchAndPadding5x5[] = {
+        (uint8_t*) WHITE WHITE BLACK WHITE WHITE,
+        (uint8_t*) WHITE RED   RED   RED   WHITE,
+        (uint8_t*) BLACK RED   RED   RED   BLACK,
+        (uint8_t*) WHITE RED   RED   RED   WHITE,
+        (uint8_t*) WHITE WHITE BLACK WHITE WHITE,
+};
+
+TEST(NinePatchTest, Minimum3x3) {
+    std::string err;
+    EXPECT_EQ(nullptr, NinePatch::create(k2x2, 2, 2, &err));
+    EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, MixedNeutralColors) {
+    std::string err;
+    EXPECT_EQ(nullptr, NinePatch::create(kMixedNeutralColor3x3, 3, 3, &err));
+    EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, TransparentNeutralColor) {
+    std::string err;
+    EXPECT_NE(nullptr, NinePatch::create(kTransparentNeutralColor3x3, 3, 3, &err));
+}
+
+TEST(NinePatchTest, SingleStretchRegion) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kSingleStretch7x6, 7, 6, &err);
+    ASSERT_NE(nullptr, ninePatch);
+
+    ASSERT_EQ(1u, ninePatch->horizontalStretchRegions.size());
+    ASSERT_EQ(1u, ninePatch->verticalStretchRegions.size());
+
+    EXPECT_EQ(Range(1, 4), ninePatch->horizontalStretchRegions.front());
+    EXPECT_EQ(Range(1, 3), ninePatch->verticalStretchRegions.front());
+}
+
+TEST(NinePatchTest, MultipleStretchRegions) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kMultipleStretch10x7, 10, 7, &err);
+    ASSERT_NE(nullptr, ninePatch);
+
+    ASSERT_EQ(3u, ninePatch->horizontalStretchRegions.size());
+    ASSERT_EQ(2u, ninePatch->verticalStretchRegions.size());
+
+    EXPECT_EQ(Range(1, 2), ninePatch->horizontalStretchRegions[0]);
+    EXPECT_EQ(Range(3, 5), ninePatch->horizontalStretchRegions[1]);
+    EXPECT_EQ(Range(6, 7), ninePatch->horizontalStretchRegions[2]);
+
+    EXPECT_EQ(Range(0, 2), ninePatch->verticalStretchRegions[0]);
+    EXPECT_EQ(Range(3, 5), ninePatch->verticalStretchRegions[1]);
+}
+
+TEST(NinePatchTest, InferPaddingFromStretchRegions) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kMultipleStretch10x7, 10, 7, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(1, 0, 1, 0), ninePatch->padding);
+}
+
+TEST(NinePatchTest, Padding) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kPadding6x5, 6, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->padding);
+}
+
+TEST(NinePatchTest, LayoutBoundsAreOnWrongEdge) {
+    std::string err;
+    EXPECT_EQ(nullptr, NinePatch::create(kLayoutBoundsWrongEdge3x3, 3, 3, &err));
+    EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, LayoutBoundsMustTouchEdges) {
+    std::string err;
+    EXPECT_EQ(nullptr, NinePatch::create(kLayoutBoundsNotEdgeAligned5x5, 5, 5, &err));
+    EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, LayoutBounds) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kLayoutBounds5x5, 5, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->layoutBounds);
+
+    ninePatch = NinePatch::create(kAsymmetricLayoutBounds5x5, 5, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(1, 1, 0, 0), ninePatch->layoutBounds);
+}
+
+TEST(NinePatchTest, PaddingAndLayoutBounds) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kPaddingAndLayoutBounds5x5, 5, 5,
+                                                             &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->padding);
+    EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->layoutBounds);
+}
+
+TEST(NinePatchTest, RegionColorsAreCorrect) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kColorfulImage5x5, 5, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+
+    std::vector<uint32_t> expectedColors = {
+            NinePatch::packRGBA((uint8_t*) RED),
+            (uint32_t) android::Res_png_9patch::NO_COLOR,
+            NinePatch::packRGBA((uint8_t*) GREEN),
+            (uint32_t) android::Res_png_9patch::TRANSPARENT_COLOR,
+            NinePatch::packRGBA((uint8_t*) BLUE),
+            NinePatch::packRGBA((uint8_t*) GREEN),
+    };
+    EXPECT_EQ(expectedColors, ninePatch->regionColors);
+}
+
+TEST(NinePatchTest, OutlineFromOpaqueImage) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineOpaque10x10, 10, 10, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(2, 2, 2, 2), ninePatch->outline);
+    EXPECT_EQ(0x000000ffu, ninePatch->outlineAlpha);
+    EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineFromTranslucentImage) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineTranslucent10x10, 10, 10,
+                                                             &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(3, 3, 3, 3), ninePatch->outline);
+    EXPECT_EQ(0x000000b3u, ninePatch->outlineAlpha);
+    EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineFromOffCenterImage) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineOffsetTranslucent12x10, 12, 10,
+                                                             &err);
+    ASSERT_NE(nullptr, ninePatch);
+
+    // TODO(adamlesinski): The old AAPT algorithm searches from the outside to the middle
+    // for each inset. If the outline is shifted, the search may not find a closer bounds.
+    // This check should be:
+    //   EXPECT_EQ(Bounds(5, 3, 3, 3), ninePatch->outline);
+    // but until I know what behaviour I'm breaking, I will leave it at the incorrect:
+    EXPECT_EQ(Bounds(4, 3, 3, 3), ninePatch->outline);
+
+    EXPECT_EQ(0x000000b3u, ninePatch->outlineAlpha);
+    EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineRadius) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineRadius5x5, 5, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+    EXPECT_EQ(Bounds(0, 0, 0, 0), ninePatch->outline);
+    EXPECT_EQ(3.4142f, ninePatch->outlineRadius);
+}
+
+::testing::AssertionResult bigEndianOne(uint8_t* cursor) {
+    if (cursor[0] == 0 && cursor[1] == 0 && cursor[2] == 0 && cursor[3] == 1) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure() << "Not BigEndian 1";
+}
+
+TEST(NinePatchTest, SerializePngEndianness) {
+    std::string err;
+    std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kStretchAndPadding5x5, 5, 5, &err);
+    ASSERT_NE(nullptr, ninePatch);
+
+    size_t len;
+    std::unique_ptr<uint8_t[]> data = ninePatch->serializeBase(&len);
+    ASSERT_NE(nullptr, data);
+    ASSERT_NE(0u, len);
+
+    // Skip past wasDeserialized + numXDivs + numYDivs + numColors + xDivsOffset + yDivsOffset
+    // (12 bytes)
+    uint8_t* cursor = data.get() + 12;
+
+    // Check that padding is big-endian. Expecting value 1.
+    EXPECT_TRUE(bigEndianOne(cursor));
+    EXPECT_TRUE(bigEndianOne(cursor + 4));
+    EXPECT_TRUE(bigEndianOne(cursor + 8));
+    EXPECT_TRUE(bigEndianOne(cursor + 12));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index f835b06e..4a15d95 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -17,10 +17,14 @@
 #ifndef AAPT_PNG_H
 #define AAPT_PNG_H
 
-#include "util/BigBuffer.h"
 #include "Diagnostics.h"
 #include "Source.h"
+#include "compile/Image.h"
+#include "io/Io.h"
+#include "process/IResourceTableConsumer.h"
+#include "util/BigBuffer.h"
 
+#include <android-base/macros.h>
 #include <iostream>
 #include <string>
 
@@ -40,8 +44,51 @@
 
 private:
     IDiagnostics* mDiag;
+
+    DISALLOW_COPY_AND_ASSIGN(Png);
 };
 
+/**
+ * An InputStream that filters out unimportant PNG chunks.
+ */
+class PngChunkFilter : public io::InputStream {
+public:
+    explicit PngChunkFilter(const StringPiece& data);
+
+    bool Next(const void** buffer, int* len) override;
+    void BackUp(int count) override;
+    bool Skip(int count) override;
+
+    int64_t ByteCount() const override {
+        return static_cast<int64_t>(mWindowStart);
+    }
+
+    bool HadError() const override {
+        return mError;
+    }
+
+private:
+    bool consumeWindow(const void** buffer, int* len);
+
+    StringPiece mData;
+    size_t mWindowStart = 0;
+    size_t mWindowEnd = 0;
+    bool mError = false;
+
+    DISALLOW_COPY_AND_ASSIGN(PngChunkFilter);
+};
+
+/**
+ * Reads a PNG from the InputStream into memory as an RGBA Image.
+ */
+std::unique_ptr<Image> readPng(IAaptContext* context, io::InputStream* in);
+
+/**
+ * Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream as a PNG.
+ */
+bool writePng(IAaptContext* context, const Image* image, const NinePatch* ninePatch,
+              io::OutputStream* out, const PngOptions& options);
+
 } // namespace aapt
 
 #endif // AAPT_PNG_H
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
new file mode 100644
index 0000000..70a881f
--- /dev/null
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "compile/Png.h"
+#include "io/Io.h"
+#include "util/StringPiece.h"
+
+namespace aapt {
+
+static constexpr const char* kPngSignature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
+
+// Useful helper function that encodes individual bytes into a uint32
+// at compile time.
+constexpr uint32_t u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
+    return (((uint32_t) a) << 24)
+            | (((uint32_t) b) << 16)
+            | (((uint32_t) c) << 8)
+            | ((uint32_t) d);
+}
+
+// Whitelist of PNG chunk types that we want to keep in the resulting PNG.
+enum PngChunkTypes {
+    kPngChunkIHDR = u32(73, 72, 68, 82),
+    kPngChunkIDAT = u32(73, 68, 65, 84),
+    kPngChunkIEND = u32(73, 69, 78, 68),
+    kPngChunkPLTE = u32(80, 76, 84, 69),
+    kPngChunktRNS = u32(116, 82, 78, 83),
+    kPngChunksRGB = u32(115, 82, 71, 66),
+};
+
+static uint32_t peek32LE(const char* data) {
+    uint32_t word = ((uint32_t) data[0]) & 0x000000ff;
+    word <<= 8;
+    word |= ((uint32_t) data[1]) & 0x000000ff;
+    word <<= 8;
+    word |= ((uint32_t) data[2]) & 0x000000ff;
+    word <<= 8;
+    word |= ((uint32_t) data[3]) & 0x000000ff;
+    return word;
+}
+
+static bool isPngChunkWhitelisted(uint32_t type) {
+    switch (type) {
+    case kPngChunkIHDR:
+    case kPngChunkIDAT:
+    case kPngChunkIEND:
+    case kPngChunkPLTE:
+    case kPngChunktRNS:
+    case kPngChunksRGB:
+        return true;
+    default:
+        return false;
+    }
+}
+
+PngChunkFilter::PngChunkFilter(const StringPiece& data) : mData(data) {
+    if (util::stringStartsWith(mData, kPngSignature)) {
+        mWindowStart = 0;
+        mWindowEnd = strlen(kPngSignature);
+    } else {
+        mError = true;
+    }
+}
+
+bool PngChunkFilter::consumeWindow(const void** buffer, int* len) {
+    if (mWindowStart != mWindowEnd) {
+        // We have bytes to give from our window.
+        const int bytesRead = (int) (mWindowEnd - mWindowStart);
+        *buffer = mData.data() + mWindowStart;
+        *len = bytesRead;
+        mWindowStart = mWindowEnd;
+        return true;
+    }
+    return false;
+}
+
+bool PngChunkFilter::Next(const void** buffer, int* len) {
+    if (mError) {
+        return false;
+    }
+
+    // In case BackUp was called, we must consume the window.
+    if (consumeWindow(buffer, len)) {
+        return true;
+    }
+
+    // Advance the window as far as possible (until we meet a chunk that
+    // we want to strip).
+    while (mWindowEnd < mData.size()) {
+        // Chunk length (4 bytes) + type (4 bytes) + crc32 (4 bytes) = 12 bytes.
+        const size_t kMinChunkHeaderSize = 3 * sizeof(uint32_t);
+
+        // Is there enough room for a chunk header?
+        if (mData.size() - mWindowStart < kMinChunkHeaderSize) {
+            mError = true;
+            return false;
+        }
+
+        // Verify the chunk length.
+        const uint32_t chunkLen = peek32LE(mData.data() + mWindowEnd);
+        if (((uint64_t) chunkLen) + ((uint64_t) mWindowEnd) + sizeof(uint32_t) > mData.size()) {
+            // Overflow.
+            mError = true;
+            return false;
+        }
+
+        // Do we strip this chunk?
+        const uint32_t chunkType = peek32LE(mData.data() + mWindowEnd + sizeof(uint32_t));
+        if (isPngChunkWhitelisted(chunkType)) {
+            // Advance the window to include this chunk.
+            mWindowEnd += kMinChunkHeaderSize + chunkLen;
+        } else {
+            // We want to strip this chunk. If we accumulated a window,
+            // we must return the window now.
+            if (mWindowStart != mWindowEnd) {
+                break;
+            }
+
+            // The window is empty, so we can advance past this chunk
+            // and keep looking for the next good chunk,
+            mWindowEnd += kMinChunkHeaderSize + chunkLen;
+            mWindowStart = mWindowEnd;
+        }
+    }
+
+    if (consumeWindow(buffer, len)) {
+        return true;
+    }
+    return false;
+}
+
+void PngChunkFilter::BackUp(int count) {
+    if (mError) {
+        return;
+    }
+    mWindowStart -= count;
+}
+
+bool PngChunkFilter::Skip(int count) {
+    if (mError) {
+        return false;
+    }
+
+    const void* buffer;
+    int len;
+    while (count > 0) {
+        if (!Next(&buffer, &len)) {
+            return false;
+        }
+        if (len > count) {
+            BackUp(len - count);
+            count = 0;
+        } else {
+            count -= len;
+        }
+    }
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
new file mode 100644
index 0000000..a2e3f4f
--- /dev/null
+++ b/tools/aapt2/compile/PngCrunch.cpp
@@ -0,0 +1,724 @@
+/*
+ * 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 "compile/Png.h"
+
+#include <algorithm>
+#include <android-base/errors.h>
+#include <android-base/macros.h>
+#include <png.h>
+#include <unordered_map>
+#include <unordered_set>
+#include <zlib.h>
+
+namespace aapt {
+
+// Size in bytes of the PNG signature.
+constexpr size_t kPngSignatureSize = 8u;
+
+/**
+ * Custom deleter that destroys libpng read and info structs.
+ */
+class PngReadStructDeleter {
+public:
+    explicit PngReadStructDeleter(png_structp readPtr, png_infop infoPtr) :
+            mReadPtr(readPtr), mInfoPtr(infoPtr) {
+    }
+
+    ~PngReadStructDeleter() {
+        png_destroy_read_struct(&mReadPtr, &mInfoPtr, nullptr);
+    }
+
+private:
+    png_structp mReadPtr;
+    png_infop mInfoPtr;
+
+    DISALLOW_COPY_AND_ASSIGN(PngReadStructDeleter);
+};
+
+/**
+ * Custom deleter that destroys libpng write and info structs.
+ */
+class PngWriteStructDeleter {
+public:
+    explicit PngWriteStructDeleter(png_structp writePtr, png_infop infoPtr) :
+            mWritePtr(writePtr), mInfoPtr(infoPtr) {
+    }
+
+    ~PngWriteStructDeleter() {
+        png_destroy_write_struct(&mWritePtr, &mInfoPtr);
+    }
+
+private:
+    png_structp mWritePtr;
+    png_infop mInfoPtr;
+
+    DISALLOW_COPY_AND_ASSIGN(PngWriteStructDeleter);
+};
+
+// Custom warning logging method that uses IDiagnostics.
+static void logWarning(png_structp pngPtr, png_const_charp warningMsg) {
+    IDiagnostics* diag = (IDiagnostics*) png_get_error_ptr(pngPtr);
+    diag->warn(DiagMessage() << warningMsg);
+}
+
+// Custom error logging method that uses IDiagnostics.
+static void logError(png_structp pngPtr, png_const_charp errorMsg) {
+    IDiagnostics* diag = (IDiagnostics*) png_get_error_ptr(pngPtr);
+    diag->error(DiagMessage() << errorMsg);
+}
+
+static void readDataFromStream(png_structp pngPtr, png_bytep buffer, png_size_t len) {
+    io::InputStream* in = (io::InputStream*) png_get_io_ptr(pngPtr);
+
+    const void* inBuffer;
+    int inLen;
+    if (!in->Next(&inBuffer, &inLen)) {
+        if (in->HadError()) {
+            std::string err = in->GetError();
+            png_error(pngPtr, err.c_str());
+        }
+        return;
+    }
+
+    const size_t bytesRead = std::min(static_cast<size_t>(inLen), len);
+    memcpy(buffer, inBuffer, bytesRead);
+    if (bytesRead != static_cast<size_t>(inLen)) {
+        in->BackUp(inLen - static_cast<int>(bytesRead));
+    }
+}
+
+static void writeDataToStream(png_structp pngPtr, png_bytep buffer, png_size_t len) {
+    io::OutputStream* out = (io::OutputStream*) png_get_io_ptr(pngPtr);
+
+    void* outBuffer;
+    int outLen;
+    while (len > 0) {
+        if (!out->Next(&outBuffer, &outLen)) {
+            if (out->HadError()) {
+                std::string err = out->GetError();
+                png_error(pngPtr, err.c_str());
+            }
+            return;
+        }
+
+        const size_t bytesWritten = std::min(static_cast<size_t>(outLen), len);
+        memcpy(outBuffer, buffer, bytesWritten);
+
+        // Advance the input buffer.
+        buffer += bytesWritten;
+        len -= bytesWritten;
+
+        // Advance the output buffer.
+        outLen -= static_cast<int>(bytesWritten);
+    }
+
+    // If the entire output buffer wasn't used, backup.
+    if (outLen > 0) {
+        out->BackUp(outLen);
+    }
+}
+
+std::unique_ptr<Image> readPng(IAaptContext* context, io::InputStream* in) {
+    // Read the first 8 bytes of the file looking for the PNG signature.
+    // Bail early if it does not match.
+    const png_byte* signature;
+    int bufferSize;
+    if (!in->Next((const void**) &signature, &bufferSize)) {
+        context->getDiagnostics()->error(DiagMessage()
+                                         << android::base::SystemErrorCodeToString(errno));
+        return {};
+    }
+
+    if (static_cast<size_t>(bufferSize) < kPngSignatureSize
+            || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
+        context->getDiagnostics()->error(DiagMessage()
+                                         << "file signature does not match PNG signature");
+        return {};
+    }
+
+    // Start at the beginning of the first chunk.
+    in->BackUp(bufferSize - static_cast<int>(kPngSignatureSize));
+
+    // Create and initialize the png_struct with the default error and warning handlers.
+    // The header version is also passed in to ensure that this was built against the same
+    // version of libpng.
+    png_structp readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+    if (readPtr == nullptr) {
+        context->getDiagnostics()->error(DiagMessage()
+                                         << "failed to create libpng read png_struct");
+        return {};
+    }
+
+    // Create and initialize the memory for image header and data.
+    png_infop infoPtr = png_create_info_struct(readPtr);
+    if (infoPtr == nullptr) {
+        context->getDiagnostics()->error(DiagMessage() << "failed to create libpng read png_info");
+        png_destroy_read_struct(&readPtr, nullptr, nullptr);
+        return {};
+    }
+
+    // Automatically release PNG resources at end of scope.
+    PngReadStructDeleter pngReadDeleter(readPtr, infoPtr);
+
+    // libpng uses longjmp to jump to an error handling routine.
+    // setjmp will only return true if it was jumped to, aka there was
+    // an error.
+    if (setjmp(png_jmpbuf(readPtr))) {
+        return {};
+    }
+
+    // Handle warnings ourselves via IDiagnostics.
+    png_set_error_fn(readPtr, (png_voidp) context->getDiagnostics(), logError, logWarning);
+
+    // Set up the read functions which read from our custom data sources.
+    png_set_read_fn(readPtr, (png_voidp) in, readDataFromStream);
+
+    // Skip the signature that we already read.
+    png_set_sig_bytes(readPtr, kPngSignatureSize);
+
+    // Read the chunk headers.
+    png_read_info(readPtr, infoPtr);
+
+    // Extract image meta-data from the various chunk headers.
+    uint32_t width, height;
+    int bitDepth, colorType, interlaceMethod, compressionMethod, filterMethod;
+    png_get_IHDR(readPtr, infoPtr, &width, &height, &bitDepth, &colorType, &interlaceMethod,
+                 &compressionMethod, &filterMethod);
+
+    // When the image is read, expand it so that it is in RGBA 8888 format
+    // so that image handling is uniform.
+
+    if (colorType == PNG_COLOR_TYPE_PALETTE) {
+        png_set_palette_to_rgb(readPtr);
+    }
+
+    if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
+        png_set_expand_gray_1_2_4_to_8(readPtr);
+    }
+
+    if (png_get_valid(readPtr, infoPtr, PNG_INFO_tRNS)) {
+        png_set_tRNS_to_alpha(readPtr);
+    }
+
+    if (bitDepth == 16) {
+        png_set_strip_16(readPtr);
+    }
+
+    if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
+        png_set_add_alpha(readPtr, 0xFF, PNG_FILLER_AFTER);
+    }
+
+    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        png_set_gray_to_rgb(readPtr);
+    }
+
+    if (interlaceMethod != PNG_INTERLACE_NONE) {
+        png_set_interlace_handling(readPtr);
+    }
+
+    // Once all the options for reading have been set, we need to flush
+    // them to libpng.
+    png_read_update_info(readPtr, infoPtr);
+
+    // 9-patch uses int32_t to index images, so we cap the image dimensions to something
+    // that can always be represented by 9-patch.
+    if (width > std::numeric_limits<int32_t>::max() ||
+            height > std::numeric_limits<int32_t>::max()) {
+        context->getDiagnostics()->error(DiagMessage() << "PNG image dimensions are too large: "
+                                         << width << "x" << height);
+        return {};
+    }
+
+    std::unique_ptr<Image> outputImage = util::make_unique<Image>();
+    outputImage->width = static_cast<int32_t>(width);
+    outputImage->height = static_cast<int32_t>(height);
+
+    const size_t rowBytes = png_get_rowbytes(readPtr, infoPtr);
+    assert(rowBytes == 4 * width); // RGBA
+
+    // Allocate one large block to hold the image.
+    outputImage->data = std::unique_ptr<uint8_t[]>(new uint8_t[height * rowBytes]);
+
+    // Create an array of rows that index into the data block.
+    outputImage->rows = std::unique_ptr<uint8_t*[]>(new uint8_t*[height]);
+    for (uint32_t h = 0; h < height; h++) {
+        outputImage->rows[h] = outputImage->data.get() + (h * rowBytes);
+    }
+
+    // Actually read the image pixels.
+    png_read_image(readPtr, outputImage->rows.get());
+
+    // Finish reading. This will read any other chunks after the image data.
+    png_read_end(readPtr, infoPtr);
+
+    return outputImage;
+}
+
+/**
+ * Experimentally chosen constant to be added to the overhead of using color type
+ * PNG_COLOR_TYPE_PALETTE to account for the uncompressability of the palette chunk.
+ * Without this, many small PNGs encoded with palettes are larger after compression than
+ * the same PNGs encoded as RGBA.
+ */
+constexpr static const size_t kPaletteOverheadConstant = 1024u * 10u;
+
+// Pick a color type by which to encode the image, based on which color type will take
+// the least amount of disk space.
+//
+// 9-patch images traditionally have not been encoded with palettes.
+// The original rationale was to avoid dithering until after scaling,
+// but I don't think this would be an issue with palettes. Either way,
+// our naive size estimation tends to be wrong for small images like 9-patches
+// and using palettes balloons the size of the resulting 9-patch.
+// In order to not regress in size, restrict 9-patch to not use palettes.
+
+// The options are:
+//
+// - RGB
+// - RGBA
+// - RGB + cheap alpha
+// - Color palette
+// - Color palette + cheap alpha
+// - Color palette + alpha palette
+// - Grayscale
+// - Grayscale + cheap alpha
+// - Grayscale + alpha
+//
+static int pickColorType(int32_t width, int32_t height,
+                         bool grayScale, bool convertibleToGrayScale, bool hasNinePatch,
+                         size_t colorPaletteSize, size_t alphaPaletteSize) {
+    const size_t paletteChunkSize = 16 + colorPaletteSize * 3;
+    const size_t alphaChunkSize = 16 + alphaPaletteSize;
+    const size_t colorAlphaDataChunkSize = 16 + 4 * width * height;
+    const size_t colorDataChunkSize = 16 + 3 * width * height;
+    const size_t grayScaleAlphaDataChunkSize = 16 + 2 * width * height;
+    const size_t paletteDataChunkSize = 16 + width * height;
+
+    if (grayScale) {
+        if (alphaPaletteSize == 0) {
+            // This is the smallest the data can be.
+            return PNG_COLOR_TYPE_GRAY;
+        } else if (colorPaletteSize <= 256 && !hasNinePatch) {
+            // This grayscale has alpha and can fit within a palette.
+            // See if it is worth fitting into a palette.
+            const size_t paletteThreshold = paletteChunkSize + alphaChunkSize +
+                    paletteDataChunkSize + kPaletteOverheadConstant;
+            if (grayScaleAlphaDataChunkSize > paletteThreshold) {
+                return PNG_COLOR_TYPE_PALETTE;
+            }
+        }
+        return PNG_COLOR_TYPE_GRAY_ALPHA;
+    }
+
+
+    if (colorPaletteSize <= 256 && !hasNinePatch) {
+        // This image can fit inside a palette. Let's see if it is worth it.
+        size_t totalSizeWithPalette = paletteDataChunkSize + paletteChunkSize;
+        size_t totalSizeWithoutPalette = colorDataChunkSize;
+        if (alphaPaletteSize > 0) {
+            totalSizeWithPalette += alphaPaletteSize;
+            totalSizeWithoutPalette = colorAlphaDataChunkSize;
+        }
+
+        if (totalSizeWithoutPalette > totalSizeWithPalette + kPaletteOverheadConstant) {
+            return PNG_COLOR_TYPE_PALETTE;
+        }
+    }
+
+    if (convertibleToGrayScale) {
+        if (alphaPaletteSize == 0) {
+            return PNG_COLOR_TYPE_GRAY;
+        } else {
+            return PNG_COLOR_TYPE_GRAY_ALPHA;
+        }
+    }
+
+    if (alphaPaletteSize == 0) {
+        return PNG_COLOR_TYPE_RGB;
+    }
+    return PNG_COLOR_TYPE_RGBA;
+}
+
+// Assigns indices to the color and alpha palettes, encodes them, and then invokes
+// png_set_PLTE/png_set_tRNS.
+// This must be done before writing image data.
+// Image data must be transformed to use the indices assigned within the palette.
+static void writePalette(png_structp writePtr, png_infop writeInfoPtr,
+                  std::unordered_map<uint32_t, int>* colorPalette,
+                  std::unordered_set<uint32_t>* alphaPalette) {
+    assert(colorPalette->size() <= 256);
+    assert(alphaPalette->size() <= 256);
+
+    // Populate the PNG palette struct and assign indices to the color
+    // palette.
+
+    // Colors in the alpha palette should have smaller indices.
+    // This will ensure that we can truncate the alpha palette if it is
+    // smaller than the color palette.
+    int index = 0;
+    for (uint32_t color : *alphaPalette) {
+        (*colorPalette)[color] = index++;
+    }
+
+    // Assign the rest of the entries.
+    for (auto& entry : *colorPalette) {
+        if (entry.second == -1) {
+            entry.second = index++;
+        }
+    }
+
+    // Create the PNG color palette struct.
+    auto colorPaletteBytes = std::unique_ptr<png_color[]>(new png_color[colorPalette->size()]);
+
+    std::unique_ptr<png_byte[]> alphaPaletteBytes;
+    if (!alphaPalette->empty()) {
+        alphaPaletteBytes = std::unique_ptr<png_byte[]>(new png_byte[alphaPalette->size()]);
+    }
+
+    for (const auto& entry : *colorPalette) {
+        const uint32_t color = entry.first;
+        const int index = entry.second;
+        assert(index >= 0);
+        assert(static_cast<size_t>(index) < colorPalette->size());
+
+        png_colorp slot = colorPaletteBytes.get() + index;
+        slot->red = color >> 24;
+        slot->green = color >> 16;
+        slot->blue = color >> 8;
+
+        const png_byte alpha = color & 0x000000ff;
+        if (alpha != 0xff && alphaPaletteBytes) {
+            assert(static_cast<size_t>(index) < alphaPalette->size());
+            alphaPaletteBytes[index] = alpha;
+        }
+    }
+
+    // The bytes get copied here, so it is safe to release colorPaletteBytes at the end of function
+    // scope.
+    png_set_PLTE(writePtr, writeInfoPtr, colorPaletteBytes.get(), colorPalette->size());
+
+    if (alphaPaletteBytes) {
+        png_set_tRNS(writePtr, writeInfoPtr, alphaPaletteBytes.get(), alphaPalette->size(),
+                     nullptr);
+    }
+}
+
+// Write the 9-patch custom PNG chunks to writeInfoPtr. This must be done before
+// writing image data.
+static void writeNinePatch(png_structp writePtr, png_infop writeInfoPtr,
+                           const NinePatch* ninePatch) {
+    // The order of the chunks is important.
+    // 9-patch code in older platforms expects the 9-patch chunk to
+    // be last.
+
+    png_unknown_chunk unknownChunks[3];
+    memset(unknownChunks, 0, sizeof(unknownChunks));
+
+    size_t index = 0;
+    size_t chunkLen = 0;
+
+    std::unique_ptr<uint8_t[]> serializedOutline =
+            ninePatch->serializeRoundedRectOutline(&chunkLen);
+    strcpy((char*) unknownChunks[index].name, "npOl");
+    unknownChunks[index].size = chunkLen;
+    unknownChunks[index].data = (png_bytep) serializedOutline.get();
+    unknownChunks[index].location = PNG_HAVE_PLTE;
+    index++;
+
+    std::unique_ptr<uint8_t[]> serializedLayoutBounds;
+    if (ninePatch->layoutBounds.nonZero()) {
+        serializedLayoutBounds = ninePatch->serializeLayoutBounds(&chunkLen);
+        strcpy((char*) unknownChunks[index].name, "npLb");
+        unknownChunks[index].size = chunkLen;
+        unknownChunks[index].data = (png_bytep) serializedLayoutBounds.get();
+        unknownChunks[index].location = PNG_HAVE_PLTE;
+        index++;
+    }
+
+    std::unique_ptr<uint8_t[]> serializedNinePatch = ninePatch->serializeBase(&chunkLen);
+    strcpy((char*) unknownChunks[index].name, "npTc");
+    unknownChunks[index].size = chunkLen;
+    unknownChunks[index].data = (png_bytep) serializedNinePatch.get();
+    unknownChunks[index].location = PNG_HAVE_PLTE;
+    index++;
+
+    // Handle all unknown chunks. We are manually setting the chunks here,
+    // so we will only ever handle our custom chunks.
+    png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS, nullptr, 0);
+
+    // Set the actual chunks here. The data gets copied, so our buffers can
+    // safely go out of scope.
+    png_set_unknown_chunks(writePtr, writeInfoPtr, unknownChunks, index);
+}
+
+bool writePng(IAaptContext* context, const Image* image, const NinePatch* ninePatch,
+              io::OutputStream* out, const PngOptions& options) {
+    // Create and initialize the write png_struct with the default error and warning handlers.
+    // The header version is also passed in to ensure that this was built against the same
+    // version of libpng.
+    png_structp writePtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+                                                   nullptr, nullptr, nullptr);
+    if (writePtr == nullptr) {
+        context->getDiagnostics()->error(DiagMessage()
+                                         << "failed to create libpng write png_struct");
+        return false;
+    }
+
+    // Allocate memory to store image header data.
+    png_infop writeInfoPtr = png_create_info_struct(writePtr);
+    if (writeInfoPtr == nullptr) {
+        context->getDiagnostics()->error(DiagMessage() << "failed to create libpng write png_info");
+        png_destroy_write_struct(&writePtr, nullptr);
+        return false;
+    }
+
+    // Automatically release PNG resources at end of scope.
+    PngWriteStructDeleter pngWriteDeleter(writePtr, writeInfoPtr);
+
+    // libpng uses longjmp to jump to error handling routines.
+    // setjmp will return true only if it was jumped to, aka, there was an error.
+    if (setjmp(png_jmpbuf(writePtr))) {
+        return false;
+    }
+
+    // Handle warnings with our IDiagnostics.
+    png_set_error_fn(writePtr, (png_voidp) context->getDiagnostics(), logError, logWarning);
+
+    // Set up the write functions which write to our custom data sources.
+    png_set_write_fn(writePtr, (png_voidp) out, writeDataToStream, nullptr);
+
+    // We want small files and can take the performance hit to achieve this goal.
+    png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
+
+    // Begin analysis of the image data.
+    // Scan the entire image and determine if:
+    // 1. Every pixel has R == G == B (grayscale)
+    // 2. Every pixel has A == 255 (opaque)
+    // 3. There are no more than 256 distinct RGBA colors (palette).
+    std::unordered_map<uint32_t, int> colorPalette;
+    std::unordered_set<uint32_t> alphaPalette;
+    bool needsToZeroRGBChannelsOfTransparentPixels = false;
+    bool grayScale = true;
+    int maxGrayDeviation = 0;
+
+    for (int32_t y = 0; y < image->height; y++) {
+        const uint8_t* row = image->rows[y];
+        for (int32_t x = 0; x < image->width; x++) {
+            int red = *row++;
+            int green = *row++;
+            int blue = *row++;
+            int alpha = *row++;
+
+            if (alpha == 0) {
+                // The color is completely transparent.
+                // For purposes of palettes and grayscale optimization,
+                // treat all channels as 0x00.
+                needsToZeroRGBChannelsOfTransparentPixels =
+                        needsToZeroRGBChannelsOfTransparentPixels ||
+                        (red != 0 || green != 0 || blue != 0);
+                red = green = blue = 0;
+            }
+
+            // Insert the color into the color palette.
+            const uint32_t color = red << 24 | green << 16 | blue << 8 | alpha;
+            colorPalette[color] = -1;
+
+            // If the pixel has non-opaque alpha, insert it into the
+            // alpha palette.
+            if (alpha != 0xff) {
+                alphaPalette.insert(color);
+            }
+
+            // Check if the image is indeed grayscale.
+            if (grayScale) {
+                if (red != green || red != blue) {
+                    grayScale = false;
+                }
+            }
+
+            // Calculate the gray scale deviation so that it can be compared
+            // with the threshold.
+            maxGrayDeviation = std::max(std::abs(red - green), maxGrayDeviation);
+            maxGrayDeviation = std::max(std::abs(green - blue), maxGrayDeviation);
+            maxGrayDeviation = std::max(std::abs(blue - red), maxGrayDeviation);
+        }
+    }
+
+    if (context->verbose()) {
+        DiagMessage msg;
+        msg << " paletteSize=" << colorPalette.size()
+                << " alphaPaletteSize=" << alphaPalette.size()
+                << " maxGrayDeviation=" << maxGrayDeviation
+                << " grayScale=" << (grayScale ? "true" : "false");
+        context->getDiagnostics()->note(msg);
+    }
+
+    const bool convertibleToGrayScale = maxGrayDeviation <= options.grayScaleTolerance;
+
+    const int newColorType = pickColorType(image->width, image->height, grayScale,
+                                           convertibleToGrayScale, ninePatch != nullptr,
+                                           colorPalette.size(), alphaPalette.size());
+
+    if (context->verbose()) {
+        DiagMessage msg;
+        msg << "encoding PNG ";
+        if (ninePatch) {
+            msg << "(with 9-patch) as ";
+        }
+        switch (newColorType) {
+        case PNG_COLOR_TYPE_GRAY:
+            msg << "GRAY";
+            break;
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            msg << "GRAY + ALPHA";
+            break;
+        case PNG_COLOR_TYPE_RGB:
+            msg << "RGB";
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            msg << "RGBA";
+            break;
+        case PNG_COLOR_TYPE_PALETTE:
+            msg << "PALETTE";
+            break;
+        default:
+            msg << "unknown type " << newColorType;
+            break;
+        }
+        context->getDiagnostics()->note(msg);
+    }
+
+    png_set_IHDR(writePtr, writeInfoPtr, image->width, image->height, 8, newColorType,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    if (newColorType & PNG_COLOR_MASK_PALETTE) {
+        // Assigns indices to the palette, and writes the encoded palette to the libpng writePtr.
+        writePalette(writePtr, writeInfoPtr, &colorPalette, &alphaPalette);
+        png_set_filter(writePtr, 0, PNG_NO_FILTERS);
+    } else {
+        png_set_filter(writePtr, 0, PNG_ALL_FILTERS);
+    }
+
+    if (ninePatch) {
+        writeNinePatch(writePtr, writeInfoPtr, ninePatch);
+    }
+
+    // Flush our updates to the header.
+    png_write_info(writePtr, writeInfoPtr);
+
+    // Write out each row of image data according to its encoding.
+    if (newColorType == PNG_COLOR_TYPE_PALETTE) {
+        // 1 byte/pixel.
+        auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width]);
+
+        for (int32_t y = 0; y < image->height; y++) {
+            png_const_bytep inRow = image->rows[y];
+            for (int32_t x = 0; x < image->width; x++) {
+                int rr = *inRow++;
+                int gg = *inRow++;
+                int bb = *inRow++;
+                int aa = *inRow++;
+                if (aa == 0) {
+                    // Zero out color channels when transparent.
+                    rr = gg = bb = 0;
+                }
+
+                const uint32_t color = rr << 24 | gg << 16 | bb << 8 | aa;
+                const int idx = colorPalette[color];
+                assert(idx != -1);
+                outRow[x] = static_cast<png_byte>(idx);
+            }
+            png_write_row(writePtr, outRow.get());
+        }
+    } else if (newColorType == PNG_COLOR_TYPE_GRAY || newColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        const size_t bpp = newColorType == PNG_COLOR_TYPE_GRAY ? 1 : 2;
+        auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
+
+        for (int32_t y = 0; y < image->height; y++) {
+            png_const_bytep inRow = image->rows[y];
+            for (int32_t x = 0; x < image->width; x++) {
+                int rr = inRow[x * 4];
+                int gg = inRow[x * 4 + 1];
+                int bb = inRow[x * 4 + 2];
+                int aa = inRow[x * 4 + 3];
+                if (aa == 0) {
+                    // Zero out the gray channel when transparent.
+                    rr = gg = bb = 0;
+                }
+
+                if (grayScale) {
+                    // The image was already grayscale, red == green == blue.
+                    outRow[x * bpp] = inRow[x * 4];
+                } else {
+                    // The image is convertible to grayscale, use linear-luminance of
+                    // sRGB colorspace: https://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale
+                    outRow[x * bpp] = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
+                }
+
+                if (bpp == 2) {
+                    // Write out alpha if we have it.
+                    outRow[x * bpp + 1] = aa;
+                }
+            }
+            png_write_row(writePtr, outRow.get());
+        }
+    } else if (newColorType == PNG_COLOR_TYPE_RGB || newColorType == PNG_COLOR_TYPE_RGBA) {
+        const size_t bpp = newColorType == PNG_COLOR_TYPE_RGB ? 3 : 4;
+        if (needsToZeroRGBChannelsOfTransparentPixels) {
+            // The source RGBA data can't be used as-is, because we need to zero out the RGB
+            // values of transparent pixels.
+            auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
+
+            for (int32_t y = 0; y < image->height; y++) {
+                png_const_bytep inRow = image->rows[y];
+                for (int32_t x = 0; x < image->width; x++) {
+                    int rr = *inRow++;
+                    int gg = *inRow++;
+                    int bb = *inRow++;
+                    int aa = *inRow++;
+                    if (aa == 0) {
+                        // Zero out the RGB channels when transparent.
+                        rr = gg = bb = 0;
+                    }
+                    outRow[x * bpp] = rr;
+                    outRow[x * bpp + 1] = gg;
+                    outRow[x * bpp + 2] = bb;
+                    if (bpp == 4) {
+                        outRow[x * bpp + 3] = aa;
+                    }
+                }
+                png_write_row(writePtr, outRow.get());
+            }
+        } else {
+            // The source image can be used as-is, just tell libpng whether or not to ignore
+            // the alpha channel.
+            if (newColorType == PNG_COLOR_TYPE_RGB) {
+                // Delete the extraneous alpha values that we appended to our buffer
+                // when reading the original values.
+                png_set_filler(writePtr, 0, PNG_FILLER_AFTER);
+            }
+            png_write_image(writePtr, image->rows.get());
+        }
+    } else {
+        assert(false && "unreachable");
+    }
+
+    png_write_end(writePtr, writeInfoPtr);
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index 88c6f64..f61ec94 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -37,6 +37,7 @@
     std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(pbFile, source,
                                                                        context->getDiagnostics());
     if (!file) {
+        context->getDiagnostics()->warn(DiagMessage() << "failed to read compiled file");
         return;
     }
 
@@ -112,9 +113,27 @@
         if (!table) {
             // Try as a compiled file.
             CompiledFileInputStream input(fileMap->getDataPtr(), fileMap->getDataLength());
-            if (const pb::CompiledFile* pbFile = input.CompiledFile()) {
-               dumpCompiledFile(*pbFile, input.data(), input.size(), Source(filePath), context);
-               return;
+
+            uint32_t numFiles = 0;
+            if (!input.ReadLittleEndian32(&numFiles)) {
+                return;
+            }
+
+            for (uint32_t i = 0; i < numFiles; i++) {
+                pb::CompiledFile compiledFile;
+                if (!input.ReadCompiledFile(&compiledFile)) {
+                    context->getDiagnostics()->warn(DiagMessage() << "failed to read compiled file");
+                    return;
+                }
+
+                uint64_t offset, len;
+                if (!input.ReadDataMetaData(&offset, &len)) {
+                    context->getDiagnostics()->warn(DiagMessage() << "failed to read meta data");
+                    return;
+                }
+
+                const void* data = static_cast<const uint8_t*>(fileMap->getDataPtr()) + offset;
+                dumpCompiledFile(compiledFile, data, len, Source(filePath), context);
             }
         }
     }
diff --git a/tools/aapt2/flatten/Archive.h b/tools/aapt2/flatten/Archive.h
index 34c10ad..96d8512 100644
--- a/tools/aapt2/flatten/Archive.h
+++ b/tools/aapt2/flatten/Archive.h
@@ -41,7 +41,8 @@
     size_t uncompressedSize;
 };
 
-struct IArchiveWriter : public google::protobuf::io::CopyingOutputStream {
+class IArchiveWriter : public google::protobuf::io::CopyingOutputStream {
+public:
     virtual ~IArchiveWriter() = default;
 
     virtual bool startEntry(const StringPiece& path, uint32_t flags) = 0;
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 6a35e8c..d5067b1 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -83,19 +83,19 @@
 
     void visit(Attribute* attr) override {
         {
-            Reference key = Reference(ResTable_map::ATTR_TYPE);
+            Reference key = Reference(ResourceId(ResTable_map::ATTR_TYPE));
             BinaryPrimitive val(Res_value::TYPE_INT_DEC, attr->typeMask);
             flattenEntry(&key, &val);
         }
 
         if (attr->minInt != std::numeric_limits<int32_t>::min()) {
-            Reference key = Reference(ResTable_map::ATTR_MIN);
+            Reference key = Reference(ResourceId(ResTable_map::ATTR_MIN));
             BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->minInt));
             flattenEntry(&key, &val);
         }
 
         if (attr->maxInt != std::numeric_limits<int32_t>::max()) {
-            Reference key = Reference(ResTable_map::ATTR_MAX);
+            Reference key = Reference(ResourceId(ResTable_map::ATTR_MAX));
             BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->maxInt));
             flattenEntry(&key, &val);
         }
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png b/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png
new file mode 100644
index 0000000..0522a99
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png
new file mode 100644
index 0000000..baf9fff
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png
new file mode 100644
index 0000000..7b331e1
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png
new file mode 100644
index 0000000..0ec6c70
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png
new file mode 100644
index 0000000..e05708a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png
new file mode 100644
index 0000000..a11377a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png
new file mode 100644
index 0000000..6803e42
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png
new file mode 100644
index 0000000..1a3731b
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png
new file mode 100644
index 0000000..489ace2
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/special.xml b/tools/aapt2/integration-tests/AppOne/res/layout/special.xml
new file mode 100644
index 0000000..28c85ca
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/layout/special.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <include>
+        <aapt:attr name="layout" xmlns:aapt="http://schemas.android.com/aapt">
+            <RelativeLayout android:id="@+id/hello" />
+        </aapt:attr>
+    </include>
+</View>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
index f4b7471..91f8bfd 100644
--- a/tools/aapt2/integration-tests/AppOne/res/values/test.xml
+++ b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
@@ -29,4 +29,11 @@
         <flag name="pub" value="2" />
         <flag name="weak" value="4" />
     </attr>
+
+    <!-- Override the Widget styleable declared in StaticLibOne.
+         This should merge the two when built in overlay mode. -->
+    <declare-styleable name="Widget">
+        <attr name="android:text" />
+        <attr name="layout_width" />
+    </declare-styleable>
 </resources>
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
index d09a485..b4dc90b 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
+++ b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
@@ -23,5 +23,6 @@
 
     <declare-styleable name="Widget">
         <attr name="StaticLibOne_attr" />
+        <attr name="android:text" />
     </declare-styleable>
 </resources>
diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h
index 467e604..34eed63 100644
--- a/tools/aapt2/io/Data.h
+++ b/tools/aapt2/io/Data.h
@@ -17,9 +17,9 @@
 #ifndef AAPT_IO_DATA_H
 #define AAPT_IO_DATA_H
 
-#include <utils/FileMap.h>
-
+#include <android-base/macros.h>
 #include <memory>
+#include <utils/FileMap.h>
 
 namespace aapt {
 namespace io {
@@ -35,6 +35,28 @@
     virtual size_t size() const = 0;
 };
 
+class DataSegment : public IData {
+public:
+    explicit DataSegment(std::unique_ptr<IData> data, size_t offset, size_t len) :
+            mData(std::move(data)), mOffset(offset), mLen(len) {
+    }
+
+    const void* data() const override {
+        return static_cast<const uint8_t*>(mData->data()) + mOffset;
+    }
+
+    size_t size() const override {
+        return mLen;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(DataSegment);
+
+    std::unique_ptr<IData> mData;
+    size_t mOffset;
+    size_t mLen;
+};
+
 /**
  * Implementation of IData that exposes a memory mapped file. The mmapped file is owned by this
  * object.
diff --git a/tools/aapt2/io/File.cpp b/tools/aapt2/io/File.cpp
new file mode 100644
index 0000000..739c0d2
--- /dev/null
+++ b/tools/aapt2/io/File.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "io/File.h"
+
+#include <memory>
+
+namespace aapt {
+namespace io {
+
+IFile* IFile::createFileSegment(size_t offset, size_t len) {
+   FileSegment* fileSegment = new FileSegment(this, offset, len);
+   mSegments.push_back(std::unique_ptr<IFile>(fileSegment));
+   return fileSegment;
+}
+
+std::unique_ptr<IData> FileSegment::openAsData() {
+    std::unique_ptr<IData> data = mFile->openAsData();
+    if (!data) {
+        return {};
+    }
+
+    if (mOffset <= data->size() - mLen) {
+        return util::make_unique<DataSegment>(std::move(data), mOffset, mLen);
+    }
+    return {};
+}
+
+} // namespace io
+} // namespace aapt
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index b4d4971..807981e 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -19,7 +19,10 @@
 
 #include "Source.h"
 #include "io/Data.h"
+#include "util/Util.h"
 
+#include <android-base/macros.h>
+#include <list>
 #include <memory>
 #include <vector>
 
@@ -50,6 +53,37 @@
      * a ZIP archive from the path to the containing ZIP archive.
      */
     virtual const Source& getSource() const = 0;
+
+    IFile* createFileSegment(size_t offset, size_t len);
+
+private:
+    // Any segments created from this IFile need to be owned by this IFile, so keep them
+    // in a list. This will never be read, so we prefer better insertion performance
+    // than cache locality, hence the list.
+    std::list<std::unique_ptr<IFile>> mSegments;
+};
+
+/**
+ * An IFile that wraps an underlying IFile but limits it to a subsection of that file.
+ */
+class FileSegment : public IFile {
+public:
+    explicit FileSegment(IFile* file, size_t offset, size_t len) :
+            mFile(file), mOffset(offset), mLen(len) {
+    }
+
+    std::unique_ptr<IData> openAsData() override;
+
+    const Source& getSource() const override {
+        return mFile->getSource();
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(FileSegment);
+
+    IFile* mFile;
+    size_t mOffset;
+    size_t mLen;
 };
 
 class IFileCollectionIterator {
diff --git a/tools/aapt2/io/Io.cpp b/tools/aapt2/io/Io.cpp
new file mode 100644
index 0000000..963c21c
--- /dev/null
+++ b/tools/aapt2/io/Io.cpp
@@ -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.
+ */
+
+#include "io/Io.h"
+
+#include <algorithm>
+#include <cstring>
+
+namespace aapt {
+namespace io {
+
+bool copy(OutputStream* out, InputStream* in) {
+    const void* inBuffer;
+    int inLen;
+    while (in->Next(&inBuffer, &inLen)) {
+        void* outBuffer;
+        int outLen;
+        if (!out->Next(&outBuffer, &outLen)) {
+            return !out->HadError();
+        }
+
+        const int bytesToCopy = std::min(inLen, outLen);
+        memcpy(outBuffer, inBuffer, bytesToCopy);
+        out->BackUp(outLen - bytesToCopy);
+        in->BackUp(inLen - bytesToCopy);
+    }
+    return !in->HadError();
+}
+
+} // namespace io
+} // namespace aapt
diff --git a/tools/aapt2/io/Io.h b/tools/aapt2/io/Io.h
new file mode 100644
index 0000000..e1e9107
--- /dev/null
+++ b/tools/aapt2/io/Io.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_IO_IO_H
+#define AAPT_IO_IO_H
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <string>
+
+namespace aapt {
+namespace io {
+
+/**
+ * InputStream interface that inherits from protobuf's ZeroCopyInputStream,
+ * but adds error handling methods to better report issues.
+ *
+ * The code style here matches the protobuf style.
+ */
+class InputStream : public google::protobuf::io::ZeroCopyInputStream {
+public:
+    virtual std::string GetError() const {
+        return {};
+    }
+
+    virtual bool HadError() const = 0;
+};
+
+/**
+ * OutputStream interface that inherits from protobuf's ZeroCopyOutputStream,
+ * but adds error handling methods to better report issues.
+ *
+ * The code style here matches the protobuf style.
+ */
+class OutputStream : public google::protobuf::io::ZeroCopyOutputStream {
+public:
+    virtual std::string GetError() const {
+        return {};
+    }
+
+    virtual bool HadError() const = 0;
+};
+
+/**
+ * Copies the data from in to out. Returns true if there was no error.
+ * If there was an error, check the individual streams' HadError/GetError
+ * methods.
+ */
+bool copy(OutputStream* out, InputStream* in);
+
+} // namespace io
+} // namespace aapt
+
+#endif /* AAPT_IO_IO_H */
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 5a2bb6a..b6b4b473 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -48,10 +48,13 @@
 #include <google/protobuf/io/coded_stream.h>
 
 #include <fstream>
+#include <queue>
 #include <sys/stat.h>
 #include <unordered_map>
 #include <vector>
 
+using google::protobuf::io::CopyingOutputStreamAdaptor;
+
 namespace aapt {
 
 struct LinkOptions {
@@ -69,11 +72,13 @@
 
     bool noAutoVersion = false;
     bool noVersionVectors = false;
+    bool noResourceDeduping = false;
     bool staticLib = false;
     bool noStaticLibPackages = false;
     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;
@@ -165,19 +170,7 @@
     }
 
     const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data->data());
-    size_t bufferSize = data->size();
-
-    // If the file ends with .flat, we must strip off the CompiledFileHeader from it.
-    if (util::stringEndsWith(file->getSource().path, ".flat")) {
-        CompiledFileInputStream inputStream(data->data(), data->size());
-        if (!inputStream.CompiledFile()) {
-            context->getDiagnostics()->error(DiagMessage(file->getSource())
-                                             << "invalid compiled file header");
-            return false;
-        }
-        buffer = reinterpret_cast<const uint8_t*>(inputStream.data());
-        bufferSize = inputStream.size();
-    }
+    const size_t bufferSize = data->size();
 
     if (context->verbose()) {
         context->getDiagnostics()->note(DiagMessage() << "writing " << outPath << " to archive");
@@ -254,45 +247,10 @@
     return xml::inflate(&fin, diag, Source(path));
 }
 
-static std::unique_ptr<xml::XmlResource> loadBinaryXmlSkipFileExport(const Source& source,
-                                                                     const void* data, size_t len,
-                                                                     IDiagnostics* diag) {
-    CompiledFileInputStream inputStream(data, len);
-    if (!inputStream.CompiledFile()) {
-        diag->error(DiagMessage(source) << "invalid compiled file header");
-        return {};
-    }
-
-    const uint8_t* xmlData = reinterpret_cast<const uint8_t*>(inputStream.data());
-    const size_t xmlDataLen = inputStream.size();
-
-    std::unique_ptr<xml::XmlResource> xmlRes = xml::inflate(xmlData, xmlDataLen, diag, source);
-    if (!xmlRes) {
-        return {};
-    }
-    return xmlRes;
-}
-
-static std::unique_ptr<ResourceFile> loadFileExportHeader(const Source& source,
-                                                          const void* data, size_t len,
-                                                          IDiagnostics* diag) {
-    CompiledFileInputStream inputStream(data, len);
-    const pb::CompiledFile* pbFile = inputStream.CompiledFile();
-    if (!pbFile) {
-        diag->error(DiagMessage(source) << "invalid compiled file header");
-        return {};
-    }
-
-    std::unique_ptr<ResourceFile> resFile = deserializeCompiledFileFromPb(*pbFile, source, diag);
-    if (!resFile) {
-        return {};
-    }
-    return resFile;
-}
-
 struct ResourceFileFlattenerOptions {
     bool noAutoVersion = false;
     bool noVersionVectors = false;
+    bool noXmlNamespaces = false;
     bool keepRawValues = false;
     bool doNotCompressAnything = false;
     bool updateProguardSpec = false;
@@ -310,16 +268,26 @@
 
 private:
     struct FileOperation {
+        ConfigDescription config;
+
+        // The entry this file came from.
+        const ResourceEntry* entry;
+
+        // The file to copy as-is.
         io::IFile* fileToCopy;
+
+        // The XML to process and flatten.
         std::unique_ptr<xml::XmlResource> xmlToFlatten;
+
+        // The destination to write this file to.
         std::string dstPath;
         bool skipVersion = false;
     };
 
     uint32_t getCompressionFlags(const StringPiece& str);
 
-    bool linkAndVersionXmlFile(const ResourceEntry* entry, const ResourceFile& fileDesc,
-                               io::IFile* file, ResourceTable* table, FileOperation* outFileOp);
+    bool linkAndVersionXmlFile(ResourceTable* table, FileOperation* fileOp,
+                               std::queue<FileOperation>* outFileOpQueue);
 
     ResourceFileFlattenerOptions mOptions;
     IAaptContext* mContext;
@@ -339,97 +307,87 @@
     return ArchiveEntry::kCompress;
 }
 
-bool ResourceFileFlattener::linkAndVersionXmlFile(const ResourceEntry* entry,
-                                                  const ResourceFile& fileDesc,
-                                                  io::IFile* file,
-                                                  ResourceTable* table,
-                                                  FileOperation* outFileOp) {
-    const StringPiece srcPath = file->getSource().path;
+bool ResourceFileFlattener::linkAndVersionXmlFile(ResourceTable* table,
+                                                  FileOperation* fileOp,
+                                                  std::queue<FileOperation>* outFileOpQueue) {
+    xml::XmlResource* doc = fileOp->xmlToFlatten.get();
+    const Source& src = doc->file.source;
+
     if (mContext->verbose()) {
-        mContext->getDiagnostics()->note(DiagMessage() << "linking " << srcPath);
+        mContext->getDiagnostics()->note(DiagMessage() << "linking " << src.path);
     }
 
-    std::unique_ptr<io::IData> data = file->openAsData();
-    if (!data) {
-        mContext->getDiagnostics()->error(DiagMessage(file->getSource()) << "failed to open file");
-        return false;
-    }
-
-    if (util::stringEndsWith(srcPath, ".flat")) {
-        outFileOp->xmlToFlatten = loadBinaryXmlSkipFileExport(file->getSource(),
-                                                              data->data(), data->size(),
-                                                              mContext->getDiagnostics());
-    } else {
-        outFileOp->xmlToFlatten = xml::inflate(data->data(), data->size(),
-                                               mContext->getDiagnostics(),
-                                               file->getSource());
-    }
-
-    if (!outFileOp->xmlToFlatten) {
-        return false;
-    }
-
-    // Copy the the file description header.
-    outFileOp->xmlToFlatten->file = fileDesc;
-
     XmlReferenceLinker xmlLinker;
-    if (!xmlLinker.consume(mContext, outFileOp->xmlToFlatten.get())) {
+    if (!xmlLinker.consume(mContext, doc)) {
         return false;
     }
 
-    if (mOptions.updateProguardSpec && !proguard::collectProguardRules(
-            outFileOp->xmlToFlatten->file.source, outFileOp->xmlToFlatten.get(), mKeepSet)) {
+    if (mOptions.updateProguardSpec && !proguard::collectProguardRules(src, doc, mKeepSet)) {
         return false;
     }
 
+    if (mOptions.noXmlNamespaces) {
+        XmlNamespaceRemover namespaceRemover;
+        if (!namespaceRemover.consume(mContext, doc)) {
+            return false;
+        }
+    }
+
     if (!mOptions.noAutoVersion) {
         if (mOptions.noVersionVectors) {
             // Skip this if it is a vector or animated-vector.
-            xml::Element* el = xml::findRootElement(outFileOp->xmlToFlatten.get());
+            xml::Element* el = xml::findRootElement(doc);
             if (el && el->namespaceUri.empty()) {
                 if (el->name == "vector" || el->name == "animated-vector") {
                     // We are NOT going to version this file.
-                    outFileOp->skipVersion = true;
+                    fileOp->skipVersion = true;
                     return true;
                 }
             }
         }
 
+        const ConfigDescription& config = fileOp->config;
+
         // Find the first SDK level used that is higher than this defined config and
         // not superseded by a lower or equal SDK level resource.
         const int minSdkVersion = mContext->getMinSdkVersion();
         for (int sdkLevel : xmlLinker.getSdkLevels()) {
-            if (sdkLevel > minSdkVersion
-                    && sdkLevel > outFileOp->xmlToFlatten->file.config.sdkVersion) {
-                if (!shouldGenerateVersionedResource(entry, outFileOp->xmlToFlatten->file.config,
-                                                     sdkLevel)) {
+            if (sdkLevel > minSdkVersion && sdkLevel > config.sdkVersion) {
+                if (!shouldGenerateVersionedResource(fileOp->entry, config, sdkLevel)) {
                     // If we shouldn't generate a versioned resource, stop checking.
                     break;
                 }
 
-                ResourceFile versionedFileDesc = outFileOp->xmlToFlatten->file;
+                ResourceFile versionedFileDesc = doc->file;
                 versionedFileDesc.config.sdkVersion = (uint16_t) sdkLevel;
 
+                FileOperation newFileOp;
+                newFileOp.xmlToFlatten = util::make_unique<xml::XmlResource>(
+                        versionedFileDesc, doc->root->clone());
+                newFileOp.config = versionedFileDesc.config;
+                newFileOp.entry = fileOp->entry;
+                newFileOp.dstPath = ResourceUtils::buildResourceFileName(
+                        versionedFileDesc, mContext->getNameMangler());
+
                 if (mContext->verbose()) {
                     mContext->getDiagnostics()->note(DiagMessage(versionedFileDesc.source)
                                                      << "auto-versioning resource from config '"
-                                                     << outFileOp->xmlToFlatten->file.config
+                                                     << config
                                                      << "' -> '"
                                                      << versionedFileDesc.config << "'");
                 }
 
-                std::string genPath = ResourceUtils::buildResourceFileName(
-                        versionedFileDesc, mContext->getNameMangler());
-
                 bool added = table->addFileReferenceAllowMangled(versionedFileDesc.name,
                                                                  versionedFileDesc.config,
                                                                  versionedFileDesc.source,
-                                                                 genPath,
-                                                                 file,
+                                                                 newFileOp.dstPath,
+                                                                 nullptr,
                                                                  mContext->getDiagnostics());
                 if (!added) {
                     return false;
                 }
+
+                outFileOpQueue->push(std::move(newFileOp));
                 break;
             }
         }
@@ -449,12 +407,11 @@
         for (auto& type : pkg->types) {
             // Sort by config and name, so that we get better locality in the zip file.
             configSortedFiles.clear();
-            for (auto& entry : type->entries) {
-                // Iterate via indices because auto generated values can be inserted ahead of
-                // the value being processed.
-                for (size_t i = 0; i < entry->values.size(); i++) {
-                    ResourceConfigValue* configValue = entry->values[i].get();
+            std::queue<FileOperation> fileOperations;
 
+            // Populate the queue with all files in the ResourceTable.
+            for (auto& entry : type->entries) {
+                for (auto& configValue : entry->values) {
                     FileReference* fileRef = valueCast<FileReference>(configValue->value.get());
                     if (!fileRef) {
                         continue;
@@ -468,35 +425,67 @@
                     }
 
                     FileOperation fileOp;
+                    fileOp.entry = entry.get();
                     fileOp.dstPath = *fileRef->path;
+                    fileOp.config = configValue->config;
 
                     const StringPiece srcPath = file->getSource().path;
                     if (type->type != ResourceType::kRaw &&
                             (util::stringEndsWith(srcPath, ".xml.flat") ||
                             util::stringEndsWith(srcPath, ".xml"))) {
-                        ResourceFile fileDesc;
-                        fileDesc.config = configValue->config;
-                        fileDesc.name = ResourceName(pkg->name, type->type, entry->name);
-                        fileDesc.source = fileRef->getSource();
-                        if (!linkAndVersionXmlFile(entry.get(), fileDesc, file, table, &fileOp)) {
-                            error = true;
-                            continue;
+                        std::unique_ptr<io::IData> data = file->openAsData();
+                        if (!data) {
+                            mContext->getDiagnostics()->error(DiagMessage(file->getSource())
+                                                              << "failed to open file");
+                            return false;
                         }
 
+                        fileOp.xmlToFlatten = xml::inflate(data->data(), data->size(),
+                                                           mContext->getDiagnostics(),
+                                                           file->getSource());
+
+                        if (!fileOp.xmlToFlatten) {
+                            return false;
+                        }
+
+                        fileOp.xmlToFlatten->file.config = configValue->config;
+                        fileOp.xmlToFlatten->file.source = fileRef->getSource();
+                        fileOp.xmlToFlatten->file.name =
+                                ResourceName(pkg->name, type->type, entry->name);
+
+                        // Enqueue the XML files to be processed.
+                        fileOperations.push(std::move(fileOp));
                     } else {
                         fileOp.fileToCopy = file;
-                    }
 
-                    // NOTE(adamlesinski): Explicitly construct a StringPiece16 here, or else
-                    // we end up copying the string in the std::make_pair() method, then creating
-                    // a StringPiece16 from the copy, which would cause us to end up referencing
-                    // garbage in the map.
-                    const StringPiece entryName(entry->name);
-                    configSortedFiles[std::make_pair(configValue->config, entryName)] =
-                                      std::move(fileOp);
+                        // NOTE(adamlesinski): Explicitly construct a StringPiece here, or else
+                        // we end up copying the string in the std::make_pair() method, then
+                        // creating a StringPiece from the copy, which would cause us to end up
+                        // referencing garbage in the map.
+                        const StringPiece entryName(entry->name);
+                        configSortedFiles[std::make_pair(configValue->config, entryName)] =
+                                std::move(fileOp);
+                    }
                 }
             }
 
+            // Now process the XML queue
+            for (; !fileOperations.empty(); fileOperations.pop()) {
+                FileOperation& fileOp = fileOperations.front();
+
+                if (!linkAndVersionXmlFile(table, &fileOp, &fileOperations)) {
+                    error = true;
+                    continue;
+                }
+
+                // NOTE(adamlesinski): Explicitly construct a StringPiece here, or else
+                // we end up copying the string in the std::make_pair() method, then creating
+                // a StringPiece from the copy, which would cause us to end up referencing
+                // garbage in the map.
+                const StringPiece entryName(fileOp.entry->name);
+                configSortedFiles[std::make_pair(fileOp.config, entryName)] = std::move(fileOp);
+            }
+
             if (error) {
                 return false;
             }
@@ -509,10 +498,8 @@
                 if (fileOp.xmlToFlatten) {
                     Maybe<size_t> maxSdkLevel;
                     if (!mOptions.noAutoVersion && !fileOp.skipVersion) {
-                        maxSdkLevel =
-                                std::max<size_t>(
-                                        std::max<size_t>(config.sdkVersion, 1u),
-                                        mContext->getMinSdkVersion());
+                        maxSdkLevel = std::max<size_t>(std::max<size_t>(config.sdkVersion, 1u),
+                                                       mContext->getMinSdkVersion());
                     }
 
                     bool result = flattenXml(fileOp.xmlToFlatten.get(), fileOp.dstPath, maxSdkLevel,
@@ -857,13 +844,13 @@
             return false;
         }
 
-        std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table);
-
-        // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
-        // interface.
+        // Make sure CopyingOutputStreamAdaptor is deleted before we call writer->finishEntry().
         {
-            google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+            // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+            // interface.
+            CopyingOutputStreamAdaptor adaptor(writer);
 
+            std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table);
             if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed to write");
                 return false;
@@ -1100,7 +1087,9 @@
 
     bool mergeCompiledFile(io::IFile* file, ResourceFile* fileDesc, bool override) {
         if (mContext->verbose()) {
-            mContext->getDiagnostics()->note(DiagMessage() << "merging compiled file "
+            mContext->getDiagnostics()->note(DiagMessage()
+                                             << "merging '" << fileDesc->name
+                                             << "' from compiled file "
                                              << file->getSource());
         }
 
@@ -1221,12 +1210,40 @@
                 return false;
             }
 
-            std::unique_ptr<ResourceFile> resourceFile = loadFileExportHeader(
-                    src, data->data(), data->size(), mContext->getDiagnostics());
-            if (resourceFile) {
-                return mergeCompiledFile(file, resourceFile.get(), override);
+            CompiledFileInputStream inputStream(data->data(), data->size());
+            uint32_t numFiles = 0;
+            if (!inputStream.ReadLittleEndian32(&numFiles)) {
+                mContext->getDiagnostics()->error(DiagMessage(src) << "failed read num files");
+                return false;
             }
-            return false;
+
+            for (uint32_t i = 0; i < numFiles; i++) {
+                pb::CompiledFile compiledFile;
+                if (!inputStream.ReadCompiledFile(&compiledFile)) {
+                    mContext->getDiagnostics()->error(DiagMessage(src)
+                                                      << "failed to read compiled file header");
+                    return false;
+                }
+
+                uint64_t offset, len;
+                if (!inputStream.ReadDataMetaData(&offset, &len)) {
+                    mContext->getDiagnostics()->error(DiagMessage(src)
+                                                      << "failed to read data meta data");
+                    return false;
+                }
+
+                std::unique_ptr<ResourceFile> resourceFile = deserializeCompiledFileFromPb(
+                        compiledFile, file->getSource(), mContext->getDiagnostics());
+                if (!resourceFile) {
+                    return false;
+                }
+
+                if (!mergeCompiledFile(file->createFileSegment(offset, len), resourceFile.get(),
+                                       override)) {
+                    return false;
+                }
+            }
+            return true;
         }
 
         // Ignore non .flat files. This could be classes.dex or something else that happens
@@ -1296,6 +1313,7 @@
         fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
         fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
         fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors;
+        fileFlattenerOptions.noXmlNamespaces = mOptions.noXmlNamespaces;
         fileFlattenerOptions.updateProguardSpec =
                 static_cast<bool>(mOptions.generateProguardRulesPath);
 
@@ -1488,6 +1506,14 @@
             }
         }
 
+        if (!mOptions.noResourceDeduping) {
+            ResourceDeduper deduper;
+            if (!deduper.consume(mContext, &mFinalTable)) {
+                mContext->getDiagnostics()->error(DiagMessage() << "failed deduping resources");
+                return 1;
+            }
+        }
+
         proguard::KeepSet proguardKeepSet;
         proguard::KeepSet proguardMainDexKeepSet;
 
@@ -1594,6 +1620,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;
             }
@@ -1718,6 +1752,9 @@
                             "Disables automatic versioning of vector drawables. Use this only\n"
                             "when building with vector drawable support library",
                             &options.noVersionVectors)
+            .optionalSwitch("--no-resource-deduping", "Disables automatic deduping of resources with\n"
+                            "identical values across compatible configurations.",
+                            &options.noResourceDeduping)
             .optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
                             &legacyXFlag)
             .optionalSwitch("-z", "Require localization of strings marked 'suggested'",
@@ -1732,6 +1769,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..ce455da 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -60,6 +60,14 @@
 };
 
 /**
+ * Removes duplicated key-value entries from dominated resources.
+ */
+class ResourceDeduper : public IResourceTableConsumer {
+public:
+    bool consume(IAaptContext* context, ResourceTable* table) override;
+};
+
+/**
  * If any attribute resource values are defined as public, this consumer will move all private
  * attribute resource values to a private ^private-attr type, avoiding backwards compatibility
  * issues with new apps running on old platforms.
@@ -86,6 +94,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/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index e7edcc5..45f5acd 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -194,7 +194,10 @@
     manifestAction["uses-configuration"];
     manifestAction["uses-feature"];
     manifestAction["supports-screens"];
+
     manifestAction["compatible-screens"];
+    manifestAction["compatible-screens"]["screen"];
+
     manifestAction["supports-gl-texture"];
 
     // Application actions.
diff --git a/tools/aapt2/link/ResourceDeduper.cpp b/tools/aapt2/link/ResourceDeduper.cpp
new file mode 100644
index 0000000..0276261
--- /dev/null
+++ b/tools/aapt2/link/ResourceDeduper.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "DominatorTree.h"
+#include "ResourceTable.h"
+#include "link/Linkers.h"
+
+#include <algorithm>
+
+namespace aapt {
+
+namespace {
+
+/**
+ * Remove duplicated key-value entries from dominated resources.
+ *
+ * Based on the dominator tree, we can remove a value of an entry if:
+ *
+ * 1. The configuration for the entry's value is dominated by a configuration
+ *    with an equivalent entry value.
+ * 2. All compatible configurations for the entry (those not in conflict and
+ *    unrelated by domination with the configuration for the entry's value) have
+ *    an equivalent entry value.
+ */
+class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor {
+public:
+    using Node = DominatorTree::Node;
+
+    explicit DominatedKeyValueRemover(IAaptContext* context, ResourceEntry* entry) :
+            mContext(context), mEntry(entry) {
+    }
+
+    void visitConfig(Node* node) {
+        Node* parent = node->parent();
+        if (!parent) {
+            return;
+        }
+        ResourceConfigValue* nodeValue = node->value();
+        ResourceConfigValue* parentValue = parent->value();
+        if (!nodeValue || !parentValue) {
+            return;
+        }
+        if (!nodeValue->value->equals(parentValue->value.get())) {
+            return;
+        }
+
+        // Compare compatible configs for this entry and ensure the values are
+        // equivalent.
+        const ConfigDescription& nodeConfiguration = nodeValue->config;
+        for (const auto& sibling : mEntry->values) {
+            if (!sibling->value) {
+                // Sibling was already removed.
+                continue;
+            }
+            if (nodeConfiguration.isCompatibleWith(sibling->config)
+                    && !nodeValue->value->equals(sibling->value.get())) {
+                // The configurations are compatible, but the value is
+                // different, so we can't remove this value.
+                return;
+            }
+        }
+        if (mContext->verbose()) {
+            mContext->getDiagnostics()->note(
+                    DiagMessage(nodeValue->value->getSource())
+                            << "removing dominated duplicate resource with name \""
+                            << mEntry->name << "\"");
+        }
+        nodeValue->value = {};
+    }
+
+private:
+    IAaptContext* mContext;
+    ResourceEntry* mEntry;
+};
+
+static void dedupeEntry(IAaptContext* context, ResourceEntry* entry) {
+    DominatorTree tree(entry->values);
+    DominatedKeyValueRemover remover(context, entry);
+    tree.accept(&remover);
+
+    // Erase the values that were removed.
+    entry->values.erase(std::remove_if(entry->values.begin(), entry->values.end(),
+            [](const std::unique_ptr<ResourceConfigValue>& val) -> bool {
+        return val == nullptr || val->value == nullptr;
+    }), entry->values.end());
+}
+
+} // namespace
+
+bool ResourceDeduper::consume(IAaptContext* context, ResourceTable* table) {
+    for (auto& package : table->packages) {
+        for (auto& type : package->types) {
+            for (auto& entry : type->entries) {
+                dedupeEntry(context, entry.get());
+            }
+        }
+    }
+    return true;
+}
+
+} // aapt
diff --git a/tools/aapt2/link/ResourceDeduper_test.cpp b/tools/aapt2/link/ResourceDeduper_test.cpp
new file mode 100644
index 0000000..47071a51
--- /dev/null
+++ b/tools/aapt2/link/ResourceDeduper_test.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 "test/Test.h"
+
+namespace aapt {
+
+TEST(ResourceDeduperTest, SameValuesAreDeduped) {
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    const ConfigDescription defaultConfig = {};
+    const ConfigDescription enConfig = test::parseConfigOrDie("en");
+    const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+    // Chosen because this configuration is compatible with en.
+    const ConfigDescription landConfig = test::parseConfigOrDie("land");
+
+    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+            .addString("android:string/dedupe", ResourceId{}, defaultConfig, "dedupe")
+            .addString("android:string/dedupe", ResourceId{}, enConfig, "dedupe")
+            .addString("android:string/dedupe", ResourceId{}, landConfig, "dedupe")
+            .addString("android:string/dedupe2", ResourceId{}, defaultConfig, "dedupe")
+            .addString("android:string/dedupe2", ResourceId{}, enConfig, "dedupe")
+            .addString("android:string/dedupe2", ResourceId{}, enV21Config, "keep")
+            .addString("android:string/dedupe2", ResourceId{}, landConfig, "dedupe")
+            .build();
+
+    ASSERT_TRUE(ResourceDeduper().consume(context.get(), table.get()));
+    EXPECT_EQ(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/dedupe", enConfig));
+    EXPECT_EQ(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/dedupe", landConfig));
+    EXPECT_EQ(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/dedupe2", enConfig));
+    EXPECT_NE(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/dedupe2", enV21Config));
+}
+
+TEST(ResourceDeduperTest, DifferentValuesAreKept) {
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    const ConfigDescription defaultConfig = {};
+    const ConfigDescription enConfig = test::parseConfigOrDie("en");
+    const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+    // Chosen because this configuration is compatible with en.
+    const ConfigDescription landConfig = test::parseConfigOrDie("land");
+
+    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+            .addString("android:string/keep", ResourceId{}, defaultConfig, "keep")
+            .addString("android:string/keep", ResourceId{}, enConfig, "keep")
+            .addString("android:string/keep", ResourceId{}, enV21Config, "keep2")
+            .addString("android:string/keep", ResourceId{}, landConfig, "keep2")
+            .build();
+
+    ASSERT_TRUE(ResourceDeduper().consume(context.get(), table.get()));
+    EXPECT_NE(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/keep", enConfig));
+    EXPECT_NE(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/keep", enV21Config));
+    EXPECT_NE(
+            nullptr,
+            test::getValueForConfig<String>(table.get(), "android:string/keep", landConfig));
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 379c991..eea4306 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -55,12 +55,17 @@
     bool error = false;
     for (auto& package : table->packages) {
         // Warn of packages with an unrelated ID.
-        if (package->id && package->id.value() != 0x0 && package->id.value() != desiredPackageId) {
+        const Maybe<ResourceId>& id = package->id;
+        if (id && id.value() != 0x0 && id.value() != desiredPackageId) {
             mContext->getDiagnostics()->warn(DiagMessage(src)
                                              << "ignoring package " << package->name);
             continue;
         }
 
+        // Only merge an empty package or the package we're building.
+        // Other packages may exist, which likely contain attribute definitions.
+        // This is because at compile time it is unknown if the attributes are simply
+        // uses of the attribute or definitions.
         if (package->name.empty() || mContext->getCompilationPackage() == package->name) {
             FileMergeCallback callback;
             if (collection) {
@@ -85,8 +90,8 @@
             // mangled, then looked up at resolution time.
             // Also, when linking, we convert references with no package name to use
             // the compilation package name.
-            error |= !doMerge(src, table, package.get(),
-                              false /* mangle */, overlay, allowNew, callback);
+            error |= !doMerge(src, table, package.get(), false /* mangle */, overlay, allowNew,
+                              callback);
         }
     }
     return !error;
@@ -129,6 +134,106 @@
     return !error;
 }
 
+static bool mergeType(IAaptContext* context, const Source& src, ResourceTableType* dstType,
+                      ResourceTableType* srcType) {
+    if (dstType->symbolStatus.state < srcType->symbolStatus.state) {
+        // The incoming type's visibility is stronger, so we should override
+        // the visibility.
+        if (srcType->symbolStatus.state == SymbolState::kPublic) {
+            // Only copy the ID if the source is public, or else the ID is meaningless.
+            dstType->id = srcType->id;
+        }
+        dstType->symbolStatus = std::move(srcType->symbolStatus);
+    } else if (dstType->symbolStatus.state == SymbolState::kPublic
+            && srcType->symbolStatus.state == SymbolState::kPublic
+            && dstType->id && srcType->id
+            && dstType->id.value() != srcType->id.value()) {
+        // Both types are public and have different IDs.
+        context->getDiagnostics()->error(DiagMessage(src)
+                                         << "cannot merge type '" << srcType->type
+                                         << "': conflicting public IDs");
+        return false;
+    }
+    return true;
+}
+
+static bool mergeEntry(IAaptContext* context, const Source& src, ResourceEntry* dstEntry,
+                       ResourceEntry* srcEntry) {
+    if (dstEntry->symbolStatus.state < srcEntry->symbolStatus.state) {
+        // The incoming type's visibility is stronger, so we should override
+        // the visibility.
+        if (srcEntry->symbolStatus.state == SymbolState::kPublic) {
+            // Only copy the ID if the source is public, or else the ID is meaningless.
+            dstEntry->id = srcEntry->id;
+        }
+        dstEntry->symbolStatus = std::move(srcEntry->symbolStatus);
+    } else if (srcEntry->symbolStatus.state == SymbolState::kPublic
+            && dstEntry->symbolStatus.state == SymbolState::kPublic
+            && dstEntry->id && srcEntry->id
+            && dstEntry->id.value() != srcEntry->id.value()) {
+        // Both entries are public and have different IDs.
+        context->getDiagnostics()->error(DiagMessage(src)
+                                         << "cannot merge entry '" << srcEntry->name
+                                         << "': conflicting public IDs");
+        return false;
+    }
+    return true;
+}
+
+/**
+ * Modified CollisionResolver which will merge Styleables. Used with overlays.
+ *
+ * Styleables are not actual resources, but they are treated as such during the
+ * compilation phase. Styleables don't simply overlay each other, their definitions merge
+ * and accumulate. If both values are Styleables, we just merge them into the existing value.
+ */
+static ResourceTable::CollisionResult resolveMergeCollision(Value* existing, Value* incoming) {
+    if (Styleable* existingStyleable = valueCast<Styleable>(existing)) {
+        if (Styleable* incomingStyleable = valueCast<Styleable>(incoming)) {
+            // Styleables get merged.
+            existingStyleable->mergeWith(incomingStyleable);
+            return ResourceTable::CollisionResult::kKeepOriginal;
+        }
+    }
+    // Delegate to the default handler.
+    return ResourceTable::resolveValueCollision(existing, incoming);
+}
+
+static ResourceTable::CollisionResult mergeConfigValue(IAaptContext* context,
+                                                       const ResourceNameRef& resName,
+                                                       const bool overlay,
+                                                       ResourceConfigValue* dstConfigValue,
+                                                       ResourceConfigValue* srcConfigValue) {
+    using CollisionResult = ResourceTable::CollisionResult;
+
+    Value* dstValue = dstConfigValue->value.get();
+    Value* srcValue = srcConfigValue->value.get();
+
+    CollisionResult collisionResult;
+    if (overlay) {
+        collisionResult = resolveMergeCollision(dstValue, srcValue);
+    } else {
+        collisionResult = ResourceTable::resolveValueCollision(dstValue, srcValue);
+    }
+
+    if (collisionResult == CollisionResult::kConflict) {
+        if (overlay) {
+            return CollisionResult::kTakeNew;
+        }
+
+        // Error!
+        context->getDiagnostics()->error(DiagMessage(srcValue->getSource())
+                                         << "resource '" << resName
+                                         << "' has a conflicting value for "
+                                         << "configuration ("
+                                         << srcConfigValue->config << ")");
+        context->getDiagnostics()->note(DiagMessage(dstValue->getSource())
+                                        << "originally defined here");
+        return CollisionResult::kConflict;
+    }
+    return collisionResult;
+}
+
 bool TableMerger::doMerge(const Source& src,
                           ResourceTable* srcTable,
                           ResourceTablePackage* srcPackage,
@@ -140,115 +245,64 @@
 
     for (auto& srcType : srcPackage->types) {
         ResourceTableType* dstType = mMasterPackage->findOrCreateType(srcType->type);
-        if (srcType->symbolStatus.state == SymbolState::kPublic) {
-            if (dstType->symbolStatus.state == SymbolState::kPublic && dstType->id && srcType->id
-                    && dstType->id.value() != srcType->id.value()) {
-                // Both types are public and have different IDs.
-                mContext->getDiagnostics()->error(DiagMessage(src)
-                                                  << "can not merge type '"
-                                                  << srcType->type
-                                                  << "': conflicting public IDs");
-                error = true;
-                continue;
-            }
-
-            dstType->symbolStatus = std::move(srcType->symbolStatus);
-            dstType->id = srcType->id;
+        if (!mergeType(mContext, src, dstType, srcType.get())) {
+            error = true;
+            continue;
         }
 
         for (auto& srcEntry : srcType->entries) {
-            ResourceEntry* dstEntry;
+            std::string entryName = srcEntry->name;
             if (manglePackage) {
-                std::string mangledName = NameMangler::mangleEntry(srcPackage->name,
-                                                                   srcEntry->name);
-                if (allowNewResources) {
-                    dstEntry = dstType->findOrCreateEntry(mangledName);
-                } else {
-                    dstEntry = dstType->findEntry(mangledName);
-                }
-            } else {
-                if (allowNewResources) {
-                    dstEntry = dstType->findOrCreateEntry(srcEntry->name);
-                } else {
-                    dstEntry = dstType->findEntry(srcEntry->name);
-                }
+                entryName = NameMangler::mangleEntry(srcPackage->name, srcEntry->name);
             }
 
+            ResourceEntry* dstEntry;
+            if (allowNewResources) {
+                dstEntry = dstType->findOrCreateEntry(entryName);
+            } else {
+                dstEntry = dstType->findEntry(entryName);
+            }
+
+            const ResourceNameRef resName(srcPackage->name, srcType->type, srcEntry->name);
+
             if (!dstEntry) {
                 mContext->getDiagnostics()->error(DiagMessage(src)
-                                                  << "resource "
-                                                  << ResourceNameRef(srcPackage->name,
-                                                                     srcType->type,
-                                                                     srcEntry->name)
+                                                  << "resource " << resName
                                                   << " does not override an existing resource");
                 mContext->getDiagnostics()->note(DiagMessage(src)
                                                  << "define an <add-resource> tag or use "
-                                                    "--auto-add-overlay");
+                                                 << "--auto-add-overlay");
                 error = true;
                 continue;
             }
 
-            if (srcEntry->symbolStatus.state != SymbolState::kUndefined) {
-                if (srcEntry->symbolStatus.state == SymbolState::kPublic) {
-                    if (dstEntry->symbolStatus.state == SymbolState::kPublic &&
-                            dstEntry->id && srcEntry->id &&
-                            dstEntry->id.value() != srcEntry->id.value()) {
-                        // Both entries are public and have different IDs.
-                        mContext->getDiagnostics()->error(DiagMessage(src)
-                                                          << "can not merge entry '"
-                                                          << srcEntry->name
-                                                          << "': conflicting public IDs");
-                        error = true;
-                        continue;
-                    }
-
-                    if (srcEntry->id) {
-                        dstEntry->id = srcEntry->id;
-                    }
-                }
-
-                if (dstEntry->symbolStatus.state != SymbolState::kPublic &&
-                        dstEntry->symbolStatus.state != srcEntry->symbolStatus.state) {
-                    dstEntry->symbolStatus = std::move(srcEntry->symbolStatus);
-                }
+            if (!mergeEntry(mContext, src, dstEntry, srcEntry.get())) {
+                error = true;
+                continue;
             }
 
-            ResourceNameRef resName(mMasterPackage->name, dstType->type, dstEntry->name);
+            for (auto& srcConfigValue : srcEntry->values) {
+                using CollisionResult = ResourceTable::CollisionResult;
 
-            for (auto& srcValue : srcEntry->values) {
-                ResourceConfigValue* dstValue = dstEntry->findValue(srcValue->config,
-                                                                    srcValue->product);
-                if (dstValue) {
-                    const int collisionResult = ResourceTable::resolveValueCollision(
-                            dstValue->value.get(), srcValue->value.get());
-                    if (collisionResult == 0 && !overlay) {
-                        // Error!
-                        ResourceNameRef resourceName(srcPackage->name,
-                                                     srcType->type,
-                                                     srcEntry->name);
-
-                        mContext->getDiagnostics()->error(DiagMessage(srcValue->value->getSource())
-                                                          << "resource '" << resourceName
-                                                          << "' has a conflicting value for "
-                                                          << "configuration ("
-                                                          << srcValue->config << ")");
-                        mContext->getDiagnostics()->note(DiagMessage(dstValue->value->getSource())
-                                                         << "originally defined here");
+                ResourceConfigValue* dstConfigValue = dstEntry->findValue(srcConfigValue->config,
+                                                                          srcConfigValue->product);
+                if (dstConfigValue) {
+                    CollisionResult collisionResult = mergeConfigValue(
+                            mContext, resName, overlay, dstConfigValue, srcConfigValue.get());
+                    if (collisionResult == CollisionResult::kConflict) {
                         error = true;
                         continue;
-                    } else if (collisionResult < 0) {
-                        // Keep our existing value.
+                    } else if (collisionResult == CollisionResult::kKeepOriginal) {
                         continue;
                     }
-
+                } else {
+                    dstConfigValue = dstEntry->findOrCreateValue(srcConfigValue->config,
+                                                                 srcConfigValue->product);
                 }
 
-                if (!dstValue) {
-                    // Force create the entry if we didn't have it.
-                    dstValue = dstEntry->findOrCreateValue(srcValue->config, srcValue->product);
-                }
+                // Continue if we're taking the new resource.
 
-                if (FileReference* f = valueCast<FileReference>(srcValue->value.get())) {
+                if (FileReference* f = valueCast<FileReference>(srcConfigValue->value.get())) {
                     std::unique_ptr<FileReference> newFileRef;
                     if (manglePackage) {
                         newFileRef = cloneAndMangleFile(srcPackage->name, *f);
@@ -258,15 +312,15 @@
                     }
 
                     if (callback) {
-                        if (!callback(resName, srcValue->config, newFileRef.get(), f)) {
+                        if (!callback(resName, srcConfigValue->config, newFileRef.get(), f)) {
                             error = true;
                             continue;
                         }
                     }
-                    dstValue->value = std::move(newFileRef);
+                    dstConfigValue->value = std::move(newFileRef);
 
                 } else {
-                    dstValue->value = std::unique_ptr<Value>(srcValue->value->clone(
+                    dstConfigValue->value = std::unique_ptr<Value>(srcConfigValue->value->clone(
                             &mMasterTable->stringPool));
                 }
             }
@@ -277,7 +331,6 @@
 
 std::unique_ptr<FileReference> TableMerger::cloneAndMangleFile(const std::string& package,
                                                                const FileReference& fileRef) {
-
     StringPiece prefix, entry, suffix;
     if (util::extractResFilePathParts(*fileRef.path, &prefix, &entry, &suffix)) {
         std::string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index ff3e21f..fb1cb21 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -274,4 +274,43 @@
     ASSERT_FALSE(merger.mergeOverlay({}, tableB.get()));
 }
 
+TEST_F(TableMergerTest, OverlaidStyleablesShouldBeMerged) {
+    std::unique_ptr<ResourceTable> tableA = test::ResourceTableBuilder()
+            .setPackageId("com.app.a", 0x7f)
+            .addValue("com.app.a:styleable/Foo", test::StyleableBuilder()
+                    .addItem("com.app.a:attr/bar")
+                    .addItem("com.app.a:attr/foo", ResourceId(0x01010000))
+                    .build())
+            .build();
+
+    std::unique_ptr<ResourceTable> tableB = test::ResourceTableBuilder()
+            .setPackageId("com.app.a", 0x7f)
+            .addValue("com.app.a:styleable/Foo", test::StyleableBuilder()
+                    .addItem("com.app.a:attr/bat")
+                    .addItem("com.app.a:attr/foo")
+                    .build())
+            .build();
+
+    ResourceTable finalTable;
+    TableMergerOptions options;
+    options.autoAddOverlay = true;
+    TableMerger merger(mContext.get(), &finalTable, options);
+
+    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.mergeOverlay({}, tableB.get()));
+
+    Debug::printTable(&finalTable, {});
+
+    Styleable* styleable = test::getValue<Styleable>(&finalTable, "com.app.a:styleable/Foo");
+    ASSERT_NE(nullptr, styleable);
+
+    std::vector<Reference> expectedRefs = {
+            Reference(test::parseNameOrDie("com.app.a:attr/bar")),
+            Reference(test::parseNameOrDie("com.app.a:attr/bat")),
+            Reference(test::parseNameOrDie("com.app.a:attr/foo"), ResourceId(0x01010000)),
+    };
+
+    EXPECT_EQ(expectedRefs, styleable->entries);
+}
+
 } // namespace aapt
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/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 69b7d92..a7e752a 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -51,7 +51,7 @@
 };
 
 namespace xml {
-struct XmlResource;
+class XmlResource;
 }
 
 struct IXmlResourceConsumer {
diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/proto/ProtoSerialize.h
index 6e224ab..cc7c251 100644
--- a/tools/aapt2/proto/ProtoSerialize.h
+++ b/tools/aapt2/proto/ProtoSerialize.h
@@ -28,6 +28,40 @@
 
 namespace aapt {
 
+class CompiledFileOutputStream {
+public:
+    explicit CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out);
+
+    void WriteLittleEndian32(uint32_t value);
+    void WriteCompiledFile(const pb::CompiledFile* compiledFile);
+    void WriteData(const BigBuffer* buffer);
+    void WriteData(const void* data, size_t len);
+    bool HadError();
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(CompiledFileOutputStream);
+
+    void ensureAlignedWrite();
+
+    google::protobuf::io::CodedOutputStream mOut;
+};
+
+class CompiledFileInputStream {
+public:
+    explicit CompiledFileInputStream(const void* data, size_t size);
+
+    bool ReadLittleEndian32(uint32_t* outVal);
+    bool ReadCompiledFile(pb::CompiledFile* outVal);
+    bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen);
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
+
+    void ensureAlignedRead();
+
+    google::protobuf::io::CodedInputStream mIn;
+};
+
 std::unique_ptr<pb::ResourceTable> serializeTableToPb(ResourceTable* table);
 std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
                                                       const Source& source,
@@ -38,40 +72,6 @@
                                                             const Source& source,
                                                             IDiagnostics* diag);
 
-class CompiledFileOutputStream : public google::protobuf::io::CopyingOutputStream {
-public:
-    CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out,
-                             pb::CompiledFile* pbFile);
-    bool Write(const void* data, int size) override;
-    bool Finish();
-
-private:
-    bool ensureFileWritten();
-
-    google::protobuf::io::CodedOutputStream mOut;
-    pb::CompiledFile* mPbFile;
-
-    DISALLOW_COPY_AND_ASSIGN(CompiledFileOutputStream);
-};
-
-class CompiledFileInputStream {
-public:
-    CompiledFileInputStream(const void* data, size_t size);
-
-    const pb::CompiledFile* CompiledFile();
-
-    const void* data();
-    size_t size();
-
-private:
-    google::protobuf::io::CodedInputStream mIn;
-    std::unique_ptr<pb::CompiledFile> mPbFile;
-    const uint8_t* mData;
-    size_t mSize;
-
-    DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream);
-};
-
 } // namespace aapt
 
 #endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
index ca25c6a..595fa6f 100644
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -468,52 +468,4 @@
     return file;
 }
 
-CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
-        mIn(static_cast<const uint8_t*>(data), size), mPbFile(),
-        mData(static_cast<const uint8_t*>(data)), mSize(size) {
-}
-
-const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
-    if (!mPbFile) {
-        std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
-        uint64_t pbSize = 0u;
-        if (!mIn.ReadLittleEndian64(&pbSize)) {
-            return nullptr;
-        }
-        mIn.PushLimit(static_cast<int>(pbSize));
-        if (!pbFile->ParsePartialFromCodedStream(&mIn)) {
-            return nullptr;
-        }
-
-        const size_t padding = 4 - (pbSize & 0x03);
-        const size_t offset = sizeof(uint64_t) + pbSize + padding;
-        if (offset > mSize) {
-            return nullptr;
-        }
-
-        mData += offset;
-        mSize -= offset;
-        mPbFile = std::move(pbFile);
-    }
-    return mPbFile.get();
-}
-
-const void* CompiledFileInputStream::data() {
-    if (!mPbFile) {
-        if (!CompiledFile()) {
-            return nullptr;
-        }
-    }
-    return mData;
-}
-
-size_t CompiledFileInputStream::size() {
-    if (!mPbFile) {
-        if (!CompiledFile()) {
-            return 0;
-        }
-    }
-    return mSize;
-}
-
 } // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 425fca6..a5c2cbc 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -22,6 +22,10 @@
 #include "proto/ProtoSerialize.h"
 #include "util/BigBuffer.h"
 
+using google::protobuf::io::CodedOutputStream;
+using google::protobuf::io::CodedInputStream;
+using google::protobuf::io::ZeroCopyOutputStream;
+
 namespace aapt {
 
 namespace {
@@ -210,7 +214,7 @@
     });
     table->stringPool.prune();
 
-    std::unique_ptr<pb::ResourceTable> pbTable = util::make_unique<pb::ResourceTable>();
+    auto pbTable = util::make_unique<pb::ResourceTable>();
     serializeStringPoolToPb(table->stringPool, pbTable->mutable_string_pool());
 
     StringPool sourcePool, symbolPool;
@@ -274,7 +278,7 @@
 }
 
 std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file) {
-    std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
+    auto pbFile = util::make_unique<pb::CompiledFile>();
     pbFile->set_resource_name(file.name.toString());
     pbFile->set_source_path(file.source.path);
     serializeConfig(file.config, pbFile->mutable_config());
@@ -287,36 +291,112 @@
     return pbFile;
 }
 
-CompiledFileOutputStream::CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out,
-                                                   pb::CompiledFile* pbFile) :
-        mOut(out), mPbFile(pbFile) {
+CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : mOut(out) {
 }
 
-bool CompiledFileOutputStream::ensureFileWritten() {
-    if (mPbFile) {
-        const uint64_t pbSize = mPbFile->ByteSize();
-        mOut.WriteLittleEndian64(pbSize);
-        mPbFile->SerializeWithCachedSizes(&mOut);
-        const size_t padding = 4 - (pbSize & 0x03);
-        if (padding > 0) {
-            uint32_t zero = 0u;
-            mOut.WriteRaw(&zero, padding);
-        }
-        mPbFile = nullptr;
+void CompiledFileOutputStream::ensureAlignedWrite() {
+    const int padding = mOut.ByteCount() % 4;
+    if (padding > 0) {
+        uint32_t zero = 0u;
+        mOut.WriteRaw(&zero, padding);
     }
-    return !mOut.HadError();
 }
 
-bool CompiledFileOutputStream::Write(const void* data, int size) {
-    if (!ensureFileWritten()) {
+void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian32(val);
+}
+
+void CompiledFileOutputStream::WriteCompiledFile(const pb::CompiledFile* compiledFile) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(compiledFile->ByteSize()));
+    compiledFile->SerializeWithCachedSizes(&mOut);
+}
+
+void CompiledFileOutputStream::WriteData(const BigBuffer* buffer) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(buffer->size()));
+    for (const BigBuffer::Block& block : *buffer) {
+        mOut.WriteRaw(block.buffer.get(), block.size);
+    }
+}
+
+void CompiledFileOutputStream::WriteData(const void* data, size_t len) {
+    ensureAlignedWrite();
+    mOut.WriteLittleEndian64(static_cast<uint64_t>(len));
+    mOut.WriteRaw(data, len);
+}
+
+bool CompiledFileOutputStream::HadError() {
+    return mOut.HadError();
+}
+
+CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
+        mIn(static_cast<const uint8_t*>(data), size) {
+}
+
+void CompiledFileInputStream::ensureAlignedRead() {
+    const int padding = mIn.CurrentPosition() % 4;
+    if (padding > 0) {
+        // Reads are always 4 byte aligned.
+        mIn.Skip(padding);
+    }
+}
+
+bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* outVal) {
+    ensureAlignedRead();
+    return mIn.ReadLittleEndian32(outVal);
+}
+
+bool CompiledFileInputStream::ReadCompiledFile(pb::CompiledFile* outVal) {
+    ensureAlignedRead();
+
+    uint64_t pbSize = 0u;
+    if (!mIn.ReadLittleEndian64(&pbSize)) {
         return false;
     }
-    mOut.WriteRaw(data, size);
-    return !mOut.HadError();
+
+    CodedInputStream::Limit l = mIn.PushLimit(static_cast<int>(pbSize));
+
+    // Check that we haven't tried to read past the end.
+    if (static_cast<uint64_t>(mIn.BytesUntilLimit()) != pbSize) {
+        mIn.PopLimit(l);
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    if (!outVal->ParsePartialFromCodedStream(&mIn)) {
+        mIn.PopLimit(l);
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    mIn.PopLimit(l);
+    return true;
 }
 
-bool CompiledFileOutputStream::Finish() {
-    return ensureFileWritten();
+bool CompiledFileInputStream::ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen) {
+    ensureAlignedRead();
+
+    uint64_t pbSize = 0u;
+    if (!mIn.ReadLittleEndian64(&pbSize)) {
+        return false;
+    }
+
+    // Check that we aren't trying to read past the end.
+    if (pbSize > static_cast<uint64_t>(mIn.BytesUntilLimit())) {
+        mIn.PushLimit(0);
+        return false;
+    }
+
+    uint64_t offset = static_cast<uint64_t>(mIn.CurrentPosition());
+    if (!mIn.Skip(pbSize)) {
+        return false;
+    }
+
+    *outOffset = offset;
+    *outLen = pbSize;
+    return true;
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
index af1b011..2bd9767 100644
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp
@@ -18,6 +18,8 @@
 #include "proto/ProtoSerialize.h"
 #include "test/Test.h"
 
+using namespace google::protobuf::io;
+
 namespace aapt {
 
 TEST(TableProtoSerializer, SerializeSinglePackage) {
@@ -115,33 +117,66 @@
     f.source.path = "res/layout-hdpi-v9/main.xml";
     f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie("id/unchecked"), 23u });
 
-    const std::string expectedData = "1234";
-
-    std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
+    const std::string expectedData1 = "123";
+    const std::string expectedData2 = "1234";
 
     std::string outputStr;
     {
-        google::protobuf::io::StringOutputStream outStream(&outputStr);
-        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
+        std::unique_ptr<pb::CompiledFile> pbFile1 = serializeCompiledFileToPb(f);
 
-        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
-        ASSERT_TRUE(outFileStream.Finish());
+        f.name.entry = "__" + f.name.entry + "$0";
+        std::unique_ptr<pb::CompiledFile> pbFile2 = serializeCompiledFileToPb(f);
+
+        StringOutputStream outStream(&outputStr);
+        CompiledFileOutputStream outFileStream(&outStream);
+        outFileStream.WriteLittleEndian32(2);
+        outFileStream.WriteCompiledFile(pbFile1.get());
+        outFileStream.WriteData(expectedData1.data(), expectedData1.size());
+        outFileStream.WriteCompiledFile(pbFile2.get());
+        outFileStream.WriteData(expectedData2.data(), expectedData2.size());
+        ASSERT_FALSE(outFileStream.HadError());
     }
 
     CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
-    const pb::CompiledFile* newPbFile = inFileStream.CompiledFile();
-    ASSERT_NE(nullptr, newPbFile);
+    uint32_t numFiles = 0;
+    ASSERT_TRUE(inFileStream.ReadLittleEndian32(&numFiles));
+    ASSERT_EQ(2u, numFiles);
 
-    std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(*newPbFile, Source("test"),
+    // Read the first compiled file.
+
+    pb::CompiledFile newPbFile;
+    ASSERT_TRUE(inFileStream.ReadCompiledFile(&newPbFile));
+
+    std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(newPbFile, Source("test"),
                                                                        context->getDiagnostics());
     ASSERT_NE(nullptr, file);
 
-    std::string actualData((const char*)inFileStream.data(), inFileStream.size());
-    EXPECT_EQ(expectedData, actualData);
-    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(inFileStream.data()) & 0x03);
+    uint64_t offset, len;
+    ASSERT_TRUE(inFileStream.ReadDataMetaData(&offset, &len));
+
+    std::string actualData(outputStr.data() + offset, len);
+    EXPECT_EQ(expectedData1, actualData);
+
+    // Expect the data to be aligned.
+    EXPECT_EQ(0u, offset & 0x03);
 
     ASSERT_EQ(1u, file->exportedSymbols.size());
     EXPECT_EQ(test::parseNameOrDie("id/unchecked"), file->exportedSymbols[0].name);
+
+    // Read the second compiled file.
+
+    ASSERT_TRUE(inFileStream.ReadCompiledFile(&newPbFile));
+
+    file = deserializeCompiledFileFromPb(newPbFile, Source("test"), context->getDiagnostics());
+    ASSERT_NE(nullptr, file);
+
+    ASSERT_TRUE(inFileStream.ReadDataMetaData(&offset, &len));
+
+    actualData = std::string(outputStr.data() + offset, len);
+    EXPECT_EQ(expectedData2, actualData);
+
+    // Expect the data to be aligned.
+    EXPECT_EQ(0u, offset & 0x03);
 }
 
 TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
@@ -152,19 +187,27 @@
 
     std::string outputStr;
     {
-        google::protobuf::io::StringOutputStream outStream(&outputStr);
-        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
-
-        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
-        ASSERT_TRUE(outFileStream.Finish());
+        StringOutputStream outStream(&outputStr);
+        CompiledFileOutputStream outFileStream(&outStream);
+        outFileStream.WriteLittleEndian32(1);
+        outFileStream.WriteCompiledFile(pbFile.get());
+        outFileStream.WriteData(expectedData.data(), expectedData.size());
+        ASSERT_FALSE(outFileStream.HadError());
     }
 
-    outputStr[0] = 0xff;
+    outputStr[4] = 0xff;
 
     CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
-    EXPECT_EQ(nullptr, inFileStream.CompiledFile());
-    EXPECT_EQ(nullptr, inFileStream.data());
-    EXPECT_EQ(0u, inFileStream.size());
+
+    uint32_t numFiles = 0;
+    EXPECT_TRUE(inFileStream.ReadLittleEndian32(&numFiles));
+    EXPECT_EQ(1u, numFiles);
+
+    pb::CompiledFile newPbFile;
+    EXPECT_FALSE(inFileStream.ReadCompiledFile(&newPbFile));
+
+    uint64_t offset, len;
+    EXPECT_FALSE(inFileStream.ReadDataMetaData(&offset, &len));
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index a68d6f6..93c790d 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,14 @@
 # Android Asset Packaging Tool 2.0 (AAPT2) release notes
 
+## Version 2.2
+### `aapt2 compile ...`
+- Added support for inline complex XML resources. See
+  https://developer.android.com/guide/topics/resources/complex-xml-resources.html
+### `aapt link ...`
+- Duplicate resource filtering: removes duplicate resources in dominated configurations
+  that are always identical when selected at runtime. This can be disabled with
+  `--no-resource-deduping`.
+
 ## Version 2.1
 ### `aapt2 link ...`
 - Configuration Split APK support: supports splitting resources that match a set of
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..4f70b6c
--- /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 '{1}'".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/tools/aapt2/util/BigBuffer.cpp b/tools/aapt2/util/BigBuffer.cpp
index c88e3c1..de4ecd2 100644
--- a/tools/aapt2/util/BigBuffer.cpp
+++ b/tools/aapt2/util/BigBuffer.cpp
@@ -49,4 +49,29 @@
     return mBlocks.back().buffer.get();
 }
 
+void* BigBuffer::nextBlock(size_t* outSize) {
+    if (!mBlocks.empty()) {
+        Block& block = mBlocks.back();
+        if (block.size != block.mBlockSize) {
+            void* outBuffer = block.buffer.get() + block.size;
+            size_t size = block.mBlockSize - block.size;
+            block.size = block.mBlockSize;
+            mSize += size;
+            *outSize = size;
+            return outBuffer;
+        }
+    }
+
+    // Zero-allocate the block's buffer.
+    Block block = {};
+    block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[mBlockSize]());
+    assert(block.buffer);
+    block.size = mBlockSize;
+    block.mBlockSize = mBlockSize;
+    mBlocks.push_back(std::move(block));
+    mSize += mBlockSize;
+    *outSize = mBlockSize;
+    return mBlocks.back().buffer.get();
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h
index ba8532f..685614f 100644
--- a/tools/aapt2/util/BigBuffer.h
+++ b/tools/aapt2/util/BigBuffer.h
@@ -82,6 +82,20 @@
     T* nextBlock(size_t count = 1);
 
     /**
+     * Returns the next block available and puts the size in outCount.
+     * This is useful for grabbing blocks where the size doesn't matter.
+     * Use backUp() to give back any bytes that were not used.
+     */
+    void* nextBlock(size_t* outCount);
+
+    /**
+     * Backs up count bytes. This must only be called after nextBlock()
+     * and can not be larger than sizeof(T) * count of the last nextBlock()
+     * call.
+     */
+    void backUp(size_t count);
+
+    /**
      * Moves the specified BigBuffer into this one. When this method
      * returns, buffer is empty.
      */
@@ -97,6 +111,8 @@
      */
     void align4();
 
+    size_t getBlockSize() const;
+
     const_iterator begin() const;
     const_iterator end() const;
 
@@ -123,6 +139,10 @@
     return mSize;
 }
 
+inline size_t BigBuffer::getBlockSize() const {
+    return mBlockSize;
+}
+
 template <typename T>
 inline T* BigBuffer::nextBlock(size_t count) {
     static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
@@ -130,6 +150,12 @@
     return reinterpret_cast<T*>(nextBlockImpl(sizeof(T) * count));
 }
 
+inline void BigBuffer::backUp(size_t count) {
+    Block& block = mBlocks.back();
+    block.size -= count;
+    mSize -= count;
+}
+
 inline void BigBuffer::appendBuffer(BigBuffer&& buffer) {
     std::move(buffer.mBlocks.begin(), buffer.mBlocks.end(), std::back_inserter(mBlocks));
     mSize += buffer.mSize;
diff --git a/tools/aapt2/util/StringPiece.h b/tools/aapt2/util/StringPiece.h
index 4300a67..266c003 100644
--- a/tools/aapt2/util/StringPiece.h
+++ b/tools/aapt2/util/StringPiece.h
@@ -39,6 +39,9 @@
     using const_iterator = const TChar*;
     using difference_type = size_t;
 
+    // End of string marker.
+    constexpr static const size_t npos = static_cast<size_t>(-1);
+
     BasicStringPiece();
     BasicStringPiece(const BasicStringPiece<TChar>& str);
     BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(implicit)
@@ -48,7 +51,7 @@
     BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
     BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
 
-    BasicStringPiece<TChar> substr(size_t start, size_t len) const;
+    BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
     BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
                                    BasicStringPiece<TChar>::const_iterator end) const;
 
@@ -81,6 +84,9 @@
 //
 
 template <typename TChar>
+constexpr const size_t BasicStringPiece<TChar>::npos;
+
+template <typename TChar>
 inline BasicStringPiece<TChar>::BasicStringPiece() : mData(nullptr) , mLength(0) {
 }
 
@@ -127,7 +133,11 @@
 
 template <typename TChar>
 inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
-    if (start + len > mLength) {
+    if (len == npos) {
+        len = mLength - start;
+    }
+
+    if (start > mLength || start + len > mLength) {
         return BasicStringPiece<TChar>();
     }
     return BasicStringPiece<TChar>(mData + start, len);
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index e743247..b0bec62 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -314,6 +314,9 @@
         return *this;
     }
 
+    // Where the new data will be appended to.
+    size_t newDataIndex = mStr.size();
+
     const char* const end = str.end();
     const char* start = str.begin();
     const char* current = start;
@@ -422,6 +425,16 @@
         current++;
     }
     mStr.append(start, end - start);
+
+    // Accumulate the added string's UTF-16 length.
+    ssize_t len = utf8_to_utf16_length(
+            reinterpret_cast<const uint8_t*>(mStr.data()) + newDataIndex,
+            mStr.size() - newDataIndex);
+    if (len < 0) {
+        mError = "invalid unicode code point";
+        return *this;
+    }
+    mUtf16Len += len;
     return *this;
 }
 
@@ -434,11 +447,8 @@
 
     std::u16string utf16;
     utf16.resize(utf16Length);
-    utf8_to_utf16(
-            reinterpret_cast<const uint8_t*>(utf8.data()),
-            utf8.length(),
-            &*utf16.begin(),
-            (size_t) utf16Length + 1);
+    utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(),
+                  &*utf16.begin(), utf16Length + 1);
     return utf16;
 }
 
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 998ecf7..9c88354 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -163,10 +163,16 @@
     StringBuilder& append(const StringPiece& str);
     const std::string& str() const;
     const std::string& error() const;
+
+    // When building StyledStrings, we need UTF-16 indices into the string,
+    // which is what the Java layer expects when dealing with java String.charAt().
+    size_t utf16Len() const;
+
     operator bool() const;
 
 private:
     std::string mStr;
+    size_t mUtf16Len = 0;
     bool mQuote = false;
     bool mTrailingSpace = false;
     bool mLastCharWasEscape = false;
@@ -181,6 +187,10 @@
     return mError;
 }
 
+inline size_t StringBuilder::utf16Len() const {
+    return mUtf16Len;
+}
+
 inline StringBuilder::operator bool() const {
     return mError.empty();
 }
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 39bd5bf..28de78a 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -322,6 +322,21 @@
     return util::make_unique<XmlResource>(ResourceFile{}, std::move(root));
 }
 
+std::unique_ptr<Node> Namespace::clone() {
+    auto ns = util::make_unique<Namespace>();
+    ns->comment = comment;
+    ns->lineNumber = lineNumber;
+    ns->columnNumber = columnNumber;
+    ns->namespacePrefix = namespacePrefix;
+    ns->namespaceUri = namespaceUri;
+
+    ns->children.reserve(children.size());
+    for (const std::unique_ptr<xml::Node>& child : children) {
+        ns->addChild(child->clone());
+    }
+    return std::move(ns);
+}
+
 Element* findRootElement(XmlResource* doc) {
     return findRootElement(doc->root.get());
 }
@@ -406,6 +421,36 @@
     return elements;
 }
 
+std::unique_ptr<Node> Element::clone() {
+    auto el = util::make_unique<Element>();
+    el->comment = comment;
+    el->lineNumber = lineNumber;
+    el->columnNumber = columnNumber;
+    el->name = name;
+    el->namespaceUri = namespaceUri;
+
+    el->attributes.reserve(attributes.size());
+    for (xml::Attribute& attr : attributes) {
+        // Don't copy compiled values or attributes.
+        el->attributes.push_back(xml::Attribute{ attr.namespaceUri, attr.name, attr.value });
+    }
+
+    el->children.reserve(children.size());
+    for (const std::unique_ptr<xml::Node>& child : children) {
+        el->addChild(child->clone());
+    }
+    return std::move(el);
+}
+
+std::unique_ptr<Node> Text::clone() {
+    auto t = util::make_unique<Text>();
+    t->comment = comment;
+    t->lineNumber = lineNumber;
+    t->columnNumber = columnNumber;
+    t->text = text;
+    return std::move(t);
+}
+
 void PackageAwareVisitor::visit(Namespace* ns) {
    bool added = false;
    if (Maybe<ExtractedPackage> maybePackage = extractPackageFromNamespace(ns->namespaceUri)) {
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index d083d82..e4f41b0 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -32,12 +32,13 @@
 namespace aapt {
 namespace xml {
 
-struct RawVisitor;
+class RawVisitor;
 
 /**
  * Base class for all XML nodes.
  */
-struct Node {
+class Node {
+public:
     Node* parent = nullptr;
     size_t lineNumber = 0;
     size_t columnNumber = 0;
@@ -48,6 +49,7 @@
 
     void addChild(std::unique_ptr<Node> child);
     virtual void accept(RawVisitor* visitor) = 0;
+    virtual std::unique_ptr<Node> clone() = 0;
 };
 
 /**
@@ -55,16 +57,20 @@
  * subclass of Node.
  */
 template <typename Derived>
-struct BaseNode : public Node {
+class BaseNode : public Node {
+public:
     virtual void accept(RawVisitor* visitor) override;
 };
 
 /**
  * A Namespace XML node. Can only have one child.
  */
-struct Namespace : public BaseNode<Namespace> {
+class Namespace : public BaseNode<Namespace> {
+public:
     std::string namespacePrefix;
     std::string namespaceUri;
+
+    std::unique_ptr<Node> clone() override;
 };
 
 struct AaptAttribute {
@@ -87,7 +93,8 @@
 /**
  * An Element XML node.
  */
-struct Element : public BaseNode<Element> {
+class Element : public BaseNode<Element> {
+public:
     std::string namespaceUri;
     std::string name;
     std::vector<Attribute> attributes;
@@ -99,19 +106,24 @@
                                          const StringPiece& attrName,
                                          const StringPiece& attrValue);
     std::vector<xml::Element*> getChildElements();
+    std::unique_ptr<Node> clone() override;
 };
 
 /**
  * A Text (CDATA) XML node. Can not have any children.
  */
-struct Text : public BaseNode<Text> {
+class Text : public BaseNode<Text> {
+public:
     std::string text;
+
+    std::unique_ptr<Node> clone() override;
 };
 
 /**
  * An XML resource with a source, name, and XML tree.
  */
-struct XmlResource {
+class XmlResource {
+public:
     ResourceFile file;
     std::unique_ptr<xml::Node> root;
 };
@@ -136,7 +148,8 @@
  * A visitor interface for the different XML Node subtypes. This will not traverse into
  * children. Use Visitor for that.
  */
-struct RawVisitor {
+class RawVisitor {
+public:
     virtual ~RawVisitor() = default;
 
     virtual void visit(Namespace* node) {}
@@ -147,7 +160,8 @@
 /**
  * Visitor whose default implementation visits the children nodes of any node.
  */
-struct Visitor : public RawVisitor {
+class Visitor : public RawVisitor {
+public:
     using RawVisitor::visit;
 
     void visit(Namespace* node) override {
@@ -173,6 +187,13 @@
  * An XML DOM visitor that will record the package name for a namespace prefix.
  */
 class PackageAwareVisitor : public Visitor, public IPackageDeclStack {
+public:
+    using Visitor::visit;
+
+    void visit(Namespace* ns) override;
+    Maybe<ExtractedPackage> transformPackageAlias(
+            const StringPiece& alias, const StringPiece& localPackage) const override;
+
 private:
     struct PackageDecl {
         std::string prefix;
@@ -180,13 +201,6 @@
     };
 
     std::vector<PackageDecl> mPackageDecls;
-
-public:
-    using Visitor::visit;
-
-    void visit(Namespace* ns) override;
-    Maybe<ExtractedPackage> transformPackageAlias(
-            const StringPiece& alias, const StringPiece& localPackage) const override;
 };
 
 // Implementations
@@ -197,7 +211,8 @@
 }
 
 template <typename T>
-struct NodeCastImpl : public RawVisitor {
+class NodeCastImpl : public RawVisitor {
+public:
     using RawVisitor::visit;
 
     T* value = nullptr;
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index 0e9d005..b570fd7 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -23,8 +23,8 @@
 namespace aapt {
 namespace xml {
 
-std::string buildPackageNamespace(const StringPiece& package) {
-    std::string result = kSchemaPublicPrefix;
+std::string buildPackageNamespace(const StringPiece& package, bool privateReference) {
+    std::string result = privateReference ? kSchemaPrivatePrefix : kSchemaPublicPrefix;
     result.append(package.data(), package.size());
     return result;
 }
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index b75d8ac..a6ad79d 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -30,6 +30,7 @@
 constexpr const char* kSchemaPrivatePrefix = "http://schemas.android.com/apk/prv/res/";
 constexpr const char* kSchemaAndroid = "http://schemas.android.com/apk/res/android";
 constexpr const char* kSchemaTools = "http://schemas.android.com/tools";
+constexpr const char* kSchemaAapt = "http://schemas.android.com/aapt";
 
 /**
  * Result of extracting a package name from a namespace URI declaration.
@@ -62,8 +63,12 @@
  * Returns an XML Android namespace for the given package of the form:
  *
  * http://schemas.android.com/apk/res/<package>
+ *
+ * If privateReference == true, the package will be of the form:
+ *
+ * http://schemas.android.com/apk/prv/res/<package>
  */
-std::string buildPackageNamespace(const StringPiece& package);
+std::string buildPackageNamespace(const StringPiece& package, bool privateReference=false);
 
 /**
  * Interface representing a stack of XML namespace declarations. When looking up the package
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 372cb20..219fa2d 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -314,8 +314,11 @@
             continue
         # For later fonts, we only check them if they have a script
         # defined, since the defined script may get them to a higher
-        # score even if they appear after the emoji font.
-        if emoji_font_seen and not record.scripts:
+        # score even if they appear after the emoji font. However,
+        # we should skip checking the text symbols font, since
+        # symbol fonts should be able to override the emoji display
+        # style when 'Zsym' is explicitly specified by the user.
+        if emoji_font_seen and (not record.scripts or 'Zsym' in record.scripts):
             continue
 
         # Check default emoji-style characters
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index f1da3a2..bcfe3bf 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -627,7 +627,7 @@
         boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
 
         // and create/return a new Bitmap with it
-        return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable,
+        return new Bitmap(nativeInt, width, height, density, isMutable,
                           isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 94f3f54..85584d3 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -34,7 +34,7 @@
         Display display = wm.getDefaultDisplay();
         ViewRootImpl root = new ViewRootImpl(context, display);
         AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
-                display, root, new Handler(), null);
+                display, root, new Handler(), null, context);
         info.mHasWindowFocus = true;
         info.mWindowVisibility = View.VISIBLE;
         info.mInTouchMode = false; // this is so that we can display selections.
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 1cfb030..f4f92ec 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.view.AppTransitionAnimationSpec;
@@ -96,7 +97,7 @@
     }
 
     @Override
-    public void clearForcedDisplayDensity(int displayId) throws RemoteException {
+    public void clearForcedDisplayDensityForUser(int displayId, int userId) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -351,7 +352,8 @@
     }
 
     @Override
-    public void notifyAppResumed(IBinder token, boolean wasStopped) throws RemoteException {
+    public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface)
+            throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -396,7 +398,8 @@
     }
 
     @Override
-    public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId)
+            throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -458,6 +461,16 @@
     }
 
     @Override
+    public void setRecentsVisibility(boolean visible) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void setTvPipVisibility(boolean visible) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
     }
@@ -608,4 +621,12 @@
     public Bitmap screenshotWallpaper() throws RemoteException {
         return null;
     }
+
+    @Override
+    public void enableSurfaceTrace(ParcelFileDescriptor fd) throws RemoteException {
+    }
+
+    @Override
+    public void disableSurfaceTrace() throws RemoteException {
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 8d93b7f..a0b2977 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -76,6 +76,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -1180,7 +1181,7 @@
 
                 @Override
                 public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-                  String[] args, ResultReceiver resultReceiver) {
+                  String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver) {
                 }
             };
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index a39eb4d..769ee33 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -620,7 +620,8 @@
             int y = 0;
             int width;
             int height;
-            Rectangle clipBounds = originalGraphics.getClipBounds();
+            Rectangle clipBounds = originalGraphics.getClip() != null ? originalGraphics
+                    .getClipBounds() : null;
             if (clipBounds != null) {
                 if (clipBounds.width == 0 || clipBounds.height == 0) {
                     // Clip is 0 so no need to paint anything.
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index 863abae..199fafa 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -51,7 +51,7 @@
     liblog \
     libcutils \
     libexpat \
-    libziparchive-host \
+    libziparchive \
     libbase
 
 cFlags := -Wall -Werror
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index b62ffac..017525b 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -97,10 +97,6 @@
 
     String getCountryCode();
 
-    void setFrequencyBand(int band, boolean persist);
-
-    int getFrequencyBand();
-
     boolean isDualBandSupported();
 
     boolean saveConfiguration();
@@ -133,14 +129,8 @@
 
     void setWifiApConfiguration(in WifiConfiguration wifiConfig);
 
-    void addToBlacklist(String bssid);
-
-    void clearBlacklist();
-
     Messenger getWifiServiceMessenger();
 
-    String getConfigFile();
-
     void enableTdls(String remoteIPAddress, boolean enable);
 
     void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 67cf107..465addf 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -139,12 +139,6 @@
     public long seen;
 
     /**
-     * If the scan result is a valid autojoin candidate
-     * {@hide}
-     */
-    public int isAutoJoinCandidate;
-
-    /**
      * @hide
      * Update RSSI of the scan result
      * @param previousRssi
@@ -452,7 +446,6 @@
             numConnection = source.numConnection;
             numUsage = source.numUsage;
             numIpConfigFailures = source.numIpConfigFailures;
-            isAutoJoinCandidate = source.isAutoJoinCandidate;
             venueName = source.venueName;
             operatorFriendlyName = source.operatorFriendlyName;
             flags = source.flags;
@@ -530,7 +523,6 @@
         dest.writeInt(numConnection);
         dest.writeInt(numUsage);
         dest.writeInt(numIpConfigFailures);
-        dest.writeInt(isAutoJoinCandidate);
         dest.writeString((venueName != null) ? venueName.toString() : "");
         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
         dest.writeLong(this.flags);
@@ -600,7 +592,6 @@
                 sr.numConnection = in.readInt();
                 sr.numUsage = in.readInt();
                 sr.numIpConfigFailures = in.readInt();
-                sr.isAutoJoinCandidate = in.readInt();
                 sr.venueName = in.readString();
                 sr.operatorFriendlyName = in.readString();
                 sr.flags = in.readLong();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a64bfe5..24cd275 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -817,6 +817,7 @@
          */
         public static final int NETWORK_SELECTION_ENABLE = 0;
         /**
+         * @deprecated it is not used any more.
          * This network is disabled because higher layer (>2) network is bad
          */
         public static final int DISABLED_BAD_LINK = 1;
@@ -870,7 +871,7 @@
          */
         public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
                 "NETWORK_SELECTION_ENABLE",
-                "NETWORK_SELECTION_DISABLED_BAD_LINK",
+                "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
@@ -1265,6 +1266,9 @@
             }
             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+            setSeenInLastQualifiedNetworkSelection(source.getSeenInLastQualifiedNetworkSelection());
+            setCandidate(source.getCandidate());
+            setCandidateScore(source.getCandidateScore());
             setConnectChoice(source.getConnectChoice());
             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
             setHasEverConnected(source.getHasEverConnected());
@@ -1403,8 +1407,10 @@
      * @hide
      */
     public boolean isEnterprise() {
-        return allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
-            allowedKeyManagement.get(KeyMgmt.IEEE8021X);
+        return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+                || allowedKeyManagement.get(KeyMgmt.IEEE8021X))
+                && enterpriseConfig != null
+                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
     }
 
     @Override
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 08ad35e..c0e8bc2 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -33,7 +33,9 @@
 import java.security.cert.X509Certificate;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -116,7 +118,6 @@
     /** @hide */
     public static final String CA_CERT_ALIAS_DELIMITER = " ";
 
-
     // Fields to copy verbatim from wpa_supplicant.
     private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] {
             IDENTITY_KEY,
@@ -133,6 +134,11 @@
             CA_PATH_KEY
     };
 
+    /**
+     * Fields that have unquoted values in {@link #mFields}.
+     */
+    private static final List<String> UNQUOTED_KEYS = Arrays.asList(ENGINE_KEY, OPP_KEY_CACHING);
+
     private HashMap<String, String> mFields = new HashMap<String, String>();
     private X509Certificate[] mCaCerts;
     private PrivateKey mClientPrivateKey;
@@ -155,6 +161,9 @@
         for (String key : source.mFields.keySet()) {
             mFields.put(key, source.mFields.get(key));
         }
+        mCaCerts = source.mCaCerts;
+        mClientPrivateKey = source.mClientPrivateKey;
+        mClientCertificate = source.mClientCertificate;
         mEapMethod = source.mEapMethod;
         mPhase2Method = source.mPhase2Method;
     }
@@ -455,7 +464,7 @@
             case Eap.AKA:
             case Eap.AKA_PRIME:
                 mEapMethod = eapMethod;
-                mFields.put(OPP_KEY_CACHING, "1");
+                setFieldValue(OPP_KEY_CACHING, "1");
                 break;
             default:
                 throw new IllegalArgumentException("Unknown EAP method");
@@ -514,7 +523,7 @@
      * @return the identity
      */
     public String getIdentity() {
-        return getFieldValue(IDENTITY_KEY, "");
+        return getFieldValue(IDENTITY_KEY);
     }
 
     /**
@@ -523,7 +532,7 @@
      * @param anonymousIdentity the anonymous identity
      */
     public void setAnonymousIdentity(String anonymousIdentity) {
-        setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, "");
+        setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity);
     }
 
     /**
@@ -531,7 +540,7 @@
      * @return anonymous identity
      */
     public String getAnonymousIdentity() {
-        return getFieldValue(ANON_IDENTITY_KEY, "");
+        return getFieldValue(ANON_IDENTITY_KEY);
     }
 
     /**
@@ -539,7 +548,7 @@
      * @param password the password
      */
     public void setPassword(String password) {
-        setFieldValue(PASSWORD_KEY, password, "");
+        setFieldValue(PASSWORD_KEY, password);
     }
 
     /**
@@ -549,7 +558,7 @@
      * framework, returns "*".
      */
     public String getPassword() {
-        return getFieldValue(PASSWORD_KEY, "");
+        return getFieldValue(PASSWORD_KEY);
     }
 
     /**
@@ -639,7 +648,7 @@
      * @hide
      */
     @Nullable public String[] getCaCertificateAliases() {
-        String value = getFieldValue(CA_CERT_KEY, "");
+        String value = getFieldValue(CA_CERT_KEY);
         if (value.startsWith(CA_CERT_PREFIX)) {
             // Backwards compatibility: parse the original alias prefix.
             return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
@@ -766,7 +775,7 @@
      * @hide
      */
     public String getCaPath() {
-        return getFieldValue(CA_PATH_KEY, "");
+        return getFieldValue(CA_PATH_KEY);
     }
 
     /** Set Client certificate alias.
@@ -782,11 +791,11 @@
         setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
         // Also, set engine parameters
         if (TextUtils.isEmpty(alias)) {
-            mFields.put(ENGINE_KEY, ENGINE_DISABLE);
-            mFields.put(ENGINE_ID_KEY, EMPTY_VALUE);
+            setFieldValue(ENGINE_KEY, ENGINE_DISABLE);
+            setFieldValue(ENGINE_ID_KEY, "");
         } else {
-            mFields.put(ENGINE_KEY, ENGINE_ENABLE);
-            mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE));
+            setFieldValue(ENGINE_KEY, ENGINE_ENABLE);
+            setFieldValue(ENGINE_ID_KEY, ENGINE_ID_KEYSTORE);
         }
     }
 
@@ -859,7 +868,7 @@
      * @deprecated in favor of altSubjectMatch
      */
     public void setSubjectMatch(String subjectMatch) {
-        setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, "");
+        setFieldValue(SUBJECT_MATCH_KEY, subjectMatch);
     }
 
     /**
@@ -868,7 +877,7 @@
      * @deprecated in favor of altSubjectMatch
      */
     public String getSubjectMatch() {
-        return getFieldValue(SUBJECT_MATCH_KEY, "");
+        return getFieldValue(SUBJECT_MATCH_KEY);
     }
 
     /**
@@ -878,7 +887,7 @@
      *                     DNS:server.example.com;EMAIL:server@example.com
      */
     public void setAltSubjectMatch(String altSubjectMatch) {
-        setFieldValue(ALTSUBJECT_MATCH_KEY, altSubjectMatch, "");
+        setFieldValue(ALTSUBJECT_MATCH_KEY, altSubjectMatch);
     }
 
     /**
@@ -886,7 +895,7 @@
      * @return the alternate subject match string
      */
     public String getAltSubjectMatch() {
-        return getFieldValue(ALTSUBJECT_MATCH_KEY, "");
+        return getFieldValue(ALTSUBJECT_MATCH_KEY);
     }
 
     /**
@@ -916,7 +925,7 @@
      * @return The domain value.
      */
     public String getDomainSuffixMatch() {
-        return getFieldValue(DOM_SUFFIX_MATCH_KEY, "");
+        return getFieldValue(DOM_SUFFIX_MATCH_KEY);
     }
 
     /**
@@ -925,7 +934,7 @@
      * @param realm the realm
      */
     public void setRealm(String realm) {
-        setFieldValue(REALM_KEY, realm, "");
+        setFieldValue(REALM_KEY, realm);
     }
 
     /**
@@ -933,7 +942,7 @@
      * @return the realm
      */
     public String getRealm() {
-        return getFieldValue(REALM_KEY, "");
+        return getFieldValue(REALM_KEY);
     }
 
     /**
@@ -941,7 +950,7 @@
      * @param plmn the plmn value derived from mcc (mobile country code) & mnc (mobile network code)
      */
     public void setPlmn(String plmn) {
-        setFieldValue(PLMN_KEY, plmn, "");
+        setFieldValue(PLMN_KEY, plmn);
     }
 
     /**
@@ -950,7 +959,7 @@
      * @return the plmn
      */
     public String getPlmn() {
-        return getFieldValue(PLMN_KEY, "");
+        return getFieldValue(PLMN_KEY);
     }
 
     /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
@@ -995,13 +1004,13 @@
     }
 
     /**
-     * Returns the field value for the key.
+     * Returns the field value for the key with prefix removed.
      * @param key into the hash
      * @param prefix is the prefix that the value may have
      * @return value
      * @hide
      */
-    public String getFieldValue(String key, String prefix) {
+    private String getFieldValue(String key, String prefix) {
         // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
         // neither of these keys should be retrieved in this manner.
         String value = mFields.get(key);
@@ -1017,23 +1026,15 @@
     }
 
     /**
-     * Set a value with an optional prefix at key
+     * Returns the field value for the key.
      * @param key into the hash
-     * @param value to be set
-     * @param prefix an optional value to be prefixed to actual value
+     * @return value
      * @hide
      */
-    public void setFieldValue(String key, String value, String prefix) {
-        // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
-        // neither of these keys should be set in this manner.
-        if (TextUtils.isEmpty(value)) {
-            mFields.put(key, EMPTY_VALUE);
-        } else {
-            mFields.put(key, convertToQuotedString(prefix + value));
-        }
+    public String getFieldValue(String key) {
+        return getFieldValue(key, "");
     }
 
-
     /**
      * Set a value with an optional prefix at key
      * @param key into the hash
@@ -1041,16 +1042,32 @@
      * @param prefix an optional value to be prefixed to actual value
      * @hide
      */
-    public void setFieldValue(String key, String value) {
+    private void setFieldValue(String key, String value, String prefix) {
         // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
         // neither of these keys should be set in this manner.
         if (TextUtils.isEmpty(value)) {
-           mFields.put(key, EMPTY_VALUE);
+            mFields.put(key, EMPTY_VALUE);
         } else {
-            mFields.put(key, convertToQuotedString(value));
+            String valueToSet;
+            if (!UNQUOTED_KEYS.contains(key)) {
+                valueToSet = convertToQuotedString(prefix + value);
+            } else {
+                valueToSet = prefix + value;
+            }
+            mFields.put(key, valueToSet);
         }
     }
 
+    /**
+     * Set a value at key
+     * @param key into the hash
+     * @param value to be set
+     * @hide
+     */
+    public void setFieldValue(String key, String value) {
+        setFieldValue(key, value, "");
+    }
+
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b134cf7..8d819b9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -50,6 +50,8 @@
  * This class provides the primary API for managing all aspects of Wi-Fi
  * connectivity. Get an instance of this class by calling
  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
+ * On releases before NYC, it should only be obtained from an application context, and not from
+ * any other derived context to avoid memory leaks within the calling process.
 
  * It deals with several categories of items:
  * <ul>
@@ -1143,7 +1145,7 @@
 
     /**
      * @return true if this adapter supports Neighbour Awareness Network APIs
-     * @hide PROPOSED_NAN_API
+     * @hide
      */
     public boolean isNanSupported() {
         return isFeatureSupported(WIFI_FEATURE_NAN);
@@ -1399,40 +1401,6 @@
     }
 
     /**
-     * Set the operational frequency band.
-     * @param band  One of
-     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
-     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
-     *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
-     * @param persist {@code true} if this needs to be remembered
-     * @hide
-     */
-    public void setFrequencyBand(int band, boolean persist) {
-        try {
-            mService.setFrequencyBand(band, persist);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Get the operational frequency band.
-     * @return One of
-     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
-     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
-     *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
-     *     {@code -1} on failure.
-     * @hide
-     */
-    public int getFrequencyBand() {
-        try {
-            return mService.getFrequencyBand();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
      * @return {@code true} if supported, {@code false} otherwise.
      * @hide
@@ -1639,41 +1607,6 @@
     }
 
     /**
-     * Add a bssid to the supplicant blacklist
-     *
-     * This API is used by WifiWatchdogService
-     *
-     * @return {@code true} if the operation succeeds else {@code false}
-     * @hide
-     */
-    public boolean addToBlacklist(String bssid) {
-        try {
-            mService.addToBlacklist(bssid);
-            return true;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Clear the supplicant blacklist
-     *
-     * This API is used by WifiWatchdogService
-     *
-     * @return {@code true} if the operation succeeds else {@code false}
-     * @hide
-     */
-    public boolean clearBlacklist() {
-        try {
-            mService.clearBlacklist();
-            return true;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-
-    /**
      * Enable/Disable TDLS on a specific local route.
      *
      * <p>
@@ -2171,18 +2104,6 @@
 
 
     /**
-     * Returns the file in which IP and proxy configuration data is stored
-     * @hide
-     */
-    public String getConfigFile() {
-        try {
-            return mService.getConfigFile();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Allows an application to keep the Wi-Fi radio awake.
      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 716f1d3..5847f79 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -34,9 +34,10 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
-
 /**
  * This class provides a way to scan the Wifi universe around the device
  * Get an instance of this class by calling
@@ -167,18 +168,32 @@
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
      */
     public static class ScanSettings implements Parcelable {
+        /**
+         * Hidden network to be scanned for.
+         * {@hide}
+         */
+        public static class HiddenNetwork {
+            /** SSID of the network */
+            public String ssid;
+
+            /**
+             * Default constructor for HiddenNetwork.
+             */
+            public HiddenNetwork(String ssid) {
+                this.ssid = ssid;
+            }
+        }
 
         /** one of the WIFI_BAND values */
         public int band;
         /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
         public ChannelSpec[] channels;
         /**
-         * list of networkId's of hidden networks to scan for.
-         * These Id's should correspond to the wpa_supplicant's networkId's and will be used
-         * in connectivity scans using wpa_supplicant.
+         * list of hidden networks to scan for. Explicit probe requests are sent out for such
+         * networks during scan. Only valid for single scan requests.
          * {@hide}
          * */
-        public int[] hiddenNetworkIds;
+        public HiddenNetwork[] hiddenNetworks;
         /** period of background scan; in millisecond, 0 => single shot scan */
         public int periodInMs;
         /** must have a valid REPORT_EVENT value */
@@ -233,7 +248,14 @@
             } else {
                 dest.writeInt(0);
             }
-            dest.writeIntArray(hiddenNetworkIds);
+            if (hiddenNetworks != null) {
+                dest.writeInt(hiddenNetworks.length);
+                for (int i = 0; i < hiddenNetworks.length; i++) {
+                    dest.writeString(hiddenNetworks[i].ssid);
+                }
+            } else {
+                dest.writeInt(0);
+            }
         }
 
         /** Implement the Parcelable interface {@hide} */
@@ -258,7 +280,12 @@
                             spec.passive = in.readInt() == 1;
                             settings.channels[i] = spec;
                         }
-                        settings.hiddenNetworkIds = in.createIntArray();
+                        int numNetworks = in.readInt();
+                        settings.hiddenNetworks = new HiddenNetwork[numNetworks];
+                        for (int i = 0; i < numNetworks; i++) {
+                            String ssid = in.readString();
+                            settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
+                        }
                         return settings;
                     }
 
@@ -286,6 +313,12 @@
          * {@hide}
          */
         private int mBucketsScanned;
+        /**
+         * Indicates that the scan results received are as a result of a scan of all available
+         * channels. This should only be expected to function for single scans.
+         * {@hide}
+         */
+        private boolean mAllChannelsScanned;
         /** all scan results discovered in this scan, sorted by timestamp in ascending order */
         private ScanResult mResults[];
 
@@ -298,10 +331,12 @@
         }
 
         /** {@hide} */
-        public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) {
+        public ScanData(int id, int flags, int bucketsScanned, boolean allChannelsScanned,
+                ScanResult[] results) {
             mId = id;
             mFlags = flags;
             mBucketsScanned = bucketsScanned;
+            mAllChannelsScanned = allChannelsScanned;
             mResults = results;
         }
 
@@ -309,6 +344,7 @@
             mId = s.mId;
             mFlags = s.mFlags;
             mBucketsScanned = s.mBucketsScanned;
+            mAllChannelsScanned = s.mAllChannelsScanned;
             mResults = new ScanResult[s.mResults.length];
             for (int i = 0; i < s.mResults.length; i++) {
                 ScanResult result = s.mResults[i];
@@ -330,6 +366,11 @@
             return mBucketsScanned;
         }
 
+        /** {@hide} */
+        public boolean isAllChannelsScanned() {
+            return mAllChannelsScanned;
+        }
+
         public ScanResult[] getResults() {
             return mResults;
         }
@@ -345,6 +386,7 @@
                 dest.writeInt(mId);
                 dest.writeInt(mFlags);
                 dest.writeInt(mBucketsScanned);
+                dest.writeInt(mAllChannelsScanned ? 1 : 0);
                 dest.writeInt(mResults.length);
                 for (int i = 0; i < mResults.length; i++) {
                     ScanResult result = mResults[i];
@@ -362,12 +404,13 @@
                         int id = in.readInt();
                         int flags = in.readInt();
                         int bucketsScanned = in.readInt();
+                        boolean allChannelsScanned = in.readInt() != 0;
                         int n = in.readInt();
                         ScanResult results[] = new ScanResult[n];
                         for (int i = 0; i < n; i++) {
                             results[i] = ScanResult.CREATOR.createFromParcel(in);
                         }
-                        return new ScanData(id, flags, bucketsScanned, results);
+                        return new ScanData(id, flags, bucketsScanned, allChannelsScanned, results);
                     }
 
                     public ScanData[] newArray(int size) {
@@ -520,10 +563,6 @@
 
             /** SSID of the network */
             public String ssid;
-            /** Network ID in wpa_supplicant */
-            public int networkId;
-            /** Assigned priority for the network */
-            public int priority;
             /** Bitmask of the FLAG_XXX */
             public byte flags;
             /** Bitmask of the ATUH_XXX */
@@ -580,8 +619,6 @@
                 dest.writeInt(networkList.length);
                 for (int i = 0; i < networkList.length; i++) {
                     dest.writeString(networkList[i].ssid);
-                    dest.writeInt(networkList[i].networkId);
-                    dest.writeInt(networkList[i].priority);
                     dest.writeByte(networkList[i].flags);
                     dest.writeByte(networkList[i].authBitField);
                 }
@@ -608,8 +645,6 @@
                         for (int i = 0; i < numNetworks; i++) {
                             String ssid = in.readString();
                             PnoNetwork network = new PnoNetwork(ssid);
-                            network.networkId = in.readInt();
-                            network.priority = in.readInt();
                             network.flags = in.readByte();
                             network.authBitField = in.readByte();
                             settings.networkList[i] = network;
@@ -788,6 +823,22 @@
         mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
     }
 
+    /**
+     * Retrieve the most recent scan results from a single scan request.
+     * {@hide}
+     */
+    public List<ScanResult> getSingleScanResults() {
+        validateChannel();
+        Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0);
+        if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
+            return Arrays.asList(((ParcelableScanResults) reply.obj).getResults());
+        }
+        OperationResult result = (OperationResult) reply.obj;
+        Log.e(TAG, "Error retrieving SingleScan results reason: " + result.reason
+                + " description: " + result.description);
+        return new ArrayList<ScanResult>();
+    }
+
     private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
         // Bundle up both the settings and send it across.
         Bundle pnoParams = new Bundle();
@@ -1167,6 +1218,8 @@
     public static final int CMD_REGISTER_SCAN_LISTENER      = BASE + 27;
     /** @hide */
     public static final int CMD_DEREGISTER_SCAN_LISTENER    = BASE + 28;
+    /** @hide */
+    public static final int CMD_GET_SINGLE_SCAN_RESULTS     = BASE + 29;
 
     private Context mContext;
     private IWifiScanner mService;
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java
index cd47359..bcd7932 100644
--- a/wifi/java/android/net/wifi/nan/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java
@@ -16,87 +16,65 @@
 
 package android.net.wifi.nan;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
  * 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#attach(android.os.Handler, WifiNanAttachCallback)}.
+ * Note that the actual achieved configuration may be different from the
+ * requested configuration - since different applications may request different
  * configurations.
  *
- * @hide PROPOSED_NAN_API
+ * @hide
  */
-public class ConfigRequest implements Parcelable {
+public final class ConfigRequest implements Parcelable {
     /**
      * Lower range of possible cluster ID.
-     *
-     * @hide
      */
     public static final int CLUSTER_ID_MIN = 0;
 
     /**
      * Upper range of possible cluster ID.
-     *
-     * @hide
      */
     public static final int CLUSTER_ID_MAX = 0xFFFF;
 
     /**
      * Indicates whether 5G band support is requested.
-     *
-     * @hide
      */
     public final boolean mSupport5gBand;
 
     /**
      * Specifies the desired master preference.
-     *
-     * @hide
      */
     public final int mMasterPreference;
 
     /**
      * Specifies the desired lower range of the cluster ID. Must be lower then
      * {@link ConfigRequest#mClusterHigh}.
-     *
-     * @hide
      */
     public final int mClusterLow;
 
     /**
      * Specifies the desired higher range of the cluster ID. Must be higher then
      * {@link ConfigRequest#mClusterLow}.
-     *
-     * @hide
      */
     public final int mClusterHigh;
 
-    /**
-     * Indicates whether we want to get callbacks when our identity is changed.
-     *
-     * @hide
-     */
-    public final boolean mEnableIdentityChangeCallback;
-
     private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
-            int clusterHigh, boolean enableIdentityChangeCallback) {
+            int clusterHigh) {
         mSupport5gBand = support5gBand;
         mMasterPreference = masterPreference;
         mClusterLow = clusterLow;
         mClusterHigh = clusterHigh;
-        mEnableIdentityChangeCallback = enableIdentityChangeCallback;
     }
 
     @Override
     public String toString() {
         return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
                 + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
-                + mClusterHigh + ", mEnableIdentityChangeCallback=" + mEnableIdentityChangeCallback
-                + "]";
+                + mClusterHigh + "]";
     }
 
     @Override
@@ -110,7 +88,6 @@
         dest.writeInt(mMasterPreference);
         dest.writeInt(mClusterLow);
         dest.writeInt(mClusterHigh);
-        dest.writeInt(mEnableIdentityChangeCallback ? 1 : 0);
     }
 
     public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
@@ -125,9 +102,7 @@
             int masterPreference = in.readInt();
             int clusterLow = in.readInt();
             int clusterHigh = in.readInt();
-            boolean enableIdentityChangeCallback = in.readInt() != 0;
-            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
-                    enableIdentityChangeCallback);
+            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh);
         }
     };
 
@@ -144,32 +119,17 @@
         ConfigRequest lhs = (ConfigRequest) o;
 
         return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
-                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
-                && mEnableIdentityChangeCallback == lhs.mEnableIdentityChangeCallback;
+                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
     }
 
     /**
-     * Checks for equality of two configuration - but only considering their
-     * on-the-air NAN configuration impact.
+     * Checks whether the configuration's settings are non-default.
      *
-     * @param o Object to compare to.
-     * @return true if configuration objects have the same on-the-air
-     *         configuration, false otherwise.
-     * @hide
+     * @return true if any of the settings are non-default.
      */
-    public boolean equalsOnTheAir(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof ConfigRequest)) {
-            return false;
-        }
-
-        ConfigRequest lhs = (ConfigRequest) o;
-
-        return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
-                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
+    public boolean isNonDefault() {
+        return mSupport5gBand || mMasterPreference != 0 || mClusterLow != CLUSTER_ID_MIN
+                || mClusterHigh != CLUSTER_ID_MAX;
     }
 
     @Override
@@ -180,16 +140,13 @@
         result = 31 * result + mMasterPreference;
         result = 31 * result + mClusterLow;
         result = 31 * result + mClusterHigh;
-        result = 31 * result + (mEnableIdentityChangeCallback ? 1 : 0);
 
         return result;
     }
 
     /**
-     * Validates that the contents of the ConfigRequest are valid. Otherwise
+     * Verifies that the contents of the ConfigRequest are valid. Otherwise
      * throws an IllegalArgumentException.
-     *
-     * @hide
      */
     public void validate() throws IllegalArgumentException {
         if (mMasterPreference < 0) {
@@ -226,15 +183,14 @@
         private int mMasterPreference = 0;
         private int mClusterLow = CLUSTER_ID_MIN;
         private int mClusterHigh = CLUSTER_ID_MAX;
-        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) {
             mSupport5gBand = support5gBand;
@@ -242,13 +198,13 @@
         }
 
         /**
-         * 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) {
             if (masterPreference < 0) {
@@ -268,14 +224,14 @@
          * 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) {
             if (clusterLow < CLUSTER_ID_MIN) {
@@ -294,13 +250,13 @@
          * 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) {
             if (clusterHigh < CLUSTER_ID_MIN) {
@@ -315,25 +271,6 @@
         }
 
         /**
-         * 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.
-         *
-         * @param enableIdentityChangeCallback Enable the callback informing
-         *            listener when identity is changed.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setEnableIdentityChangeCallback(boolean enableIdentityChangeCallback) {
-            mEnableIdentityChangeCallback = enableIdentityChangeCallback;
-            return this;
-        }
-
-        /**
          * Build {@link ConfigRequest} given the current requests made on the
          * builder.
          */
@@ -343,8 +280,7 @@
                         "Invalid argument combination - must have Cluster Low <= Cluster High");
             }
 
-            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
-                    mEnableIdentityChangeCallback);
+            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
new file mode 100644
index 0000000..f2e371d
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/IWifiNanDiscoverySessionCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.net.wifi.nan;
+
+/**
+ * Callback interface that WifiNanManager implements
+ *
+ * {@hide}
+ */
+oneway interface IWifiNanDiscoverySessionCallback
+{
+    void onSessionStarted(int discoverySessionId);
+    void onSessionConfigSuccess();
+    void onSessionConfigFail(int reason);
+    void onSessionTerminated(int reason);
+
+    void onMatch(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter);
+
+    void onMessageSendSuccess(int messageId);
+    void onMessageSendFail(int messageId, int reason);
+    void onMessageReceived(int peerId, in byte[] message);
+}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
index a4e590b..9ac7bf2 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
@@ -26,7 +26,7 @@
  */
 oneway interface IWifiNanEventCallback
 {
-    void onConnectSuccess();
+    void onConnectSuccess(int clientId);
     void onConnectFail(int reason);
     void onIdentityChanged(in byte[] mac);
 
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index b8dd1a5..56baba9 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -19,8 +19,8 @@
 import android.app.PendingIntent;
 
 import android.net.wifi.nan.ConfigRequest;
+import android.net.wifi.nan.IWifiNanDiscoverySessionCallback;
 import android.net.wifi.nan.IWifiNanEventCallback;
-import android.net.wifi.nan.IWifiNanSessionCallback;
 import android.net.wifi.nan.PublishConfig;
 import android.net.wifi.nan.SubscribeConfig;
 import android.net.wifi.RttManager;
@@ -38,19 +38,20 @@
     boolean isUsageEnabled();
 
     // client API
-    int connect(in IBinder binder, in IWifiNanEventCallback callback,
-            in ConfigRequest configRequest);
+    void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
+            in ConfigRequest configRequest, boolean notifyOnIdentityChanged);
     void disconnect(int clientId, in IBinder binder);
 
-    void publish(int clientId, in PublishConfig publishConfig, in IWifiNanSessionCallback callback);
+    void publish(int clientId, in PublishConfig publishConfig,
+            in IWifiNanDiscoverySessionCallback callback);
     void subscribe(int clientId, in SubscribeConfig subscribeConfig,
-            in IWifiNanSessionCallback callback);
+            in IWifiNanDiscoverySessionCallback callback);
 
     // session API
-    void updatePublish(int clientId, int sessionId, in PublishConfig publishConfig);
-    void updateSubscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig);
-    void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageId,
-        int retryCount);
-    void terminateSession(int clientId, int sessionId);
-    int startRanging(int clientId, int sessionId, in RttManager.ParcelableRttParams parms);
+    void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
+    void updateSubscribe(int clientId, int discoverySessionId, in SubscribeConfig subscribeConfig);
+    void sendMessage(int clientId, int discoverySessionId, int peerId, in byte[] message,
+        int messageId, int retryCount);
+    void terminateSession(int clientId, int discoverySessionId);
+    int startRanging(int clientId, int discoverySessionId, in RttManager.ParcelableRttParams parms);
 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
deleted file mode 100644
index ff2c409..0000000
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.net.wifi.nan;
-
-/**
- * Callback interface that WifiNanManager implements
- *
- * {@hide}
- */
-oneway interface IWifiNanSessionCallback
-{
-    void onSessionStarted(int sessionId);
-    void onSessionConfigSuccess();
-    void onSessionConfigFail(int reason);
-    void onSessionTerminated(int reason);
-
-    void onMatch(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter);
-
-    void onMessageSendSuccess(int messageId);
-    void onMessageSendFail(int messageId, int reason);
-    void onMessageReceived(int peerId, in byte[] message);
-}
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index 3fd756e..4b67f9a 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -31,13 +31,15 @@
 
 /**
  * Defines the configuration of a NAN publish session. Built using
- * {@link PublishConfig.Builder}. Publish is done using
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
- * {@link WifiNanPublishSession#updatePublish(PublishConfig)}.
+ * {@link PublishConfig.Builder}. A publish session is created using
+ * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * or updated using
+ * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_NAN_API
  */
-public class PublishConfig implements Parcelable {
+public final class PublishConfig implements Parcelable {
+    /** @hide */
     @IntDef({
             PUBLISH_TYPE_UNSOLICITED, PUBLISH_TYPE_SOLICITED })
     @Retention(RetentionPolicy.SOURCE)
@@ -45,67 +47,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 +99,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 +114,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 +131,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 +155,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 +167,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 +177,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 +185,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 +198,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 +206,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 +215,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 +239,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,73 +257,34 @@
         }
 
         /**
-         * Specify service specific information for the publish session - same
-         * as {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}
-         * but obtaining the data from a String.
-         *
-         * @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(..)}.
-         */
-        public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) {
-            mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
-            return this;
-        }
-
-        /**
-         * 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.
-         *
-         * @param txFilter The byte-array containing the LV formatted transmit
-         *            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 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.
+         * 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>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
+         *     Optional. Empty by default.
          *
-         * @param rxFilter The byte-array containing the LV formatted receive
-         *            filter.
+         * @param matchFilter The byte-array containing the LV formatted match 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;
         }
 
         /**
-         * 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 +297,19 @@
         }
 
         /**
-         * 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
-         * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)}
-         * with reason={@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * will be broadcast. When the count is reached an event will be
+         * generated for {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
+         * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
+         * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} 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 +322,20 @@
         }
 
         /**
-         * 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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
+         * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}  [unless
+         * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} is
+         *     called.
          *
          * @param ttlSec Lifetime of a publish session in seconds.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -406,15 +349,16 @@
 
         /**
          * Configure whether a publish terminate notification
-         * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported
+         * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
          * back to the callback.
          *
          * @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(..)}.
          */
-        public Builder setEnableTerminateNotification(boolean enable) {
+        public Builder setTerminateNotificationEnabled(boolean enable) {
             mEnableTerminateNotification = enable;
             return this;
         }
@@ -424,8 +368,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..4352fcf 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -32,12 +32,14 @@
 /**
  * Defines the configuration of a NAN subscribe session. Built using
  * {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} or
- * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+ * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+ * or
+ * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
  *
  * @hide PROPOSED_NAN_API
  */
-public class SubscribeConfig implements Parcelable {
+public final class SubscribeConfig implements Parcelable {
+    /** @hide */
     @IntDef({
             SUBSCRIBE_TYPE_PASSIVE, SUBSCRIBE_TYPE_ACTIVE })
     @Retention(RetentionPolicy.SOURCE)
@@ -45,7 +47,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 +55,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 +70,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 +123,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 +138,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 +156,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 +181,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 +193,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 +204,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 +212,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 +229,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 +237,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 +247,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 +269,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,60 +289,21 @@
         }
 
         /**
-         * Specify service specific information for the subscribe session - same
-         * as
-         * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}
-         * but obtaining the data from a String.
-         *
-         * @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(..)}.
-         */
-        public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) {
-            mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
-            return this;
-        }
-
-        /**
-         * 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.
-         *
-         * @param txFilter The byte-array containing the LV formatted transmit
-         *            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.
+         * 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>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
+         *     Optional. Empty by default.
          *
-         * @param rxFilter The byte-array containing the LV formatted receive
-         *            filter.
+         * @param matchFilter The byte-array containing the LV formatted match 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 +313,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 +330,17 @@
 
         /**
          * 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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)}
+         * with {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} 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 +354,18 @@
 
         /**
          * 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 WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * {@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 WifiNanDiscoverySessionCallback#onSessionTerminated(int)} with
+         * {@link WifiNanDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanDiscoveryBaseSession#destroy()} is
+         *     called.
          *
          * @param ttlSec Lifetime of a subscribe session in seconds.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -441,10 +381,10 @@
          * Sets the match style of the subscription - how are matches from a
          * single match session (corresponding to the same publish action on the
          * peer) reported to the host (using the
-         * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])}
+         * {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, 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
@@ -461,15 +401,16 @@
 
         /**
          * Configure whether a subscribe terminate notification
-         * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported
+         * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} is reported
          * back to the callback.
          *
          * @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(..)}.
          */
-        public Builder setEnableTerminateNotification(boolean enable) {
+        public Builder setTerminateNotificationEnabled(boolean enable) {
             mEnableTerminateNotification = enable;
             return this;
         }
@@ -479,7 +420,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/WifiNanAttachCallback.java b/wifi/java/android/net/wifi/nan/WifiNanAttachCallback.java
new file mode 100644
index 0000000..d8c310b
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanAttachCallback.java
@@ -0,0 +1,47 @@
+/*
+ * 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.net.wifi.nan;
+
+/**
+ * Base class for NAN attach callbacks. Should be extended by applications and set when calling
+ * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)}. These are callbacks
+ * applying to the NAN connection as a whole - not to specific publish or subscribe sessions -
+ * for that see {@link WifiNanDiscoverySessionCallback}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanAttachCallback {
+    /**
+     * Called when NAN attach operation
+     * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)}
+     * is completed and that we can now start discovery sessions or connections.
+     *
+     * @param session The NAN object on which we can execute further NAN operations - e.g.
+     *                discovery, connections.
+     */
+    public void onAttached(WifiNanSession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when NAN attach operation
+     * {@link WifiNanManager#attach(android.os.Handler, WifiNanAttachCallback)} failed.
+     */
+    public void onAttachFailed() {
+        /* empty */
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java b/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
new file mode 100644
index 0000000..17e974b
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanDiscoveryBaseSession.java
@@ -0,0 +1,289 @@
+/*
+ * 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.net.wifi.nan;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.wifi.RttManager;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A class representing a single publish or subscribe NAN session. This object
+ * will not be created directly - only its child classes are available:
+ * {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}. This
+ * class provides functionality common to both publish and subscribe discovery sessions:
+ * <ul>
+ *     <li>Sending messages: {@link #sendMessage(Object, int, byte[])} or
+ *     {@link #sendMessage(Object, int, byte[], int)} methods.
+ *     <li>Creating a network-specifier when requesting a NAN connection:
+ *     {@link #createNetworkSpecifier(int, Object, byte[])}.
+ * </ul>
+ * The {@link #destroy()} method must be called to destroy discovery sessions once they are
+ * no longer needed.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanDiscoveryBaseSession {
+    private static final String TAG = "WifiNanDiscoveryBaseSsn";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false; // STOPSHIP if true
+
+    private static final int MAX_SEND_RETRY_COUNT = 5;
+
+    /** @hide */
+    protected WeakReference<WifiNanManager> mMgr;
+    /** @hide */
+    protected final int mClientId;
+    /** @hide */
+    protected final int mSessionId;
+    /** @hide */
+    protected boolean mTerminated = false;
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    /**
+     * Return the maximum permitted retry count when sending messages using
+     * {@link #sendMessage(Object, int, byte[], int)}.
+     *
+     * @return Maximum retry count when sending messages.
+     */
+    public static int getMaxSendRetryCount() {
+        return MAX_SEND_RETRY_COUNT;
+    }
+
+    /** @hide */
+    public WifiNanDiscoveryBaseSession(WifiNanManager manager, int clientId, int sessionId) {
+        if (VDBG) {
+            Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
+                    + clientId + ", sessionId=" + sessionId);
+        }
+
+        mMgr = new WeakReference<>(manager);
+        mClientId = clientId;
+        mSessionId = sessionId;
+
+        mCloseGuard.open("destroy");
+    }
+
+    /**
+     * Destroy 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 after its destruction.
+     * <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 exits. The only
+     *     exception is a session for which we received a termination callback,
+     *     {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)}.
+     */
+    public void destroy() {
+        WifiNanManager mgr = mMgr.get();
+        if (mgr == null) {
+            Log.w(TAG, "destroy: called post GC on WifiNanManager");
+            return;
+        }
+        mgr.terminateSession(mClientId, mSessionId);
+        mTerminated = true;
+        mMgr.clear();
+        mCloseGuard.close();
+    }
+
+    /**
+     * Sets the status of the session to terminated - i.e. an indication that
+     * already terminated rather than executing a termination.
+     *
+     * @hide
+     */
+    public void setTerminated() {
+        if (mTerminated) {
+            Log.w(TAG, "terminate: already terminated.");
+            return;
+        }
+        mTerminated = true;
+        mMgr.clear();
+        mCloseGuard.close();
+    }
+
+    /** @hide */
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (!mTerminated) {
+                mCloseGuard.warnIfOpen();
+                destroy();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * <p>
+     *     NAN messages are not guaranteed delivery. Callbacks on
+     *     {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link WifiNanDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
+     *     (possibly after several retries) -
+     *     {@link WifiNanDiscoverySessionCallback#onMessageSendFailed(int)}.
+     * <p>
+     *     The peer will get a callback indicating a message was received using
+     *     {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
+     *
+     * @param peerHandle The peer's handle for the message. Must be a result of an
+     *        {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
+     *        or
+     *        {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     * @param messageId An arbitrary integer used by the caller to identify the message. The same
+     *            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 message The message to be transmitted.
+     * @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 permitted value is {@link #getMaxSendRetryCount()}.
+     */
+    public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message,
+            int retryCount) {
+        if (mTerminated) {
+            Log.w(TAG, "sendMessage: called on terminated session");
+            return;
+        } else {
+            WifiNanManager mgr = mMgr.get();
+            if (mgr == null) {
+                Log.w(TAG, "sendMessage: called post GC on WifiNanManager");
+                return;
+            }
+
+            mgr.sendMessage(mClientId, mSessionId, peerHandle, message, messageId, retryCount);
+        }
+    }
+
+    /**
+     * 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 WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} event.
+     * <p>
+     *     NAN messages are not guaranteed delivery. Callbacks on
+     *     {@link WifiNanDiscoverySessionCallback} indicate message was transmitted successfully,
+     *     {@link WifiNanDiscoverySessionCallback#onMessageSent(int)}, or transmission failed
+     *     (possibly after several retries) -
+     *     {@link WifiNanDiscoverySessionCallback#onMessageSendFailed(int)}.
+     * <p>
+     *     The peer will get a callback indicating a message was received using
+     *     {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])}.
+     * Equivalent to {@link #sendMessage(Object, int, byte[], int)} with a {@code retryCount} of
+     * 0.
+     *
+     * @param peerHandle The peer's handle for the message. Must be a result of an
+     *        {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])}
+     *        or
+     *        {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, byte[])} events.
+     * @param messageId An arbitrary integer used by the caller to identify the message. The same
+     *            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 message The message to be transmitted.
+     */
+    public void sendMessage(@NonNull Object peerHandle, int messageId, @Nullable byte[] message) {
+        sendMessage(peerHandle, messageId, message, 0);
+    }
+
+    /**
+     * Start a ranging operation with the specified peers. The peer IDs are obtained from an
+     * {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
+     * {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, 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
+     *                 must be identical). The
+     *                 {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
+     *                 a peer ID - not to a MAC address.
+     * @param listener The listener to receive the results of the ranging session.
+     * @hide PROPOSED_NAN_SYSTEM_API [TODO: b/28847998 - track RTT API & visilibity]
+     */
+    public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
+        if (mTerminated) {
+            Log.w(TAG, "startRanging: called on terminated session");
+            return;
+        } else {
+            WifiNanManager mgr = mMgr.get();
+            if (mgr == null) {
+                Log.w(TAG, "startRanging: called post GC on WifiNanManager");
+                return;
+            }
+
+            mgr.startRanging(mClientId, mSessionId, params, listener);
+        }
+    }
+
+    /**
+     * 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 WifiNanSession#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 peerHandle The peer's handle obtained through
+     * {@link WifiNanDiscoverySessionCallback#onServiceDiscovered(Object, byte[], byte[])} or
+     * {@link WifiNanDiscoverySessionCallback#onMessageReceived(Object, 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 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(android.net.NetworkRequest,android.net.ConnectivityManager.NetworkCallback)}
+     * [or other varieties of that API].
+     */
+    public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role,
+            @Nullable Object peerHandle, @Nullable byte[] token) {
+        if (mTerminated) {
+            Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+            return null;
+        } else {
+            WifiNanManager mgr = mMgr.get();
+            if (mgr == null) {
+                Log.w(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
+                return null;
+            }
+
+            return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
new file mode 100644
index 0000000..271f420
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanDiscoverySessionCallback.java
@@ -0,0 +1,182 @@
+/*
+ * 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.net.wifi.nan;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base class for NAN session events callbacks. Should be extended by
+ * applications wanting notifications. The callbacks are set when a
+ * publish or subscribe session is created using
+ * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * or
+ * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)} .
+ * <p>
+ * A single callback is set at session creation - it cannot be replaced.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanDiscoverySessionCallback {
+    /** @hide */
+    @IntDef({
+            TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SessionTerminateCodes {
+    }
+
+    /**
+     * Indicates that publish or subscribe session is done - all the
+     * requested operations (per {@link PublishConfig} or
+     * {@link SubscribeConfig}) have been executed. Failure reason flag for
+     * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
+     */
+    public static final int TERMINATE_REASON_DONE = 100;
+
+    /**
+     * Indicates that publish or subscribe session is terminated due to a
+     * failure.
+     * Failure reason flag for
+     * {@link WifiNanDiscoverySessionCallback#onSessionTerminated(int)} callback.
+     */
+    public static final int TERMINATE_REASON_FAIL = 101;
+
+    /**
+     * Called when a publish operation is started successfully in response to a
+     * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+     * operation.
+     *
+     * @param session The {@link WifiNanPublishDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onPublishStarted(@NonNull WifiNanPublishDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a subscribe operation is started successfully in response to a
+     * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+     * operation.
+     *
+     * @param session The {@link WifiNanSubscribeDiscoverySession} used to control the
+     *            discovery session.
+     */
+    public void onSubscribeStarted(@NonNull WifiNanSubscribeDiscoverySession session) {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session configuration update request
+     * succeeds. Called in response to
+     * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     */
+    public void onSessionConfigUpdated() {
+        /* empty */
+    }
+
+    /**
+     * Called when a publish or subscribe discovery session cannot be created:
+     * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+     * or
+     * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)},
+     * or when a configuration update fails:
+     * {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} or
+     * {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *     For discovery session updates failure leaves the session running with its previous
+     *     configuration - the discovery session is not terminated.
+     */
+    public void onSessionConfigFailed() {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
+     * to user-request (either directly through {@link WifiNanDiscoveryBaseSession#destroy()} 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 WifiNanDiscoverySessionCallback.TERMINATE_*} codes.
+     */
+    public void onSessionTerminated(@SessionTerminateCodes int reason) {
+        /* empty */
+    }
+
+    /**
+     * Called when a discovery (publish or subscribe) operation results in a
+     * service discovery.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param serviceSpecificInfo The service specific information (arbitrary
+     *            byte array) provided by the peer as part of its discovery
+     *            configuration.
+     * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
+     *            resulted in this service discovery.
+     */
+    public void onServiceDiscovered(Object peerHandle, byte[] serviceSpecificInfo,
+            byte[] matchFilter) {
+        /* empty */
+    }
+
+    /**
+     * Called in response to {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])}
+     * when a message is transmitted successfully - i.e. when it was received successfully by the
+     * peer (corresponds to an ACK being received).
+     * <p>
+     * Note that either this callback or
+     * {@link WifiNanDiscoverySessionCallback#onMessageSendFailed(int)} will be
+     * received - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSent(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * 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 WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[], int)} method) - this
+     * event is received after all retries are exhausted.
+     * <p>
+     * Note that either this callback or
+     * {@link WifiNanDiscoverySessionCallback#onMessageSent(int)} will be received
+     * - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
+     */
+    public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
+        /* empty */
+    }
+
+    /**
+     * Called when a message is received from a discovery session peer - in response to the
+     * peer's {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} or
+     * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[], int)}.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param message A byte array containing the message.
+     */
+    public void onMessageReceived(Object peerHandle, byte[] message) {
+        /* empty */
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
deleted file mode 100644
index 148307d..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.net.wifi.nan;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-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}.
- *
- * @hide PROPOSED_NAN_API
- */
-public class WifiNanEventCallback {
-    @IntDef({
-            REASON_INVALID_ARGS, REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG, REASON_OTHER
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface EventReasonCodes {
-    }
-
-    /**
-     * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates
-     * invalid argument in the requested operation.
-     */
-    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.
-     */
-    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.
-     */
-    public static final int REASON_OTHER = 1003;
-
-    /**
-     * 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[])}.
-     */
-    public void onConnectSuccess() {
-        /* empty */
-    }
-
-    /**
-     * Called when NAN connect operation
-     * {@code WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)}
-     * failed.
-     *
-     * @param reason Failure reason code, see
-     *            {@code WifiNanEventCallback.REASON_*}.
-     */
-    public void onConnectFail(@EventReasonCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * 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.
-     */
-    public void onIdentityChanged(byte[] mac) {
-        /* empty */
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java b/wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java
new file mode 100644
index 0000000..7cb928f
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanIdentityChangedListener.java
@@ -0,0 +1,40 @@
+/*
+ * 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.net.wifi.nan;
+
+/**
+ * Base class for a listener which is called with the MAC address of the NAN interface whenever
+ * it is 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 WifiNanSession#createNetworkSpecifier(int, byte[], byte[])}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanIdentityChangedListener {
+    /**
+     * @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..bb15434 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -21,14 +21,13 @@
 import android.annotation.Nullable;
 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;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -49,17 +48,69 @@
 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 #attach(Handler, WifiNanAttachCallback)}.
+ * <li>Create discovery sessions (publish or subscribe sessions). Refer to
+ * {@link WifiNanSession#publish(Handler, PublishConfig, WifiNanDiscoverySessionCallback)} and
+ * {@link WifiNanSession#subscribe(Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}.
+ * <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 WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])} and
+ * {@link WifiNanSession#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 #isAvailable()} 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 #attach(Handler, WifiNanAttachCallback)} 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 attach success (or failure) are
+ *     returned in callbacks of {@link WifiNanAttachCallback}. Proceed with NAN discovery or
+ *     connection setup only after receiving confirmation that NAN attach succeeded -
+ *     {@link WifiNanAttachCallback#onAttached(WifiNanSession)}. When an application is
+ *     finished using NAN it <b>must</b> use the {@link WifiNanSession#destroy()} API
+ *     to indicate to the NAN service that the device may detach from the NAN cluster. The
+ *     device will actually disable NAN once the last application detaches.
+ * <p>
+ *     Once a NAN attach is confirmed use the
+ *     {@link WifiNanSession#publish(Handler, PublishConfig, WifiNanDiscoverySessionCallback)} or
+ *     {@link WifiNanSession#subscribe(Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+ *     to create publish or subscribe NAN discovery sessions. Events are called on the provided
+ *     callback object {@link WifiNanDiscoverySessionCallback}. Specifically, the
+ *     {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+ *     and
+ *     {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
+ *     return {@link WifiNanPublishDiscoverySession} and {@link WifiNanSubscribeDiscoverySession}
+ *     objects respectively on which additional session operations can be performed, e.g. updating
+ *     the session {@link WifiNanPublishDiscoverySession#updatePublish(PublishConfig)} and
+ *     {@link WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can also
+ *     be used to send messages using the
+ *     {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} APIs. When an
+ *     application is finished with a discovery session it <b>must</b> terminate it using the
+ *     {@link WifiNanDiscoveryBaseSession#destroy()} 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 WifiNanSession#createNetworkSpecifier(int, byte[], byte[])} or
+ *        {@link WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])}.
+ *    </ul>
  *
  * @hide PROPOSED_NAN_API
  */
@@ -68,8 +119,6 @@
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
-    private static final int INVALID_CLIENT_ID = 0;
-
     /**
      * Keys used to generate a Network Specifier for the NAN network request. The network specifier
      * is formatted as a JSON string.
@@ -123,82 +172,43 @@
      */
     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.
-     *
-     * @see #EXTRA_WIFI_STATE
+     * Broadcast intent action to indicate that the state of Wi-Fi NAN availability has changed.
+     * Use the {@link #isAvailable()} to query the current status.
+     * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
+     * the broadcast to check the current state of Wi-Fi NAN.
+     * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
+     * components will be launched.
      */
     @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
-     * 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";
-
-    /**
-     * Wi-Fi NAN is disabled.
-     *
-     * @see #WIFI_NAN_STATE_CHANGED_ACTION
-     */
-    public static final int WIFI_NAN_STATE_DISABLED = 1;
-
-    /**
-     * Wi-Fi NAN is enabled.
-     *
-     * @see #WIFI_NAN_STATE_CHANGED_ACTION
-     */
-    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,368 +216,276 @@
     }
 
     /**
-     * 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 WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiNanSession#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 WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, byte[])
+     * @see WifiNanSession#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 Object mLock = new Object(); // lock access to the following vars
 
     @GuardedBy("mLock")
-    private final IBinder mBinder = new Binder();
-
-    @GuardedBy("mLock")
-    private int mClientId = INVALID_CLIENT_ID;
-
-    @GuardedBy("mLock")
-    private Looper mLooper;
-
-    @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
-     * triggered.
+     * Enable the usage of the NAN API. Doesn't actually turn on NAN cluster formation - that
+     * only happens when an attach is attempted. {@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
+     * Disable the usage of the NAN API. All attempts to attach() will be rejected. All open
+     * 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 NAN is available. 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).
+     * @return A boolean indicating whether the app can use the NAN API at this time (true) or
+     * not (false).
      */
-    public boolean isUsageEnabled() {
+    public boolean isAvailable() {
         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.
+     * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
+     * create connections to peers. The device will attach 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 attach to a cluster) are provided to the {@code attachCallback} object.
+     * An application <b>must</b> call {@link WifiNanSession#destroy()} when done with the
+     * Wi-Fi NAN object.
+     * <p>
+     * Note: a NAN cluster is a shared resource - if the device is already attached to a cluster
+     * then this function will simply indicate success immediately using the same {@code
+     * attachCallback}.
      *
-     * @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 handler The Handler on whose thread to execute the callbacks of the {@code
+     * attachCallback} object. If a null is provided then the application's main thread will be
+     *                used.
+     * @param attachCallback A callback for attach events, extended from
+     * {@link WifiNanAttachCallback}.
      */
-    public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback) {
-        connect(looper, callback, null);
+    public void attach(@Nullable Handler handler, @NonNull WifiNanAttachCallback attachCallback) {
+        attach(handler, null, attachCallback, null);
     }
 
     /**
-     * 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.
+     * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
+     * create connections to peers. The device will attach 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 attach to a cluster) are provided to the {@code attachCallback} object.
+     * An application <b>must</b> call {@link WifiNanSession#destroy()} when done with the
+     * Wi-Fi NAN object.
+     * <p>
+     * Note: a NAN cluster is a shared resource - if the device is already attached to a cluster
+     * then this function will simply indicate success immediately using the same {@code
+     * attachCallback}.
+     * <p>
+     * This version of the API attaches a listener to receive the MAC address of the NAN interface
+     * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
+     * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * permission to execute this attach request. Otherwise, use the
+     * {@link #attach(Handler, WifiNanAttachCallback)} version. Note that aside from permission
+     * requirements this listener will wake up the host at regular intervals causing higher power
+     * consumption, do not use it unless the information is necessary (e.g. for OOB discovery).
      *
-     * @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 handler The Handler on whose thread to execute the callbacks of the {@code
+     * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
+     *                application's main thread will be used.
+     * @param attachCallback A callback for attach events, extended from
+     * {@link WifiNanAttachCallback}.
+     * @param identityChangedListener A listener for changed identity, extended from
+     * {@link WifiNanIdentityChangedListener}.
      */
-    public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback,
-            @Nullable ConfigRequest configRequest) {
+    public void attach(@Nullable Handler handler, @NonNull WifiNanAttachCallback attachCallback,
+            @NonNull WifiNanIdentityChangedListener identityChangedListener) {
+        attach(handler, null, attachCallback, identityChangedListener);
+    }
+
+    /** @hide */
+    public void attach(Handler handler, ConfigRequest configRequest,
+            WifiNanAttachCallback attachCallback,
+            WifiNanIdentityChangedListener identityChangedListener) {
         if (VDBG) {
-            Log.v(TAG, "connect(): looper=" + looper + ", callback=" + callback + ", configRequest="
-                    + configRequest);
+            Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
+                    + ", configRequest=" + configRequest + ", identityChangedListener="
+                    + identityChangedListener);
         }
 
         synchronized (mLock) {
-            mLooper = looper;
+            Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
 
             try {
-                mClientId = mService.connect(mBinder,
-                        new WifiNanEventCallbackProxy(this, looper, callback), configRequest);
+                Binder binder = new Binder();
+                mService.connect(binder, mContext.getOpPackageName(),
+                        new WifiNanEventCallbackProxy(this, looper, binder, attachCallback,
+                                identityChangedListener), configRequest,
+                        identityChangedListener != null);
             } catch (RemoteException e) {
-                mClientId = INVALID_CLIENT_ID;
-                mLooper = null;
-                e.rethrowFromSystemServer();
+                throw e.rethrowFromSystemServer();
             }
         }
     }
 
-    /**
-     * 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.
-     * <p>
-     * An application may then re-connect using
-     * {@link WifiNanManager#connect(Looper, WifiNanEventCallback)} .
-     */
-    public void disconnect() {
+    /** @hide */
+    public void disconnect(int clientId, Binder binder) {
         if (VDBG) Log.v(TAG, "disconnect()");
 
-        IBinder binder;
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.w(TAG, "disconnect(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            binder = mBinder;
-            clientId = mClientId;
-
-            mLooper = null;
-            mClientId = INVALID_CLIENT_ID;
-        }
-
         try {
             mService.disconnect(clientId, binder);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        disconnect();
-        super.finalize();
-    }
+    /** @hide */
+    public void publish(int clientId, Looper looper, PublishConfig publishConfig,
+            WifiNanDiscoverySessionCallback callback) {
+        if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
 
-    /**
-     * 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*}.
-     *
-     * @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}.
-     */
-    public void publish(@NonNull PublishConfig publishConfig,
-            @NonNull WifiNanSessionCallback callback) {
-        if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig);
-
-        int clientId;
-        Looper looper;
-        synchronized (mLock) {
-            if (mLooper == null || mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "publish(): called with null looper or invalid client ID - "
-                        + "not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
-            looper = mLooper;
-        }
         try {
             mService.publish(clientId, publishConfig,
-                    new WifiNanSessionCallbackProxy(this, looper, true, callback));
+                    new WifiNanDiscoverySessionCallbackProxy(this, looper, true, callback,
+                            clientId));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public void updatePublish(int sessionId, PublishConfig publishConfig) {
-        if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig);
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "updatePublish(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+    /** @hide */
+    public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) {
+        if (VDBG) {
+            Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId
+                    + ", config=" + publishConfig);
         }
+
         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*}
-     *
-     * @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}.
-     */
-    public void subscribe(@NonNull SubscribeConfig subscribeConfig,
-            @NonNull WifiNanSessionCallback callback) {
+    /** @hide */
+    public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
+            WifiNanDiscoverySessionCallback callback) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): config=" + subscribeConfig);
-        }
-
-        int clientId;
-        Looper looper;
-        synchronized (mLock) {
-            if (mLooper == null || mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "subscribe(): called with null looper or invalid client ID - "
-                        + "not connected first?");
-                return;
+            if (VDBG) {
+                Log.v(TAG,
+                        "subscribe(): clientId=" + clientId + ", config=" + subscribeConfig);
             }
-
-            clientId = mClientId;
-            looper = mLooper;
         }
 
         try {
             mService.subscribe(clientId, subscribeConfig,
-                    new WifiNanSessionCallbackProxy(this, looper, false, callback));
+                    new WifiNanDiscoverySessionCallbackProxy(this, looper, false, callback,
+                            clientId));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) {
+    /** @hide */
+    public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): config=" + subscribeConfig);
-        }
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG,
-                        "updateSubscribe(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+            Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId
+                    + ", config=" + subscribeConfig);
         }
 
         try {
             mService.updateSubscribe(clientId, sessionId, subscribeConfig);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public void terminateSession(int sessionId) {
-        if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId);
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG,
-                        "terminateSession(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+    /** @hide */
+    public void terminateSession(int clientId, int sessionId) {
+        if (VDBG) {
+            Log.d(TAG,
+                    "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId);
         }
 
         try {
             mService.terminateSession(clientId, sessionId);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public void sendMessage(int sessionId, int peerId, byte[] message, int messageId,
-            int retryCount) {
-        if (VDBG) {
-            Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
-                    + ", messageId=" + messageId + ", retryCount=" + retryCount);
+    /** @hide */
+    public void sendMessage(int clientId, int sessionId, Object peerHandle, byte[] message,
+            int messageId, int retryCount) {
+        if (peerHandle == null) {
+            throw new IllegalArgumentException(
+                    "sendMessage: invalid peerHandle - must be non-null");
         }
 
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "sendMessage(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+        if (VDBG) {
+            Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId
+                    + ", peerHandle=" + ((OpaquePeerHandle) peerHandle).peerId + ", messageId="
+                    + messageId + ", retryCount=" + retryCount);
         }
 
         try {
-            mService.sendMessage(clientId, sessionId, peerId, message, messageId, retryCount);
+            mService.sendMessage(clientId, sessionId, ((OpaquePeerHandle) peerHandle).peerId,
+                    message, messageId, retryCount);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public void startRanging(int sessionId, RttManager.RttParams[] params,
+    /** @hide */
+    public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params,
                              RttManager.RttListener listener) {
         if (VDBG) {
-            Log.v(TAG, "startRanging: sessionId=" + sessionId + ", " + "params="
-                    + Arrays.toString(params) + ", listener=" + listener);
-        }
-
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG, "startRanging(): called with invalid client ID - not connected first?");
-                return;
-            }
-
-            clientId = mClientId;
+            Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", "
+                    + "params=" + Arrays.toString(params) + ", listener=" + listener);
         }
 
         int rangingKey = 0;
@@ -575,7 +493,7 @@
             rangingKey = mService.startRanging(clientId, sessionId,
                     new RttManager.ParcelableRttParams(params));
         } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
 
         synchronized (mLock) {
@@ -583,22 +501,21 @@
         }
     }
 
-    /**
-     * {@hide}
-     */
-    public String createNetworkSpecifier(@DataPathRole int role, int sessionId, int peerId,
+    /** @hide */
+    public String createNetworkSpecifier(int clientId, int role, int sessionId, Object peerHandle,
             byte[] token) {
         if (VDBG) {
             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
-                    + ", peerId=" + peerId + ", token=" + token);
+                    + ", peerHandle=" + ((peerHandle == null) ? peerHandle
+                    : ((OpaquePeerHandle) peerHandle).peerId) + ", token=" + token);
         }
 
         int type;
-        if (token != null && peerId != 0) {
+        if (token != null && peerHandle != null) {
             type = NETWORK_SPECIFIER_TYPE_1A;
-        } else if (token == null && peerId != 0) {
+        } else if (token == null && peerHandle != null) {
             type = NETWORK_SPECIFIER_TYPE_1B;
-        } else if (token != null && peerId == 0) {
+        } else if (token != null && peerHandle == null) {
             type = NETWORK_SPECIFIER_TYPE_1C;
         } else {
             type = NETWORK_SPECIFIER_TYPE_1D;
@@ -615,25 +532,13 @@
                 throw new IllegalArgumentException(
                         "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
             }
-            if (peerId == 0) {
+            if (peerHandle == null) {
                 throw new IllegalArgumentException(
-                        "createNetworkSpecifier: Invalid peer ID (value of 0) - not permitted on "
-                                + "INITIATOR");
+                        "createNetworkSpecifier: Invalid peer handle (value of null) - not "
+                                + "permitted on INITIATOR");
             }
         }
 
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG,
-                        "createNetworkSpecifier: called with invalid client ID - not connected "
-                                + "first?");
-                return null;
-            }
-
-            clientId = mClientId;
-        }
-
         JSONObject json;
         try {
             json = new JSONObject();
@@ -641,8 +546,8 @@
             json.put(NETWORK_SPECIFIER_KEY_ROLE, role);
             json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId);
             json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId);
-            if (peerId != 0) {
-                json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerId);
+            if (peerHandle != null) {
+                json.put(NETWORK_SPECIFIER_KEY_PEER_ID, ((OpaquePeerHandle) peerHandle).peerId);
             }
             if (token != null) {
                 json.put(NETWORK_SPECIFIER_KEY_TOKEN,
@@ -655,28 +560,9 @@
         return json.toString();
     }
 
-    /**
-     * 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.
-     *
-     * @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.
-     * @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].
-     */
-    public String createNetworkSpecifier(@DataPathRole int role, @Nullable byte[] peer,
-            @Nullable byte[] token) {
+    /** @hide */
+    public String createNetworkSpecifier(int clientId, @DataPathRole int role,
+            @Nullable byte[] peer, @Nullable byte[] token) {
         if (VDBG) {
             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
         }
@@ -714,18 +600,6 @@
             }
         }
 
-        int clientId;
-        synchronized (mLock) {
-            if (mClientId == INVALID_CLIENT_ID) {
-                Log.e(TAG,
-                        "createNetworkSpecifier: called with invalid client ID - not connected "
-                                + "first?");
-                return null;
-            }
-
-            clientId = mClientId;
-        }
-
         JSONObject json;
         try {
             json = new JSONObject();
@@ -756,6 +630,8 @@
 
         private final Handler mHandler;
         private final WeakReference<WifiNanManager> mNanManager;
+        private final Binder mBinder;
+        private final Looper mLooper;
 
         RttManager.RttListener getAndRemoveRangingListener(int rangingId) {
             WifiNanManager mgr = mNanManager.get();
@@ -772,14 +648,17 @@
         }
 
         /**
-         * Constructs a {@link WifiNanEventCallback} using the specified looper.
-         * I.e. all callbacks will delivered on the thread of the specified looper.
+         * Constructs a {@link WifiNanAttachCallback} using the specified looper.
+         * All callbacks will delivered on the thread of the specified looper.
          *
          * @param looper The looper on which to execute the callbacks.
          */
-        WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper,
-                final WifiNanEventCallback originalCallback) {
+        WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, Binder binder,
+                final WifiNanAttachCallback attachCallback,
+                final WifiNanIdentityChangedListener identityChangedListener) {
             mNanManager = new WeakReference<>(mgr);
+            mLooper = looper;
+            mBinder = binder;
 
             if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper);
             mHandler = new Handler(looper) {
@@ -797,18 +676,15 @@
 
                     switch (msg.what) {
                         case CALLBACK_CONNECT_SUCCESS:
-                            originalCallback.onConnectSuccess();
+                            attachCallback.onAttached(
+                                    new WifiNanSession(mgr, mBinder, msg.arg1));
                             break;
                         case CALLBACK_CONNECT_FAIL:
-                            synchronized (mgr.mLock) {
-                                mgr.mLooper = null;
-                                mgr.mClientId = INVALID_CLIENT_ID;
-                            }
                             mNanManager.clear();
-                            originalCallback.onConnectFail(msg.arg1);
+                            attachCallback.onAttachFailed();
                             break;
                         case CALLBACK_IDENTITY_CHANGED:
-                            originalCallback.onIdentityChanged((byte[]) msg.obj);
+                            identityChangedListener.onIdentityChanged((byte[]) msg.obj);
                             break;
                         case CALLBACK_RANGING_SUCCESS: {
                             RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
@@ -847,16 +723,17 @@
         }
 
         @Override
-        public void onConnectSuccess() {
+        public void onConnectSuccess(int clientId) {
             if (VDBG) Log.v(TAG, "onConnectSuccess");
 
             Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS);
+            msg.arg1 = clientId;
             mHandler.sendMessage(msg);
         }
 
         @Override
         public void onConnectFail(int reason) {
-            if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason);
+            if (VDBG) Log.v(TAG, "onConnectFail: reason=" + reason);
 
             Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_FAIL);
             msg.arg1 = reason;
@@ -910,7 +787,8 @@
         }
     }
 
-    private static class WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub {
+    private static class WifiNanDiscoverySessionCallbackProxy extends
+            IWifiNanDiscoverySessionCallback.Stub {
         private static final int CALLBACK_SESSION_STARTED = 0;
         private static final int CALLBACK_SESSION_CONFIG_SUCCESS = 1;
         private static final int CALLBACK_SESSION_CONFIG_FAIL = 2;
@@ -925,18 +803,22 @@
 
         private final WeakReference<WifiNanManager> mNanManager;
         private final boolean mIsPublish;
-        private final WifiNanSessionCallback mOriginalCallback;
+        private final WifiNanDiscoverySessionCallback mOriginalCallback;
+        private final int mClientId;
 
         private final Handler mHandler;
-        private WifiNanSession mSession;
+        private WifiNanDiscoveryBaseSession mSession;
 
-        WifiNanSessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
-                WifiNanSessionCallback originalCallback) {
+        WifiNanDiscoverySessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish,
+                WifiNanDiscoverySessionCallback originalCallback, int clientId) {
             mNanManager = new WeakReference<>(mgr);
             mIsPublish = isPublish;
             mOriginalCallback = originalCallback;
+            mClientId = clientId;
 
-            if (VDBG) Log.v(TAG, "WifiNanSessionCallbackProxy ctor: isPublish=" + isPublish);
+            if (VDBG) {
+                Log.v(TAG, "WifiNanDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
+            }
 
             mHandler = new Handler(looper) {
                 @Override
@@ -944,7 +826,7 @@
                     if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
 
                     if (mNanManager.get() == null) {
-                        Log.w(TAG, "WifiNanSessionCallbackProxy: handleMessage post GC");
+                        Log.w(TAG, "WifiNanDiscoverySessionCallbackProxy: handleMessage post GC");
                         return;
                     }
 
@@ -953,10 +835,10 @@
                             onProxySessionStarted(msg.arg1);
                             break;
                         case CALLBACK_SESSION_CONFIG_SUCCESS:
-                            mOriginalCallback.onSessionConfigSuccess();
+                            mOriginalCallback.onSessionConfigUpdated();
                             break;
                         case CALLBACK_SESSION_CONFIG_FAIL:
-                            mOriginalCallback.onSessionConfigFail(msg.arg1);
+                            mOriginalCallback.onSessionConfigFailed();
                             if (mSession == null) {
                                 /*
                                  * creation failed (as opposed to update
@@ -969,19 +851,20 @@
                             onProxySessionTerminated(msg.arg1);
                             break;
                         case CALLBACK_MATCH:
-                            mOriginalCallback.onMatch(
-                                    msg.arg1,
+                            mOriginalCallback.onServiceDiscovered(
+                                    new OpaquePeerHandle(msg.arg1),
                                     msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE),
                                     msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2));
                             break;
                         case CALLBACK_MESSAGE_SEND_SUCCESS:
-                            mOriginalCallback.onMessageSendSuccess(msg.arg1);
+                            mOriginalCallback.onMessageSent(msg.arg1);
                             break;
                         case CALLBACK_MESSAGE_SEND_FAIL:
-                            mOriginalCallback.onMessageSendFail(msg.arg1, msg.arg2);
+                            mOriginalCallback.onMessageSendFailed(msg.arg1);
                             break;
                         case CALLBACK_MESSAGE_RECEIVED:
-                            mOriginalCallback.onMessageReceived(msg.arg1, (byte[]) msg.obj);
+                            mOriginalCallback.onMessageReceived(new OpaquePeerHandle(msg.arg1),
+                                    (byte[]) msg.obj);
                             break;
                     }
                 }
@@ -1087,11 +970,13 @@
             }
 
             if (mIsPublish) {
-                WifiNanPublishSession session = new WifiNanPublishSession(mgr, sessionId);
+                WifiNanPublishDiscoverySession session = new WifiNanPublishDiscoverySession(mgr,
+                        mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onPublishStarted(session);
             } else {
-                WifiNanSubscribeSession session = new WifiNanSubscribeSession(mgr, sessionId);
+                WifiNanSubscribeDiscoverySession
+                        session = new WifiNanSubscribeDiscoverySession(mgr, mClientId, sessionId);
                 mSession = session;
                 mOriginalCallback.onSubscribeStarted(session);
             }
@@ -1109,4 +994,13 @@
             mOriginalCallback.onSessionTerminated(reason);
         }
     }
+
+    /** @hide */
+    public static class OpaquePeerHandle {
+        public OpaquePeerHandle(int peerId) {
+            this.peerId = peerId;
+        }
+
+        public int peerId;
+    }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
new file mode 100644
index 0000000..75c6cb7
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanPublishDiscoverySession.java
@@ -0,0 +1,70 @@
+/*
+ * 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.net.wifi.nan;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * A class representing a NAN publish session. Created when
+ * {@link WifiNanSession#publish(android.os.Handler, PublishConfig, WifiNanDiscoverySessionCallback)}
+ * is called and a discovery session is created and returned in
+ * {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}. This
+ * object allows updating an existing/running publish discovery session using
+ * {@link #updatePublish(PublishConfig)}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanPublishDiscoverySession extends WifiNanDiscoveryBaseSession {
+    private static final String TAG = "WifiNanPublishDiscSsn";
+
+    /** @hide */
+    public WifiNanPublishDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+        super(manager, clientId, sessionId);
+    }
+
+    /**
+     * Re-configure the currently active publish session. The
+     * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
+     * at creation is still used. The results of the configuration are returned using
+     * {@link WifiNanDiscoverySessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     update succeeded.
+     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFailed()}: 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 new discovery publish session configuration ({@link PublishConfig}).
+     */
+    public void updatePublish(@NonNull PublishConfig publishConfig) {
+        if (mTerminated) {
+            Log.w(TAG, "updatePublish: called on terminated session");
+            return;
+        } else {
+            WifiNanManager mgr = mMgr.get();
+            if (mgr == null) {
+                Log.w(TAG, "updatePublish: called post GC on WifiNanManager");
+                return;
+            }
+
+            mgr.updatePublish(mClientId, mSessionId, publishConfig);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
deleted file mode 100644
index a0e3fba..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.net.wifi.nan;
-
-import android.annotation.NonNull;
-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.
- *
- * @hide PROPOSED_NAN_API
- */
-public class WifiNanPublishSession extends WifiNanSession {
-    private static final String TAG = "WifiNanPublishSession";
-
-    /**
-     * {@hide}
-     */
-    public WifiNanPublishSession(WifiNanManager manager, int sessionId) {
-        super(manager, sessionId);
-    }
-
-    /**
-     * Re-configure the publish session. Note that the
-     * {@link WifiNanSessionCallback} is not replaced - the same listener used
-     * at creation is still used.
-     *
-     * @param publishConfig The configuration ({@link PublishConfig}) of the
-     *            publish session.
-     */
-    public void updatePublish(@NonNull PublishConfig publishConfig) {
-        if (mTerminated) {
-            Log.w(TAG, "updatePublish: called on terminated session");
-            return;
-        } else {
-            WifiNanManager mgr = mMgr.get();
-            if (mgr == null) {
-                Log.w(TAG, "updatePublish: called post GC on WifiNanManager");
-                return;
-            }
-
-            mgr.updatePublish(mSessionId, publishConfig);
-        }
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c10cd52..5fb2c06 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -16,17 +16,21 @@
 
 package android.net.wifi.nan;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.net.wifi.RttManager;
+import android.net.NetworkRequest;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
 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
- * will not be created directly - only its child classes are available:
- * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession}.
+ * This class represents a Wi-Fi NAN session - an attachment to the Wi-Fi NAN service through
+ * which the app can execute discovery operations.
  *
  * @hide PROPOSED_NAN_API
  */
@@ -35,187 +39,186 @@
     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 final WeakReference<WifiNanManager> mMgr;
+    private final Binder mBinder;
+    private final int mClientId;
 
-    /**
-     * @hide
-     */
-    protected WeakReference<WifiNanManager> mMgr;
+    private boolean mTerminated = true;
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
-    /**
-     * @hide
-     */
-    protected final int mSessionId;
-
-    /**
-     * @hide
-     */
-    protected boolean mTerminated = false;
-
-    /**
-     * {@hide}
-     */
-    public WifiNanSession(WifiNanManager manager, int sessionId) {
-        if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId);
+    /** @hide */
+    public WifiNanSession(WifiNanManager manager, Binder binder, int clientId) {
+        if (VDBG) Log.v(TAG, "New session created: manager=" + manager + ", clientId=" + clientId);
 
         mMgr = new WeakReference<>(manager);
-        mSessionId = sessionId;
+        mBinder = binder;
+        mClientId = clientId;
+        mTerminated = false;
+
+        mCloseGuard.open("destroy");
     }
 
     /**
-     * Terminate the current publish or subscribe session - i.e. stop
-     * transmitting packet 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.
+     * Destroy the Wi-Fi NAN service session and, if no other applications are attached to NAN,
+     * also disable NAN. 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 destroy these discovery sessions and connections explicitly before a
+     * session-wide destroy.
+     * <p>
+     * An application may re-attach after a destroy using
+     * {@link WifiNanManager#attach(Handler, WifiNanAttachCallback)} .
      */
-    public void terminate() {
+    public void destroy() {
         WifiNanManager mgr = mMgr.get();
         if (mgr == null) {
-            Log.w(TAG, "terminate: called post GC on WifiNanManager");
+            Log.w(TAG, "destroy: called post GC on WifiNanManager");
             return;
         }
-        mgr.terminateSession(mSessionId);
+        mgr.disconnect(mClientId, mBinder);
         mTerminated = true;
         mMgr.clear();
+        mCloseGuard.close();
     }
 
-    /**
-     * Sets the status of the session to terminated - i.e. an indication that
-     * already terminated rather than executing a termination.
-     *
-     * @hide
-     */
-    public void setTerminated() {
-        if (mTerminated) {
-            Log.w(TAG, "terminate: already terminated.");
-            return;
-        }
-        mTerminated = true;
-        mMgr.clear();
-    }
-
+    /** @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();
-        }
-        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
-     * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
-     *
-     * @param peerId The peer's ID for the message. Must be a result of an
-     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
-     * @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.
-     * @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}.
-     */
-    public void sendMessage(int peerId, @Nullable byte[] message, int messageId, int retryCount) {
-        if (mTerminated) {
-            Log.w(TAG, "sendMessage: called on terminated session");
-            return;
-        } else {
-            WifiNanManager mgr = mMgr.get();
-            if (mgr == null) {
-                Log.w(TAG, "sendMessage: called post GC on WifiNanManager");
-                return;
+        try {
+            if (!mTerminated) {
+                mCloseGuard.warnIfOpen();
+                destroy();
             }
-
-            mgr.sendMessage(mSessionId, peerId, message, messageId, retryCount);
+        } finally {
+            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
-     * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event. This is
-     * equivalent to {@link #sendMessage(int, byte[], int, int)} with a {@code retryCount} of
-     * 0.
+     * 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 WifiNanDiscoverySessionCallback}:
+     * <ul>
+     *     <li>
+     *     {@link WifiNanDiscoverySessionCallback#onPublishStarted(WifiNanPublishDiscoverySession)}
+     *     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 WifiNanDiscoverySessionCallback#onSessionConfigFailed()} 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 WifiNanPublishDiscoverySession#updatePublish(PublishConfig)}.
+     * <p>
+     *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
+     *      terminate the publish discovery session once it isn't needed. This will free
+     *      resources as well terminate any on-air transmissions.
      *
-     * @param peerId The peer's ID for the message. Must be a result of an
-     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
-     * @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.
+     * @param handler The Handler on whose thread to execute the callbacks of the {@code
+     * callback} object. If a null is provided then the application's main thread will be used.
+     * @param publishConfig The {@link PublishConfig} specifying the
+     *            configuration of the requested publish session.
+     * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+     *                 session event callbacks.
      */
-    public void sendMessage(int peerId, @Nullable byte[] message, int messageId) {
-        sendMessage(peerId, message, messageId, 0);
-    }
-
-    /**
-     * 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
-     * range devices which are part of an ongoing discovery session.
-     *
-     * @param params   RTT parameters - each corresponding to a specific peer ID (the array sizes
-     *                 must be identical). The
-     *                 {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
-     *                 a peer ID - not to a MAC address.
-     * @param listener The listener to receive the results of the ranging session.
-     * @hide PROPOSED_NAN_SYSTEM_API [TODO: b/28847998 - track RTT API & visilibity]
-     */
-    public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
-        if (mTerminated) {
-            Log.w(TAG, "startRanging: called on terminated session");
+    public void publish(@Nullable Handler handler, @NonNull PublishConfig publishConfig,
+            @NonNull WifiNanDiscoverySessionCallback callback) {
+        WifiNanManager mgr = mMgr.get();
+        if (mgr == null) {
+            Log.e(TAG, "publish: called post GC on WifiNanManager");
             return;
-        } else {
-            WifiNanManager mgr = mMgr.get();
-            if (mgr == null) {
-                Log.w(TAG, "startRanging: called post GC on WifiNanManager");
-                return;
-            }
-
-            mgr.startRanging(mSessionId, params, listener);
         }
+        if (mTerminated) {
+            Log.e(TAG, "publish: called after termination");
+            return;
+        }
+        mgr.publish(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
+                publishConfig, callback);
     }
 
     /**
-     * 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.
+     * 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 WifiNanDiscoverySessionCallback}:
+     * <ul>
+     *     <li>
+     *  {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}
+     *     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 WifiNanDiscoverySessionCallback#onSessionConfigFailed()} 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 WifiNanSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
+     *      terminate the subscribe discovery session once it isn't needed. This will free
+     *      resources as well terminate any on-air transmissions.
      *
-     * @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.
+     * @param handler The Handler on whose thread to execute the callbacks of the {@code
+     * callback} object. If a null is provided then the application's main thread will be used.
+     * @param subscribeConfig The {@link SubscribeConfig} specifying the
+     *            configuration of the requested subscribe session.
+     * @param callback A {@link WifiNanDiscoverySessionCallback} derived object to be used for
+     *                 session event callbacks.
+     */
+    public void subscribe(@Nullable Handler handler, @NonNull SubscribeConfig subscribeConfig,
+            @NonNull WifiNanDiscoverySessionCallback callback) {
+        WifiNanManager mgr = mMgr.get();
+        if (mgr == null) {
+            Log.e(TAG, "publish: called post GC on WifiNanManager");
+            return;
+        }
+        if (mTerminated) {
+            Log.e(TAG, "publish: called after termination");
+            return;
+        }
+        mgr.subscribe(mClientId, (handler == null) ? Looper.getMainLooper() : handler.getLooper(),
+                subscribeConfig, callback);
+    }
+
+    /**
+     * 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 WifiNanDiscoveryBaseSession#createNetworkSpecifier(int, Object, 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. 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)} [or other varieties of that API].
+     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+     * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest, android.net.ConnectivityManager.NetworkCallback)}
+     * [or other varieties of that API].
      */
-    public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, int peerId,
+    public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, @Nullable byte[] peer,
             @Nullable byte[] token) {
-        if (mTerminated) {
-            Log.w(TAG, "createNetworkSpecifier: called on terminated session");
-            return null;
-        } else {
-            WifiNanManager mgr = mMgr.get();
-            if (mgr == null) {
-                Log.w(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
-                return null;
-            }
-
-            return mgr.createNetworkSpecifier(role, mSessionId, peerId, token);
+        WifiNanManager mgr = mMgr.get();
+        if (mgr == null) {
+            Log.e(TAG, "createNetworkSpecifier: called post GC on WifiNanManager");
+            return "";
         }
+        if (mTerminated) {
+            Log.e(TAG, "createNetworkSpecifier: called after termination");
+            return "";
+        }
+        return mgr.createNetworkSpecifier(mClientId, role, peer, token);
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
deleted file mode 100644
index f2337dd..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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.net.wifi.nan;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Base class for NAN session events callbacks. Should be extended by
- * applications wanting notifications. The callbacks are registered 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.
- *
- * @hide PROPOSED_NAN_API
- */
-public class WifiNanSessionCallback {
-    @IntDef({
-            REASON_NO_RESOURCES, REASON_INVALID_ARGS, REASON_NO_MATCH_SESSION,
-            REASON_TX_FAIL, REASON_OTHER })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionReasonCodes {
-    }
-
-    @IntDef({
-            TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionTerminateCodes {
-    }
-
-    /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
-     * Indicates no resources to execute the requested operation.
-     */
-    public static final int REASON_NO_RESOURCES = 0;
-
-    /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
-     * Indicates invalid argument in the requested operation.
-     */
-    public static final int REASON_INVALID_ARGS = 1;
-
-    /**
-     * 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.
-     */
-    public static final int REASON_TX_FAIL = 3;
-
-    /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
-     * Indicates an unspecified error occurred during the operation.
-     */
-    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
-     * requested operations (per {@link PublishConfig} or
-     * {@link SubscribeConfig}) have been executed.
-     */
-    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.
-     */
-    public static final int TERMINATE_REASON_FAIL = 101;
-
-    /**
-     * Called when a publish operation is started successfully.
-     *
-     * @param session The {@link WifiNanPublishSession} used to control the
-     *            discovery session.
-     */
-    public void onPublishStarted(@NonNull WifiNanPublishSession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a subscribe operation is started successfully.
-     *
-     * @param session The {@link WifiNanSubscribeSession} used to control the
-     *            discovery session.
-     */
-    public void onSubscribeStarted(@NonNull WifiNanSubscribeSession session) {
-        /* empty */
-    }
-
-    /**
-     * Called when a session update configuration (publish or subscribe update)
-     * succeeds.
-     */
-    public void onSessionConfigSuccess() {
-        /* empty */
-    }
-
-    /**
-     * Called when a session configuration (publish or subscribe setup or
-     * update) fails.
-     *
-     * @param reason The failure reason using
-     *            {@code WifiNanSessionCallback.REASON_*} codes.
-     */
-    public void onSessionConfigFail(@SessionReasonCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * Called when a session (publish or subscribe) terminates.
-     *
-     * @param reason The termination reason using
-     *            {@code WifiNanSessionCallback.TERMINATE_*} codes.
-     */
-    public void onSessionTerminated(@SessionTerminateCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * Called when a discovery (publish or subscribe) operation results in a
-     * match - i.e. 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.
-     * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
-     *            resulted in this match.
-     */
-    public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter) {
-        /* empty */
-    }
-
-    /**
-     * Called when a message is transmitted successfully - i.e. when we know
-     * that it was received successfully (corresponding to an ACK being
-     * received).
-     * <p>
-     * Note that either this callback or
-     * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be
-     * received - never both.
-     */
-    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
-     * <p>
-     * Note that either this callback or
-     * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received
-     * - never both
-     *
-     * @param reason The failure reason using
-     *            {@code WifiNanSessionCallback.REASON_*} codes.
-     */
-    public void onMessageSendFail(@SuppressWarnings("unused") int messageId,
-            @SessionReasonCodes int reason) {
-        /* empty */
-    }
-
-    /**
-     * Called when a message is received from a discovery session peer.
-     *
-     * @param peerId The ID of the peer sending the message.
-     * @param message A byte array containing the message.
-     */
-    public void onMessageReceived(int peerId, byte[] message) {
-        /* empty */
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
new file mode 100644
index 0000000..f5b4c0c
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeDiscoverySession.java
@@ -0,0 +1,73 @@
+/*
+ * 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.net.wifi.nan;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * A class representing a NAN subscribe session. Created when
+ * {@link WifiNanSession#subscribe(android.os.Handler, SubscribeConfig, WifiNanDiscoverySessionCallback)}
+ * is called and a discovery session is created and returned in
+ * {@link WifiNanDiscoverySessionCallback#onSubscribeStarted(WifiNanSubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link WifiNanDiscoveryBaseSession}.
+ * This object allows updating an existing/running subscribe discovery session using
+ * {@link #updateSubscribe(SubscribeConfig)}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanSubscribeDiscoverySession extends WifiNanDiscoveryBaseSession {
+    private static final String TAG = "WifiNanSubscribeDiscSsn";
+
+    /**
+     * {@hide}
+     */
+    public WifiNanSubscribeDiscoverySession(WifiNanManager manager, int clientId, int sessionId) {
+        super(manager, clientId, sessionId);
+    }
+
+    /**
+     * Re-configure the currently active subscribe session. The
+     * {@link WifiNanDiscoverySessionCallback} is not replaced - the same listener used
+     * at creation is still used. The results of the configuration are returned using
+     * {@link WifiNanDiscoverySessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+     *     update succeeded.
+     *     <li>{@link WifiNanDiscoverySessionCallback#onSessionConfigFailed()}: 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 new discovery subscribe session configuration
+     *                        ({@link SubscribeConfig}).
+     */
+    public void updateSubscribe(@NonNull SubscribeConfig subscribeConfig) {
+        if (mTerminated) {
+            Log.w(TAG, "updateSubscribe: called on terminated session");
+            return;
+        } else {
+            WifiNanManager mgr = mMgr.get();
+            if (mgr == null) {
+                Log.w(TAG, "updateSubscribe: called post GC on WifiNanManager");
+                return;
+            }
+
+            mgr.updateSubscribe(mClientId, mSessionId, subscribeConfig);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
deleted file mode 100644
index 2e6d769..0000000
--- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.net.wifi.nan;
-
-import android.annotation.NonNull;
-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.
- *
- * @hide PROPOSED_NAN_API
- */
-public class WifiNanSubscribeSession extends WifiNanSession {
-    private static final String TAG = "WifiNanSubscribeSession";
-
-    /**
-     * {@hide}
-     */
-    public WifiNanSubscribeSession(WifiNanManager manager, int sessionId) {
-        super(manager, sessionId);
-    }
-
-    /**
-     * Re-configure the subscribe session. Note that the
-     * {@link WifiNanSessionCallback} is not replaced - the same listener used
-     * at creation is still used.
-     *
-     * @param subscribeConfig The configuration ({@link SubscribeConfig}) of the
-     *            subscribe session.
-     */
-    public void updateSubscribe(@NonNull SubscribeConfig subscribeConfig) {
-        if (mTerminated) {
-            Log.w(TAG, "updateSubscribe: called on terminated session");
-            return;
-        } else {
-            WifiNanManager mgr = mMgr.get();
-            if (mgr == null) {
-                Log.w(TAG, "updateSubscribe: called post GC on WifiNanManager");
-                return;
-            }
-
-            mgr.updateSubscribe(mSessionId, subscribeConfig);
-        }
-    }
-}
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>
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
new file mode 100644
index 0000000..5850fee
--- /dev/null
+++ b/wifi/tests/Android.mk
@@ -0,0 +1,61 @@
+# 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)
+
+# Make test APK
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+# This list is generated from the java source files in this module
+# The list is a comma separated list of class names with * matching zero or more characters.
+# Example:
+#   Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
+#   Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
+
+# Filter all src files to just java files
+local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
+# Transform java file names into full class names.
+# This only works if the class name matches the file name and the directory structure
+# matches the package.
+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
+# Utility variables to allow replacing a space with a comma
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+# These patterns will match all classes in this module and their inner classes.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+jacoco_include := android.net.wifi.*
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	android-support-test \
+	mockito-target-minus-junit4 \
+	frameworks-base-testutils \
+
+LOCAL_JAVA_LIBRARIES := \
+	android.test.runner \
+
+LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+
+include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
new file mode 100644
index 0000000..4eaca2b
--- /dev/null
+++ b/wifi/tests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?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="android.net.wifi.test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:label="WifiTestDummyLabel"
+                  android:name="WifiTestDummyName">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.net.wifi.test"
+        android:label="Frameworks Wifi API Tests">
+    </instrumentation>
+
+</manifest>
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
new file mode 100644
index 0000000..b418abd
--- /dev/null
+++ b/wifi/tests/README.md
@@ -0,0 +1,50 @@
+# Wifi Unit Tests
+This package contains unit tests for the android wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+frameworks/base/wifi/tests/runtests.sh
+```
+
+`runtests.sh` will build the test project and all of its dependencies and push the APK to the
+connected device. It will then run the tests on the device.
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+See below for a few example of options to limit which tests are run.
+See the
+[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
+for more details on the supported options.
+
+```
+runtests.sh -e package android.net.wifi
+runtests.sh -e class android.net.wifi.WifiScannerTest
+```
+
+If you manually build and push the test APK to the device you can run tests using
+
+```
+adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+```
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
new file mode 100755
index 0000000..ebcc2a2
--- /dev/null
+++ b/wifi/tests/runtests.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+echo "Running tests"
+
+set -e # fail early
+
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
+# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
+#      caller.
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
+
+set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
+
+adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java
new file mode 100644
index 0000000..0c73070
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/FakeKeys.java
@@ -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
+ */
+
+package android.net.wifi;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+/**
+ * A class containing test certificates.
+ */
+public class FakeKeys {
+    private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" +
+            "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" +
+            "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" +
+            "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" +
+            "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" +
+            "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" +
+            "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" +
+            "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" +
+            "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" +
+            "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" +
+            "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" +
+            "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING);
+
+    private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" +
+            "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" +
+            "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" +
+            "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" +
+            "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" +
+            "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" +
+            "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" +
+            "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" +
+            "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" +
+            "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" +
+            "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" +
+            "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+
+
+    private static X509Certificate loadCertificate(String blob) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8));
+
+            return (X509Certificate) certFactory.generateCertificate(stream);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
new file mode 100644
index 0000000..0d964b7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -0,0 +1,282 @@
+/*
+ * 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.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiEnterpriseConfig.Eap;
+import android.net.wifi.WifiEnterpriseConfig.Phase2;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.cert.X509Certificate;
+
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
+ */
+@SmallTest
+public class WifiEnterpriseConfigTest {
+    // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant.
+    public static final String KEYSTORE_URI = "keystore://";
+    public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+    public static final String KEYSTORES_URI = "keystores://";
+
+    private WifiEnterpriseConfig mEnterpriseConfig;
+
+    @Before
+    public void setUp() throws Exception {
+        mEnterpriseConfig = new WifiEnterpriseConfig();
+    }
+
+    @Test
+    public void testGetEmptyCaCertificate() {
+        // A newly-constructed WifiEnterpriseConfig object should have no CA certificate.
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to null explicitly.
+        mEnterpriseConfig.setCaCertificate(null);
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        // Setting CA certificate to null using setCaCertificates().
+        mEnterpriseConfig.setCaCertificates(null);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to zero-length array.
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[0]);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+    }
+
+    @Test
+    public void testSetGetSingleCaCertificate() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        mEnterpriseConfig.setCaCertificate(cert0);
+        assertEquals(mEnterpriseConfig.getCaCertificate(), cert0);
+    }
+
+    @Test
+    public void testSetGetMultipleCaCertificates() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        X509Certificate cert1 = FakeKeys.CA_CERT1;
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1});
+        X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+        assertEquals(result.length, 2);
+        assertTrue(result[0] == cert0 && result[1] == cert1);
+    }
+
+    @Test
+    public void testSaveSingleCaCertificateAlias() {
+        final String alias = "single_alias 0";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
+        assertEquals(getCaCertField(), CA_CERT_PREFIX + alias);
+    }
+
+    @Test
+    public void testLoadSingleCaCertificateAlias() {
+        final String alias = "single_alias 1";
+        setCaCertField(CA_CERT_PREFIX + alias);
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 1);
+        assertEquals(aliases[0], alias);
+    }
+
+    @Test
+    public void testSaveMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1});
+        assertEquals(getCaCertField(), String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+    }
+
+    @Test
+    public void testLoadMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        setCaCertField(String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 2);
+        assertEquals(aliases[0], alias0);
+        assertEquals(aliases[1], alias1);
+    }
+
+    private String getCaCertField() {
+        return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY);
+    }
+
+    private void setCaCertField(String value) {
+        mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value);
+    }
+
+    // Retrieves the value for a specific key supplied to wpa_supplicant.
+    private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver {
+        private String mValue = null;
+        private String mKey;
+
+        SupplicantConfigExtractor(String key) {
+            mKey = key;
+        }
+
+        @Override
+        public boolean saveValue(String key, String value) {
+            if (key.equals(mKey)) {
+                mValue = value;
+            }
+            return true;
+        }
+
+        public String getValue() {
+            return mValue;
+        }
+    }
+
+    private String getSupplicantEapMethod() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.EAP_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    private String getSupplicantPhase2Method() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.PHASE2_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    /** Verifies the default value for EAP outer and inner methods */
+    @Test
+    public void eapInnerDefault() {
+        assertEquals(null, getSupplicantEapMethod());
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verifies that the EAP inner method is reset when we switch to TLS */
+    @Test
+    public void eapPhase2MethodForTls() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to another type which supports a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to TLS which does not support a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TLS);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */
+    @Test
+    public void eapPhase2None() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the phase2 method to NONE and ensure the value is cleared.
+        mEnterpriseConfig.setPhase2Method(Phase2.NONE);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */
+    @Test
+    public void peapGtcToTtls() {
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */
+    @Test
+    public void ttlsGtcToPeap() {
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the copy constructor preseves the inner method information. */
+    @Test
+    public void copyConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
+    @Test
+    public void parcelConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        Parcel parcel = Parcel.obtain();
+        enterpriseConfig.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
+        mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verifies proper operation of the getKeyId() method. */
+    @Test
+    public void getKeyId() {
+        assertEquals("NULL", mEnterpriseConfig.getKeyId(null));
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig));
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig));
+    }
+
+    /** Verifies that passwords are not displayed in toString. */
+    @Test
+    public void passwordNotInToString() {
+        String password = "supersecret";
+        mEnterpriseConfig.setPassword(password);
+        assertFalse(mEnterpriseConfig.toString().contains(password));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
new file mode 100644
index 0000000..a829eb9
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.validateMockitoUsage;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiScanner.BssidInfo;
+import android.net.wifi.WifiScanner.BssidListener;
+import android.os.Handler;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.util.test.BidirectionalAsyncChannelServer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiScanner}.
+ */
+@SmallTest
+public class WifiScannerTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private IWifiScanner mService;
+    @Mock
+    private BssidListener mBssidListener;
+
+    private WifiScanner mWifiScanner;
+    private TestLooper mLooper;
+    private Handler mHandler;
+
+    /**
+     * Setup before tests.
+     */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLooper = new TestLooper();
+        mHandler = mock(Handler.class);
+        BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
+                mContext, mLooper.getLooper(), mHandler);
+        when(mService.getMessenger()).thenReturn(server.getMessenger());
+        mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
+        mLooper.dispatchAll();
+    }
+
+    /**
+     * Clean up after tests.
+     */
+    @After
+    public void cleanup() {
+        validateMockitoUsage();
+    }
+
+    private void verifySetHotlistMessage(Handler handler) {
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture());
+        assertEquals("message.what is not CMD_SET_HOTLIST",
+                WifiScanner.CMD_SET_HOTLIST,
+                messageCaptor.getValue().what);
+    }
+
+    /**
+     * Test duplicate listeners for bssid tracking.
+     */
+    @Test
+    public void testStartTrackingBssidsDuplicateListeners() throws Exception {
+        BssidInfo[] bssids = new BssidInfo[] {
+                new BssidInfo()
+        };
+
+        // First start tracking succeeds.
+        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+        mLooper.dispatchAll();
+        verifySetHotlistMessage(mHandler);
+
+        // Second start tracking should fail.
+        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+        mLooper.dispatchAll();
+        verify(mBssidListener).onFailure(eq(WifiScanner.REASON_DUPLICATE_REQEUST), anyString());
+    }
+}